boneill@hawk.ulowell.edu (SoftXc Coordinator) (03/26/88)
Article 3347 of net.sources: Path: brl-smoke!brl-adm!rutgers!clyde!burl!codas!cpsc6a!cpsc6b!crs From: crs@cpsc6b.cpsc6a.ATT.COM (C. R. Seaman) Newsgroups: net.sources Subject: System V ARC Ver. 1.1, Part 3 of 3 Message-ID: <249@cpsc6b.cpsc6a.ATT.COM> Date: 30 Mar 87 23:46:42 GMT Distribution: usa Organization: AT&T (CPSC), Oakland, CA Lines: 1135 Keywords: arc [Hello, Line eater. NICE Line eater. ARGHHHHHH!!!!] This is part 3 of System V ARC. see part 1 for details ---------------------------- CUT HERE!! ---------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # arcsq.c # arcsvc.c # arctst.c # arcunp.c # arcusq.c # This archive created: Sun Mar 22 10:47:39 1987 # By: C. R. Seaman () export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'arcsq.c'" '(16916 characters)' if test -f 'arcsq.c' then echo shar: "will not over-write existing file 'arcsq.c'" else sed 's/^ X//' << \SHAR_EOF > 'arcsq.c' X/* X * arcsq.c 1.1 X * X * Author: Thom Henderson X * Original System V port: Mike Stump X * Enhancements, Bug fixes, and cleanup: Chris Seaman X * Date: Fri Mar 20 09:57:02 1987 X * Last Mod. 3/21/87 X * X */ X X/* X * ARC - Archive utility - ARCSQ X * X * Version 3.10, created on 01/30/86 at 20:10:46 X * X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED X * X * Description: X * This file contains the routines used to squeeze a file X * when placing it in an archive. X * X * Programming notes: X * Most of the routines used for the Huffman squeezing algorithm X * were lifted from the SQ program by Dick Greenlaw, as adapted X * to CI-C86 by Robert J. Beilstein. X */ X X#include "arc.h" X X/* stuff for Huffman squeezing */ X X#define TRUE 1 X#define FALSE 0 X#define ERROR (-1) X#define SPEOF 256 /* special endfile token */ X#define NOCHILD (-1) /* marks end of path through tree */ X#define NUMVALS 257 /* 256 data values plus SPEOF*/ X#define NUMNODES (NUMVALS+NUMVALS-1) /* number of nodes */ X#define MAXCOUNT (unsigned INT) 65535 /* biggest unsigned integer */ X X/* X * The following array of structures are the nodes of the X * binary trees. The first NUMVALS nodes become the leaves of the X * final tree and represent the values of the data bytes being X * encoded and the special endfile, SPEOF. X * The remaining nodes become the internal nodes of the final tree. X */ X Xstruct nd { /* shared by unsqueezer */ X unsigned INT weight; /* number of appearances */ X INT tdepth; /* length on longest path in tree */ X INT lchild, rchild; /* indices to next level */ X} node[NUMNODES]; /* use large buffer */ X Xstatic INT dctreehd; /* index to head of final tree */ X X/* X * This is the encoding table: X * The bit strings have first bit in low bit. X * Note that counts were scaled so code fits unsigned integer. X */ X Xstatic INT codelen[NUMVALS]; /* number of bits in code */ Xstatic unsigned INT code[NUMVALS]; /* code itself, right adjusted */ Xstatic unsigned INT tcode; /* temporary code value */ Xstatic long valcount[NUMVALS]; /* actual count of times seen */ X X/* Variables used by encoding process */ X Xstatic INT curin; /* value currently being encoded */ Xstatic INT cbitsrem; /* # of code string bits left */ Xstatic unsigned INT ccode; /* current code right justified */ X XINT init_sq() /* prepare for scanning pass */ X{ X INT i; /* node index */ X X /* X * Initialize all nodes to single element binary trees X * with zero weight and depth. X */ X X for (i=0; i<NUMNODES; ++i) X { X node[i].weight = 0; X node[i].tdepth = 0; X node[i].lchild = NOCHILD; X node[i].rchild = NOCHILD; X } X X for (i=0; i<NUMVALS; i++) X valcount[i] = 0; X} X XINT scan_sq(c) /* add a byte to the tables */ XINT c; /* byte to add */ X{ X unsigned INT *wp; /* speeds up weight counting */ X X /* Build frequency info in tree */ X X if (c == EOF) /* it's traditional */ X c = SPEOF; /* dumb, but traditional */ X X if (*(wp = &node[c].weight) != MAXCOUNT) X ++(*wp); /* bump weight counter */ X X valcount[c]++; /* bump byte counter */ X} X Xlong pred_sq() /* predict size of squeezed file */ X{ X INT i; X INT btlist[NUMVALS]; /* list of intermediate b-trees */ X INT listlen; /* length of btlist */ X unsigned INT ceiling; /* limit for scaling */ X long size = 0; /* predicted size */ X INT numnodes; /* # of nodes in simplified tree */ X INT scale(); X INT heap(); X INT bld_tree(); X INT buildenc(); X INT init_enc(); X X scan_sq(EOF); /* signal end of input */ X X ceiling = MAXCOUNT; X X /* Keep trying to scale and encode */ X X do X { X scale(ceiling); X ceiling /= 2; /* in case we rescale */ X X /* X * Build list of single node binary trees having X * leaves for the input values with non-zero counts X */ X X for (i=listlen=0; i<NUMVALS; ++i) X { X if (node[i].weight != 0) X { X node[i].tdepth = 0; X btlist[listlen++] = i; X } X } X X /* X * Arrange list of trees into a heap with the entry X * indexing the node with the least weight at the top. X */ X X heap(btlist,listlen); X X /* Convert the list of trees to a single decoding tree */ X X bld_tree(btlist,listlen); X X /* Initialize the encoding table */ X X init_enc(); X X /* X * Try to build encoding table. X * Fail if any code is > 16 bits long. X */ X } X while (buildenc(0,dctreehd) == ERROR); X X /* Initialize encoding variables */ X X cbitsrem = 0; /* force initial read */ X curin = 0; /* anything but endfile */ X X for (i=0; i<NUMVALS; i++) /* add bits for each code */ X size += valcount[i] * codelen[i]; X X size = (size+7)/8; /* reduce to number of bytes */ X X numnodes = dctreehd<NUMVALS ? 0 : dctreehd-(NUMVALS-1); X X size += sizeof(INT) + 2*numnodes*sizeof(INT); X X return(size); X} X X/* X * The count of number of occurrances of each input value X * have already been prevented from exceeding MAXCOUNT. X * Now we must scale them so that their sum doesn't exceed X * ceiling and yet no non-zero count can become zero. X * This scaling prevents errors in the weights of the X * interior nodes of the Huffman tree and also ensures that X * the codes will fit in an unsigned integer. Rescaling is X * used if necessary to limit the code length. X */ X Xstatic INT scale(ceil) Xunsigned INT ceil; /* upper limit on total weight */ X{ X register INT i; X INT ovflw, divisor; X unsigned INT w, sum; X unsigned char increased; /* flag */ X X do X { X for (i=sum=ovflw=0; i<NUMVALS; ++i) X { X if (node[i].weight > (ceil-sum)) X ++ovflw; X sum += node[i].weight; X } X X divisor = ovflw + 1; X X /* Ensure no non-zero values are lost */ X X increased = FALSE; X for (i=0; i<NUMVALS; ++i) X { X w = node[i].weight; X if (w<divisor && w!=0) X { X /* Don't fail to provide a code if it's used at all */ X X node[i].weight = divisor; X increased = TRUE; X } X } X } X while (increased); X X /* Scaling factor choosen, now scale */ X X if (divisor>1) X for (i=0; i<NUMVALS; ++i) X node[i].weight /= divisor; X} X X/* X * heap() and adjust() maintain a list of binary trees as a X * heap with the top indexing the binary tree on the list X * which has the least weight or, in case of equal weights, X * least depth in its longest path. The depth part is not X * strictly necessary, but tends to avoid long codes which X * might provoke rescaling. X */ X Xstatic INT heap(list,length) XINT list[], length; X{ X register INT i; X INT adjust(); X X for (i=(length-2)/2; i>=0; --i) X adjust(list,i,length-1); X} X X/* Make a heap from a heap with a new top */ X Xstatic INT adjust(list,top,bottom) XINT list[], top, bottom; X{ X register INT k, temp; X INT cmptrees(); X X k = 2 * top + 1; /* left child of top */ X temp = list[top]; /* remember root node of top tree */ X X if (k<=bottom) X { X if (k<bottom && cmptrees(list[k],list[k+1])) X ++k; X X /* k indexes "smaller" child (in heap of trees) of top */ X /* now make top index "smaller" of old top and smallest child */ X X if (cmptrees(temp,list[k])) X { X list[top] = list[k]; X list[k] = temp; X X /* Make the changed list a heap */ X X adjust(list,k,bottom); /* recursive */ X } X } X} X X/* X * Compare two trees, if a > b return true, else return false. X * Note comparison rules in previous comments. X */ X Xstatic INT cmptrees(a,b) XINT a, b; /* root nodes of trees */ X{ X if (node[a].weight > node[b].weight) X return(TRUE); X if (node[a].weight == node[b].weight) X if (node[a].tdepth > node[b].tdepth) X return(TRUE); X return(FALSE); X} X X/* X * HUFFMAN ALGORITHM: develops the single element trees X * into a single binary tree by forming subtrees rooted in X * interior nodes having weights equal to the sum of weights of all X * their descendents and having depth counts indicating the X * depth of their longest paths. X * X * When all trees have been formed into a single tree satisfying X * the heap property (on weight, with depth as a tie breaker) X * then the binary code assigned to a leaf (value to be encoded) X * is then the series of left (0) and right (1) X * paths leading from the root to the leaf. X * Note that trees are removed from the heaped list by X * moving the last element over the top element and X * reheaping the shorter list. X */ X Xstatic INT bld_tree(list,len) XINT list[]; XINT len; X{ X register INT freenode; /* next free node in tree */ X register struct nd *frnp; /* free node pointer */ X INT lch, rch; /* temps for left, right children */ X INT maxchar(); X X /* X * Initialize index to next available (non-leaf) node. X * Lower numbered nodes correspond to leaves (data values). X */ X X freenode = NUMVALS; X X while (len>1) X { X /* X * Take from list two btrees with least weight X * and build an interior node pointing to them. X * This forms a new tree. X */ X X lch = list[0]; /* This one will be left child */ X X /* delete top (least) tree from the list of trees */ X X list[0] = list[--len]; X adjust(list,0,len-1); X X /* Take new top (least) tree. Reuse list slot later */ X X rch = list[0]; /* This one will be right child */ X X /* X * Form new tree from the two least trees using X * a free node as root. Put the new tree in the list. X */ X X frnp = &node[freenode]; /* address of next free node */ X list[0] = freenode++; /* put at top for now */ X frnp->lchild = lch; X frnp->rchild = rch; X frnp->weight = node[lch].weight + node[rch].weight; X frnp->tdepth = 1 + maxchar(node[lch].tdepth, node[rch].tdepth); X X /* reheap list to get least tree at top */ X X adjust(list,0,len-1); X } X dctreehd = list[0]; /* head of final tree */ X} X Xstatic INT maxchar(a,b) X{ X return(a>b ? a : b); X} X Xstatic INT init_enc() X{ X register INT i; X X for (i=0; i<NUMVALS; ++i) /* Initialize encoding table */ X codelen[i] = 0; X} X X/* X * Recursive routine to walk the indicated subtree and level X * and maintain the current path code in bstree. When a leaf X * is found the entire code string and length are put into X * the encoding table entry for the leaf's data value . X * X * Returns ERROR if codes are too long. X */ X Xstatic INT buildenc(level,root) XINT level; /* level being examined */ XINT root; /* root of subtree/data value if leaf*/ X{ X register INT l, r; X X l = node[root].lchild; X r = node[root].rchild; X X if (l==NOCHILD && r==NOCHILD) X { X /* X * Leaf. Previous path determines bit string X * code of length level (bits 0 to level - 1). X * Ensures unused code bits are zero. X */ X X codelen[root] = level; X code[root] = tcode & (((unsigned INT)~0) >> (16-level)); X return((level>16) ? ERROR : NULL); X } X else X { X if (l!=NOCHILD) X { X /* Clear path bit and continue deeper */ X X tcode &= ~(1 << level); X if (buildenc(level+1,l)==ERROR) X return(ERROR); /* pass back bad statuses */ X } X if (r!=NOCHILD) X { X /* Set path bit and continue deeper */ X X tcode |= 1 << level; X if (buildenc(level+1,r)==ERROR) X return(ERROR); /* pass back bad statuses */ X } X } X return(NULL); /* it worked if we reach here */ X} X Xstatic INT put_int(n,f) /* output an integer */ XINT n; /* integer to output */ XFILE *f; /* file to put it to */ X{ X putc_pak(n&0xff,f); /* first the low byte */ X putc_pak(n>>8,f); /* then the high byte */ X} X X/* Write out the header of the compressed file */ X Xstatic long wrt_head(ob) XFILE *ob; X{ X register INT l,r; X INT i, k; X INT numnodes; /* # of nodes in simplified tree */ X X /* X * Write out a simplified decoding tree. Only the interior X * nodes are written. When a child is a leaf index X * (representing a data value) it is recoded as X * -(index + 1) to distinguish it from interior indexes X * which are recoded as positive indexes in the new tree. X * X * Note that this tree will be empty for an empty file. X */ X X numnodes = dctreehd<NUMVALS ? 0 : dctreehd-(NUMVALS-1); X put_int(numnodes,ob); X X for (k=0, i=dctreehd; k<numnodes; ++k, --i) X { X l = node[i].lchild; X r = node[i].rchild; X l = l<NUMVALS ? -(l+1) : dctreehd-l; X r = r<NUMVALS ? -(r+1) : dctreehd-r; X put_int(l,ob); X put_int(r,ob); X } X X return(sizeof(INT) + numnodes*2*sizeof(INT)); X} X X/* X * Get an encoded byte or EOF. Reads from specified stream AS NEEDED. X * X * There are two unsynchronized bit-byte relationships here. X * The input stream bytes are converted to bit strings of X * various lengths via the static variables named c... X * These bit strings are concatenated without padding to X * become the stream of encoded result bytes, which this X * function returns one at a time. The EOF (end of file) is X * converted to SPEOF for convenience and encoded like any X * other input value. True EOF is returned after that. X */ X Xstatic INT gethuff(ib) /* Returns bytes except for EOF */ XFILE *ib; X{ X INT rbyte; /* Result byte value */ X INT need; /* numbers of bits */ X X rbyte = 0; X need = 8; /* build one byte per call */ X X /* X * Loop to build a byte of encoded data. X * Initialization forces read the first time. X */ X X while (1) X { X if (cbitsrem>=need) /* if current code is big enough */ X { X if (need==0) X return(rbyte); X X rbyte |= ccode << (8-need);/* take what we need */ X ccode >>= need; /* and leave the rest */ X cbitsrem -= need; X return(rbyte & 0xff); X } X X /* We need more than current code */ X X if (cbitsrem>0) X { X rbyte |= ccode << (8-need);/* take what there is */ X need -= cbitsrem; X } X X /* No more bits in current code string */ X X if (curin==SPEOF) X { X /* X * The end of file token has been encoded. If X * result byte has data return it and do EOF next time. X */ X X cbitsrem = 0; X return((need==8) ? EOF : rbyte + 0); X } X X /* Get an input byte */ X X if ((curin=getc_ncr(ib)) == EOF) X curin = SPEOF; /* convenient for encoding */ X X ccode = code[curin]; /* get the new byte's code */ X cbitsrem = codelen[curin]; X } X} X X/* X * This routine is used to perform the actual squeeze operation. It can X * only be called after the file has been scanned. It returns the true X * length of the squeezed entry. X */ X Xlong file_sq(f,t) /* squeeze a file into an archive */ XFILE *f; /* file to squeeze */ XFILE *t; /* archive to receive file */ X{ X INT c; /* one byte of squeezed data */ X long size; /* size after squeezing */ X X size = wrt_head(t); /* write out the decode tree */ X X while ((c=gethuff(f))!=EOF) X { X putc_pak(c,t); X size++; X } X X return(size); /* report true size */ X} SHAR_EOF if test 16916 -ne "`wc -c < 'arcsq.c'`" then echo shar: "error transmitting 'arcsq.c'" '(should have been 16916 characters)' fi fi echo shar: "extracting 'arcsvc.c'" '(4943 characters)' if test -f 'arcsvc.c' then echo shar: "will not over-write existing file 'arcsvc.c'" else sed 's/^ X//' << \SHAR_EOF > 'arcsvc.c' X/* X * arcsvc.c 1.1 X * X * Author: Thom Henderson X * Original System V port: Mike Stump X * Enhancements, Bug fixes, and cleanup: Chris Seaman X * Date: Fri Mar 20 09:57:02 1987 X * Last Mod. 3/21/87 X * X */ X X/* X * ARC - Archive utility - ARCSVC X * X * Version 2.15, created on 12/17/85 at 15:17:16 X * X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED X * X * Description: X * This file contains service routines needed to maintain an archive. X */ X X#include "arc.h" X XINT openarc(chg) /* open archive */ XINT chg; /* true to open for changes */ X{ X FILE *fopen(); /* file opener */ X X if(!(arc=fopen(arcname,"r"))) X { X if(chg) X printf("Creating new archive: %s\n",arcname); X else X abort("Cannot read archive: %s",arcname); X } X X if(chg) /* if opening for changes */ X if(!(new=fopen(newname,"w"))) X abort("Cannot create archive copy: %s",newname); X} X XINT closearc(chg) /* close an archive */ XINT chg; /* true if archive was changed */ X{ X signal(SIGINT,SIG_IGN); /* We are now committed, so trap */ X signal(SIGQUIT,SIG_IGN); /* for all normal signals */ X X if(arc) /* if we had an initial archive */ X fclose(arc); /* then close it */ X X if(chg) /* if things have changed */ X { X fclose(new); /* close the new copy */ X X if(arc) /* if we had an original archive */ X { X if(keepbak) /* if a backup is wanted */ X { X unlink(bakname); /* erase any old copies */ X if(rename(arcname,bakname)) X abort("Cannot rename %s to %s",arcname,bakname); X printf("Keeping backup archive: %s\n",bakname); X } X else if(unlink(arcname)) X abort("Cannot delete old archive: %s",arcname); X } X X if(rename(newname,arcname)) X abort("Cannot rename %s to %s",newname,arcname); X } X} X X/* X * CRC computation logic X * The logic for this method of calculating the CRC 16 bit polynomial X * is taken from an article by David Schwaderer in the April 1985 X * issue of PC Tech Journal. X */ X Xstatic INT crctab[] = { /* CRC lookup table */ X 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, X 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, X 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, X 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, X 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, X 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, X 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, X 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, X 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, X 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, X 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, X 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, X 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, X 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, X 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, X 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, X 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, X 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, X 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, X 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, X 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, X 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, X 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, X 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, X 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, X 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, X 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, X 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, X 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, X 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, X 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, X 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 X}; X XINT addcrc(crc,c) /* update a CRC check */ XINT crc; /* running CRC value */ Xunsigned char c; /* character to add */ X{ X return((((crc>>8)&0x00ff) ^ crctab[(crc^c)&0x00ff]) & 0x0000ffff); X} SHAR_EOF if test 4943 -ne "`wc -c < 'arcsvc.c'`" then echo shar: "error transmitting 'arcsvc.c'" '(should have been 4943 characters)' fi fi echo shar: "extracting 'arctst.c'" '(1606 characters)' if test -f 'arctst.c' then echo shar: "will not over-write existing file 'arctst.c'" else sed 's/^ X//' << \SHAR_EOF > 'arctst.c' X/* X * arctst.c 1.1 X * X * Author: Thom Henderson X * Original System V port: Mike Stump X * Enhancements, Bug fixes, and cleanup: Chris Seaman X * Date: Fri Mar 20 09:57:02 1987 X * Last Mod. 3/21/87 X * X */ X X/* X * ARC - Archive utility - ARCTST X * X * Version 2.12, created on 02/03/86 at 23:00:40 X * X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED X * X * Description: X * This file contains the routines used to test archive integrity. X */ X X#include "arc.h" X XINT tstarc() /* test integrity of an archive */ X{ X struct heads hdr; /* file header */ X long arcsize, ftell(); /* archive size */ X X openarc(0); /* open archive for reading */ X fseek(arc,0L,2); /* move to end of archive */ X arcsize = ftell(arc); /* see how big it is */ X fseek(arc,0L,0); /* return to top of archive */ X X printf("Testing archive...\n"); X while (readhdr(&hdr,arc)) X { X if (ftell(arc)+hdr.size>arcsize) X { X printf("Archive truncated in file %s\n",hdr.name); X nerrs++; X break; X } X else X { X printf(" File: %-14s ",hdr.name); X fflush(stdout); X if (unpack(arc,NULL,&hdr)) X nerrs++; X else X printf("okay\n"); X } X } X X if (nerrs<1) X printf("No errors detected\n"); X else if (nerrs==1) X printf("One error detected\n"); X else X printf("%d errors detected\n",nerrs); X} SHAR_EOF if test 1606 -ne "`wc -c < 'arctst.c'`" then echo shar: "error transmitting 'arctst.c'" '(should have been 1606 characters)' fi fi echo shar: "extracting 'arcunp.c'" '(6134 characters)' if test -f 'arcunp.c' then echo shar: "will not over-write existing file 'arcunp.c'" else sed 's/^ X//' << \SHAR_EOF > 'arcunp.c' X/* X * arcunp.c 1.1 X * X * Author: Thom Henderson X * Original System V port: Mike Stump X * Enhancements, Bug fixes, and cleanup: Chris Seaman X * Date: Fri Mar 20 09:57:02 1987 X * Last Mod. 3/21/87 X * X */ X X/* X * ARC - Archive utility - ARCUNP X * X * Version 3.16, created on 02/03/86 at 23:01:16 X * X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED X * X * Description: X * This file contains the routines used to expand a file X * when taking it out of an archive. X */ X X#include "arc.h" X X/* stuff for repeat unpacking */ X X#define DLE 0x90 /* repeat byte flag */ X Xstatic INT state; /* repeat unpacking state */ X X/* repeat unpacking states */ X X#define NOHIST 0 /* no relevant history */ X#define INREP 1 /* sending a repeated value */ X Xstatic INT crcval; /* CRC check value */ Xstatic long size; /* bytes to read */ X XINT unpack(f,t,hdr) /* unpack an archive entry */ XFILE *f, *t; /* source, destination */ Xstruct heads *hdr; /* pointer to file header data */ X{ X INT c; /* one char of stream */ X INT putc_unp(); X INT putc_ncr(); X INT getc_unp(); X X /* setups common to all methods */ X X crcval = 0; /* reset CRC check value */ X size = hdr->size; /* set input byte counter */ X state = NOHIST; /* initial repeat unpacking state */ X setcode(); /* set up for decoding */ X X /* use whatever method is appropriate */ X X switch(hdrver) /* choose proper unpack method */ X { X case 1: /* standard packing */ X case 2: X while ((c=getc_unp(f))!=EOF) X putc_unp(c,t); X break; X case 3: /* non-repeat packing */ X while ((c=getc_unp(f))!=EOF) X putc_ncr(c,t); X break; X case 4: /* Huffman squeezing */ X init_usq(f); X while ((c=getc_usq(f))!=EOF) X putc_ncr(c,t); X break; X case 5: /* Lempel-Zev compression */ X init_ucr(0); X while ((c=getc_ucr(f))!=EOF) X putc_unp(c,t); X break; X case 6: /* Lempel-Zev plus non-repeat */ X init_ucr(0); X while ((c=getc_ucr(f))!=EOF) X putc_ncr(c,t); X break; X case 7: /* L-Z plus ncr with new hash */ X init_ucr(1); X while ((c=getc_ucr(f))!=EOF) X putc_ncr(c,t); X break; X case 8: /* dynamic Lempel-Zev */ X decomp(f,t); X break; X default: /* unknown method */ X if (warn) X { X printf("I don't know how to unpack file %s\n",hdr->name); X printf("I think you need a newer version of ARC\n"); X nerrs++; X } X fseek(f,hdr->size,1); /* skip over bad file */ X return(1); /* note defective file */ X } X X /* cleanups common to all methods */ X X if ((crcval&0xffff)!=(hdr->crc&0x0000ffff)) X { X if (warn) X { X printf("WARNING: File %s fails CRC check\n",hdr->name); X nerrs++; X } X return(1); /* note defective file */ X } X return(0); /* file is okay */ X} X X/* X * This routine is used to put bytes in the output file. It also X * performs various housekeeping functions, such as maintaining the X * CRC check value. X */ X Xstatic INT putc_unp(c,t) /* output an unpacked byte */ Xchar c; /* byte to output */ XFILE *t; /* file to output to */ X{ X crcval = addcrc(crcval,c); /* update the CRC check value */ X putc_tst(c,t); X} X X/* X * This routine is used to decode non-repeat compression. Bytes are X * passed one at a time in coded format, and are written out uncoded. X * The data is stored normally, except that runs of more than two X * characters are represented as: X * X * <char> <DLE> <count> X * X * With a special case that a count of zero indicates a DLE as data, X * not as a repeat marker. X */ X XINT 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 switch(state) /* action depends on our state */ X { X case NOHIST: /* no previous history */ X if (c==DLE) /* if starting a series */ X state = INREP; /* then remember it next time */ X else X putc_unp(lastc=c,t); /* else nothing unusual */ X return; X case INREP: /* in a repeat */ X if (c) /* if count is nonzero */ X while (--c) /* then repeatedly ... */ X putc_unp(lastc,t); /* ... output the byte */ X else X putc_unp(DLE,t); /* else output DLE as data */ X state = NOHIST; /* back to no history */ X return; X default: X abort("Bad NCR unpacking state (%d)",state); X } X} X X/* X * This routine provides low-level byte input from an archive. This X * routine MUST be used, as end-of-file is simulated at the end of X * the archive entry. X */ X XINT getc_unp(f) /* get a byte from an archive */ XFILE *f; /* archive file to read */ X{ X if (!size) /* if no data left */ X return(EOF); /* then pretend end of file */ X X size--; /* deduct from input counter */ X return(code(fgetc(f))); /* and return next decoded byte */ X} SHAR_EOF if test 6134 -ne "`wc -c < 'arcunp.c'`" then echo shar: "error transmitting 'arcunp.c'" '(should have been 6134 characters)' fi fi echo shar: "extracting 'arcusq.c'" '(2992 characters)' if test -f 'arcusq.c' then echo shar: "will not over-write existing file 'arcusq.c'" else sed 's/^ X//' << \SHAR_EOF > 'arcusq.c' X/* X * arcusq.c 1.1 X * X * Author: Thom Henderson X * Original System V port: Mike Stump X * Enhancements, Bug fixes, and cleanup: Chris Seaman X * Date: Fri Mar 20 09:57:02 1987 X * Last Mod. 3/21/87 X * X */ X X/* X * ARC - Archive utility - ARCUSQ X * X * Version 3.13, created on 01/30/86 at 20:11:42 X * X * (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED X * X * Description: X * This file contains the routines used to expand a file X * which was packed using Huffman squeezing. X * X * Most of this code is taken from an USQ program by Richard X * Greenlaw, which was adapted to CI-C86 by Robert J. Beilstein. X */ X X#include "arc.h" X X/* stuff for Huffman unsqueezing */ X X#define ERROR (-1) X#define SPEOF 256 /* special endfile token */ X#define NUMVALS 257 /* 256 data values plus SPEOF */ X Xstruct u_nd { /* decoding tree */ X INT child[2]; /* left, right */ X} u_node[NUMVALS]; /* use large buffer */ X Xstatic INT bpos; /* last bit position read */ Xstatic INT curin; /* last byte value read */ Xstatic INT numnodes; /* number of nodes in decode tree */ X Xstatic INT get_int(f) /* get an integer */ XFILE *f; /* file to get it from */ X{ X INT i; X X i = getc_unp(f); X return((short)(i | (getc_unp(f)<<8))); X} X XINT init_usq(f) /* initialize Huffman unsqueezing */ XFILE *f; /* file containing squeezed data */ X{ X INT i; /* node index */ X X bpos = 99; /* force initial read */ X X numnodes = get_int(f); X X if (numnodes<0 || numnodes>=NUMVALS) X abort("File has an invalid decode tree"); X X /* initialize for possible empty tree (SPEOF only) */ X X u_node[0].child[0] = -(SPEOF + 1); X u_node[0].child[1] = -(SPEOF + 1); X X for (i=0; i<numnodes; ++i) /* get decoding tree from file */ X { X u_node[i].child[0] = get_int(f); X u_node[i].child[1] = get_int(f); X } X} X XINT getc_usq(f) /* get byte from squeezed file */ XFILE *f; /* file containing squeezed data */ X{ X INT i; /* tree index */ X X /* follow bit stream in tree to a leaf */ X X for (i=0; i>=0; ) /* work down(up?) from root */ X { X if (++bpos>7) X { X if ((curin=getc_unp(f)) == ERROR) X return(ERROR); X bpos = 0; X X /* move a level deeper in tree */ X i = u_node[i].child[1&curin]; X } X else X i = u_node[i].child[1 & (curin >>= 1)]; X } X X /* decode fake node index to original data value */ X X i = -(i + 1); X X /* decode special endfile token to normal EOF */ X X i = (i==SPEOF) ? EOF : i; X return(i); X} SHAR_EOF if test 2992 -ne "`wc -c < 'arcusq.c'`" then echo shar: "error transmitting 'arcusq.c'" '(should have been 2992 characters)' fi fi exit 0 # End of shell archive