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