decompress.c revision 94917da6
123a0898aSmrg/* $Xorg: decompress.c,v 1.4 2001/02/09 02:04:03 xorgcvs Exp $ */
223a0898aSmrg/*
323a0898aSmrg * Copyright 1985, 1986 The Regents of the University of California.
423a0898aSmrg * All rights reserved.
523a0898aSmrg *
623a0898aSmrg * This code is derived from software contributed to Berkeley by
723a0898aSmrg * James A. Woods, derived from original work by Spencer Thomas
823a0898aSmrg * and Joseph Orost.
923a0898aSmrg *
1023a0898aSmrg * Redistribution and use in source and binary forms are permitted
1123a0898aSmrg * provided that the above copyright notice and this paragraph are
1223a0898aSmrg * duplicated in all such forms and that any documentation,
1323a0898aSmrg * advertising materials, and other materials related to such
1423a0898aSmrg * distribution and use acknowledge that the software was developed
1523a0898aSmrg * by the University of California, Berkeley.  The name of the
1623a0898aSmrg * University may not be used to endorse or promote products derived
1723a0898aSmrg * from this software without specific prior written permission.
1823a0898aSmrg * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1923a0898aSmrg * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2023a0898aSmrg * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2123a0898aSmrg */
2223a0898aSmrg
2323a0898aSmrg/*
2423a0898aSmrg
2523a0898aSmrgCopyright 1993, 1998  The Open Group
2623a0898aSmrg
2723a0898aSmrgPermission to use, copy, modify, distribute, and sell this software and its
2823a0898aSmrgdocumentation for any purpose is hereby granted without fee, provided that
2923a0898aSmrgthe above copyright notice appear in all copies and that both that
3023a0898aSmrgcopyright notice and this permission notice appear in supporting
3123a0898aSmrgdocumentation.
3223a0898aSmrg
3323a0898aSmrgThe above copyright notice and this permission notice shall be included in
3423a0898aSmrgall copies or substantial portions of the Software.
3523a0898aSmrg
3623a0898aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3723a0898aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3823a0898aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
3923a0898aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
4023a0898aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
4123a0898aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4223a0898aSmrg
4323a0898aSmrgExcept as contained in this notice, the name of The Open Group shall not be
4423a0898aSmrgused in advertising or otherwise to promote the sale, use or other dealings
4523a0898aSmrgin this Software without prior written authorization from The Open Group.
4623a0898aSmrg
4723a0898aSmrg*/
4823a0898aSmrg/* $XFree86: xc/lib/font/fontfile/decompress.c,v 1.4 2001/01/17 19:43:29 dawes Exp $ */
4923a0898aSmrg/*
5023a0898aSmrg * decompress - cat a compressed file
5123a0898aSmrg */
5223a0898aSmrg
5323a0898aSmrg#ifdef HAVE_CONFIG_H
5423a0898aSmrg#include <config.h>
5523a0898aSmrg#endif
5623a0898aSmrg#include <X11/fonts/fontmisc.h>
5723a0898aSmrg#include <X11/fonts/bufio.h>
5823a0898aSmrg
5923a0898aSmrg#define BITS	16
6023a0898aSmrg
6123a0898aSmrg/*
6223a0898aSmrg * a code_int must be able to hold 2**BITS values of type int, and also -1
6323a0898aSmrg */
6423a0898aSmrg#if BITS > 15
6523a0898aSmrgtypedef long int	code_int;
6623a0898aSmrg#else
6723a0898aSmrgtypedef int		code_int;
6823a0898aSmrg#endif
6923a0898aSmrg
7023a0898aSmrgtypedef long int	  count_int;
7123a0898aSmrg
7223a0898aSmrg#ifdef NO_UCHAR
7323a0898aSmrg typedef char	char_type;
7423a0898aSmrg#else
7523a0898aSmrg typedef	unsigned char	char_type;
7623a0898aSmrg#endif /* UCHAR */
7723a0898aSmrg
7823a0898aSmrgstatic char_type magic_header[] = { "\037\235" };	/* 1F 9D */
7923a0898aSmrg
8023a0898aSmrg/* Defines for third byte of header */
8123a0898aSmrg#define BIT_MASK	0x1f
8223a0898aSmrg#define BLOCK_MASK	0x80
8323a0898aSmrg/* Masks 0x40 and 0x20 are free.  I think 0x20 should mean that there is
8423a0898aSmrg   a fourth header byte (for expansion).
8523a0898aSmrg*/
8623a0898aSmrg
8723a0898aSmrg#define INIT_BITS 9			/* initial number of bits/code */
8823a0898aSmrg
8923a0898aSmrg#ifdef COMPATIBLE		/* But wrong! */
9023a0898aSmrg# define MAXCODE(n_bits)	(1 << (n_bits) - 1)
9123a0898aSmrg#else
9223a0898aSmrg# define MAXCODE(n_bits)	((1 << (n_bits)) - 1)
9323a0898aSmrg#endif /* COMPATIBLE */
9423a0898aSmrg
9523a0898aSmrg/*
9623a0898aSmrg * the next two codes should not be changed lightly, as they must not
9723a0898aSmrg * lie within the contiguous general code space.
9823a0898aSmrg */
9923a0898aSmrg#define FIRST	257	/* first free entry */
10023a0898aSmrg#define	CLEAR	256	/* table clear output code */
10123a0898aSmrg
10294917da6Sjoerg#define STACK_SIZE  65300
10323a0898aSmrg
10423a0898aSmrgtypedef struct _compressedFILE {
10523a0898aSmrg    BufFilePtr	    file;
10623a0898aSmrg
10723a0898aSmrg    char_type	    *stackp;
10823a0898aSmrg    code_int	    oldcode;
10923a0898aSmrg    char_type	    finchar;
11023a0898aSmrg
11123a0898aSmrg    int		block_compress;
11223a0898aSmrg    int		maxbits;
11323a0898aSmrg    code_int	maxcode, maxmaxcode;
11423a0898aSmrg
11523a0898aSmrg    code_int	free_ent;
11623a0898aSmrg    int		clear_flg;
11723a0898aSmrg    int		n_bits;
11823a0898aSmrg
11923a0898aSmrg    /* bit buffer */
12023a0898aSmrg    int		offset, size;
12123a0898aSmrg    char_type	buf[BITS];
12223a0898aSmrg
12323a0898aSmrg    char_type	    de_stack[STACK_SIZE];
12423a0898aSmrg    char_type	    *tab_suffix;
12523a0898aSmrg    unsigned short  *tab_prefix;
12623a0898aSmrg} CompressedFile;
12723a0898aSmrg
12823a0898aSmrg
12923a0898aSmrgstatic int hsize_table[] = {
13023a0898aSmrg    5003,	/* 12 bits - 80% occupancy */
13123a0898aSmrg    9001,	/* 13 bits - 91% occupancy */
13223a0898aSmrg    18013,	/* 14 bits - 91% occupancy */
13323a0898aSmrg    35023,	/* 15 bits - 94% occupancy */
13423a0898aSmrg    69001	/* 16 bits - 95% occupancy */
13523a0898aSmrg};
13623a0898aSmrg
13723a0898aSmrgstatic int BufCompressedClose ( BufFilePtr f, int doClose );
13823a0898aSmrgstatic int BufCompressedFill ( BufFilePtr f );
13923a0898aSmrgstatic code_int getcode ( CompressedFile *file );
14023a0898aSmrgstatic int BufCompressedSkip ( BufFilePtr f, int bytes );
14123a0898aSmrg
14223a0898aSmrgBufFilePtr
14323a0898aSmrgBufFilePushCompressed (BufFilePtr f)
14423a0898aSmrg{
14523a0898aSmrg    int		    code;
14623a0898aSmrg    int		    maxbits;
14723a0898aSmrg    int		    hsize;
14823a0898aSmrg    CompressedFile  *file;
14923a0898aSmrg    int		    extra;
15023a0898aSmrg
15123a0898aSmrg    if ((BufFileGet(f) != (magic_header[0] & 0xFF)) ||
15223a0898aSmrg	(BufFileGet(f) != (magic_header[1] & 0xFF)))
15323a0898aSmrg    {
15423a0898aSmrg	return 0;
15523a0898aSmrg    }
15623a0898aSmrg    code = BufFileGet (f);
15723a0898aSmrg    if (code == BUFFILEEOF) return 0;
15823a0898aSmrg
15923a0898aSmrg    maxbits = code & BIT_MASK;
16023a0898aSmrg    if (maxbits > BITS || maxbits < 12)
16123a0898aSmrg	return 0;
16223a0898aSmrg    hsize = hsize_table[maxbits - 12];
16323a0898aSmrg    extra = (1 << maxbits) * sizeof (char_type) +
16423a0898aSmrg	    hsize * sizeof (unsigned short);
1657f7f5e4eSmrg    file = malloc (sizeof (CompressedFile) + extra);
16623a0898aSmrg    if (!file)
16723a0898aSmrg	return 0;
16823a0898aSmrg    file->file = f;
16923a0898aSmrg    file->maxbits = maxbits;
17023a0898aSmrg    file->block_compress = code & BLOCK_MASK;
17123a0898aSmrg    file->maxmaxcode = 1 << file->maxbits;
17223a0898aSmrg    file->tab_suffix = (char_type *) &file[1];
17323a0898aSmrg    file->tab_prefix = (unsigned short *) (file->tab_suffix + file->maxmaxcode);
17423a0898aSmrg    /*
17523a0898aSmrg     * As above, initialize the first 256 entries in the table.
17623a0898aSmrg     */
17723a0898aSmrg    file->maxcode = MAXCODE(file->n_bits = INIT_BITS);
17823a0898aSmrg    for ( code = 255; code >= 0; code-- ) {
17923a0898aSmrg	file->tab_prefix[code] = 0;
18023a0898aSmrg	file->tab_suffix[code] = (char_type) code;
18123a0898aSmrg    }
18223a0898aSmrg    file->free_ent = ((file->block_compress) ? FIRST : 256 );
18394917da6Sjoerg    file->oldcode = -1;
18423a0898aSmrg    file->clear_flg = 0;
18523a0898aSmrg    file->offset = 0;
18623a0898aSmrg    file->size = 0;
18723a0898aSmrg    file->stackp = file->de_stack;
18823a0898aSmrg    bzero(file->buf, BITS);
18923a0898aSmrg    return BufFileCreate ((char *) file,
19023a0898aSmrg			  BufCompressedFill,
19123a0898aSmrg			  0,
19223a0898aSmrg			  BufCompressedSkip,
19323a0898aSmrg			  BufCompressedClose);
19423a0898aSmrg}
19523a0898aSmrg
19623a0898aSmrgstatic int
19723a0898aSmrgBufCompressedClose (BufFilePtr f, int doClose)
19823a0898aSmrg{
19923a0898aSmrg    CompressedFile  *file;
20023a0898aSmrg    BufFilePtr	    raw;
20123a0898aSmrg
20223a0898aSmrg    file = (CompressedFile *) f->private;
20323a0898aSmrg    raw = file->file;
2047f7f5e4eSmrg    free (file);
20523a0898aSmrg    BufFileClose (raw, doClose);
20623a0898aSmrg    return 1;
20723a0898aSmrg}
20823a0898aSmrg
20923a0898aSmrgstatic int
21023a0898aSmrgBufCompressedFill (BufFilePtr f)
21123a0898aSmrg{
21223a0898aSmrg    CompressedFile  *file;
21323a0898aSmrg    register char_type *stackp, *de_stack;
21423a0898aSmrg    register char_type finchar;
21523a0898aSmrg    register code_int code, oldcode, incode;
21623a0898aSmrg    BufChar	    *buf, *bufend;
21723a0898aSmrg
21823a0898aSmrg    file = (CompressedFile *) f->private;
21923a0898aSmrg
22023a0898aSmrg    buf = f->buffer;
22123a0898aSmrg    bufend = buf + BUFFILESIZE;
22223a0898aSmrg    stackp = file->stackp;
22323a0898aSmrg    de_stack = file->de_stack;
22423a0898aSmrg    finchar = file->finchar;
22523a0898aSmrg    oldcode = file->oldcode;
22623a0898aSmrg    while (buf < bufend) {
22723a0898aSmrg	while (stackp > de_stack && buf < bufend)
22823a0898aSmrg	    *buf++ = *--stackp;
22923a0898aSmrg
23023a0898aSmrg	if (buf == bufend)
23123a0898aSmrg	    break;
23223a0898aSmrg
23323a0898aSmrg	code = getcode (file);
23423a0898aSmrg	if (code == -1)
23523a0898aSmrg	    break;
23623a0898aSmrg
23723a0898aSmrg    	if ( (code == CLEAR) && file->block_compress ) {
23823a0898aSmrg	    for ( code = 255; code >= 0; code-- )
23923a0898aSmrg	    	file->tab_prefix[code] = 0;
24023a0898aSmrg	    file->clear_flg = 1;
24194917da6Sjoerg	    file->free_ent = FIRST;
24294917da6Sjoerg	    oldcode = -1;
24394917da6Sjoerg	    continue;
24423a0898aSmrg    	}
24523a0898aSmrg    	incode = code;
24623a0898aSmrg    	/*
24723a0898aSmrg     	 * Special case for KwKwK string.
24823a0898aSmrg     	 */
24923a0898aSmrg    	if ( code >= file->free_ent ) {
25094917da6Sjoerg	    if ( code > file->free_ent || oldcode == -1 ) {
25194917da6Sjoerg		/* Bad stream. */
25294917da6Sjoerg		return BUFFILEEOF;
25394917da6Sjoerg	    }
25423a0898aSmrg	    *stackp++ = finchar;
25523a0898aSmrg	    code = oldcode;
25623a0898aSmrg    	}
25794917da6Sjoerg	/*
25894917da6Sjoerg	 * The above condition ensures that code < free_ent.
25994917da6Sjoerg	 * The construction of tab_prefixof in turn guarantees that
26094917da6Sjoerg	 * each iteration decreases code and therefore stack usage is
26194917da6Sjoerg	 * bound by 1 << BITS - 256.
26294917da6Sjoerg	 */
26394917da6Sjoerg
26423a0898aSmrg    	/*
26523a0898aSmrg     	 * Generate output characters in reverse order
26623a0898aSmrg     	 */
26723a0898aSmrg    	while ( code >= 256 )
26823a0898aSmrg    	{
26923a0898aSmrg	    *stackp++ = file->tab_suffix[code];
27023a0898aSmrg	    code = file->tab_prefix[code];
27123a0898aSmrg    	}
27223a0898aSmrg	finchar = file->tab_suffix[code];
27323a0898aSmrg	*stackp++ = finchar;
27423a0898aSmrg
27523a0898aSmrg    	/*
27623a0898aSmrg     	 * Generate the new entry.
27723a0898aSmrg     	 */
27894917da6Sjoerg    	if ( (code=file->free_ent) < file->maxmaxcode && oldcode != -1) {
27923a0898aSmrg	    file->tab_prefix[code] = (unsigned short)oldcode;
28023a0898aSmrg	    file->tab_suffix[code] = finchar;
28123a0898aSmrg	    file->free_ent = code+1;
28223a0898aSmrg    	}
28323a0898aSmrg	/*
28423a0898aSmrg	 * Remember previous code.
28523a0898aSmrg	 */
28623a0898aSmrg	oldcode = incode;
28723a0898aSmrg    }
28823a0898aSmrg    file->oldcode = oldcode;
28923a0898aSmrg    file->stackp = stackp;
29023a0898aSmrg    file->finchar = finchar;
29123a0898aSmrg    if (buf == f->buffer) {
29223a0898aSmrg	f->left = 0;
29323a0898aSmrg	return BUFFILEEOF;
29423a0898aSmrg    }
29523a0898aSmrg    f->bufp = f->buffer + 1;
29623a0898aSmrg    f->left = (buf - f->buffer) - 1;
29723a0898aSmrg    return f->buffer[0];
29823a0898aSmrg}
29923a0898aSmrg
30023a0898aSmrg/*****************************************************************
30123a0898aSmrg * TAG( getcode )
30223a0898aSmrg *
30323a0898aSmrg * Read one code from the standard input.  If BUFFILEEOF, return -1.
30423a0898aSmrg * Inputs:
30523a0898aSmrg * 	stdin
30623a0898aSmrg * Outputs:
30723a0898aSmrg * 	code or -1 is returned.
30823a0898aSmrg */
30923a0898aSmrg
31023a0898aSmrgstatic char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
31123a0898aSmrg
31223a0898aSmrgstatic code_int
31323a0898aSmrggetcode(CompressedFile *file)
31423a0898aSmrg{
31523a0898aSmrg    register code_int code;
31623a0898aSmrg    register int r_off, bits;
31723a0898aSmrg    register char_type *bp = file->buf;
31823a0898aSmrg    register BufFilePtr	raw;
31923a0898aSmrg
32023a0898aSmrg    if ( file->clear_flg > 0 || file->offset >= file->size ||
32123a0898aSmrg	file->free_ent > file->maxcode )
32223a0898aSmrg    {
32323a0898aSmrg	/*
32423a0898aSmrg	 * If the next entry will be too big for the current code
32523a0898aSmrg	 * size, then we must increase the size.  This implies reading
32623a0898aSmrg	 * a new buffer full, too.
32723a0898aSmrg	 */
32823a0898aSmrg	if ( file->free_ent > file->maxcode ) {
32923a0898aSmrg	    file->n_bits++;
33023a0898aSmrg	    if ( file->n_bits == file->maxbits )
33123a0898aSmrg		file->maxcode = file->maxmaxcode;	/* won't get any bigger now */
33223a0898aSmrg	    else
33323a0898aSmrg		file->maxcode = MAXCODE(file->n_bits);
33423a0898aSmrg	}
33523a0898aSmrg	if ( file->clear_flg > 0) {
33623a0898aSmrg    	    file->maxcode = MAXCODE (file->n_bits = INIT_BITS);
33723a0898aSmrg	    file->clear_flg = 0;
33823a0898aSmrg	}
33923a0898aSmrg	bits = file->n_bits;
34023a0898aSmrg	raw = file->file;
34123a0898aSmrg	while (bits > 0 && (code = BufFileGet (raw)) != BUFFILEEOF)
34223a0898aSmrg	{
34323a0898aSmrg	    *bp++ = code;
34423a0898aSmrg	    --bits;
34523a0898aSmrg	}
34623a0898aSmrg	bp = file->buf;
34723a0898aSmrg	if (bits == file->n_bits)
34823a0898aSmrg	    return -1;			/* end of file */
34923a0898aSmrg	file->size = file->n_bits - bits;
35023a0898aSmrg	file->offset = 0;
35123a0898aSmrg	/* Round size down to integral number of codes */
35223a0898aSmrg	file->size = (file->size << 3) - (file->n_bits - 1);
35323a0898aSmrg    }
35423a0898aSmrg    r_off = file->offset;
35523a0898aSmrg    bits = file->n_bits;
35623a0898aSmrg    /*
35723a0898aSmrg     * Get to the first byte.
35823a0898aSmrg     */
35923a0898aSmrg    bp += (r_off >> 3);
36023a0898aSmrg    r_off &= 7;
36123a0898aSmrg    /* Get first part (low order bits) */
36223a0898aSmrg#ifdef NO_UCHAR
36323a0898aSmrg    code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff;
36423a0898aSmrg#else
36523a0898aSmrg    code = (*bp++ >> r_off);
36623a0898aSmrg#endif /* NO_UCHAR */
36723a0898aSmrg    bits -= (8 - r_off);
36823a0898aSmrg    r_off = 8 - r_off;		/* now, offset into code word */
36923a0898aSmrg    /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
37023a0898aSmrg    if ( bits >= 8 ) {
37123a0898aSmrg#ifdef NO_UCHAR
37223a0898aSmrg	code |= (*bp++ & 0xff) << r_off;
37323a0898aSmrg#else
37423a0898aSmrg	code |= *bp++ << r_off;
37523a0898aSmrg#endif /* NO_UCHAR */
37623a0898aSmrg	r_off += 8;
37723a0898aSmrg	bits -= 8;
37823a0898aSmrg    }
37923a0898aSmrg    /* high order bits. */
38023a0898aSmrg    code |= (*bp & rmask[bits]) << r_off;
38123a0898aSmrg    file->offset += file->n_bits;
38223a0898aSmrg
38323a0898aSmrg    return code;
38423a0898aSmrg}
38523a0898aSmrg
38623a0898aSmrgstatic int
38723a0898aSmrgBufCompressedSkip (BufFilePtr f, int bytes)
38823a0898aSmrg{
38923a0898aSmrg    int		    c;
39023a0898aSmrg    while (bytes--)
39123a0898aSmrg    {
39223a0898aSmrg	c = BufFileGet(f);
39323a0898aSmrg	if (c == BUFFILEEOF)
39423a0898aSmrg	    return BUFFILEEOF;
39523a0898aSmrg    }
39623a0898aSmrg    return 0;
39723a0898aSmrg}
39823a0898aSmrg
39923a0898aSmrg#ifdef TEST
40023a0898aSmrgint
40123a0898aSmrgmain (int argc, char *argv[])
40223a0898aSmrg{
40323a0898aSmrg    BufFilePtr	    inputraw, input, output;
40423a0898aSmrg    int		    c;
40523a0898aSmrg
40623a0898aSmrg    inputraw = BufFileOpenRead (0);
40723a0898aSmrg    input = BufFilePushCompressed (inputraw);
40823a0898aSmrg    output = BufFileOpenWrite (1);
40923a0898aSmrg    while ((c = BufFileGet (input)) != BUFFILEEOF)
41023a0898aSmrg	BufFilePut (c, output);
41123a0898aSmrg    BufFileClose (input, FALSE);
41223a0898aSmrg    BufFileClose (output, FALSE);
41323a0898aSmrg    return 0;
41423a0898aSmrg}
41523a0898aSmrg#endif
416