/* File: minunsplay.c Author: Douglas Jones, Dept. of Comp. Sci., U. of Iowa, Iowa City, IA 52242. Date: Nov. 5, 1990. (derived from the Feb. 14 1990 version by stripping out irrelevancies) (minor revision of Feb. 20, 1989 to add exit(0) at end of program). (minor revision of Nov. 14, 1988 to detect corrupt input better). (minor revision of Aug. 8, 1988 to eliminate unused vars, fix -c). Copyright: This material is derived from code Copyrighted 1988 by Jeffrey Chilton and Douglas Jones. That code contained a copyright notice allowing copying for personal or research purposes, so long as copies of the code were not sold for direct commercial advantage. This version of the code has been stripped of most of the material added by Jeff Chilton, and this release of the code may be used or copied for any purpose, public or private. Patents: The algorithm central to this code is entirely the invention of Douglas Jones, and it has not been patented. Any patents claiming to cover this material are invalid. Exportability: Splay-tree based compression algorithms may be used for cryptography, and when used as such, they may not be exported from the United States without appropriate approval. All cryptographic features of the original version of this code have been removed. Language: C Purpose: Data uncompression program, a companion to minsplay.c Algorithm: Uses a splay-tree based prefix code. For a full understanding of the operation of this data compression scheme, refer to the paper "Applications of Splay Trees to Data Compression" by Douglas W. Jones in Communications of the ACM, Aug. 1988, pages 996-1007. */ #include /* The magic numbers are a two byte prefix on the stream of compressed data. This prefix is applied by the main program, and it serves to distinguish files compressed this way from files produced by other software. The particular prefix used here is compatible with the splay-compress UNIX data compression utility. In other contexts, there is no reason to use this particular prefix or any prefix at all. */ #define MAGIC1 0x93 /* ^S with the high bit set */ #define MAGIC2 0x10 /* ^P */ /* The following constants depend on the size of the alphabet being compressed, and are used to dimension the arrays that hold the tree used for compression and to mark key elements in these trees. Throughout, it is assumed that the alphabet of source characters is contiguous and runs from zero to some maximum. */ #define MAXCHAR 256 /* maximum source character code */ #define SUCCMAX 257 /* MAXCHAR + 1 */ #define TWICEMAX 513 /* 2 * MAXCHAR + 1 */ #define SUCCTWICE 514 /* TWICEMAX + 1 */ #define ROOT 1 /* index of root node in the arrays left,right,up */ /* data structures used to unpack successive bits from bytes. */ #define TOPBITINBUFFER 128 /* mask for the most sig bit of 8 bit byte */ #define MAXBITCOUNTER 8 /* size of a byte */ short int bitbuffer; /* buffer to hold a byte for unpacking bits */ short int bitcounter = 0; /* count of remaining bits in buffer */ short int plain; /* most recent character uncompressed */ /* global variables that hold the tree used for uncompression. Node i of the tree is stored in left[i], right[i] and up[i]. Nodes from the root (node 1) to node MAXCHAR are internal nodes of the tree, and nodes SUCCMAX to SUCCTWICE are leaves. For an alphabet of MAXCHAR characters, this allows one extra character to be used as an end-of-file mark. */ short int left[SUCCMAX]; short int right[SUCCMAX]; short int up[SUCCTWICE]; /* begin error messages */ bad_magic() { fprintf(stderr, "Error: input not in splayed format\n"); exit(-1); } bad_data() { fprintf(stderr, "Error: corrupt input\n"); exit(-1); } /* end error messages */ /* begin build initial splay tree */ initsplay() { short int i, j; for (i = 2; i <= TWICEMAX; ++i) { up[i] = i/2; } for (j = 1; j <= MAXCHAR; ++j) { left[j] = 2 * j; right[j] = 2 * j + 1; } } /* end build initial splay tree */ /* begin uncompress function */ uncompress() { register short int a, b, c, d; \ a = ROOT; do { /* once for each bit on path */ if(bitcounter == 0) { bitbuffer = getchar(); if ((bitbuffer == EOF) && feof(stdin)) { bad_data(); } bitcounter = MAXBITCOUNTER; } --bitcounter; if ((bitbuffer & TOPBITINBUFFER) != 0) { a = right[a]; } else { a = left[a]; } bitbuffer = bitbuffer << 1; } while (a <= MAXCHAR); plain = a - SUCCMAX; /* now splay tree about leaf a */ do { /* walk up the tree semi-rotating pairs of nodes */ if ((c = up[a]) != ROOT) { /* a pair remains */ d = up[c]; b = left[d]; if (c == b) { b = right[d]; right[d] = a; } else { left[d] = a; } if (left[c] == a) { left[c] = b; } else { right[c] = b; } up[a] = d; up[b] = c; a = d; } else { a = c; } } while (a != ROOT); } /* end uncompress function */ /* THE MAIN PROGRAM */ main(argc, argv) int argc; char *argv[]; { initsplay(); /* check the magic number as produced by the UNIX splay utility */ if (getchar() != MAGIC1) bad_magic(); if (getchar() != MAGIC2) bad_magic(); if (getchar() != 1) bad_magic(); /* begin uncompress input */ for (;;) { uncompress(); if (plain != MAXCHAR) { putchar(plain); } else { break; } } /* end uncompress input */ /* see if file really ended */ if ((getchar() != EOF) || !feof(stdin)) { bad_data(); } }