/* * Huffman decompressor (new files to standard output) * Usage: pcat filename... */ static char pcatvers[] = "@(#)pcat.c 1.3"; #include <stdio.h> #include <setjmp.h> #include <sys/types.h> #include <sys/stat.h> jmp_buf env; char *argv0, *argvk; short errorm; #if u370 #define BLKSIZE 4096 /*u370*/ #else #define BLKSIZE 512 #endif #define NAMELEN 80 #define SUF0 '.' #define SUF1 'z' #define US 037 #define RS 036 #ifdef pdp11 #define COMPATABILITY #endif /* variables associated with i/o */ char filename [NAMELEN+2]; short infile; short outfile; short inleft; char *inp; char *outp; char inbuff [BLKSIZE]; char outbuff [BLKSIZE]; /* the dictionary */ long origsize; short maxlev; short intnodes [25]; char *tree [25]; char characters [256]; char *eof; /* read in the dictionary portion and build decoding structures */ /* return 1 if successful, 0 otherwise */ getdict () { register int c, i, nchildren; /* * check two-byte header * get size of original file, * get number of levels in maxlev, * get number of leaves on level i in intnodes[i], * set tree[i] to point to leaves for level i */ eof = &characters[0]; inbuff[6] = 25; inleft = read(infile, &inbuff[0], BLKSIZE); if (inleft < 0) { eprintf (".z: read error"); return (0); } if (inbuff[0] != US) goto goof; #ifdef COMPATABILITY if (inbuff[1] == US) { /* oldstyle packing */ if (setjmp(env)) return (0); expand(); return (1); } #endif if (inbuff[1] != RS) goto goof; inp = &inbuff[2]; origsize = 0; for (i=0; i<4; i++) { origsize = origsize*256 + ((*inp++) & 0377); } maxlev = *inp++ & 0377; if (maxlev > 24) { goof: eprintf (".z: not in packed format"); return (0); } for (i=1; i<=maxlev; i++) intnodes[i] = *inp++ & 0377; for (i=1; i<=maxlev; i++) { tree[i] = eof; for (c=intnodes[i]; c>0; c--) { if (eof >= &characters[255]) goto goof; *eof++ = *inp++; } } *eof++ = *inp++; intnodes[maxlev] += 2; inleft -= inp-&inbuff[0]; if (inleft < 0) goto goof; /* * convert intnodes[i] to be number of * internal nodes possessed by level i */ nchildren = 0; for (i=maxlev; i>=1; i--) { c = intnodes[i]; intnodes[i] = nchildren /= 2; nchildren += c; } return (decode()); } /* unpack the file */ /* return 1 if successful, 0 otherwise */ decode () { register int bitsleft, c, i; int j, lev; char *p; outp = &outbuff[0]; lev = 1; i = 0; while (1) { if (inleft <= 0) { inleft = read(infile, inp = &inbuff[0], BLKSIZE); if (inleft < 0) { eprintf (".z: read error"); return (0); } } if (--inleft < 0) { uggh: eprintf (".z: unpacking error"); return (0); } c = *inp++; bitsleft = 8; while (--bitsleft >= 0) { i *= 2; if (c & 0200) i++; c <<= 1; if ((j = i-intnodes[lev]) >= 0) { p = &tree[lev][j]; if (p == eof) { c = outp-&outbuff[0]; if (write(outfile, outbuff, c) != c) { wrerr: eprintf (": write error"); return (0); } origsize -= c; if (origsize != 0) goto uggh; return(1); } *outp++ = *p; if (outp == &outbuff[BLKSIZE]) { if (write(outfile, outp = &outbuff[0], BLKSIZE) != BLKSIZE) goto wrerr; origsize -= BLKSIZE; } lev = 1; i = 0; } else lev++; } } } main(argc, argv) short argc; char *argv[]; { register int i, k; int sep; register char *cp; int fcount = 0; /* failure count */ argv0 = argv[0]; for (k = 1; k<argc; k++) { errorm = 0; sep = -1; cp = filename; for (i=0; i < (NAMELEN-3) && (*cp = argv[k][i]); i++) if (*cp++ == '/') sep = i; if (cp[-1]==SUF1 && cp[-2]==SUF0) { argv[k][i-2] = '\0'; /* Remove suffix and try again */ k--; continue; } fcount++; /* expect the worst */ argvk = argv[k]; if (i >= (NAMELEN-3) || (i-sep) > 13) { eprintf (": file name too long"); goto done; } *cp++ = SUF0; *cp++ = SUF1; *cp = '\0'; if ((infile = open(filename, 0)) == -1) { eprintf (".z: cannot open"); goto done; } outfile = 1; /* standard output */ if (getdict()) { /* unpack */ fcount--; /* success after all */ } close(infile); done: if (errorm) fprintf (stderr, "\n"); } return (fcount); } eprintf(s) char *s; { if (!errorm) { errorm = 1; fprintf (stderr, "%s: %s", argv0, argvk); } fprintf (stderr, s); } #ifdef COMPATABILITY /* this code is for unpacking files, which were packed using the previous algorithm */ int Tree [1024]; expand() { register int tp, bit, word; int keysize, i, *t; outp = outbuff; inp = &inbuff[2]; inleft -= 2; origsize = ((long int ) (unsigned) getwd())*256*256; origsize += (unsigned) getwd(); t = Tree; for ( keysize=getwd(); keysize--; ) { if ((i = getch()) == 0377) *t++ = getwd(); else *t++ = i & 0377; } bit = tp = 0; for (;;) { if (bit <= 0) { word = getwd(); bit = 16; } tp += Tree[tp + (word<0)]; word <<= 1; bit--; if (Tree[tp] == 0) { putch(Tree[tp+1]); tp = 0; if ((origsize -= 1) == 0) { write (outfile, outbuff, outp-&outbuff[0]); return; } } } } getch() { if (inleft <= 0) { inleft = read (infile, inp=inbuff, BLKSIZE); if (inleft < 0) { eprintf (".z: read error"); longjmp (env, 1); } } inleft--; return (*inp++ & 0377); } getwd() { register char c; register d; c = getch(); d = getch(); d <<= 8; d |= (c & 0377); return (d); } putch(c) char c; { register int n; *outp++ = c; if (outp == &outbuff[BLKSIZE]) { n = write (outfile, outp=outbuff, BLKSIZE); if (n < BLKSIZE) { eprintf (": write error"); longjmp (env, 2); } } } #endif