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