lib: Add decompression function

Add decompression function to decompress gzip package by using
zlib APIs. Modification for Zlib success compile in LK.

Change-Id: Ibc840fbc1094c0126ddc13d6422d06f5e196be7a
diff --git a/lib/zlib_inflate/decompress.c b/lib/zlib_inflate/decompress.c
new file mode 100644
index 0000000..692ccfa
--- /dev/null
+++ b/lib/zlib_inflate/decompress.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define NO_GZIP
+
+#include "zutil.h"
+
+#ifdef DYNAMIC_CRC_TABLE
+#include "crc32.h"
+#endif
+
+#include "zconf.h"
+#include "zlib.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+#include "decompress.h"
+#include <sys/types.h>	/* for size_t */
+#include <string.h>
+#include <debug.h>
+#include <malloc.h>
+
+#define GZIP_HEADER_LEN 10
+#define GZIP_FILENAME_LIMIT 256
+
+static void zlib_free(voidpf qpaque, void *addr)
+{
+	return free(addr);
+}
+
+static void *zlib_alloc(voidpf qpaque, uInt items, size_t size)
+{
+	return malloc(items * size);
+}
+
+/* decompress gzip file "in_buf", return 0 if decompressed successful,
+ * return -1 if decompressed failed.
+ * in_buf - input gzip file
+ * in_len - input the length file
+ * out_buf - output the decompressed data
+ * out_buf_len - the available length of out_buf
+ * pos - position of the end of gzip file
+ * out_len - the length of decompressed data
+ */
+int decompress(unsigned char *in_buf, unsigned int in_len,
+		       unsigned char *out_buf,
+		       unsigned int out_buf_len,
+		       unsigned int *pos,
+		       unsigned int *out_len) {
+	struct z_stream_s *stream;
+	int rc = -1;
+	int i;
+
+	if (in_len < GZIP_HEADER_LEN) {
+		dprintf(INFO, "the input data is not a gzip package.\n");
+		return rc;
+	}
+	if (out_buf_len < in_len) {
+		dprintf(INFO, "the avaiable length of out_buf is not enough.\n");
+		return rc;
+	}
+
+	stream = malloc(sizeof(*stream));
+	if (stream == NULL) {
+		dprintf(INFO, "allocating z_stream failed.\n");
+		return rc;
+	}
+
+	stream->zalloc = zlib_alloc;
+	stream->zfree = zlib_free;
+	stream->next_out = out_buf;
+	stream->avail_out = out_buf_len;
+
+	/* skip over gzip header */
+	stream->next_in = in_buf + GZIP_HEADER_LEN;
+	stream->avail_in = out_buf_len - GZIP_HEADER_LEN;
+	/* skip over asciz filename */
+	if (in_buf[3] & 0x8) {
+		for (i = 0; i < GZIP_FILENAME_LIMIT && *stream->next_in++; i++) {
+			if (stream->avail_in == 0) {
+				dprintf(INFO, "header error");
+				goto gunzip_end;
+			}
+			--stream->avail_in;
+		}
+	}
+
+	rc = inflateInit2(stream, -MAX_WBITS);
+
+	if (rc == Z_OK) {
+		if (stream->avail_in == 0) {
+			stream->next_in = in_buf;
+			stream->avail_in = out_buf_len;
+		}
+		rc = inflate(stream, 0);
+
+		/* Z_STREAM_END is "we unpacked it all" */
+		if (rc == Z_STREAM_END) {
+			rc = 0;
+		} else if (rc != Z_OK) {
+			dprintf(INFO, "uncompression error");
+			rc = -1;
+		}
+	}
+
+	inflateEnd(stream);
+	if (pos)
+		/* alculation the length of the compressed package */
+		*pos = stream->next_in - in_buf + 8;
+
+	if (out_len)
+		*out_len = stream->total_out;
+
+gunzip_end:
+	free(stream);
+	return rc; /* returns 0 if decompressed successful */
+}
+
+/* check if the input "buf" file was a gzip package.
+ * Return true if the input "buf" is a gzip package.
+ */
+int is_gzip_package(unsigned char *buf, unsigned int len)
+{
+	if (len < 10 || !buf || buf[0] != 0x1f ||
+		buf[1] != 0x8b || buf[2] != 0x08)
+	{
+		dprintf(INFO, "Not a gzip file\n");
+		return false;
+	}
+
+	return true;
+}
diff --git a/lib/zlib_inflate/decompress.h b/lib/zlib_inflate/decompress.h
new file mode 100644
index 0000000..1cdd011
--- /dev/null
+++ b/lib/zlib_inflate/decompress.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of The Linux Foundation, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLATFORM_MSM_SHARED_DECOMPRESS_H
+#define __PLATFORM_MSM_SHARED_DECOMPRESS_H
+
+int is_gzip_package(unsigned char *, unsigned int);
+
+int decompress(unsigned char *, unsigned int, unsigned char *, unsigned int, unsigned int *, unsigned int *);
+#endif /* __PLATFORM_MSM_SHARED_DECOMPRESS_H */
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index 870f89b..e341300 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -80,6 +80,8 @@
  * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
  */
 
