#ifdef STATIC /* Pre-boot environment: included */ /* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots * errors about console_printk etc... on ARM */ #define _LINUX_KERNEL_H #include #include "zlib_inflate/inftrees.c" #include "zlib_inflate/inffast.c" #include "zlib_inflate/inflate.c" #else /* STATIC */ /* initramfs et al: linked */ #define MALLOC malloc #define FREE free #include #include #include #include "zlib_inflate/inftrees.h" #include "zlib_inflate/inffast.h" #include "zlib_inflate/inflate.h" #include "zlib_inflate/infutil.h" #endif /* STATIC */ #include #define GZIP_IOBUF_SIZE (16*1024) static int nofill(void *buffer, unsigned int len) { return -1; } /* Included from initramfs et al code */ int gunzip(unsigned char *buf, int len, int(*fill)(void*, unsigned int), int(*flush)(void*, unsigned int), unsigned char *out_buf, int *pos, void(*error)(char *x)) { u8 *zbuf; struct z_stream_s *strm; int rc; size_t out_len; rc = -1; if (flush) { out_len = 0x8000; /* 32 K */ out_buf = MALLOC(out_len); } else { out_len = 0x7fffffff; /* no limit */ } if (!out_buf) { error("Out of memory while allocating output buffer"); goto gunzip_nomem1; } if (buf) zbuf = buf; else { zbuf = MALLOC(GZIP_IOBUF_SIZE); len = 0; } if (!zbuf) { error("Out of memory while allocating input buffer"); goto gunzip_nomem2; } strm = MALLOC(sizeof(*strm)); if (strm == NULL) { error("Out of memory while allocating z_stream"); goto gunzip_nomem3; } strm->workspace = MALLOC(flush ? zlib_inflate_workspacesize() : sizeof(struct inflate_state)); if (strm->workspace == NULL) { error("Out of memory while allocating workspace"); goto gunzip_nomem4; } if (!fill) fill = nofill; if (len == 0) len = fill(zbuf, GZIP_IOBUF_SIZE); /* verify the gzip header */ if (len < 10 || zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) { if (pos) *pos = 0; error("Not a gzip file"); goto gunzip_5; } /* skip over gzip header (1f,8b,08... 10 bytes total + * possible asciz filename) */ strm->next_in = zbuf + 10; strm->avail_in = len - 10; /* skip over asciz filename */ if (zbuf[3] & 0x8) { do { /* * If the filename doesn't fit into the buffer, * the file is very probably corrupt. Don't try * to read more data. */ if (strm->avail_in == 0) { error("header error"); goto gunzip_5; } --strm->avail_in; } while (*strm->next_in++); } strm->next_out = out_buf; strm->avail_out = out_len; rc = zlib_inflateInit2(strm, -MAX_WBITS); if (!flush) { WS(strm)->inflate_state.wsize = 0; WS(strm)->inflate_state.window = NULL; } while (rc == Z_OK) { if (strm->avail_in == 0) { /* TODO: handle case where both pos and fill are set */ len = fill(zbuf, GZIP_IOBUF_SIZE); if (len < 0) { rc = -1; error("read error"); break; } strm->next_in = zbuf; strm->avail_in = len; } rc = zlib_inflate(strm, 0); /* Write any data generated */ if (flush && strm->next_out > out_buf) { int l = strm->next_out - out_buf; if (l != flush(out_buf, l)) { rc = -1; error("write error"); break; } strm->next_out = out_buf; strm->avail_out = out_len; } /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ if (rc == Z_STREAM_END) { rc = 0; break; } else if (rc != Z_OK) { error("uncompression error"); rc = -1; } } zlib_inflateEnd(strm); if (pos) /* add + 8 to skip over trailer */ *pos = strm->next_in - zbuf+8; gunzip_5: FREE(strm->workspace); gunzip_nomem4: FREE(strm); gunzip_nomem3: if (!buf) FREE(zbuf); gunzip_nomem2: if (flush) FREE(out_buf); gunzip_nomem1: return rc; /* returns Z_OK (0) if successful */ } int deflate_decompress(struct z_stream_s *stream, const u8 *src, unsigned int slen, u8 *dst, unsigned int *dlen) { int ret = 0; ret = zlib_inflateReset(stream); if (ret != Z_OK) { ret = -EINVAL; goto out; } stream->next_in = (u8 *)src; stream->avail_in = slen; stream->next_out = (u8 *)dst; stream->avail_out = *dlen; ret = zlib_inflate(stream, Z_SYNC_FLUSH); /* * Work around a bug in zlib, which sometimes wants to taste an extra * byte when being used in the (undocumented) raw deflate mode. * (From USAGI). */ if (ret == Z_OK && !stream->avail_in && stream->avail_out) { u8 zerostuff = 0; stream->next_in = &zerostuff; stream->avail_in = 1; ret = zlib_inflate(stream, Z_FINISH); } if (ret != Z_STREAM_END) { ret = -EINVAL; goto out; } ret = 0; *dlen = stream->total_out; out: return ret; } #define decompress gunzip