/* * nusq.c - Huffman squeeze/unsqueeze routines * * NuLib v3.2 March 1992 Freeware (distribute, don't sell) * By Andy McFadden (fadden@uts.amdahl.com) */ #ifdef APW segment "Compress" #endif #include "nudefs.h" #include #include #ifdef UNIX # include #endif #ifdef MSDOS /* For file IO */ # include # include # include # include #endif #include "nuetc.h" /* * usq.c - undo Huffman coding * Adapated from code By Marcel J.E. Mol * Based on sq3/usq2 by Don Elton * * Squeezed file format: * 2 bytes MAGIC * 2 bytes dummy ??? (maybe CRC or checksum; not checked) * filename ended by \0 * * 2 bytes node count * node count node values, each 2 bytes * squeezed data per byte * * NuFX SQueezed format includes only the node count, node values, and * the data. The BLU routines are expected to strip off the MAGIC, * checksum, and filename before calling this. */ /*char *copyright = "@(#) usq.c 2.1 18/06/88 (c) M.J.E. Mol";*/ #define BUFSIZE 128 #define MAGIC 0xff76 /* Squeezed file magic */ #define DLE 0x90 /* repeat byte flag */ #define NOHIST 0 /* no relevant history */ #define INREP 1 /* sending a repeated value */ #define SPEOF 256 /* special endfile token */ #define NUMVALS 257 /* 256 data values plus SPEOF */ /* global variable declarations */ char *sfn; /* squeezed file name */ struct nd { /* decoding tree */ int child[2]; /* left, right */ } node[NUMVALS]; /* use large buffer */ int state; /* repeat unpacking state */ int bpos; /* last bit position read */ int curin; /* last byte value read */ int numnodes; /* number of nodes in decode tree */ static unsigned char fromc; /* for use in text translation */ static BOOLEAN trbool; /* BOOLEAN version of transfrom */ /* Get an integer from the input stream */ static twobyt get_int(f) FILE *f; { twobyt val; val = (twobyt)getc(f); val += (twobyt)getc(f) << 8; return (val); } static int getc_usq(f) /* get byte from squeezed file */ FILE *f; /* file containing squeezed data */ { register short i; /* tree index */ /* follow bit stream in tree to a leaf */ for (i=0; (i <= 0x7fff) && (i>=0); )/* work down(up?) from root */ { if (++bpos > 7) { if ((curin=getc(f)) == EOF) return(EOF); bpos = 0; /* move a level deeper in tree */ i = node[i].child[1 & curin]; } else i = node[i].child[1 & (curin >>= 1)]; } /* decode fake node index to original data value */ i = -(i + 1); /* decode special endfile token to normal EOF */ return ((i==SPEOF) ? EOF : i); } /* putc-ncr -- decode non-repeat compression. Bytes are passed one * at a time in coded format, and are written out uncoded. * The data is stored normally, except that runs of more * than two characters are represented as: * * * * With a special case that a count of zero indicates a DLE * as data, not as a repeat marker. */ static void putc_ncr(c, t) /* put NCR coded bytes */ unsigned char c; /* next byte of stream */ FILE *t; /* file to receive data */ { static int lastc; /* last character seen */ /* if converting line terminators, do so now */ if (trbool && (c == fromc)) #ifdef UNIX c = 0x0a; #else # ifdef APW c = 0x0d; # else c = 0x0d; /* No CRLF stuff in unSQueeze... sorry */ # endif #endif switch (state) { /* action depends on our state */ case NOHIST: /* no previous history */ if (c==DLE) /* if starting a series */ state = INREP; /* then remember it next time */ else putc(lastc=c, t); /* else nothing unusual */ return; case INREP: /* in a repeat */ if (c) /* if count is nonzero */ while (--c) /* then repeatedly ... */ putc(lastc, t); /* ... output the byte */ else putc(DLE, t); /* else output DLE as data */ state = NOHIST; /* back to no history */ return; default: fprintf(stderr, "%s: bad NCR unpacking state (%d)", prgName, state); } } static int init_usq(f) /* initialize Huffman unsqueezing */ FILE *f; /* file containing squeezed data */ { register int i; /* node index */ switch (transfrom) { case -1: /* no translation */ trbool = 0; break; case 0: /* from ProDOS */ trbool = 1; fromc = 0x0d; break; case 1: /* from UNIX */ trbool = 1; fromc = 0x0a; break; case 2: /* from MS-DOS... this needs fixing */ trbool = 1; fromc = 0x0a; /* just turn LFs into whatever... */ break; default: /* unknown */ fprintf(stderr, "%s: unknown translation type %d\n", prgName, trbool); fprintf(stderr, "%s: assuming conversion from CR\n", prgName); trbool = 1; /* should just ignore flag, but other procs do this */ fromc = 0x0d; break; } bpos = 99; /* force initial read */ numnodes = get_int(f); /* get number of nodes */ if (numnodes<0 || numnodes>=NUMVALS) { fprintf(stderr, "%s: usq: archived file has invalid decode tree\n", prgName); return (-1); } /* initialize for possible empty tree (SPEOF only) */ node[0].child[0] = -(SPEOF + 1); node[0].child[1] = -(SPEOF + 1); for (i=0; i