Received: by NDSUVM1 (Mailer R2.07) id 6539; Wed, 23 May 90 17:24:15 CDT Date: Wed, 23 May 90 17:47:03 EDT Reply-To: Apple II List Sender: Apple II List From: Grant Delaney Subject: NuLib v2.2 (C NuFX archiver) source (UNIX/IIgs/MS-DOS) [05/06] To: "Steven E. Nelson" ---- Cut Here and unpack ---- #!/bin/sh # This is part 05 of a multipart archive if touch 2>&1 | fgrep '[-amc]' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= nuread.c ============== if test X"$1" != X"-c" -a -f 'nuread.c'; then echo "File already exists: skipping 'nuread.c'" else echo "x - extracting nuread.c (Text)" sed 's/^X//' << 'SHAR_EOF' > nuread.c && X/* X * nuread.c - read NuFX archives (header info only) into structures X * X * By Andy McFadden (fadden@cory.berkeley.edu) X * NuLib v2.2 April 1990 Freeware (distribute, don't sell) X */ X X#include "nudefs.h" X#include X#include X#include X X#ifdef MSDOS /* For file IO */ X# include /* errno, among others */ X# include X# include X# include X# include X#endif X X#ifdef CRC_TAB X# include "crc.h" /* fast CRC lookup */ X#endif X#include "nuread.h" X#include "nupak.h" /* uses PAKBUFSIZ */ X#include "nuetc.h" X X#define UNKNOWN_FN "" X X/* quick proc to save x00 bytes of static storage */ Xvoid OtherArc(str1, str2) X{ X fprintf(stderr, "File may be %s; try \"%s\".\n", str1, str2); X} X X/* swap two bytes if HiLo is TRUE */ Xvoid HiSwap(ptr, a, b) Xonebyt *ptr; Xregister onebyt a, b; X{ X register onebyt tmp; X X if (HiLo) { X tmp = ptr[a], ptr[a] = ptr[b], ptr[b] = tmp; X } X} X X X/* copy bytes from buffer to buffer, reversing byte order if necessary */ Xvoid BCopy(srcptr, destptr, num, order) Xonebyt *srcptr, *destptr; Xregister int num; XBOOLEAN order; /* true if byte ordering is important */ X{ X register int i = num--; X X if (order && HiLo) { X while (i--) { /* copy & reverse */ X *(destptr+i) = *(srcptr + num - i); /* dest+3 = src + 3 - 3 .. */ X } X } else if (order) { X while (i--) { /* copy only */ X *(destptr+i) = *(srcptr + i); X } X } else { X while (i--) { /* byte ordering not important; just copy */ X *(destptr+i) = *(srcptr+i); X } X } X} X X X/* X * Calculate CRC on a region X * X * A CRC is the result of a mathematical operation based on the X * coefficients of a polynomial when multiplied by X^16 then divided by X * the generator polynomial (X^16 + X^12 + X^5 + 1) using modulo two X * arithmetic. X * X * This routine is a slightly modified verison of one found in: X * _Advanced Programming Techniques for the Apple //gs Toolbox_ X * By Morgan Davis and Dan Gookin (Compute! Publications, Inc.) X * It can either calculate the CRC bit-by-bit or use a table. X * [ one of the few //gs books worth the money +atm ] X */ Xtwobyt CalcCRC(seed, ptr, count) Xtwobyt seed; /* initial value for CRC */ Xonebyt *ptr; /* pointer to start of data buffer */ Xint count; /* number of bytes to scan through - note 64K max */ X{ X register int x; X register twobyt CRC = seed; X X do { X#ifndef CRC_TAB X CRC ^= *ptr++ << 8; /* XOR hi-byte of CRC w/data */ X for (x = 8; x; --x) /* Then, for 8 bit shifts... */ X if (CRC & 0x8000) /* Test hi order bit of CRC */ X CRC = CRC << 1 ^ 0x1021; /* if set, shift & XOR w/$1021 */ X else X CRC <<= 1; /* Else, just shift left once. */ X#else X CRC = updcrc(*ptr++, CRC); /* look up new value in table */ X#endif X } while (--count); X return (CRC); X} X X X/* X * Test an archive's integrity. X * X * Reads the entire file, and checks CRCs for certain things. X */ Xvoid NuTest(filename, options) Xchar *filename; Xchar *options; X{ X ListHdr *archive; X onebyt *copybuf; /* buffer for reading record */ X int partial; /* size for partial read */ X unsigned int rec; X RNode *RNodePtr; X MHblock *MHptr; X TNode *TNodePtr; X long hdr_size, total_size, thread_size; X int srcfd; /* file descriptor */ X int thread; X twobyt CRC, RecordCRC; X long CRCsum = 0L; /* sum of CRCs for all records */ X BOOLEAN check_thread_crc; /* TRUE if we want to check a give thread */ X static char *procName = "NuTest"; X X printf("Testing %s", filename); X if (verbose) printf("\n"); X else { printf("..."); fflush(stdout); } X X archive = NuRead(filename); /* this catches most errors... */ X X MHptr = archive->MHptr; X RNodePtr = archive->RNodePtr; X copybuf = (onebyt *) Malloc(PAKBUFSIZ); X if ((srcfd = open(filename, O_RDONLY | O_BINARY)) < 0) X Fatal("Unable to close archive", procName); X if (lseek(srcfd, (long) MHsize, S_ABS) < 0) /* seek past master block */ X Fatal("Bad seek (MH)", procName); X X for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) { X if (verbose) printf("Record %d (%s): ", rec, RNodePtr->filename); X hdr_size = (long) RNodePtr->RHptr->attrib_count; X hdr_size += (long) RNodePtr->filename_length; X total_size = hdr_size; X TNodePtr = RNodePtr->TNodePtr; X for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){ X if (TNodePtr == (TNode *) NULL) { X fprintf(stderr, "Internal error: Bad thread structure\n"); X Quit(-1); X } X hdr_size += (long) THsize; X total_size += (long) THsize; X total_size += TNodePtr->THptr->comp_thread_eof; X TNodePtr = TNodePtr->TNext; X } X if (verbose) { X printf("total record size = %ld (%d threads)\n", total_size, X (int) RNodePtr->RHptr->total_threads); X fflush(stdout); X } X X /* read record header */ X RecordCRC = 0; X while (hdr_size != 0L) { X if (hdr_size > (long) PAKBUFSIZ) { X partial = (unsigned int) PAKBUFSIZ; X hdr_size -= (long) PAKBUFSIZ; X } else { X partial = (unsigned int) hdr_size; X hdr_size = 0L; X } X X if (read(srcfd, copybuf, partial) != partial) { X fprintf(stderr, ">>> Read error"); X if (verbose) fprintf(stderr, "\n"); X else fprintf(stderr, X " - record %d (%s)\n", rec, RNodePtr->filename); X fprintf(stderr, "Operation aborted.\n"); X Quit(-1); X } X if (verbose) RecordCRC = CalcCRC(CRC, (onebyt *) copybuf, partial); X } X X TNodePtr = RNodePtr->TNodePtr; X for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){ X if (lseek(srcfd, (long) TNodePtr->fileposn, S_ABS) < 0) X Fatal("whoops!", procName); X thread_size = TNodePtr->THptr->comp_thread_eof; X X /* decide whether or not to check thread CRCs */ X check_thread_crc = FALSE; X if (RNodePtr->RHptr->version_number >= 2) /* valid CRCs */ X if (TNodePtr->THptr->thread_class == 2) /* data_thread */ X check_thread_crc = TRUE; X X if (check_thread_crc) CRC = 0xffff; X while (thread_size != 0L) { X if (thread_size > (long) PAKBUFSIZ) { X partial = (unsigned int) PAKBUFSIZ; X thread_size -= (long) PAKBUFSIZ; X } else { X partial = (unsigned int) thread_size; X thread_size = 0L; X } X X if (read(srcfd, copybuf, partial) != partial) { X fprintf(stderr, ">>> Read error in thread"); X if (verbose) fprintf(stderr, " %d\n", thread); X else fprintf(stderr, " - record %d (%s), thread %d\n", X rec, RNodePtr->filename, thread); X fprintf(stderr, "Operation aborted.\n"); X Quit(-1); X } X X if (verbose) X RecordCRC = CalcCRC(RecordCRC, (onebyt *)copybuf, partial); X X /* calculate CRC for thread, and compare with thread_crc */ X if (check_thread_crc) X CRC = CalcCRC(CRC, (onebyt *) copybuf, partial); X#ifdef DEBUG X printf( X"At posn %ld: rec %d/thread %d (%ld bytes) CalcCRC = 0x%.4x (0x%.4x)\n", XTNodePtr->fileposn, rec, thread, thread_size, CRC, TNodePtr->THptr->thread_crc X ); X#endif X } X X /* check and see if CRC matches */ X if (check_thread_crc) { X if (CRC != TNodePtr->THptr->thread_crc) { X fprintf(stderr, ">>> Bad CRC for thread %d", X thread); X if (verbose) fprintf(stderr, "\n"); X else fprintf(stderr, " in record %d\n", rec); X } X } X TNodePtr = TNodePtr->TNext; X } X X if (verbose) { X printf("--- CRC for entire record was $%.4x\n", RecordCRC); X CRCsum += RecordCRC; X } X RNodePtr = RNodePtr->RNext; X } X if (close(srcfd) < 0) X Fatal("Unable to close archive", procName); X X free(copybuf); X if (verbose) printf("Sum of CRCs = $%.8lx\n", CRCsum); X printf("done.\n"); X} X X X/* X * Read thread header data, and skip data fields X */ X Xstatic TNode *ReadThreads(fd, RHptr, RNodePtr, CRC_ptr) Xint fd; XRHblock *RHptr; XRNode *RNodePtr; Xtwobyt *CRC_ptr; /* CRC seed; result is returned thru this */ X{ X int i; X unsigned int size; X BOOLEAN first; X TNode *TNodePtr, *THeadPtr = (TNode *) NULL; X THblock *THptr; X char filebuf[THsize]; X twobyt CRC = *CRC_ptr; X static char *procName = "ReadThreads"; X X RNodePtr->unc_len = 0L; X RNodePtr->comp_len = 0L; X first = TRUE; X for (i = 0; i < RHptr->total_threads; i++) { X if (first) { /* create first block, or... */ X TNodePtr = (TNode *) Malloc(sizeof(TNode)); X THeadPtr = TNodePtr; X first = FALSE; X } else { /* create next block and go on */ X TNodePtr->TNext = (TNode *) Malloc(sizeof(TNode)); X TNodePtr = TNodePtr->TNext; X } X TNodePtr->TNext = (TNode *) NULL; X X /* Create the thread header block, and read it in */ X TNodePtr->THptr = (THblock *) Malloc(sizeof(THblock)); X THptr = TNodePtr->THptr; X X if (size = read(fd, filebuf, THsize) < THsize) { /* should be 16 */ X printf("read size = %d, THsize = %d\n", size, THsize); X Fatal("ReadThread (THblock)", procName); X } X CRC = CalcCRC(CRC, (onebyt *) filebuf, 16); /* hdr CRC part(s) 5/5 */ X X /* copy all fields... */ X BCopy(filebuf+0, (onebyt *) &THptr->thread_class, 2, TRUE); X BCopy(filebuf+2, (onebyt *) &THptr->thread_format, 2, TRUE); X BCopy(filebuf+4, (onebyt *) &THptr->thread_kind, 2, TRUE); X BCopy(filebuf+6, (onebyt *) &THptr->thread_crc, 2, TRUE); X BCopy(filebuf+8, (onebyt *) &THptr->thread_eof, 4, TRUE); X BCopy(filebuf+12, (onebyt *) &THptr->comp_thread_eof, 4, TRUE); X X RNodePtr->unc_len += THptr->thread_eof; X RNodePtr->comp_len += THptr->comp_thread_eof; X if (THptr->comp_thread_eof > 2097152L) /* SANITY CHECK */ X fprintf(stderr, "Sanity check: found comp_thread_eof > 2MB\n"); X } X X /* skip the actual data */ X TNodePtr = THeadPtr; X for (i = 0; i < RHptr->total_threads; i++) { X THptr = TNodePtr->THptr; X if ((TNodePtr->fileposn = lseek(fd, 0L, S_REL)) < 0) X Fatal("Bad thread posn lseek()", procName); X X /* pull filenames out of threads, if present */ X if (THptr->thread_class == 0x0003) { /* filename thread */ X RNodePtr->filename = (char *) Malloc(THptr->thread_eof +1); X if (read(fd, RNodePtr->filename, THptr->thread_eof) < 0) { X fprintf(stderr, "Error on thread %d\n", i); X Fatal("Unable to read filename", procName); X } X RNodePtr->filename[THptr->thread_eof] = '\0'; X RNodePtr->real_fn_length = THptr->thread_eof; X X { /* patch to fix bug in ShrinkIt v3.0.0 */ X int j, name_len = strlen(RNodePtr->filename); X X for (j = 0; j < name_len; j++) { X RNodePtr->filename[j] &= 0x7f; /* clear hi bit */ X } X } X X if (lseek(fd, TNodePtr->fileposn, S_ABS) < 0) X Fatal("Unable to seek back after fn", procName); X } X if (lseek(fd, THptr->comp_thread_eof, S_REL) < 0) X Fatal("Bad skip-thread seek", procName); X TNodePtr = TNodePtr->TNext; X } X *CRC_ptr = CRC; X return (THeadPtr); X} X X X/* X * Read header data from a NuFX archive into memory X */ XListHdr *NuRead(filename) Xchar *filename; X{ X int fd; /* archive file descriptor */ X char namebuf[MAXFILENAME]; X int rec, num; X BOOLEAN first; X twobyt namelen; X twobyt CRC; X ListHdr *ListPtr; /* List Header struct */ X MHblock *MHptr; /* Master Header block */ X RNode *RNodePtr; /* Record Node */ X RHblock *RHptr; /* Record Header block */ X onebyt filebuf[RECBUFSIZ]; /* must be > RH, MH, or atts-RH size */ X static char *procName = "NuRead"; X X ListPtr = (ListHdr *) Malloc(sizeof(ListHdr)); /* create head of list */ X ListPtr->arc_name = (char *) Malloc(strlen(filename)+1); /* archive fnam * / X strcpy(ListPtr->arc_name, filename); X ListPtr->MHptr = (MHblock *) Malloc(sizeof(MHblock)); /* master block */ X X if ((fd = open(filename, O_RDONLY | O_BINARY)) < 0) { X if (errno == ENOENT) { X fprintf(stderr, "%s: can't find file '%s'\n", prgName, filename); X Quit (-1); X } else X Fatal("Unable to open archive", procName); X } X X /* create and read the master header block */ X MHptr = ListPtr->MHptr; X if (read(fd, filebuf, MHsize) < MHsize) { X fprintf(stderr, "File '%s' may not be a NuFX archive\n", filename); X Fatal("Unable to read Master Header Block", procName); X } X X CRC = CalcCRC(0, (onebyt *) filebuf+8, MHsize-8); /* master header CRC */ X X /* Copy data to structs, correcting byte ordering if necessary */ X BCopy(filebuf+0, (onebyt *) MHptr->ID, 6, FALSE); X BCopy(filebuf+6, (onebyt *) &MHptr->master_crc, 2, TRUE); X BCopy(filebuf+8, (onebyt *) &MHptr->total_records, 4, TRUE); X BCopy(filebuf+12, (onebyt *) &MHptr->arc_create_when, sizeof(Time), FALSE) ; X BCopy(filebuf+20, (onebyt *) &MHptr->arc_mod_when, sizeof(Time), FALSE); X BCopy(filebuf+28, (onebyt *) &MHptr->master_version, 2, TRUE); X BCopy(filebuf+30, (onebyt *) MHptr->reserved1, 8, FALSE); X BCopy(filebuf+38, (onebyt *) &MHptr->master_eof, 4, TRUE); /* m_v $0001 * / X BCopy(filebuf+42, (onebyt *) MHptr->reserved2, 6, FALSE); X X if (strncmp(MHptr->ID, MasterID, 6)) { X fprintf(stderr, "\nFile '%s' is not a NuFX archive\n", filename); X if ((filebuf[0] == 10) && (filebuf[1] == 71) && X (filebuf[2] == 76) && (filebuf[18] == 2)) X#ifdef NO_BLU X OtherArc("Binary II", "unblu"); X#else X fprintf(stderr, "File may be Binary II; try 'B' option\n"); X#endif X if ((filebuf[0] == '\037') && (filebuf[1] == '\036')) X OtherArc("packed", "unpack"); X if ((filebuf[0] == (onebyt)'\377') && (filebuf[1] == '\037')) X OtherArc("compacted", "uncompact"); X if ((filebuf[0] == '\037') && (filebuf[1] == (onebyt)'\235')) X OtherArc("compressed", "uncompress"); X if ((filebuf[0] == 0x76) && (filebuf[1] == 0xff)) X OtherArc("SQueezed", "usq"); X if ((filebuf[0] == 0x04) && (filebuf[1] == 0x03) && X (filebuf[2] == 0x4b) && (filebuf[3] == 0x50)) X OtherArc("a ZIP archive", "UnZip"); X if (!strncmp((char *) filebuf, "SIT!", 4)) /* StuffIt */ X OtherArc("a StuffIt archive", "StuffIt (Macintosh)"); X if (!strncmp((char *) filebuf, "", 4)) /* system V arch */ X OtherArc("a library archive (Sys V)", "ar"); X if (!strncmp((char *) filebuf, "!", 7)) X OtherArc("a library archive", "ar"); X if (!strncmp((char *) filebuf, "#! /bin/sh", 10) || X !strncmp((char *) filebuf, "#!/bin/sh", 9)) X OtherArc("a shar archive", "/bin/sh"); X if (!strncmp((char *) filebuf, "GIF87a", 6)) X OtherArc("a GIF picture", "?!?"); X /* still need ARC and ZOO */ X X Quit (-1); X } X X if (CRC != MHptr->master_crc) X printf("WARNING: Master Header block may be corrupted (bad CRC)\n"); X X if (MHptr->master_version > MAXMVERS) X printf("WARNING: unknown Master Header version, trying to continue\n"); X X /* main record read loop */ X first = TRUE; X for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) { X if (first) { /* allocate first, or... */ X ListPtr->RNodePtr = (RNode *) Malloc(sizeof(RNode)); X RNodePtr = ListPtr->RNodePtr; X first = FALSE; X } else { /* allocate next, and go on */ X RNodePtr->RNext = (RNode *) Malloc(sizeof(RNode)); /* next Rnode */ X RNodePtr = RNodePtr->RNext; /* move on to next record */ X } X RNodePtr->RNext = (RNode *) NULL; X X RNodePtr->RHptr = (RHblock *) Malloc(sizeof(RHblock)); /* alloc blk */ X /* expansion here */ X RHptr = RNodePtr->RHptr; X if (read(fd, filebuf, RHsize) < RHsize) { /* get known stuff */ X fprintf(stderr,"%s: error in record %d (at EOF?)\n", prgName, rec); X Fatal("Bad RHblock read", procName); X } X X /* rec hdr CRC part 1/5 */ X CRC = CalcCRC(0, (onebyt *) filebuf+6, RHsize-6); X X BCopy(filebuf+0, (onebyt *) RHptr->ID, 4, FALSE); X BCopy(filebuf+4, (onebyt *) &RHptr->header_crc, 2, TRUE); X BCopy(filebuf+6, (onebyt *) &RHptr->attrib_count, 2, TRUE); X BCopy(filebuf+8, (onebyt *) &RHptr->version_number, 2, TRUE); X BCopy(filebuf+10, (onebyt *) &RHptr->total_threads, 2, TRUE); X BCopy(filebuf+12, (onebyt *) &RHptr->reserved1, 2, TRUE); X BCopy(filebuf+14, (onebyt *) &RHptr->file_sys_id, 2, TRUE); X BCopy(filebuf+16, (onebyt *) &RHptr->file_sys_info, 1, TRUE); X BCopy(filebuf+17, (onebyt *) &RHptr->reserved2, 1, TRUE); X BCopy(filebuf+18, (onebyt *) &RHptr->access, 4, TRUE); X BCopy(filebuf+22, (onebyt *) &RHptr->file_type, 4, TRUE); X BCopy(filebuf+26, (onebyt *) &RHptr->extra_type, 4, TRUE); X BCopy(filebuf+30, (onebyt *) &RHptr->storage_type, 2, TRUE); X BCopy(filebuf+32, (onebyt *) &RHptr->create_when, sizeof(Time), FALSE); X BCopy(filebuf+40, (onebyt *) &RHptr->mod_when, sizeof(Time), FALSE); X BCopy(filebuf+48, (onebyt *) &RHptr->archive_when, sizeof(Time), FALSE); X BCopy(filebuf+56, (onebyt *) &RHptr->option_size, 2, TRUE); X /* expansion here */ X X if (strncmp(RHptr->ID, RecordID, 4)) { X fprintf(stderr, "%s: Found bad record ID (#%d) -- exiting\n", X prgName, rec); X Quit (-1); X } X X /* read remaining (unknown) attributes into buffer, if any */ X num = RHptr->attrib_count - RHsize - 2; X if (num > RECBUFSIZ) { X fprintf(stderr, "ERROR: attrib_count > RECBUFSIZ\n"); X Quit (-1); X } X if (num > 0) { X if (read(fd, filebuf, num) < num) X Fatal("Bad xtra attr read", procName); X CRC = CalcCRC(CRC, (onebyt *) filebuf, num); /* hdr CRC part 2/5 */ X } X X if (read(fd, (char *) &namelen, 2) < 2) /* read filename len */ X Fatal("Bad namelen read", procName); X CRC = CalcCRC(CRC, (onebyt *) &namelen, 2); /* rec hdr CRC part 3/5 */ X X HiSwap((onebyt *) &namelen, 0, 1); X /* read filename, and store in struct */ X if (namelen > MAXFILENAME) { X fprintf(stderr, "ERROR: namelen > MAXFILENAME\n"); X Quit (-1); X } X RNodePtr->filename_length = namelen; X X if (namelen > 0) { X RNodePtr->real_fn_length = namelen; X if (read(fd, namebuf, namelen) < namelen) X Fatal("Bad namebuf read", procName); X /* rec hdr CRC part 4/5 */ X CRC = CalcCRC(CRC, (onebyt *) namebuf, namelen); X X RNodePtr->filename = (char *) Malloc(namelen+1); /* store fname */ X BCopy(namebuf, (onebyt *) RNodePtr->filename, namelen, FALSE); X RNodePtr->filename[namelen] = '\0'; X } else { X RNodePtr->filename = UNKNOWN_FN; X RNodePtr->real_fn_length = strlen(UNKNOWN_FN); X } X X RNodePtr->TNodePtr = ReadThreads(fd, RHptr, RNodePtr, &CRC); X /* rec hdr CRC part 5/5 calculated by ReadThreads */ X X if (CRC != RHptr->header_crc) { X printf("WARNING: Detected a bad record header CRC\n"); X printf(" Rec %d in file '%.60s'\n",rec,RNodePtr->filename); X } X } X X /* begin adding new files at this point */ X if ((ListPtr->nextposn = lseek(fd, 0L, S_REL)) < 0) X Fatal("Bad final lseek()", procName); X X if (close(fd) < 0) { X Fatal("Bad close", procName); X } X X if (MHptr->master_version > 0x0000) { X if (MHptr->master_eof != ListPtr->nextposn) { X printf("WARNING: master_eof (stored)=%ld, nextposn (actual)=%ld\n", X MHptr->master_eof, ListPtr->nextposn); X printf( X " (master_eof will be fixed if archive is changed)\n"); X } X } X X return (ListPtr); X} X SHAR_EOF $TOUCH -am 0430183990 nuread.c && chmod 0644 nuread.c || echo "restore of nuread.c failed" set `wc -c nuread.c`;Wc_c=$1 if test "$Wc_c" != "18568"; then echo original size 18568, current size $Wc_c fi fi # ============= nushk.c ============== if test X"$1" != X"-c" -a -f 'nushk.c'; then echo "File already exists: skipping 'nushk.c'" else echo "x - extracting nushk.c (Text)" sed 's/^X//' << 'SHAR_EOF' > nushk.c && X/* X * nushk.c - P8 ShrinkIt compress/uncompress routines X * X * By Andy McFadden (fadden@cory.berkeley.edu) X * NuLib v2.2 April 1990 Freeware (distribute, don't sell) X */ X X#include "nudefs.h" X#include X#include X X#ifdef MSDOS /* For file IO */ X# include X# include X# include X# include X#endif X X#include "nuread.h" /* need CalcCRC() */ X#include "nupak.h" X#include "nuetc.h" X X#define BLKSIZ 4096 X/*#define DEBUG /* do verbose debugging output */ X/*#define DEBUG1 /* debugging output in main routine */ X Xstatic onebyt *ibuf; /* large buffer (usually set to packBuffer) */ Xonebyt lbuf[BLKSIZ+1]; /* temporary buffer for storing data after LZW */ Xonebyt rbuf[BLKSIZ+1]; /* temporary buffer for storing data after RLE */ X X X/* X * Fake ShrinkIt compression routines. X * X * Only removes repeated characters; doesn't actually do the LZW. This X * means that the compression achieved will not be all that great (if it X * compresses at all). X */ X X#define ESCAPE_CHAR 0xdb X X/* X * Do run-length encoding X * X * Takes input from srcptr, and writes to dstptr. Maximum expansion is X * (BLKSIZ / 2) + (BLKSIZ / 2) * 3 == 2 * BLKSIZ X * Output of form char count X */ Xint do_RLE(srcptr, dstptr) Xonebyt *srcptr, *dstptr; X{ X int found, scount, dcount; X onebyt c, lastc, tlastc; X X c = *(srcptr++); scount = 1; X dcount = 0; X found = 1; /* one char has been found */ X lastc = '\0'; X while (scount < BLKSIZ) { X tlastc = lastc; X lastc = c; X c = *(srcptr++); scount++; X X if (found == 1) { /* no run found */ X if (c != lastc) { /* no run starting */ X if (lastc == ESCAPE_CHAR) { X *(dstptr++) = ESCAPE_CHAR; dcount++; X *(dstptr++) = lastc; dcount++; X *(dstptr++) = 0; dcount++; /* found one */ X } else { X *(dstptr++) = lastc; dcount++; X } X found = 1; X } else { X found = 2; /* they matched, so two in a row */ X } X X } else if (found == 2) { /* got two, try for three */ X if (c != lastc) { /* only got two in a row */ X if (lastc == ESCAPE_CHAR) { /* and tlastc as well */ X *(dstptr++) = ESCAPE_CHAR; dcount++; X *(dstptr++) = lastc; dcount++; X *(dstptr++) = 1; dcount++; /* found two */ X } else { X *(dstptr++) = tlastc; dcount++; X *(dstptr++) = lastc; dcount++; X } X found = 1; X } else { /* found 3, got a run going */ X found = 3; X } X X } else { /* (found >= 3), got a run going */ X if (c == lastc) { /* found another */ X found++; X } X if ((c != lastc) || (found > 256)) { /* end, or too many */ X *(dstptr++) = ESCAPE_CHAR; dcount++; X *(dstptr++) = lastc; dcount++; X *(dstptr++) = (found > 256) ? 255 : found-1; X dcount++; X found = 1; /* c has something other than the run char */ X /* or found is 257-256 = 1 */ X } X } X } /* while */ X X /* reached end of buffer; flush what was left */ X if (found == 1) { X if (c == ESCAPE_CHAR) { X *(dstptr++) = ESCAPE_CHAR; dcount++; X *(dstptr++) = c; dcount++; X *(dstptr++) = 0; dcount++; X } else { X *(dstptr++) = c; dcount++; X } X X } else if (found == 2) { X /* maybe have if lastc == c == ESCAPE_CHAR? */ X if (lastc == ESCAPE_CHAR) { X *(dstptr++) = ESCAPE_CHAR; dcount++; X *(dstptr++) = lastc; dcount++; X *(dstptr++) = 0; dcount++; X } else { X *(dstptr++) = lastc; dcount++; X } X if (c == ESCAPE_CHAR) { X *(dstptr++) = ESCAPE_CHAR; dcount++; X *(dstptr++) = c; dcount++; X *(dstptr++) = 0; dcount++; X } else { X *(dstptr++) = c; dcount++; X } X X } else { /* found >= 3, in the middle of processing a run */ X *(dstptr++) = ESCAPE_CHAR; dcount++; X *(dstptr++) = c; dcount++; X *(dstptr++) = found-1; dcount++; X } X X return (dcount); X} X X X/* X * Main entry point. X * X * Returns actual thread_format used. X */ Xlong pak_SHK(srcfd, dstfd, length, copybuf) Xint srcfd, dstfd; Xlong length; /* uncompressed size */ Xonebyt *copybuf; X{ X unsigned int partial; /* size for partial read/write */ X onebyt *rptr; X register int idx; X onebyt scratch[8]; X long srcposn, /* start in source file */ X startposn, /* start in dest file */ X endposn; /* end in dest file */ X long unc_len = length, X comp_len = 0L; X twobyt CRC; X int rlesize; /* length after RLE */ X int sc; /* spin counter */ X static char *procName = "pak_SHK"; X X CRC = 0; X if ((srcposn = lseek(srcfd, 0L, S_REL)) < 0) /* only used if */ X Fatal("Bad seek (srcposn)", procName); /* compress fails */ X if ((startposn = lseek(dstfd, 0L, S_REL)) < 0) X Fatal("Bad seek (startposn)", procName); X lseek(dstfd, 4L, S_REL); /* leave room for 4-byte header */ X comp_len += 4L; X X sc = 0; X do { /* have to handle when length == 0L */ X if (length > (long) BLKSIZ) { X partial = (unsigned int) BLKSIZ; X length -= (long) BLKSIZ; X } else { X partial = (unsigned int) length; X length = 0L; X for (idx = partial; idx < BLKSIZ; idx++) /* fill in zeroes */ X *(copybuf + idx) = 0; X } X X if (partial > 0) { /* should work anyway, but let's be careful */ X if (read(srcfd, copybuf, partial) != partial) X Fatal("Source read failed", procName); X } X /* calc CRC on all 4096 bytes */ X CRC = CalcCRC(CRC, (onebyt *) copybuf, BLKSIZ); X rlesize = do_RLE(copybuf, copybuf + BLKSIZ+1); /* pack 4096 bytes */ X if (rlesize < 0x1000) { /* did it pack or expand? */ X rptr = copybuf + BLKSIZ+1; /* use packed version */ X } else { X rlesize = 0x1000; /* just store original */ X rptr = copybuf; X } X scratch[0] = (onebyt) (rlesize & 0x00ff); X scratch[1] = (onebyt) ((rlesize >> 8) & 0x00ff); X scratch[2] = 0; /* LZW off */ X if (write(dstfd, scratch, 3) != 3) X Fatal("Dest hdr write failed", procName); X comp_len += 3; X comp_len += rlesize; X if (comp_len > unc_len) { X goto bad_compress; /* you didn't see this */ X } X if (write(dstfd, rptr, rlesize) != rlesize) /* need to do CRLF */ X Fatal("Dest write failed", procName); X X sc++; X if (sc == 15) { X sc = 0; X Spin(); X } X } while (length != 0L); X X if ((endposn = lseek(dstfd, 0L, S_REL)) < 0) X Fatal("Bad seek (now)", procName); X if (lseek(dstfd, startposn, S_ABS) < 0) X Fatal("Bad seek (to4)", procName); X scratch[0] = (char) CRC; X scratch[1] = (char) (CRC >> 8); X scratch[2] = 0; X scratch[3] = ESCAPE_CHAR; X if (write(dstfd, scratch, 4) != 4) X Fatal("Dest hdr write failed", procName); X if (lseek(dstfd, endposn, S_ABS) < 0) X Fatal("Bad seek (last)", procName); X X if (comp_len != endposn - startposn) { X printf( X "internal error: comp_len=%ld, endposn=%ld, startposn=%ld (%ld)\n", X comp_len, endposn, startposn, endposn - startposn); X } X packedSize = comp_len; X return (0x0002); /* SHK packing */ X Xbad_compress: /* I'm too lazy to do a procedure call... */ X X if (verbose) { printf("storing..."); fflush(stdout); } X if (lseek(srcfd, srcposn, S_ABS) < 0) X Fatal("Bad seek (srcposn in bad_compress)", procName); X if (lseek(dstfd, startposn, S_ABS) < 0) X Fatal("Bad seek (startposn in bad_compress)", procName); X FCopy(srcfd, dstfd, unc_len, copybuf, FALSE); X packedSize = unc_len; X return (0x0000); /* no compression */ X} X X X/* X * P8 ShrinkIt uncompression routines X * X * Copyright 1989 Kent Dickey X * C translation by Kent Dickey / Andy McFadden X * Modifications for LZW-II by Andy Nicholas / Andy McFadden X */ X Xstatic int inf; /* to make Getc() calls happy */ Xstatic BOOLEAN type2; /* true if working with LZW-II format */ X Xstatic onebyt escape_char; X Xtypedef struct { X unsigned char chr; X int prefix; X} Table_ent; X Xstatic Table_ent Real_tab[BLKSIZ-256]; /* first 256 don't exist */ Xstatic Table_ent *Table; X Xstatic int Mask_tab[16] = { X 0x0000, 0x01ff, 0x03ff, 0x03ff, 0x07ff, X 0x07ff, 0x07ff, 0x07ff, 0x0fff, 0x0fff, X 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, X 0x0fff X}; Xstatic int Number[16] = { X 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; X Xstatic onebyt Stack[100]; /* simulated stack; should be <= 64 */ Xstatic int out_bytes, stack_ptr, entry, at_bit, at_byte; Xstatic onebyt last_byte; /* used in get_code */ X X X/* fake Getc(); easier to make this a macro than to change the code */ X#ifdef DEBUG Xonebyt Getc(foo) Xint foo; /* this is ignored */ X{ X return (*(ibuf++)); X} X#else /* if not debugging, use a macro */ X# define Getc(foo) *(ibuf++) X#endif /* DEBUG */ X X X/* X * Stack operations; used by undo_LZW X */ X#ifdef DEBUG Xvoid push(a_byte) Xunsigned char a_byte; X{ X if (stack_ptr > 100) { X printf("\n*** stack_ptr exceeded 100 in push() [%d]\n", stack_ptr); X exit (-1); X } X Stack[stack_ptr++] = a_byte; X} X#else /* if not debugging, use a macro */ X# define push(a_byte) Stack[stack_ptr++] = a_byte X#endif /* DEBUG */ X X X#ifdef DEBUG Xvoid dump_stack(buffer) Xunsigned char *buffer; X{ X printf("--- Going to dump stack, stack_ptr = %d, out_bytes = %d\n", X stack_ptr, out_bytes); X while (stack_ptr > 0) { X *(buffer + out_bytes++) = Stack[--stack_ptr]; X } X} X#else /* if not debugging, use a macro */ X# define dump_stack(buffer) while (stack_ptr > 0) { \ X *( buffer +out_bytes++) = Stack[--stack_ptr];\ X } X#endif /* DEBUG */ X X X/* X * Decipher LZW codes. X */ Xstatic int get_code(/*Buffer*/) X/*unsigned char *Buffer;*/ X{ X int num_bits, old_bit, last_bit; X long value, mask; X unsigned char byte1, byte2, byte3; /* get compressed chars... */ X X#ifdef DEBUG X printf("ENT: bit=%d byte=%-4d last_byte=$%.2x ", X at_bit, at_byte, last_byte); X printf("Entry: %.4x \n", entry); X#endif X X num_bits = ((entry+1) >> 8); /* get hi-byte of entry */ X last_bit = at_bit + Number[num_bits] + 8; X old_bit = at_bit; X#ifdef DEBUG X if (at_byte >= BLKSIZ) { X fprintf(stderr, "at_byte exceeded BLKSIZ (4096) in get_code()\n"); X exit (-1); X } X#endif X if (at_bit == 0) X last_byte = Getc(inf); X byte1 = last_byte; /* first byte = last one used */ X byte2 = Getc(inf); X if (last_bit > 16) { /* get 3rd byte if nec. */ X byte3 = Getc(inf); X last_byte = byte3; X } else { X byte3 = 0; X last_byte = byte2; X } X value = ((((long)byte3 << 8) + (long)byte2) << 8) + (long)byte1; X/* value = (((Buffer[at_byte+2] << 8) + Buffer[at_byte+1]) << 8) + */ X/* Buffer[at_byte]; */ X X mask = (long) Mask_tab[num_bits]; X at_byte += (last_bit >> 3); /* new byte */ X at_bit = (last_bit & 0x07); X X#ifdef DEBUG X printf("| EX: value=$%.6x mask=$%.4x return=$%.3x\n", X value, mask, ((value >> old_bit) & mask)); X#endif X if (old_bit) X return ((value >> old_bit) & mask); X else X return (value & mask); /* shifting by zero may be undefined */ X} X X X/* X * Un-LZW a range of bytes X * X * Reads data with get_code (eventually from packBuffer) and stores the X * output in "buffer". X */ Xstatic void undo_LZW(buffer, length) Xunsigned char *buffer; /* where to put output */ Xint length; /* uncompressed length of output */ X{ X int oldc, incode, finalc, ptr; X X /* initialize variables */ X Table = Real_tab-256; X entry = 0x101; /* start at $101 */ X at_bit = at_byte = 0; X out_bytes = 0; X stack_ptr = 0; X X last_byte = 0; /* init last_byte */ X oldc = incode = get_code(/*buffer*/); X finalc = (oldc & 0xff); X *(buffer + out_bytes++) = (unsigned char) incode; X X /* main loop */ X while (out_bytes < length) { X incode = ptr = get_code(/*buffer*/); X if (ptr >= entry) { X push(finalc); X ptr = oldc; X } X while (ptr > 0xff) { X push(Table[ptr].chr); X ptr = Table[ptr].prefix; X } X X /* ptr is now < 0x100 */ X finalc = ptr; X push(finalc); X dump_stack(buffer); X Table[entry].chr = (finalc & 0xff); /* mask to get unsigned?? byte */ X Table[entry].prefix = oldc; X entry++; X oldc = incode; X } X} X X X/* X * Second pass... undo the Run Length Encoding. X * X * Copy data from inbuffer to outbuffer. Keep going until we've got X * exactly BLKSIZ bytes. Note that this uses codes of the form X * char count X * which is different from some other programs. X */ Xstatic void undo_RLE(inbuffer, outbuffer) Xunsigned char *inbuffer, *outbuffer; X/*int length; /* how many bytes from LZW; just to make sure... */ X{ X int total, count; /* count is RLE reps */ X unsigned char c; X X#ifdef DEBUG X /*printf("Starting undo_RLE, length = %d\n", length);*/ X#endif X total = 0; X while (total < BLKSIZ) { X c = *(inbuffer++); /*length--;*/ X if (c == (onebyt) escape_char) { X c = *(inbuffer++); /*length--;*/ X count = *(inbuffer++); /*length--;*/ X total += count +1; /* count of zero -> 1 byte */ X while (count-- >= 0) { X *(outbuffer++) = c; /*Putc(c, outf);*/ X } X } else { X *(outbuffer++) = c; /*Putc(c, outf);*/ X total++; X } X } X X if (total != 4096) X fprintf(stderr, "internal error: bad undo_RLE\n"); X#ifdef DEBUG X/* printf("Exiting undo_RLE, length = %d (should be 0), total = %d (4096)\n ", X length, total);*/ X#endif X} X X X/* X * Main entry point. X * X * This is among the more hellish things I've written. Uses X * a large buffer for efficiency reasons, and unpacks a stream of bytes X * (LZW-II improves things a little). X * If you find this hard to understand, imagine what it was like to debug. X * X * Could use some cleaning up, esp argument list... X */ Xvoid Xunpak_SHK(srcfd,dstfd,comp_thread_eof,thread_eof,buffer, use_type2, thread_crc ) Xint srcfd, dstfd; Xfourbyt comp_thread_eof, thread_eof; Xonebyt *buffer; XBOOLEAN use_type2; /* true if we should expect LZW-II */ Xtwobyt thread_crc; X{ X twobyt CRC, blkCRC; X onebyt vol; X onebyt *wrbuf; /* points to buffer we're about to write */ X short unlen, lzwflag, rleflag, complen; /* should be short */ X unsigned int partial, toread, still_in_buf; X fourbyt tmp4; /* temporary 4-byte variable */ X int cc; X static char *procName = "unpak_SHK"; X X CRC = 0; X type2 = use_type2; X X /* read min(PAKBUFSIZ, comp_thread_eof) bytes into buffer */ X if (comp_thread_eof > (fourbyt) PAKBUFSIZ) { X toread = (unsigned int) PAKBUFSIZ; X comp_thread_eof -= (fourbyt) PAKBUFSIZ; X } else { X toread = (unsigned int) comp_thread_eof; /* read it all... */ X comp_thread_eof = (fourbyt) 0; X } X X /* do initial read */ X#ifdef DEBUG1 X printf("initial read = %u\n", toread); X#endif X if ((cc = read(srcfd, buffer, toread)) < toread) { X#ifdef DEBUG1 X printf("Only read %d bytes\n", cc); X#endif X Fatal("Bad read during uncompress", procName); X } X ibuf = buffer; /* set input pointer to start of buffer */ X X /* get header data */ X if (type2) { X blkCRC = thread_crc; X } else { X blkCRC = Getc(inf); X blkCRC += (Getc(inf) << 8); X } X vol = (char) Getc(inf); /* disk volume #; not used here */ X escape_char = (char) Getc(inf); /* RLE delimiter */ X X#ifdef DEBUG1 X printf("vol = %d, escape_char = %x\n", vol, escape_char); X#endif X X /* X * main loop X */ X while (thread_eof != (fourbyt) 0) { X X /* note "unlen" is un-LZWed length (i.e., after RLE) */ X if (type2) { X unlen = Getc(inf); X unlen += (Getc(inf) << 8); X lzwflag = (unlen & 0x8000) ? 1 : 0; /* flag is hi bit */ X unlen &= 0x1fff; /* strip extra stuff */ X rleflag = (unlen != BLKSIZ); X if (lzwflag) { /* will the real length bytes please stand up*/ X complen = Getc(inf); X complen += (Getc(inf) << 8); X } X } else { X unlen = Getc(inf); X unlen += (Getc(inf) << 8); X lzwflag = Getc(inf); X rleflag = (unlen != BLKSIZ); X } X#ifdef DEBUG1 X printf("Length after RLE = %d ($%.4x)\n", unlen, unlen); X printf("LZW flag = %d, RLE flag = %d\n", lzwflag, rleflag); X if (lzwflag != 0 && lzwflag != 1) { /* this is weird... */ X for (lzwflag = -6; lzwflag < 3; lzwflag++) { X printf("foo %d: %.2x\n", lzwflag, *(ibuf+lzwflag)); X } X } X if (type2 && lzwflag) { X printf("Length after RLE+LZW = %d ($%.4x)\n", complen, complen); X } X#endif X X /* If it looks like we're going to run out of room, shift & read X /* Mostly a guess; LZW length is less than unlen... This is X /* complicated and very prone to errors. X /* tmp4 is the number of bytes between the current ptr and the end; X /* some (16-bit) compilers yack if it's all one statement.*/ X tmp4 = (fourbyt) buffer + (fourbyt) PAKBUFSIZ; X tmp4 -= (fourbyt) ibuf; X if (tmp4 < (unlen + 6)) { /* 6 = 3/4 byte header + two just in case */ X still_in_buf = tmp4; X X#ifdef DEBUG1 X printf("--- unlen = %d, space left = %d bytes\n", X unlen, still_in_buf); X#endif X BCopy((onebyt *) ibuf, (onebyt *) buffer, still_in_buf, FALSE); X if (comp_thread_eof != (fourbyt) 0) { /* no read, just shift */ X if (comp_thread_eof > ((fourbyt) PAKBUFSIZ - still_in_buf)){ X toread = (unsigned int) PAKBUFSIZ - still_in_buf; X comp_thread_eof -= (fourbyt) PAKBUFSIZ - still_in_buf; X } else { X toread = (unsigned int) comp_thread_eof; X comp_thread_eof = (fourbyt) 0; X } X#ifdef DEBUG1 X printf("--- reading another %u bytes\n", toread); X#endif X if (read(srcfd, buffer+still_in_buf, toread) < toread) X Fatal("Unable to read [middle]", procName); X if (verbose) Spin(); X } X ibuf = buffer; X } X X /* how much of the buffered data do we really need? */ X if (thread_eof > (fourbyt) BLKSIZ) { X partial = (unsigned int) BLKSIZ; X thread_eof -= (fourbyt) BLKSIZ; X } else { X partial = (unsigned int) thread_eof; /* last block of file */ X thread_eof = (fourbyt) 0; X } X X /* X * undo_LZW reads from ibuf (using Getc()) and writes to lbuf X * undo_RLE reads from where you tell it and writes to rbuf X * X * This is really insane... X */ X if (lzwflag && rleflag) { X undo_LZW(lbuf, unlen); /* from ibuf -> lbuf */ X undo_RLE(lbuf, rbuf); /* from lbuf -> rbuf */ X wrbuf = rbuf; /* write rbuf */ X CRC = CalcCRC(CRC, (onebyt *) rbuf, BLKSIZ); /* always 4K bytes */ X } else if (lzwflag && !rleflag) { X undo_LZW(lbuf, unlen); /* from ibuf -> lbuf */ X wrbuf = lbuf; /* write lbuf */ X CRC = CalcCRC(CRC, (onebyt *) lbuf, BLKSIZ); X } else if (!lzwflag && rleflag) { X undo_RLE(ibuf, rbuf); /* from ibuf -> rbuf */ X wrbuf = rbuf; /* write rbuf */ X CRC = CalcCRC(CRC, (onebyt *) rbuf, BLKSIZ); X ibuf += unlen; /* have to skip over RLE-only data */ X /* normally ibuf is advanced by Getc() calls */ X } else { X wrbuf = ibuf; /* write ibuf */ X CRC = CalcCRC(CRC, (onebyt *) ibuf, BLKSIZ); X ibuf += partial; /* skip over uncompressed data */ X /* normally ibuf is advanced by Getc() calls */ X } X#ifdef DEBUG1 X printf("Writing %d bytes.\n", partial); X#endif X if (crlf(dstfd, wrbuf, partial) < partial) /* write wrbuf */ X Fatal("Bad write", procName); X } X X if (CRC != blkCRC) { X fprintf(stderr, "WARNING: CRC does not match..."); X if (verbose) fprintf(stderr, "\n"); X else fprintf(stderr, "extract with V suboption to see filenames.\n"); X } X} X SHAR_EOF $TOUCH -am 0430184790 nushk.c && chmod 0644 nushk.c || echo "restore of nushk.c failed" set `wc -c nushk.c`;Wc_c=$1 if test "$Wc_c" != "18639"; then echo original size 18639, current size $Wc_c fi fi # ============= nusq.c ============== if test X"$1" != X"-c" -a -f 'nusq.c'; then echo "File already exists: skipping 'nusq.c'" else echo "x - extracting nusq.c (Text)" sed 's/^X//' << 'SHAR_EOF' > nusq.c && X/* X * nusq.c - Huffman squeeze/unsqueeze routines X * Based on sq3/usq2 by Don Elton X * X * By Andy McFadden (fadden@cory.berkeley.edu) X * NuLib v2.2 April 1990 Freeware (distribute, don't sell) X */ X X#include "nudefs.h" X#include X#include X X#ifdef MSDOS /* For file IO */ X# include X# include X# include X# include X#endif X X#include "nuetc.h" X X/* X * usq.c - undo Huffman coding X * Adapated from code By Marcel J.E. Mol X * X * Squeezed file format: X * 2 bytes MAGIC X * 2 bytes dummy ??? (maybe CRC or checksum; not checked) X * filename ended by \0 X * X * 2 bytes node count X * node count node values, each 2 bytes X * squeezed data per byte X * X * NuFX SQueezed format includes only the node count, node values, and X * the data. The BLU routines are expected to strip off the MAGIC, X * checksum, and filename before calling this. X */ X X/*char *copyright = "@(#) usq.c 2.1 18/06/88 (c) M.J.E. Mol";*/ X#define BUFSIZE 128 X#define MAGIC 0xff76 /* Squeezed file magic */ X#define DLE 0x90 /* repeat byte flag */ X#define NOHIST 0 /* no relevant history */ X#define INREP 1 /* sending a repeated value */ X#define SPEOF 256 /* special endfile token */ X#define NUMVALS 257 /* 256 data values plus SPEOF */ X X/* global variable declarations */ Xchar *sfn; /* squeezed file name */ Xstruct nd { /* decoding tree */ X int child[2]; /* left, right */ X} node[NUMVALS]; /* use large buffer */ Xint state; /* repeat unpacking state */ Xint bpos; /* last bit position read */ Xint curin; /* last byte value read */ Xint numnodes; /* number of nodes in decode tree */ X Xstatic unsigned char fromc; /* for use in text translation */ Xstatic BOOLEAN trbool; /* BOOLEAN version of transfrom */ X X X/* Get an integer from the input stream */ Xstatic twobyt get_int(f) XFILE *f; X{ X twobyt val; X X val = (twobyt)getc(f); X val += (twobyt)getc(f) << 8; X return (val); X} X X Xstatic int getc_usq(f) /* get byte from squeezed file */ XFILE *f; /* file containing squeezed data */ X{ X register short i; /* tree index */ X X /* follow bit stream in tree to a leaf */ X for (i=0; (i <= 0x7fff) && (i>=0); )/* work down(up?) from root */ X { X if (++bpos > 7) { X if ((curin=getc(f)) == EOF) X return(EOF); X bpos = 0; X X /* move a level deeper in tree */ X i = node[i].child[1 & curin]; X } X else i = node[i].child[1 & (curin >>= 1)]; X } X X /* decode fake node index to original data value */ X i = -(i + 1); X X /* decode special endfile token to normal EOF */ X return ((i==SPEOF) ? EOF : i); X} X X X/* putc-ncr -- decode non-repeat compression. Bytes are passed one X * at a time in coded format, and are written out uncoded. X * The data is stored normally, except that runs of more X * than two characters are represented as: X * X * X * X * With a special case that a count of zero indicates a DLE X * as data, not as a repeat marker. X */ Xstatic void putc_ncr(c, t) /* put NCR coded bytes */ Xunsigned char c; /* next byte of stream */ XFILE *t; /* file to receive data */ X{ X static int lastc; /* last character seen */ X X /* if converting line terminators, do so now */ X if (trbool && (c == fromc)) X#ifdef UNIX X c = 0x0a; X#else X# ifdef APW X c = 0x0d; X# else X c = 0x0d; /* No CRLF stuff in unSQueeze... sorry */ X# endif X#endif X X switch (state) { /* action depends on our state */ X case NOHIST: /* no previous history */ X if (c==DLE) /* if starting a series */ X state = INREP; /* then remember it next time */ X else putc(lastc=c, t); /* else nothing unusual */ X return; X X case INREP: /* in a repeat */ X if (c) /* if count is nonzero */ X while (--c) /* then repeatedly ... */ X putc(lastc, t); /* ... output the byte */ X else putc(DLE, t); /* else output DLE as data */ X state = NOHIST; /* back to no history */ X return; X X default: X fprintf(stderr, "%s: bad NCR unpacking state (%d)", X prgName, state); X } X} X X Xstatic int init_usq(f) /* initialize Huffman unsqueezing */ XFILE *f; /* file containing squeezed data */ X{ X register int i; /* node index */ X X switch (transfrom) { X case -1: /* no translation */ X trbool = 0; X break; X case 0: /* from ProDOS */ X trbool = 1; X fromc = 0x0d; X break; X case 1: /* from UNIX */ X trbool = 1; X fromc = 0x0a; X break; X case 2: /* from MS-DOS... this needs fixing */ X trbool = 1; X fromc = 0x0a; /* just turn LFs into whatever... */ X break; X default: /* unknown */ X fprintf(stderr, "%s: unknown translation type %d\n", prgName, trbool); X fprintf(stderr, "%s: assuming conversion from CR\n", prgName); X trbool = 1; /* should just ignore flag, but other procs do this */ X fromc = 0x0d; X break; X } X X bpos = 99; /* force initial read */ X numnodes = get_int(f); /* get number of nodes */ X X if (numnodes<0 || numnodes>=NUMVALS) { X fprintf(stderr, "%s: usq: archived file has invalid decode tree\n", X prgName); X return (-1); X } X X /* initialize for possible empty tree (SPEOF only) */ X node[0].child[0] = -(SPEOF + 1); X node[0].child[1] = -(SPEOF + 1); X X for (i=0; i