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 
13 typedef 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 
21 static int BufZipFileClose ( BufFilePtr f, int flag );
22 static int BufZipFileFill ( BufFilePtr f );
23 static int BufZipFileSkip ( BufFilePtr f, int c );
24 static int BufCheckZipHeader ( BufFilePtr f );
25 
26 BufFilePtr
BufFilePushZIP(BufFilePtr f)27 BufFilePushZIP (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 
70 static int
BufZipFileClose(BufFilePtr f,int flag)71 BufZipFileClose(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    */
89 static int
BufZipFileFill(BufFilePtr f)90 BufZipFileFill (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... */
154 static int
BufZipFileSkip(BufFilePtr f,int c)155 BufZipFileSkip (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)
196 static int
BufCheckZipHeader(BufFilePtr f)197 BufCheckZipHeader(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