gunzip.c revision 23a0898a
1/* $Xorg: gunzip.c,v 1.3 2000/08/17 19:46:37 cpqbld Exp $ */ 2/* lib/font/fontfile/gunzip.c 3 written by Mark Eichin <eichin@kitten.gen.ma.us> September 1996. 4 intended for inclusion in X11 public releases. */ 5/* $XFree86: xc/lib/font/fontfile/gunzip.c,v 1.4 2000/09/19 12:46:08 eich Exp $ */ 6 7#ifdef HAVE_CONFIG_H 8#include <config.h> 9#endif 10#include <X11/fonts/fontmisc.h> 11#include <X11/fonts/bufio.h> 12#include <zlib.h> 13 14typedef struct _xzip_buf { 15 z_stream z; 16 int zstat; 17 BufChar b[BUFFILESIZE]; 18 BufChar b_in[BUFFILESIZE]; 19 BufFilePtr f; 20} xzip_buf; 21 22static int BufZipFileClose ( BufFilePtr f, int flag ); 23static int BufZipFileFill ( BufFilePtr f ); 24static int BufZipFileSkip ( BufFilePtr f, int c ); 25static int BufCheckZipHeader ( BufFilePtr f ); 26 27BufFilePtr 28BufFilePushZIP (BufFilePtr f) 29{ 30 xzip_buf *x; 31 32 x = (xzip_buf *) xalloc (sizeof (xzip_buf)); 33 if (!x) return 0; 34 /* these are just for raw calloc/free */ 35 x->z.zalloc = Z_NULL; 36 x->z.zfree = Z_NULL; 37 x->z.opaque = Z_NULL; 38 x->f = f; 39 40 /* force inflateInit to allocate it's own history buffer */ 41 x->z.next_in = Z_NULL; 42 x->z.next_out = Z_NULL; 43 x->z.avail_in = x->z.avail_out = 0; 44 45 /* using negative windowBits sets "nowrap" mode, which turns off 46 zlib header checking [undocumented, for gzip compatibility only?] */ 47 x->zstat = inflateInit2(&(x->z), -MAX_WBITS); 48 if (x->zstat != Z_OK) { 49 xfree(x); 50 return 0; 51 } 52 53 /* now that the history buffer is allocated, we provide the data buffer */ 54 x->z.next_out = x->b; 55 x->z.avail_out = BUFFILESIZE; 56 x->z.next_out = x->b_in; 57 x->z.avail_in = 0; 58 59 if (BufCheckZipHeader(x->f)) { 60 xfree(x); 61 return 0; 62 } 63 64 return BufFileCreate((char *)x, 65 BufZipFileFill, 66 0, 67 BufZipFileSkip, 68 BufZipFileClose); 69} 70 71static int 72BufZipFileClose(BufFilePtr f, int flag) 73{ 74 xzip_buf *x = (xzip_buf *)f->private; 75 inflateEnd (&(x->z)); 76 BufFileClose (x->f, flag); 77 xfree (x); 78 return 1; 79} 80 81/* here's the real work. 82 -- we need to put stuff in f.buffer, update f.left and f.bufp, 83 then return the first byte (or BUFFILEEOF). 84 -- to do this, we need to get stuff into avail_in, and next_in, 85 and call inflate appropriately. 86 -- we may also need to add CRC maintenance - if inflate tells us 87 Z_STREAM_END, we then have 4bytes CRC and 4bytes length... 88 gzio.c:gzread shows most of the mechanism. 89 */ 90static int 91BufZipFileFill (BufFilePtr f) 92{ 93 xzip_buf *x = (xzip_buf *)f->private; 94 95 /* we only get called when left == 0... */ 96 /* but just in case, deal */ 97 if (f->left >= 0) { 98 f->left--; 99 return *(f->bufp++); 100 } 101 /* did we run out last time? */ 102 switch (x->zstat) { 103 case Z_OK: 104 break; 105 case Z_STREAM_END: 106 case Z_DATA_ERROR: 107 case Z_ERRNO: 108 f->left = 0; 109 return BUFFILEEOF; 110 default: 111 return BUFFILEEOF; 112 } 113 /* now we work to consume what we can */ 114 /* let zlib know what we can handle */ 115 x->z.next_out = x->b; 116 x->z.avail_out = BUFFILESIZE; 117 118 /* and try to consume all of it */ 119 while (x->z.avail_out > 0) { 120 /* if we don't have anything to work from... */ 121 if (x->z.avail_in == 0) { 122 /* ... fill the z buf from underlying file */ 123 int i, c; 124 for (i = 0; i < sizeof(x->b_in); i++) { 125 c = BufFileGet(x->f); 126 if (c == BUFFILEEOF) break; 127 x->b_in[i] = c; 128 } 129 x->z.avail_in += i; 130 x->z.next_in = x->b_in; 131 } 132 /* so now we have some output space and some input data */ 133 x->zstat = inflate(&(x->z), Z_NO_FLUSH); 134 /* the inflation output happens in the f buffer directly... */ 135 if (x->zstat == Z_STREAM_END) { 136 /* deal with EOF, crc */ 137 break; 138 } 139 if (x->zstat != Z_OK) { 140 break; 141 } 142 } 143 f->bufp = x->b; 144 f->left = BUFFILESIZE - x->z.avail_out; 145 146 if (f->left >= 0) { 147 f->left--; 148 return *(f->bufp++); 149 } else { 150 return BUFFILEEOF; 151 } 152} 153 154/* there should be a BufCommonSkip... */ 155static int 156BufZipFileSkip (BufFilePtr f, int c) 157{ 158 /* BufFileRawSkip returns the count unchanged. 159 BufCompressedSkip returns 0. 160 That means it probably never gets called... */ 161 int retval = c; 162 while(c--) { 163 int get = BufFileGet(f); 164 if (get == BUFFILEEOF) return get; 165 } 166 return retval; 167} 168 169/* now we need to duplicate check_header */ 170/* contents: 171 0x1f, 0x8b -- magic number 172 1 byte -- method (Z_DEFLATED) 173 1 byte -- flags (mask with RESERVED -> fail) 174 4 byte -- time (discard) 175 1 byte -- xflags (discard) 176 1 byte -- "os" code (discard) 177 [if flags & EXTRA_FIELD: 178 2 bytes -- LSBfirst length n 179 n bytes -- extra data (discard)] 180 [if flags & ORIG_NAME: 181 n bytes -- null terminated name (discard)] 182 [if flags & COMMENT: 183 n bytes -- null terminated comment (discard)] 184 [if flags & HEAD_CRC: 185 2 bytes -- crc of headers? (discard)] 186 */ 187 188/* gzip flag byte -- from gzio.c */ 189#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 190#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ 191#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 192#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 193#define COMMENT 0x10 /* bit 4 set: file comment present */ 194#define RESERVED 0xE0 /* bits 5..7: reserved */ 195 196#define GET(f) do {c = BufFileGet(f); if (c == BUFFILEEOF) return c;} while(0) 197static int 198BufCheckZipHeader(BufFilePtr f) 199{ 200 int c, flags; 201 GET(f); if (c != 0x1f) return 1; /* magic 1 */ 202 GET(f); if (c != 0x8b) return 2; /* magic 2 */ 203 GET(f); if (c != Z_DEFLATED) return 3; /* method */ 204 GET(f); if (c & RESERVED) return 4; /* reserved flags */ 205 flags = c; 206 GET(f); GET(f); GET(f); GET(f); /* time */ 207 GET(f); /* xflags */ 208 GET(f); /* os code */ 209 if (flags & EXTRA_FIELD) { 210 int len; 211 GET(f); len = c; 212 GET(f); len += (c<<8); 213 while (len-- >= 0) { 214 GET(f); 215 } 216 } 217 if (flags & ORIG_NAME) { 218 do { GET(f); } while (c != 0); 219 } 220 if (flags & COMMENT) { 221 do { GET(f); } while (c != 0); 222 } 223 if (flags & HEAD_CRC) { 224 GET(f); GET(f); /* header crc */ 225 } 226 return 0; 227} 228