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