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