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