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