123a0898aSmrg/* lib/font/fontfile/gunzip.c 223a0898aSmrg written by Mark Eichin <eichin@kitten.gen.ma.us> September 1996. 323a0898aSmrg intended for inclusion in X11 public releases. */ 423a0898aSmrg 523a0898aSmrg#ifdef HAVE_CONFIG_H 623a0898aSmrg#include <config.h> 723a0898aSmrg#endif 823a0898aSmrg#include <X11/fonts/fontmisc.h> 923a0898aSmrg#include <X11/fonts/bufio.h> 1023a0898aSmrg#include <zlib.h> 1123a0898aSmrg 1223a0898aSmrgtypedef struct _xzip_buf { 1323a0898aSmrg z_stream z; 1423a0898aSmrg int zstat; 1523a0898aSmrg BufChar b[BUFFILESIZE]; 1623a0898aSmrg BufChar b_in[BUFFILESIZE]; 1723a0898aSmrg BufFilePtr f; 1823a0898aSmrg} xzip_buf; 1923a0898aSmrg 2023a0898aSmrgstatic int BufZipFileClose ( BufFilePtr f, int flag ); 2123a0898aSmrgstatic int BufZipFileFill ( BufFilePtr f ); 2223a0898aSmrgstatic int BufZipFileSkip ( BufFilePtr f, int c ); 2323a0898aSmrgstatic int BufCheckZipHeader ( BufFilePtr f ); 2423a0898aSmrg 2523a0898aSmrgBufFilePtr 2623a0898aSmrgBufFilePushZIP (BufFilePtr f) 2723a0898aSmrg{ 2823a0898aSmrg xzip_buf *x; 2923a0898aSmrg 307f7f5e4eSmrg x = malloc (sizeof (xzip_buf)); 3123a0898aSmrg if (!x) return 0; 3223a0898aSmrg /* these are just for raw calloc/free */ 3323a0898aSmrg x->z.zalloc = Z_NULL; 3423a0898aSmrg x->z.zfree = Z_NULL; 3523a0898aSmrg x->z.opaque = Z_NULL; 3623a0898aSmrg x->f = f; 3723a0898aSmrg 3823a0898aSmrg /* force inflateInit to allocate it's own history buffer */ 3923a0898aSmrg x->z.next_in = Z_NULL; 4023a0898aSmrg x->z.next_out = Z_NULL; 4123a0898aSmrg x->z.avail_in = x->z.avail_out = 0; 4223a0898aSmrg 4323a0898aSmrg /* using negative windowBits sets "nowrap" mode, which turns off 4423a0898aSmrg zlib header checking [undocumented, for gzip compatibility only?] */ 4523a0898aSmrg x->zstat = inflateInit2(&(x->z), -MAX_WBITS); 4623a0898aSmrg if (x->zstat != Z_OK) { 477f7f5e4eSmrg free(x); 4823a0898aSmrg return 0; 4923a0898aSmrg } 5023a0898aSmrg 5123a0898aSmrg /* now that the history buffer is allocated, we provide the data buffer */ 5223a0898aSmrg x->z.next_out = x->b; 5323a0898aSmrg x->z.avail_out = BUFFILESIZE; 5423a0898aSmrg x->z.next_out = x->b_in; 5523a0898aSmrg x->z.avail_in = 0; 5623a0898aSmrg 5723a0898aSmrg if (BufCheckZipHeader(x->f)) { 587f7f5e4eSmrg free(x); 5923a0898aSmrg return 0; 6023a0898aSmrg } 6123a0898aSmrg 6223a0898aSmrg return BufFileCreate((char *)x, 6323a0898aSmrg BufZipFileFill, 6423a0898aSmrg 0, 6523a0898aSmrg BufZipFileSkip, 6623a0898aSmrg BufZipFileClose); 6723a0898aSmrg} 6823a0898aSmrg 6941c30155Smrgstatic int 7023a0898aSmrgBufZipFileClose(BufFilePtr f, int flag) 7123a0898aSmrg{ 7223a0898aSmrg xzip_buf *x = (xzip_buf *)f->private; 7323a0898aSmrg inflateEnd (&(x->z)); 7423a0898aSmrg BufFileClose (x->f, flag); 757f7f5e4eSmrg free (x); 7623a0898aSmrg return 1; 7723a0898aSmrg} 7823a0898aSmrg 7941c30155Smrg/* here's the real work. 8023a0898aSmrg -- we need to put stuff in f.buffer, update f.left and f.bufp, 8123a0898aSmrg then return the first byte (or BUFFILEEOF). 8241c30155Smrg -- to do this, we need to get stuff into avail_in, and next_in, 8323a0898aSmrg and call inflate appropriately. 8423a0898aSmrg -- we may also need to add CRC maintenance - if inflate tells us 8523a0898aSmrg Z_STREAM_END, we then have 4bytes CRC and 4bytes length... 8623a0898aSmrg gzio.c:gzread shows most of the mechanism. 8723a0898aSmrg */ 8841c30155Smrgstatic int 8923a0898aSmrgBufZipFileFill (BufFilePtr f) 9023a0898aSmrg{ 9123a0898aSmrg xzip_buf *x = (xzip_buf *)f->private; 9223a0898aSmrg 9323a0898aSmrg /* we only get called when left == 0... */ 9423a0898aSmrg /* but just in case, deal */ 9523a0898aSmrg if (f->left >= 0) { 9623a0898aSmrg f->left--; 9723a0898aSmrg return *(f->bufp++); 9823a0898aSmrg } 9923a0898aSmrg /* did we run out last time? */ 10023a0898aSmrg switch (x->zstat) { 10123a0898aSmrg case Z_OK: 10223a0898aSmrg break; 10323a0898aSmrg case Z_STREAM_END: 10423a0898aSmrg case Z_DATA_ERROR: 10523a0898aSmrg case Z_ERRNO: 10623a0898aSmrg f->left = 0; 10723a0898aSmrg return BUFFILEEOF; 10823a0898aSmrg default: 10923a0898aSmrg return BUFFILEEOF; 11023a0898aSmrg } 11123a0898aSmrg /* now we work to consume what we can */ 11223a0898aSmrg /* let zlib know what we can handle */ 11323a0898aSmrg x->z.next_out = x->b; 11423a0898aSmrg x->z.avail_out = BUFFILESIZE; 11523a0898aSmrg 11623a0898aSmrg /* and try to consume all of it */ 11723a0898aSmrg while (x->z.avail_out > 0) { 11823a0898aSmrg /* if we don't have anything to work from... */ 11923a0898aSmrg if (x->z.avail_in == 0) { 12023a0898aSmrg /* ... fill the z buf from underlying file */ 12123a0898aSmrg int i, c; 12223a0898aSmrg for (i = 0; i < sizeof(x->b_in); i++) { 12323a0898aSmrg c = BufFileGet(x->f); 12423a0898aSmrg if (c == BUFFILEEOF) break; 12523a0898aSmrg x->b_in[i] = c; 12623a0898aSmrg } 12723a0898aSmrg x->z.avail_in += i; 12823a0898aSmrg x->z.next_in = x->b_in; 12923a0898aSmrg } 13023a0898aSmrg /* so now we have some output space and some input data */ 13123a0898aSmrg x->zstat = inflate(&(x->z), Z_NO_FLUSH); 13223a0898aSmrg /* the inflation output happens in the f buffer directly... */ 13323a0898aSmrg if (x->zstat == Z_STREAM_END) { 13423a0898aSmrg /* deal with EOF, crc */ 13523a0898aSmrg break; 13623a0898aSmrg } 13723a0898aSmrg if (x->zstat != Z_OK) { 13823a0898aSmrg break; 13923a0898aSmrg } 14023a0898aSmrg } 14123a0898aSmrg f->bufp = x->b; 14241c30155Smrg f->left = BUFFILESIZE - x->z.avail_out; 14323a0898aSmrg 14423a0898aSmrg if (f->left >= 0) { 14523a0898aSmrg f->left--; 14623a0898aSmrg return *(f->bufp++); 14723a0898aSmrg } else { 14823a0898aSmrg return BUFFILEEOF; 14923a0898aSmrg } 15023a0898aSmrg} 15123a0898aSmrg 15223a0898aSmrg/* there should be a BufCommonSkip... */ 15341c30155Smrgstatic int 15423a0898aSmrgBufZipFileSkip (BufFilePtr f, int c) 15523a0898aSmrg{ 15623a0898aSmrg /* BufFileRawSkip returns the count unchanged. 15723a0898aSmrg BufCompressedSkip returns 0. 15823a0898aSmrg That means it probably never gets called... */ 15923a0898aSmrg int retval = c; 16023a0898aSmrg while(c--) { 16123a0898aSmrg int get = BufFileGet(f); 16223a0898aSmrg if (get == BUFFILEEOF) return get; 16323a0898aSmrg } 16423a0898aSmrg return retval; 16523a0898aSmrg} 16623a0898aSmrg 16723a0898aSmrg/* now we need to duplicate check_header */ 16823a0898aSmrg/* contents: 16923a0898aSmrg 0x1f, 0x8b -- magic number 17023a0898aSmrg 1 byte -- method (Z_DEFLATED) 17123a0898aSmrg 1 byte -- flags (mask with RESERVED -> fail) 17223a0898aSmrg 4 byte -- time (discard) 17323a0898aSmrg 1 byte -- xflags (discard) 17423a0898aSmrg 1 byte -- "os" code (discard) 17523a0898aSmrg [if flags & EXTRA_FIELD: 17623a0898aSmrg 2 bytes -- LSBfirst length n 17723a0898aSmrg n bytes -- extra data (discard)] 17823a0898aSmrg [if flags & ORIG_NAME: 17923a0898aSmrg n bytes -- null terminated name (discard)] 18023a0898aSmrg [if flags & COMMENT: 18123a0898aSmrg n bytes -- null terminated comment (discard)] 18223a0898aSmrg [if flags & HEAD_CRC: 18323a0898aSmrg 2 bytes -- crc of headers? (discard)] 18423a0898aSmrg */ 18523a0898aSmrg 18623a0898aSmrg/* gzip flag byte -- from gzio.c */ 18723a0898aSmrg#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ 18823a0898aSmrg#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ 18923a0898aSmrg#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ 19023a0898aSmrg#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ 19123a0898aSmrg#define COMMENT 0x10 /* bit 4 set: file comment present */ 19223a0898aSmrg#define RESERVED 0xE0 /* bits 5..7: reserved */ 19323a0898aSmrg 19423a0898aSmrg#define GET(f) do {c = BufFileGet(f); if (c == BUFFILEEOF) return c;} while(0) 19541c30155Smrgstatic int 19623a0898aSmrgBufCheckZipHeader(BufFilePtr f) 19723a0898aSmrg{ 19823a0898aSmrg int c, flags; 19923a0898aSmrg GET(f); if (c != 0x1f) return 1; /* magic 1 */ 20023a0898aSmrg GET(f); if (c != 0x8b) return 2; /* magic 2 */ 20123a0898aSmrg GET(f); if (c != Z_DEFLATED) return 3; /* method */ 20223a0898aSmrg GET(f); if (c & RESERVED) return 4; /* reserved flags */ 20323a0898aSmrg flags = c; 20423a0898aSmrg GET(f); GET(f); GET(f); GET(f); /* time */ 20523a0898aSmrg GET(f); /* xflags */ 20623a0898aSmrg GET(f); /* os code */ 20723a0898aSmrg if (flags & EXTRA_FIELD) { 20823a0898aSmrg int len; 20923a0898aSmrg GET(f); len = c; 21023a0898aSmrg GET(f); len += (c<<8); 21123a0898aSmrg while (len-- >= 0) { 21223a0898aSmrg GET(f); 21323a0898aSmrg } 21423a0898aSmrg } 21523a0898aSmrg if (flags & ORIG_NAME) { 21623a0898aSmrg do { GET(f); } while (c != 0); 21723a0898aSmrg } 21823a0898aSmrg if (flags & COMMENT) { 21923a0898aSmrg do { GET(f); } while (c != 0); 22023a0898aSmrg } 22123a0898aSmrg if (flags & HEAD_CRC) { 22223a0898aSmrg GET(f); GET(f); /* header crc */ 22323a0898aSmrg } 22423a0898aSmrg return 0; 22523a0898aSmrg} 226