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