+#define NO_GZIP
+
 #include "zutil.h"
 #include "inftrees.h"
 #include "inflate.h"
diff --git a/lib/zlib_inflate/rules.mk b/lib/zlib_inflate/rules.mk
new file mode 100755
index 0000000..96d2383
--- /dev/null
+++ b/lib/zlib_inflate/rules.mk
@@ -0,0 +1,9 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+OBJS += \
+	$(LOCAL_DIR)/zutil.o \
+	$(LOCAL_DIR)/adler32.o \
+	$(LOCAL_DIR)/inftrees.o \
+	$(LOCAL_DIR)/inflate.o \
+	$(LOCAL_DIR)/inffast.o \
+	$(LOCAL_DIR)/decompress.o
diff --git a/lib/zlib_inflate/zlib.h b/lib/zlib_inflate/zlib.h
index 3e0c767..8da7aa5 100644
--- a/lib/zlib_inflate/zlib.h
+++ b/lib/zlib_inflate/zlib.h
@@ -1114,7 +1114,7 @@
      7.6: size of z_off_t
 
     Compiler, assembler, and debug options:
-     8: DEBUG
+     8: DEBUG/ZLIB_DEBUG
      9: ASMV or ASMINF -- use ASM code
      10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
      11: 0 (reserved)
diff --git a/lib/zlib_inflate/zutil.c b/lib/zlib_inflate/zutil.c
index 23d2ebe..5f21a24 100644
--- a/lib/zlib_inflate/zutil.c
+++ b/lib/zlib_inflate/zutil.c
@@ -7,7 +7,8 @@
 
 #include "zutil.h"
 #ifndef Z_SOLO
-#  include "gzguts.h"
+/* Comment because LK does not contain gzguts.h */
+// #  include "gzguts.h"
 #endif
 
 #ifndef NO_DUMMY_DECL
@@ -61,7 +62,8 @@
     case 8:     flags += 2 << 6;        break;
     default:    flags += 3 << 6;
     }
-#ifdef DEBUG
+/* replace DEBUG with ZLIB_DEBUG since the former is already used in lk */
+#ifdef ZLIB_DEBUG
     flags += 1 << 8;
 #endif
 #if defined(ASMV) || defined(ASMINF)
@@ -115,7 +117,7 @@
     return flags;
 }
 
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
 
 #  ifndef verbose
 #    define verbose 0
diff --git a/lib/zlib_inflate/zutil.h b/lib/zlib_inflate/zutil.h
index 24ab06b..4de61bb 100644
--- a/lib/zlib_inflate/zutil.h
+++ b/lib/zlib_inflate/zutil.h
@@ -216,7 +216,8 @@
 #endif
 
 /* Diagnostic functions */
-#ifdef DEBUG
+/* replace DEBUG with ZLIB_DEBUG since the former is already used in lk. */
+#ifdef ZLIB_DEBUG
 #  include <stdio.h>
    extern int ZLIB_INTERNAL z_verbose;
    extern void ZLIB_INTERNAL z_error OF((char *m));