Git init
[framework/uifw/xorg/lib/libxfont.git] / src / fontfile / decompress.c
1 /*
2  * Copyright 1985, 1986 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * James A. Woods, derived from original work by Spencer Thomas
7  * and Joseph Orost.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by the University of California, Berkeley.  The name of the
15  * University may not be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 /*
23
24 Copyright 1993, 1998  The Open Group
25
26 Permission to use, copy, modify, distribute, and sell this software and its
27 documentation for any purpose is hereby granted without fee, provided that
28 the above copyright notice appear in all copies and that both that
29 copyright notice and this permission notice appear in supporting
30 documentation.
31
32 The above copyright notice and this permission notice shall be included in
33 all copies or substantial portions of the Software.
34
35 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
38 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
39 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
41
42 Except as contained in this notice, the name of The Open Group shall not be
43 used in advertising or otherwise to promote the sale, use or other dealings
44 in this Software without prior written authorization from The Open Group.
45
46 */
47 /* 
48  * decompress - cat a compressed file
49  */
50
51 #ifdef HAVE_CONFIG_H
52 #include <config.h>
53 #endif
54 #include <X11/fonts/fontmisc.h>
55 #include <X11/fonts/bufio.h>
56
57 #define BITS    16
58
59 /*
60  * a code_int must be able to hold 2**BITS values of type int, and also -1
61  */
62 #if BITS > 15
63 typedef long int        code_int;
64 #else
65 typedef int             code_int;
66 #endif
67
68 typedef long int          count_int;
69
70 #ifdef NO_UCHAR
71  typedef char   char_type;
72 #else
73  typedef        unsigned char   char_type;
74 #endif /* UCHAR */
75
76 static char_type magic_header[] = { "\037\235" };       /* 1F 9D */
77
78 /* Defines for third byte of header */
79 #define BIT_MASK        0x1f
80 #define BLOCK_MASK      0x80
81 /* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
82    a fourth header byte (for expansion).
83 */
84
85 #define INIT_BITS 9                     /* initial number of bits/code */
86
87 #ifdef COMPATIBLE               /* But wrong! */
88 # define MAXCODE(n_bits)        (1 << (n_bits) - 1)
89 #else
90 # define MAXCODE(n_bits)        ((1 << (n_bits)) - 1)
91 #endif /* COMPATIBLE */
92
93 /*
94  * the next two codes should not be changed lightly, as they must not
95  * lie within the contiguous general code space.
96  */ 
97 #define FIRST   257     /* first free entry */
98 #define CLEAR   256     /* table clear output code */
99
100 #define STACK_SIZE  8192
101
102 typedef struct _compressedFILE {
103     BufFilePtr      file;
104
105     char_type       *stackp;
106     code_int        oldcode;
107     char_type       finchar;
108
109     int         block_compress;
110     int         maxbits;
111     code_int    maxcode, maxmaxcode;
112
113     code_int    free_ent;
114     int         clear_flg;
115     int         n_bits;
116
117     /* bit buffer */
118     int         offset, size;
119     char_type   buf[BITS];
120
121     char_type       de_stack[STACK_SIZE];
122     char_type       *tab_suffix;
123     unsigned short  *tab_prefix;
124 } CompressedFile;
125
126
127 static int hsize_table[] = {
128     5003,       /* 12 bits - 80% occupancy */
129     9001,       /* 13 bits - 91% occupancy */
130     18013,      /* 14 bits - 91% occupancy */
131     35023,      /* 15 bits - 94% occupancy */
132     69001       /* 16 bits - 95% occupancy */
133 };
134
135 static int BufCompressedClose ( BufFilePtr f, int doClose );
136 static int BufCompressedFill ( BufFilePtr f );
137 static code_int getcode ( CompressedFile *file );
138 static int BufCompressedSkip ( BufFilePtr f, int bytes );
139
140 BufFilePtr
141 BufFilePushCompressed (BufFilePtr f)
142 {
143     int             code;
144     int             maxbits;
145     int             hsize;
146     CompressedFile  *file;
147     int             extra;
148
149     if ((BufFileGet(f) != (magic_header[0] & 0xFF)) ||
150         (BufFileGet(f) != (magic_header[1] & 0xFF)))
151     {
152         return 0;
153     }
154     code = BufFileGet (f);
155     if (code == BUFFILEEOF) return 0;
156     
157     maxbits = code & BIT_MASK;
158     if (maxbits > BITS || maxbits < 12)
159         return 0;
160     hsize = hsize_table[maxbits - 12];
161     extra = (1 << maxbits) * sizeof (char_type) +
162             hsize * sizeof (unsigned short);
163     file = malloc (sizeof (CompressedFile) + extra);
164     if (!file)
165         return 0;
166     file->file = f;
167     file->maxbits = maxbits;
168     file->block_compress = code & BLOCK_MASK;
169     file->maxmaxcode = 1 << file->maxbits;
170     file->tab_suffix = (char_type *) &file[1];
171     file->tab_prefix = (unsigned short *) (file->tab_suffix + file->maxmaxcode);
172     /*
173      * As above, initialize the first 256 entries in the table.
174      */
175     file->maxcode = MAXCODE(file->n_bits = INIT_BITS);
176     for ( code = 255; code >= 0; code-- ) {
177         file->tab_prefix[code] = 0;
178         file->tab_suffix[code] = (char_type) code;
179     }
180     file->free_ent = ((file->block_compress) ? FIRST : 256 );
181     file->clear_flg = 0;
182     file->offset = 0;
183     file->size = 0;
184     file->stackp = file->de_stack;
185     bzero(file->buf, BITS);
186     file->finchar = file->oldcode = getcode (file);
187     if (file->oldcode != -1)
188         *file->stackp++ = file->finchar;
189     return BufFileCreate ((char *) file,
190                           BufCompressedFill,
191                           0,
192                           BufCompressedSkip,
193                           BufCompressedClose);
194 }
195
196 static int
197 BufCompressedClose (BufFilePtr f, int doClose)
198 {
199     CompressedFile  *file;
200     BufFilePtr      raw;
201
202     file = (CompressedFile *) f->private;
203     raw = file->file;
204     free (file);
205     BufFileClose (raw, doClose);
206     return 1;
207 }
208
209 static int
210 BufCompressedFill (BufFilePtr f)
211 {
212     CompressedFile  *file;
213     register char_type *stackp, *de_stack;
214     register char_type finchar;
215     register code_int code, oldcode, incode;
216     BufChar         *buf, *bufend;
217
218     file = (CompressedFile *) f->private;
219
220     buf = f->buffer;
221     bufend = buf + BUFFILESIZE;
222     stackp = file->stackp;
223     de_stack = file->de_stack;
224     finchar = file->finchar;
225     oldcode = file->oldcode;
226     while (buf < bufend) {
227         while (stackp > de_stack && buf < bufend)
228             *buf++ = *--stackp;
229
230         if (buf == bufend)
231             break;
232
233         if (oldcode == -1)
234             break;
235
236         code = getcode (file);
237         if (code == -1)
238             break;
239     
240         if ( (code == CLEAR) && file->block_compress ) {
241             for ( code = 255; code >= 0; code-- )
242                 file->tab_prefix[code] = 0;
243             file->clear_flg = 1;
244             file->free_ent = FIRST - 1;
245             if ( (code = getcode (file)) == -1 )        /* O, untimely death! */
246                 break;
247         }
248         incode = code;
249         /*
250          * Special case for KwKwK string.
251          */
252         if ( code >= file->free_ent ) {
253             *stackp++ = finchar;
254             code = oldcode;
255         }
256     
257         /*
258          * Generate output characters in reverse order
259          */
260         while ( code >= 256 )
261         {
262             *stackp++ = file->tab_suffix[code];
263             code = file->tab_prefix[code];
264         }
265         finchar = file->tab_suffix[code];
266         *stackp++ = finchar;
267     
268         /*
269          * Generate the new entry.
270          */
271         if ( (code=file->free_ent) < file->maxmaxcode ) {
272             file->tab_prefix[code] = (unsigned short)oldcode;
273             file->tab_suffix[code] = finchar;
274             file->free_ent = code+1;
275         } 
276         /*
277          * Remember previous code.
278          */
279         oldcode = incode;
280     }
281     file->oldcode = oldcode;
282     file->stackp = stackp;
283     file->finchar = finchar;
284     if (buf == f->buffer) {
285         f->left = 0;
286         return BUFFILEEOF;
287     }
288     f->bufp = f->buffer + 1;
289     f->left = (buf - f->buffer) - 1;
290     return f->buffer[0];
291 }
292
293 /*****************************************************************
294  * TAG( getcode )
295  *
296  * Read one code from the standard input.  If BUFFILEEOF, return -1.
297  * Inputs:
298  *      stdin
299  * Outputs:
300  *      code or -1 is returned.
301  */
302
303 static char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
304
305 static code_int
306 getcode(CompressedFile *file)
307 {
308     register code_int code;
309     register int r_off, bits;
310     register char_type *bp = file->buf;
311     register BufFilePtr raw;
312
313     if ( file->clear_flg > 0 || file->offset >= file->size ||
314         file->free_ent > file->maxcode )
315     {
316         /*
317          * If the next entry will be too big for the current code
318          * size, then we must increase the size.  This implies reading
319          * a new buffer full, too.
320          */
321         if ( file->free_ent > file->maxcode ) {
322             file->n_bits++;
323             if ( file->n_bits == file->maxbits )
324                 file->maxcode = file->maxmaxcode;       /* won't get any bigger now */
325             else
326                 file->maxcode = MAXCODE(file->n_bits);
327         }
328         if ( file->clear_flg > 0) {
329             file->maxcode = MAXCODE (file->n_bits = INIT_BITS);
330             file->clear_flg = 0;
331         }
332         bits = file->n_bits;
333         raw = file->file;
334         while (bits > 0 && (code = BufFileGet (raw)) != BUFFILEEOF)
335         {
336             *bp++ = code;
337             --bits;
338         }
339         bp = file->buf;
340         if (bits == file->n_bits)
341             return -1;                  /* end of file */
342         file->size = file->n_bits - bits;
343         file->offset = 0;
344         /* Round size down to integral number of codes */
345         file->size = (file->size << 3) - (file->n_bits - 1);
346     }
347     r_off = file->offset;
348     bits = file->n_bits;
349     /*
350      * Get to the first byte.
351      */
352     bp += (r_off >> 3);
353     r_off &= 7;
354     /* Get first part (low order bits) */
355 #ifdef NO_UCHAR
356     code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
357 #else
358     code = (*bp++ >> r_off);
359 #endif /* NO_UCHAR */
360     bits -= (8 - r_off);
361     r_off = 8 - r_off;          /* now, offset into code word */
362     /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
363     if ( bits >= 8 ) {
364 #ifdef NO_UCHAR
365         code |= (*bp++ & 0xff) << r_off;
366 #else
367         code |= *bp++ << r_off;
368 #endif /* NO_UCHAR */
369         r_off += 8;
370         bits -= 8;
371     }
372     /* high order bits. */
373     code |= (*bp & rmask[bits]) << r_off;
374     file->offset += file->n_bits;
375
376     return code;
377 }
378
379 static int
380 BufCompressedSkip (BufFilePtr f, int bytes)
381 {
382     int             c;
383     while (bytes--) 
384     {
385         c = BufFileGet(f);
386         if (c == BUFFILEEOF)
387             return BUFFILEEOF;
388     }
389     return 0;
390 }
391
392 #ifdef TEST
393 int
394 main (int argc, char *argv[])
395 {
396     BufFilePtr      inputraw, input, output;
397     int             c;
398     
399     inputraw = BufFileOpenRead (0);
400     input = BufFilePushCompressed (inputraw);
401     output = BufFileOpenWrite (1);
402     while ((c = BufFileGet (input)) != BUFFILEEOF)
403         BufFilePut (c, output);
404     BufFileClose (input, FALSE);
405     BufFileClose (output, FALSE);
406     return 0;
407 }
408 #endif