decompress.c revision 23a0898a
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 8192 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 = (CompressedFile *) xalloc (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->clear_flg = 0; 184 file->offset = 0; 185 file->size = 0; 186 file->stackp = file->de_stack; 187 bzero(file->buf, BITS); 188 file->finchar = file->oldcode = getcode (file); 189 if (file->oldcode != -1) 190 *file->stackp++ = file->finchar; 191 return BufFileCreate ((char *) file, 192 BufCompressedFill, 193 0, 194 BufCompressedSkip, 195 BufCompressedClose); 196} 197 198static int 199BufCompressedClose (BufFilePtr f, int doClose) 200{ 201 CompressedFile *file; 202 BufFilePtr raw; 203 204 file = (CompressedFile *) f->private; 205 raw = file->file; 206 xfree (file); 207 BufFileClose (raw, doClose); 208 return 1; 209} 210 211static int 212BufCompressedFill (BufFilePtr f) 213{ 214 CompressedFile *file; 215 register char_type *stackp, *de_stack; 216 register char_type finchar; 217 register code_int code, oldcode, incode; 218 BufChar *buf, *bufend; 219 220 file = (CompressedFile *) f->private; 221 222 buf = f->buffer; 223 bufend = buf + BUFFILESIZE; 224 stackp = file->stackp; 225 de_stack = file->de_stack; 226 finchar = file->finchar; 227 oldcode = file->oldcode; 228 while (buf < bufend) { 229 while (stackp > de_stack && buf < bufend) 230 *buf++ = *--stackp; 231 232 if (buf == bufend) 233 break; 234 235 if (oldcode == -1) 236 break; 237 238 code = getcode (file); 239 if (code == -1) 240 break; 241 242 if ( (code == CLEAR) && file->block_compress ) { 243 for ( code = 255; code >= 0; code-- ) 244 file->tab_prefix[code] = 0; 245 file->clear_flg = 1; 246 file->free_ent = FIRST - 1; 247 if ( (code = getcode (file)) == -1 ) /* O, untimely death! */ 248 break; 249 } 250 incode = code; 251 /* 252 * Special case for KwKwK string. 253 */ 254 if ( code >= file->free_ent ) { 255 *stackp++ = finchar; 256 code = oldcode; 257 } 258 259 /* 260 * Generate output characters in reverse order 261 */ 262 while ( code >= 256 ) 263 { 264 *stackp++ = file->tab_suffix[code]; 265 code = file->tab_prefix[code]; 266 } 267 finchar = file->tab_suffix[code]; 268 *stackp++ = finchar; 269 270 /* 271 * Generate the new entry. 272 */ 273 if ( (code=file->free_ent) < file->maxmaxcode ) { 274 file->tab_prefix[code] = (unsigned short)oldcode; 275 file->tab_suffix[code] = finchar; 276 file->free_ent = code+1; 277 } 278 /* 279 * Remember previous code. 280 */ 281 oldcode = incode; 282 } 283 file->oldcode = oldcode; 284 file->stackp = stackp; 285 file->finchar = finchar; 286 if (buf == f->buffer) { 287 f->left = 0; 288 return BUFFILEEOF; 289 } 290 f->bufp = f->buffer + 1; 291 f->left = (buf - f->buffer) - 1; 292 return f->buffer[0]; 293} 294 295/***************************************************************** 296 * TAG( getcode ) 297 * 298 * Read one code from the standard input. If BUFFILEEOF, return -1. 299 * Inputs: 300 * stdin 301 * Outputs: 302 * code or -1 is returned. 303 */ 304 305static char_type rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; 306 307static code_int 308getcode(CompressedFile *file) 309{ 310 register code_int code; 311 register int r_off, bits; 312 register char_type *bp = file->buf; 313 register BufFilePtr raw; 314 315 if ( file->clear_flg > 0 || file->offset >= file->size || 316 file->free_ent > file->maxcode ) 317 { 318 /* 319 * If the next entry will be too big for the current code 320 * size, then we must increase the size. This implies reading 321 * a new buffer full, too. 322 */ 323 if ( file->free_ent > file->maxcode ) { 324 file->n_bits++; 325 if ( file->n_bits == file->maxbits ) 326 file->maxcode = file->maxmaxcode; /* won't get any bigger now */ 327 else 328 file->maxcode = MAXCODE(file->n_bits); 329 } 330 if ( file->clear_flg > 0) { 331 file->maxcode = MAXCODE (file->n_bits = INIT_BITS); 332 file->clear_flg = 0; 333 } 334 bits = file->n_bits; 335 raw = file->file; 336 while (bits > 0 && (code = BufFileGet (raw)) != BUFFILEEOF) 337 { 338 *bp++ = code; 339 --bits; 340 } 341 bp = file->buf; 342 if (bits == file->n_bits) 343 return -1; /* end of file */ 344 file->size = file->n_bits - bits; 345 file->offset = 0; 346 /* Round size down to integral number of codes */ 347 file->size = (file->size << 3) - (file->n_bits - 1); 348 } 349 r_off = file->offset; 350 bits = file->n_bits; 351 /* 352 * Get to the first byte. 353 */ 354 bp += (r_off >> 3); 355 r_off &= 7; 356 /* Get first part (low order bits) */ 357#ifdef NO_UCHAR 358 code = ((*bp++ >> r_off) & rmask[8 - r_off]) & 0xff; 359#else 360 code = (*bp++ >> r_off); 361#endif /* NO_UCHAR */ 362 bits -= (8 - r_off); 363 r_off = 8 - r_off; /* now, offset into code word */ 364 /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ 365 if ( bits >= 8 ) { 366#ifdef NO_UCHAR 367 code |= (*bp++ & 0xff) << r_off; 368#else 369 code |= *bp++ << r_off; 370#endif /* NO_UCHAR */ 371 r_off += 8; 372 bits -= 8; 373 } 374 /* high order bits. */ 375 code |= (*bp & rmask[bits]) << r_off; 376 file->offset += file->n_bits; 377 378 return code; 379} 380 381static int 382BufCompressedSkip (BufFilePtr f, int bytes) 383{ 384 int c; 385 while (bytes--) 386 { 387 c = BufFileGet(f); 388 if (c == BUFFILEEOF) 389 return BUFFILEEOF; 390 } 391 return 0; 392} 393 394#ifdef TEST 395int 396main (int argc, char *argv[]) 397{ 398 BufFilePtr inputraw, input, output; 399 int c; 400 401 inputraw = BufFileOpenRead (0); 402 input = BufFilePushCompressed (inputraw); 403 output = BufFileOpenWrite (1); 404 while ((c = BufFileGet (input)) != BUFFILEEOF) 405 BufFilePut (c, output); 406 BufFileClose (input, FALSE); 407 BufFileClose (output, FALSE); 408 return 0; 409} 410#endif 411