📄 gzio.c
字号:
/* gzio.c -- IO on .gz files * Copyright (C) 1995-1998 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h * * This has been seriously re-arranged for use within MicroMonitor. * The majority of the rework is to strip out unnecessary parts because this * will reside in flash space. Also, there is no file system interface, all * decompression is done from one point in memory to another point in memory. */#include "config.h"#include "tfs.h"#include "tfsprivate.h"#include "genlib.h"#include "zutil.h"struct internal_state {int dummy;}; /* for buggy compilers */#ifndef Z_BUFSIZE# ifdef MAXSEG_64K# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */# else# define Z_BUFSIZE 16384# endif#endif#ifndef Z_PRINTF_BUFSIZE# define Z_PRINTF_BUFSIZE 4096#endif#define ALLOC(size) malloc(size)#define TRYFREE(p) {if (p) free((char *)p);}static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header *//* gzip flag byte */#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */#define ORIG_NAME 0x08 /* bit 3 set: original file name present */#define COMMENT 0x10 /* bit 4 set: file comment present */#define RESERVED 0xE0 /* bits 5..7: reserved */typedef struct gz_stream { z_stream stream; int z_err; /* error code for last stream operation */ int z_eof; /* set if end of input file */ Byte *outbuf; /* output buffer */ uLong crc; /* crc32 of uncompressed data */ char *msg; /* error message */ int transparent; /* 1 if input file is not a .gz file */ char mode; /* 'w' or 'r' */} gz_stream;local int get_byte OF((gz_stream *s));local void check_header OF((gz_stream *s));local int destroy OF((gz_stream *s));local uLong getLong OF((gz_stream *s));/* =========================================================================== gzInit(): Rewritten (from gzopen()) to support only decompression of data in memory. The next_in member points directly to the compressed data and avail_in is the number of bytes remaining. Things get simpler because of the removal of the file system interface as well as the "only decompression" mode.*/gz_stream *gzInit(compressed_data, size)int size;unsigned char *compressed_data;{ int err; gz_stream *s; s = (gz_stream *)ALLOC(sizeof(gz_stream)); if (!s) return Z_NULL; s->stream.zalloc = (alloc_func)0; s->stream.zfree = (free_func)0; s->stream.opaque = (voidpf)0; s->stream.next_in = compressed_data; s->stream.next_out = s->outbuf = Z_NULL; s->stream.avail_in = size; s->stream.avail_out = 0; s->z_err = Z_OK; s->z_eof = 0; s->crc = zcrc32(0L, Z_NULL, 0); s->msg = NULL; s->transparent = 0; s->mode = 'r'; err = inflateInit2(&(s->stream), -MAX_WBITS); /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are * present after the compressed stream. */ if (err != Z_OK) { destroy(s); return((gz_stream *)Z_NULL); } s->stream.avail_out = Z_BUFSIZE; check_header(s); /* skip the .gz header */ return(s);}/* =========================================================================== get_byte() Simple now because we assume that avail_in is pointing to the number of bytes in the source buffer that are remaining to be decompressed and next_in is the pointer to the next byte to be retrieved from the buffer.*/local intget_byte(s)gz_stream *s;{ if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { s->z_eof = 1; return EOF; } s->stream.avail_in--; return *(s->stream.next_in)++;}/* =========================================================================== check_header(): Check the gzip header of a gz_stream opened for reading. Set the stream mode to transparent if the gzip magic header is not present; set s->err to Z_DATA_ERROR if the magic header is present but the rest of the header is incorrect. IN assertion: the stream s has already been created sucessfully; s->stream.avail_in is zero for the first time, but may be non-zero for concatenated .gz files.*/local voidcheck_header(s)gz_stream *s;{ int method; /* method byte */ int flags; /* flags byte */ uInt len; int c; /* Check the gzip magic header */ for (len = 0; len < 2; len++) { c = get_byte(s); if (c != gz_magic[len]) { if (len != 0) { s->stream.avail_in++; s->stream.next_in--; } if (c != EOF) { s->stream.avail_in++; s->stream.next_in--; s->transparent = 1; } s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; return; } } method = get_byte(s); flags = get_byte(s); if (method != Z_DEFLATED || (flags & RESERVED) != 0) { s->z_err = Z_DATA_ERROR; return; } /* Discard time, xflags and OS code: */ for (len = 0; len < 6; len++) (void)get_byte(s); if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ len = (uInt)get_byte(s); len += ((uInt)get_byte(s))<<8; /* len is garbage if EOF but the loop below will quit anyway */ while (len-- != 0 && get_byte(s) != EOF) ; } if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ while ((c = get_byte(s)) != 0 && c != EOF) ; } if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ for (len = 0; len < 2; len++) (void)get_byte(s); } s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;}/* =========================================================================== destroy(): Cleanup then free the given gz_stream. Return a zlib error code. Try freeing in the reverse order of allocations.*/local intdestroy (s)gz_stream *s;{ int err = Z_OK; if (!s) return Z_STREAM_ERROR; TRYFREE(s->msg); if (s->stream.state != NULL) err = inflateEnd(&(s->stream)); if (s->z_err < 0) err = s->z_err; TRYFREE(s->outbuf); TRYFREE(s); return err;}/* =========================================================================== gzRead(): Reads the given number of uncompressed bytes from the compressed file. gzRead returns the number of bytes actually read (0 for end of file).*/int ZEXPORTgzRead (file, buf, len)gzFile file;voidp buf;unsigned len;{ gz_stream *s = (gz_stream*)file; Bytef *start = (Bytef*)buf; /* starting point for crc computation */ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; if (s->z_err == Z_STREAM_END) return 0; /* EOF */ next_out = (Byte*)buf; s->stream.next_out = (Bytef*)buf; s->stream.avail_out = len; while (s->stream.avail_out != 0) { if (s->transparent) { /* Copy first the lookahead bytes: */ uInt n = s->stream.avail_in; if (n > s->stream.avail_out) n = s->stream.avail_out; if (n > 0) { zmemcpy(s->stream.next_out, s->stream.next_in, n); next_out += n; s->stream.next_out = next_out; s->stream.next_in += n; s->stream.avail_out -= n; s->stream.avail_in -= n; } if (s->stream.avail_out > 0) { int i, c; Byte *next; next = next_out; for(i=0;i<(int)(s->stream.avail_out);i++) { c = get_byte(s); if (c == EOF) break; *next_out++ = (Byte)c; s->stream.avail_out--; } } len -= s->stream.avail_out; s->stream.total_in += (uLong)len; s->stream.total_out += (uLong)len; if (len == 0) s->z_eof = 1; return (int)len; } s->z_err = inflate(&(s->stream), Z_NO_FLUSH); if (s->z_err == Z_STREAM_END) { /* Check CRC and original size */ s->crc = zcrc32(s->crc, start, (uInt)(s->stream.next_out - start)); start = s->stream.next_out; if (getLong(s) != s->crc) { s->z_err = Z_DATA_ERROR; } else { (void)getLong(s); /* The uncompressed length returned by above getlong() may * be different from s->stream.total_out) in case of * concatenated .gz files. Check for such files: */ check_header(s); if (s->z_err == Z_OK) { uLong total_in = s->stream.total_in; uLong total_out = s->stream.total_out; inflateReset(&(s->stream)); s->stream.total_in = total_in; s->stream.total_out = total_out; s->crc = zcrc32(0L, Z_NULL, 0); } } } if (s->z_err != Z_OK || s->z_eof) break; } s->crc = zcrc32(s->crc, start, (uInt)(s->stream.next_out - start)); return (int)(len - s->stream.avail_out);}/* =========================================================================== getLong(): Reads a long in LSB order from the given gz_stream. Sets z_err in case of error.*/local uLonggetLong (s)gz_stream *s;{ uLong x = (uLong)get_byte(s); int c; x += ((uLong)get_byte(s))<<8; x += ((uLong)get_byte(s))<<16; c = get_byte(s); if (c == EOF) s->z_err = Z_DATA_ERROR; x += ((uLong)c)<<24; return x;}/* =========================================================================== unZip(): This is the front end to the whole zlib decompressor. It is a chop-up of the original minigzip.c code that came with the zlib source.*/intunZip(char *src, int srclen, char *dest, int destlen){ int len; gz_stream *s; if ((s = gzInit(src,srclen)) == Z_NULL) { printf("gzInit(0x%lx,%d) failed!\n",(ulong)src,srclen); return(-1); } len = gzRead(s,dest,destlen); if (len < 0) printf("gzRead() returned %d\n",len); destroy(s); return(len);}char *UnzipHelp[] = { "Decompress block of memory to some other block of memory.", "-[s:d:]", " -s {source} filename or 'addr,len' (required option)", " -d {destination} 'addr[,len]' (default=APPRAMBASE,99999999)", "", "Works in conjunction with zlib's minigzip on host.", 0,};/* Unzip(): Access ZLIB decompressor from monitor command line.*/intUnzip(int argc,char *argv[]){ extern char *optarg; char *asc_src, *asc_dst, *comma, *src, *dest; int opt, tot; ulong srclen, destlen; destlen = 99999999; dest = (char *)getAppRamStart(); asc_src = asc_dst = (char *)0; while((opt=getopt(argc,argv,"d:s:")) != -1) { switch(opt) { case 's': asc_src = optarg; break; case 'd': asc_dst = optarg; break; default: return(0); } } if (!asc_src) return(-1); comma = strchr(asc_src,','); if (comma) { *comma = 0; src = (char *)strtoul(asc_src,(char **)0,0); srclen = strtoul(comma+1,(char **)0,0); } else { TFILE *tfp; tfp = tfsstat(asc_src); if (!tfp) return(-1); src = TFS_BASE(tfp); srclen = TFS_SIZE(tfp); } if (asc_dst) { comma = strchr(asc_dst,','); if (comma) { *comma = 0; destlen = strtoul(comma+1,(char **)0,0); } dest = (char *)strtoul(asc_dst,(char **)0,0); } tot = unZip(src,srclen,dest,destlen); printf("Decompressed %ld bytes from 0x%lx to %d bytes at 0x%lx.\n", srclen,(ulong)src,tot,(ulong)dest); return(0);}/* Front end to the rest of the unZip() stuff... Return the size of the decompressed data or -1 if failure. The same front API end is available if unpack is used instead of unzip.*/intdecompress(char *src,int srclen, char *dest){ return(unZip(src,srclen,dest,99999999));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -