Path: ns-mx!uunet!sun-barr!newstop!sun!amdahl!fadden From: fadden@uts.amdahl.com (Andy McFadden) Newsgroups: comp.binaries.apple2 Subject: NuLib v3.10 (UNIX) nulib.07 Message-ID: <5cN402sN09Qr00@amdahl.uts.amdahl.com> Date: 1 Nov 91 04:13:47 GMT Reply-To: fadden@amdahl.uts.amdahl.com (Andy McFadden) Organization: Amdahl Corporation, Sunnyvale CA Lines: 1640 NuLib v3.10 - nulib.07 ---- Cut Here and feed the following to sh ---- #!/bin/sh # This is part 07 of a multipart archive # ============= nuread.c ============== if test -f 'nuread.c' -a X"$1" != X"-c"; then echo 'x - skipping nuread.c (File already exists)' else echo 'x - extracting nuread.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'nuread.c' && /* X * nuread.c - read NuFX archives (header info only) into structures X * X * NuLib v3.1 October 1991 Freeware (distribute, don't sell) X * By Andy McFadden (fadden@cory.berkeley.edu) X */ #ifdef APW segment "NuMain" #endif X #include "nudefs.h" #include #include #include X #ifdef MSDOS /* For file IO */ # include /* errno, among others */ # include # include # include # include #endif X #ifdef CRC_TAB # include "crc.h" /* fast CRC lookup */ #endif #include "nuread.h" #include "nupak.h" /* uses PAKBUFSIZ */ #include "nuetc.h" X #define UNKNOWN_FN "" X /* quick proc to save x00 bytes of static storage */ void OtherArc(str1, str2) { X fprintf(stderr, "File may be %s; try \"%s\".\n", str1, str2); } X /* swap two bytes if HiLo is TRUE */ void HiSwap(ptr, a, b) onebyt *ptr; register onebyt a, b; { X register onebyt tmp; X X if (HiLo) { X tmp = ptr[a], ptr[a] = ptr[b], ptr[b] = tmp; X } } X X /* copy bytes from buffer to buffer, reversing byte order if necessary */ void BCopy(srcptr, destptr, num, order) register onebyt *srcptr, *destptr; int num; BOOLEAN order; /* true if byte ordering is important */ { 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 * 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 */ twobyt CalcCRC(seed, ptr, count) twobyt seed; /* initial value for CRC */ register onebyt *ptr; /* pointer to start of data buffer */ register int count; /* number of bytes to scan through - note 64K max */ { #ifndef CRC_TAB X register int x; #endif X register twobyt CRC = seed; X X do { #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. */ #else X CRC = updcrc(*ptr++, CRC); /* look up new value in table */ #endif X } while (--count); X return (CRC); } X X /* X * Test an archive's integrity. X * X * Reads the entire file, and checks CRCs for certain things. X */ void NuTest(filename, options) char *filename; char *options; { 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 if (RNodePtr->RHptr->version_number == 3) /* CRC of uncom data */ X if (TNodePtr->THptr->thread_format != 0x0000) X check_thread_crc = FALSE; /* can't check comp */ 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); #ifdef DEBUG X printf( "At posn %ld: rec %d/thread %d (%ld bytes) CalcCRC = 0x%.4x (0x%.4x)\n", TNodePtr->fileposn, rec, thread, thread_size, CRC, TNodePtr->THptr->thread_crc 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 } else { X if (verbose) printf("--- CRC matched for thread %d\n", X thread); 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 * Read thread header data, and skip data fields X */ static TNode * ReadThreads(fd, RHptr, RNodePtr, CRC_ptr) int fd; RHblock *RHptr; RNode *RNodePtr; twobyt *CRC_ptr; /* CRC seed; result is returned thru this */ { 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 * Read header data from a NuFX archive into memory X */ ListHdr * NuRead(filename) char *filename; { 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)) #ifdef NO_BLU X OtherArc("Binary II", "unblu"); #else X fprintf(stderr, "File may be Binary II; try 'B' option\n"); #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, "ZOO", 3)) /* zoo */ X OtherArc("a ZOO archive", "zoo"); X if ((filebuf[0] == 0x1a) && (filebuf[1] == 0x08)) /* arc */ X OtherArc("an ARC archive", "arc"); 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 ZIP */ 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 ((fourbyt) MHptr->master_eof != (fourbyt) 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 SHAR_EOF chmod 0644 nuread.c || echo 'restore of nuread.c failed' Wc_c="`wc -c < 'nuread.c'`" test 19109 -eq "$Wc_c" || echo 'nuread.c: original size 19109, current size' "$Wc_c" fi # ============= nushk.c ============== if test -f 'nushk.c' -a X"$1" != X"-c"; then echo 'x - skipping nushk.c (File already exists)' else echo 'x - extracting nushk.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'nushk.c' && /* X * nushk.c - P8 ShrinkIt compress/uncompress routines X * X * NuLib v3.1 October 1991 Freeware (distribute, don't sell) X * By Andy McFadden (fadden@cory.berkeley.edu) X */ #ifdef APW segment "Compress" #endif X #include "nudefs.h" #include #include X #ifdef MSDOS /* For file IO */ # include # include # include # include #endif X #include "nuread.h" /* need CalcCRC() */ #include "nupak.h" #include "nuetc.h" X #ifdef UNIX # ifdef SYSV # define BCOPY(src, dst, count) memcpy(dst, src, count) # else # define BCOPY(src, dst, count) bcopy(src, dst, count); # endif #else # ifdef APW # define BCOPY(src, dst, count) memcpy(dst, src, count) # endif # ifdef MSDOS # define BCOPY(src, dst, count) bcopy(src, dst, count); # endif /* +PORT+ */ #endif X #define BLKSIZ 4096 /*#define DEBUG /* do verbose debugging output */ /*#define DEBUG1 /* debugging output in main routine */ X static onebyt *ibuf; /* large buffer (usually set to packBuffer) */ onebyt lbuf[BLKSIZ+7]; /* temporary buffer for storing data after LZW */ onebyt rbuf[BLKSIZ+7]; /* temporary buffer for storing data after RLE */ X X /* X * P8 ShrinkIt compression routines X * Copyright 1989 Kent Dickey X * X * C translation by Kent Dickey / Andy McFadden X */ X #define ESCAPE_CHAR 0xdb #define HSIZE 4219 /* Must be prime */ X struct ht { X int entry; X int prefix; X onebyt chr; } htab[HSIZE]; X int s_at_bit; int s_at_byte; X int mask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, X 0xff, 0x1ff, 0x3ff, 0x7ff, 0xfff }; X int bit_tab[] = { 0,9,10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12 }; X X /* X * Output code to buffer. X */ static int put_code(code, ent, bfr) int code, ent; onebyt *bfr; { X int lo_byte; X register long mycode; X int bits; X register onebyt *cp; /* opt: points to bfr[s_at_byte] */ X X bits = bit_tab[(ent >> 8)]; X if (((s_at_bit + bits + 7) >> 3) + s_at_byte > BLKSIZ) { X return(-1); X } X mycode = (long)(code & mask[bits]); #ifdef DEBUG2 X fprintf(stderr,"Byte: %d, %lx\n", s_at_byte, mycode); #endif /* lo_byte = bfr[s_at_byte] & mask[s_at_bit];*/ X cp = bfr + s_at_byte; /* - */ X lo_byte = *cp & mask[s_at_bit]; /* - */ X if (s_at_bit != 0) { X mycode <<= s_at_bit; X } /* bfr[s_at_byte++] = (onebyt) lo_byte | (onebyt) (mycode & 0xff);*/ X *cp = (onebyt) lo_byte | (onebyt) (mycode & 0xff); /* - */ X s_at_byte++, cp++; /* bfr[s_at_byte] = (onebyt) ((mycode >>= 8) & 0xff);*/ X *cp = (onebyt) ((mycode >>= 8) & 0xff); /* - */ X if ((s_at_bit += bits) >= 16) { /* bfr[++s_at_byte] = (char)((mycode >>= 8) & 0xff);*/ X cp++, s_at_byte++; /* - */ X *cp = (onebyt) ((mycode >>= 8) & 0xff); /* - */ X } X s_at_bit &= 0x07; X X return(0); } X X /* X * Try LZW compression on the buffer. X * X * Compresses from "buffer" to "outbuf". "inlen" is the #of bytes of data in X * "buffer." Returns the #of bytes of data placed into "outbuf", or -1 on X * failure. X */ static int do_LZW(bufr, inlen, outbuf) onebyt *bufr; int inlen; onebyt *outbuf; { X int ent, prefix; X register int index; X register onebyt k; X register onebyt *inbuf, *endbuf; X register struct ht *htp; /* opt: htab[index] */ X X s_at_byte = 0; X s_at_bit =0; X ent = 0x101; X inbuf = bufr; X endbuf = bufr + inlen; X X X k = ((char)*inbuf++); Loop0: X prefix = (int)k; Loop1: X if (inbuf >= endbuf) { X if (put_code(prefix, ent, outbuf) < 0) { X return(BLKSIZ+2); X } X if (s_at_bit == 0) return(s_at_byte); X else return(s_at_byte+1); X } X k = (onebyt)*inbuf++; X index = (prefix + (k<<4)) & 0xfff; X Check_ent: X htp = htab + index; /* - */ /* if (htab[index].entry == 0) {*/ X if (htp->entry == 0) { /* - */ X /* Entry is 0... */ X if (put_code(prefix, ent, outbuf) < 0) { X return(-1); /* failed */ X } /* htab[index].entry = ent++;*/ /* htab[index].prefix = prefix;*/ /* htab[index].chr = k;*/ X htp->entry = ent++; /* - */ X htp->prefix = prefix; /* - */ X htp->chr = k; /* - */ X goto Loop0; X } /* else if (htab[index].prefix == prefix) {*/ X else if (htp->prefix == prefix) { /* - */ X /* Same prefix... */ /* if (htab[index].chr == k) {*/ X if (htp->chr == k) { /* - */ X /* It's HERE! Yeah! */ /* prefix = htab[index].entry;*/ X prefix = htp->entry; /* - */ X goto Loop1; X } X goto Sec_hash; X } X /* Check for more...secondary hash on index */ X else { Sec_hash: X index = (index + (unsigned int)(k) + 1) % HSIZE; #ifdef DEBUG2 X fprintf(stderr,"New ind: %d, k=%d\n", index, (unsigned int)k); #endif X goto Check_ent; X } } X X /* X * Clear out the hash table. X */ static void ClearTab() { X register int i; X register struct ht *htp; /* opt: htab[i] */ X /* for(i=0; i < HSIZE; i++)*/ /* htab[i].entry = 0;*/ X htp = htab; /* - */ X for (i = HSIZE; i; htp++, i--) /* - */ X htp->entry = 0; /* - */ } 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 where count is #of bytes -1. X * X * This really isn't very pretty, but it works. X */ static int do_RLE(srcptr, dstptr) register onebyt *srcptr, *dstptr; { #ifndef ALT_RLE X register int found, scount /*, dcount*/; X register onebyt c, lastc, tlastc; X onebyt *dststart = dstptr; 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 /* return (dcount);*/ X return (dstptr - dststart); #else /*ALT_RLE*/ X /* X * This was an attempt to write a faster do_RLE routine. However, X * the profiler on my machine showed it to be slower than the big X * wad of stuff above. In addition, this code does NOT work 100% X * correctly. I decided to leave the code here in case somebody X * wants to play with it. X */ X register onebyt *scanptr; X onebyt *endptr, *dststart; X register onebyt c; X register int i, count; X X endptr = srcptr + BLKSIZ; /* where the source ends */ X dststart = dstptr; /* where the destination begins */ X X while (srcptr < endptr) { X c = *srcptr; X scanptr = srcptr+1; X count = 1; X X while (*scanptr == c && scanptr < endptr) X scanptr++, count++; X if (count > 3) { X i = count; X do { X *(dstptr++) = ESCAPE_CHAR; X *(dstptr++) = c; X if (count > 256) { X *(dstptr++) = 255; X i -= 256; X } else { X *(dstptr++) = count-1; X break; X } X } while (i > 0); X } else { X if (c == ESCAPE_CHAR) { /* special case: 1-3 0xDBs */ X *(dstptr++) = ESCAPE_CHAR; X *(dstptr++) = ESCAPE_CHAR; X *(dstptr++) = count-1; /* count == 0 is legal */ X } else { X i = count; X while (i--) X *(dstptr++) = c; X } X } X X srcptr += count; X } X #ifdef DEBUG X if (srcptr > endptr) X printf("BUG: srcptr > endptr in do_RLE\n"); #endif X X return (dstptr - dststart); X #endif /*ALT_RLE*/ } X X /* X * Main compression entry point. X * X * Returns actual thread_format used. X * X * Note that "copybuf" should be at least twice as big as BLKSIZ. X */ long pak_SHK(srcfd, dstfd, length, copybuf) int srcfd, dstfd; long length; /* uncompressed size */ onebyt *copybuf; { X unsigned int partial; /* size for partial read/write */ X onebyt *rptr, *out_buf; 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, lzwsize, out_size; /* length after compression */ 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 ClearTab(); X lzwsize = do_LZW(rptr, rlesize, lbuf); /* compress from rle to lzw */ X if ((lzwsize > rlesize) || (lzwsize < 0)) { X /* lzw failed, use rle'd copy */ X scratch[2] = 0; X out_size = rlesize; X out_buf = rptr; X } else { X /* lzw succeeded, use it */ X scratch[2] = 1; /* LZW on */ X out_size = lzwsize; X out_buf = lbuf; X } X scratch[0] = (onebyt) (rlesize & 0x00ff); /* NOT out_size */ X scratch[1] = (onebyt) ((rlesize >> 8) & 0x00ff); X if (write(dstfd, scratch, 3) != 3) X Fatal("Dest hdr write failed", procName); X comp_len += 3; X comp_len += out_size; X if (comp_len > unc_len) X goto bad_compress; /* you didn't see this */ X if (write(dstfd, out_buf, out_size) != out_size) /* 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 bad_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 * P8 ShrinkIt uncompression routines X * X * Copyright 1989 Kent Dickey X * C translation by Kent Dickey / Andy McFadden X * Modifications for LZW-II designed by Andy Nicholas X * X * C decoder for LZW-II by Frank Petroski / Kent Dickey (simultaneously X * and independently). Speed optimizations by Kent Dickey. X */ X /*static int inf; /* to make Getc() calls happy */ static BOOLEAN type2; /* true if working with LZW-II format */ X static onebyt escape_char; X typedef struct { X unsigned char chr; X int prefix; } Table_ent; X static Table_ent Real_tab[BLKSIZ-256]; /* first 256 don't exist */ static Table_ent *Table; X static int Mask_tab[16] = { X 0x0000, 0x01ff, 0x03ff, 0x03ff, 0x07ff, X 0x07ff, 0x07ff, 0x07ff, 0x0fff, 0x0fff, X 0x0fff, 0x0fff, 0x0fff, 0x0fff, 0x0fff, X 0x0fff }; static int Number[16] = { X 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; X static onebyt Stack[100]; /* simulated stack; should be <= 64 */ static int out_bytes, stack_ptr, entry, at_bit, at_byte; static onebyt last_byte; /* used in get_code */ X X /* fake getc() */ # define Getc() *(ibuf++) X X /* X * Stack operations; used by undo_LZW and undo_LZW_2 X */ #ifdef DEBUG # define push(a_byte) \ X { \ X if (stack_ptr - Stack > 100) { \ X printf("\n*** stack_ptr exceeded 100 in push() [%d]\n", \ X (int) (stack_ptr - Stack));\ X exit (-1); \ X } \ X *(stack_ptr++) = (onebyt) a_byte; \ X } #else # define push(a_byte) *(stack_ptr++) = (onebyt) a_byte; #endif X #ifdef DEBUG # define dump_stack(buffer) \ X { \ X printf("--- Going to dump stack, stack_ptr = %d, out_bytes = %d\n", \ X (int) (stack_ptr - Stack), out_bytes); \ X while (stack_ptr-- > stack_start) { \ X *(buffer++) = *stack_ptr; \ X } \ X } #else # define dump_stack(buffer) \ X while (stack_ptr-- > stack_start) { \ X *(buffer++) = *stack_ptr; \ X } #endif X X /* X * Decipher LZW codes. X */ static int get_code() { X register unsigned int num_bits, old_bit, last_bit; X long value, mask; /* onebyt byte1, byte2, byte3;*/ /* get compressed chars... */ X long byte1, byte2, byte3; /* - */ 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); #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; #ifdef DEBUG X if (at_byte >= BLKSIZ) { X fprintf(stderr, "at_byte exceeded BLKSIZ (4096) in get_code()\n"); X exit (-1); X } #endif X if (at_bit == 0) X last_byte = Getc(); /* byte1 = last_byte;*/ /* first byte = last one used */ X byte1 = (long) last_byte; /* - */ X last_byte = Getc(); /* - */ /* byte2 = Getc(inf);*/ X byte2 = ((long) last_byte) << 8; /* - */ X if (last_bit > 16) { /* get 3rd byte if nec. */ /* byte3 = Getc(inf);*/ /* last_byte = byte3;*/ X last_byte = Getc(); /* - */ X byte3 = ((long) last_byte) << 16; /* - */ X } else { X byte3 = 0; /* last_byte = byte2;*/ X } /* value = ((((long)byte3 << 8) + (long)byte2) << 8) + (long)byte1;*/ X value = byte3 + byte2 + byte1; /* - */ X X mask = (long) Mask_tab[num_bits]; X at_byte += (last_bit >> 3); /* new byte */ X at_bit = (last_bit & 0x07); X #ifdef DEBUG X printf("| EX: value=$%.6x mask=$%.4x return=$%.3x\n", X value, mask, ((value >> old_bit) & mask)); #endif #ifdef ZERO_SHIFT_BAD X if (old_bit) X return ((value >> old_bit) & mask); X else X return (value & mask); /* shifting by zero may be undefined */ #else X return ((value >> old_bit) & mask); #endif /*ZERO_SHIFT_BAD*/ } X X /* X * Un-LZW a range of bytes X * X * Reads data with get_code() and stores the output in "buffer". X */ static void undo_LZW(buffer, length) unsigned char *buffer; /* where to put output */ int length; /* uncompressed length of output */ { X register int oldc, incode, finalc, ptr; X register onebyt *endbuf, *stack_ptr, *stack_start; X X /* initialize variables */ X Table = Real_tab-256; X entry = 0x101; /* start at $101 */ X at_bit = at_byte = 0; /* out_bytes = 0;*/ /* stack_ptr = 0;*/ X endbuf = buffer + length; /* - */ X stack_start = stack_ptr = Stack; /* - */ X X last_byte = 0; /* init last_byte */ X oldc = incode = get_code(/*buffer*/); X finalc = (oldc & 0xff); /* *(buffer + out_bytes++) = (unsigned char) incode;*/ X *(buffer++) = (onebyt) incode; X X /* main loop */ /* while (out_bytes < length) {*/ X while (buffer < endbuf) { /* - */ 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; /* push(finalc);*/ /* dump_stack(buffer);*/ X *(buffer++) = (onebyt) finalc; /* - */ X while (stack_ptr > stack_start) /* - */ X *(buffer++) = *(--stack_ptr); /* - */ 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 * Un-LZW-II a range of bytes X * X * Reads data with get_code() and stores the output in "buffer". Has X * additional code to support LZW-II's table clears. X */ static void undo_LZW_2(buffer, length) unsigned char *buffer; /* where to put output */ int length; /* uncompressed length of output */ { X register int oldc, incode, finalc, ptr; X register onebyt *endbuf, *stack_ptr, *stack_start; X X /* initialize variables */ X at_bit = at_byte = 0; /* out_bytes = 0;*/ /* stack_ptr = 0;*/ X endbuf = buffer + length; X stack_start = stack_ptr = Stack; X X last_byte = 0; /* init last_byte */ X X /* main loop */ /* while (out_bytes < length) {*/ X while (buffer < endbuf) { /* - */ X X if (entry == 0x101) { /* table is empty */ X oldc = incode = get_code(/*buffer*/); X finalc = (oldc & 0xff); /* *(buffer + out_bytes++) = (unsigned char) incode;*/ X *(buffer++) = (onebyt) incode; /* - */ X } X X incode = ptr = get_code(/*buffer*/); X if (incode == 0x100) { /* Clear table code */ X entry = 0x101; /* start at $101 */ X Table = Real_tab-256; X continue; X } X 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; /* push(finalc);*/ /* dump_stack(buffer);*/ X *(buffer++) = (onebyt) finalc; /* - */ X while (stack_ptr > stack_start) /* - */ X *(buffer++) = *(--stack_ptr); /* - */ 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 * 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 */ static void undo_RLE(inbuffer, outbuffer) unsigned char *inbuffer, *outbuffer; /*int length; /* how many bytes from LZW; just to make sure... */ { X register onebyt c; X register int count; /* count is RLE reps */ X register onebyt *outbufend; X #ifdef DEBUG X /*printf("Starting undo_RLE, length = %d\n", length);*/ #endif X outbufend = outbuffer + BLKSIZ; X while (outbuffer < outbufend) { X c = *(inbuffer++); /*length--;*/ X if (c == (onebyt) escape_char) { X c = *(inbuffer++); /*length--;*/ X count = *(inbuffer++); /*length--;*/ X while (count-- >= 0) { X *(outbuffer++) = c; /*Putc(c, outf);*/ X } X } else { X *(outbuffer++) = c; /*Putc(c, outf);*/ X } X } X X if (outbuffer != outbufend) X fprintf(stderr, "internal error: bad undo_RLE\n"); #ifdef DEBUG /* printf("Exiting undo_RLE, length = %d (should be 0), total = %d (4096)\n", X length, outbufend-outbuffer);*/ #endif } 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 * X * If you find this hard to understand, imagine what it was like to debug. X */ void unpak_SHK(srcfd,dstfd,comp_thread_eof,thread_eof,buffer, use_type2, thread_crc) int srcfd, dstfd; fourbyt comp_thread_eof, thread_eof; register onebyt *buffer; BOOLEAN use_type2; /* true if we should expect LZW-II */ twobyt thread_crc; { 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 /*, crcsize*/; X fourbyt tmp4; /* temporary 4-byte variable */ X int cc; X static char *procName = "unpak_SHK"; X X type2 = use_type2; X X if (type2) X CRC = 0xffff; /* different CRC for LZW-II */ X else X CRC = 0; X X /* initialize variables for LZW-II */ X Table = Real_tab-256; X entry = 0x101; /* start at $101 */ 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 */ #ifdef DEBUG1 X printf("initial read = %u\n", toread); #endif X if ((cc = read(srcfd, buffer, toread)) < toread) { #ifdef DEBUG1 X printf("Only read %d bytes\n", cc); #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(); X blkCRC += (Getc() << 8); X } X vol = (char) Getc(); /* disk volume #; not used here */ X escape_char = (char) Getc(); /* RLE delimiter */ X #ifdef DEBUG1 X printf("vol = %d, escape_char = %x\n", vol, escape_char); #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(); X unlen += (Getc() << 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(); X complen += (Getc() << 8); X } X } else { X unlen = Getc(); X unlen += (Getc() << 8); X lzwflag = Getc(); X rleflag = (unlen != BLKSIZ); 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 } #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 (but we err on the safe side). 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 #ifdef DEBUG1 X printf("--- unlen = %d, space left = %d bytes\n", X unlen, still_in_buf); #endif /* BCopy((onebyt *) ibuf, (onebyt *) buffer, still_in_buf, FALSE);*/ X BCOPY((onebyt *) ibuf, (onebyt *) buffer, still_in_buf); X 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 } #ifdef DEBUG1 X printf("--- reading another %u bytes\n", toread); #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_LZW_2 does what undo_LZW does, but for LZW-II. 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 if (type2) X undo_LZW_2(lbuf, unlen); /* from ibuf -> lbuf */ X else X undo_LZW(lbuf, unlen); /* from ibuf -> lbuf */ X undo_RLE(lbuf, rbuf); /* from lbuf -> rbuf */ X wrbuf = rbuf; /* write rbuf */ X } else if (lzwflag && !rleflag) { X if (type2) X undo_LZW_2(lbuf, unlen); /* from ibuf -> lbuf */ X else X undo_LZW(lbuf, unlen); /* from ibuf -> lbuf */ X wrbuf = lbuf; /* write lbuf */ X } else if (!lzwflag && rleflag) { X undo_RLE(ibuf, rbuf); /* from ibuf -> rbuf */ X wrbuf = rbuf; /* write rbuf */ 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 ibuf += partial; /* skip over uncompressed data */ X /* normally ibuf is advanced by Getc() calls */ X } X X if (type2) X CRC = CalcCRC(CRC, wrbuf, partial); X else X CRC = CalcCRC(CRC, wrbuf, BLKSIZ); X #ifdef DEBUG1 X printf("Writing %d bytes.\n", partial); #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, "CRC is %.4x vs %.4x\n", CRC, blkCRC); X else fprintf(stderr, "extract with V suboption to see filenames.\n"); X } } X SHAR_EOF chmod 0644 nushk.c || echo 'restore of nushk.c failed' Wc_c="`wc -c < 'nushk.c'`" test 26909 -eq "$Wc_c" || echo 'nushk.c: original size 26909, current size' "$Wc_c" fi true || echo 'restore of nusq.c failed' echo End of part 7, continue with part 8 exit 0 -- fadden@uts.amdahl.com (Andy McFadden) fadden@cory.berkeley.edu (expires in December) [ Above opinions are mine, Amdahl has nothing to do with them, etc, etc. ]