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