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