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