/* ARC - Archive utility - ARCUNP (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED By: Thom Henderson Description: This file contains the routines used to expand a file when taking it out of an archive. Language: Computer Innovations Optimizing C86 */ #include #include "arc.h" /* stuff for repeat unpacking */ #define DLE 0x90 /* repeat byte flag */ static int state; /* repeat unpacking state */ /* repeat unpacking states */ #define NOHIST 0 /* no relevant history */ #define INREP 1 /* sending a repeated value */ static int crcval; /* CRC check value */ static long size; /* bytes to read */ int unpack(f,t,hdr) /* unpack an archive entry */ FILE *f, *t; /* source, destination */ struct heads *hdr; /* pointer to file header data */ { int c; /* one char of stream */ /* setups common to all methods */ crcval = 0; /* reset CRC check value */ size = hdr->size; /* set input byte counter */ state = NOHIST; /* initial repeat unpacking state */ setcode(); /* set up for decoding */ /* use whatever method is appropriate */ switch(hdrver) /* choose proper unpack method */ { case 1: /* standard packing */ case 2: while((c=getc_unp(f))!=EOF) putc_unp(c,t); break; case 3: /* non-repeat packing */ while((c=getc_unp(f))!=EOF) putc_ncr(c,t); break; case 4: /* Huffman squeezing */ init_usq(f); while((c=getc_usq(f))!=EOF) putc_ncr(c,t); break; case 5: /* Lempel-Zev compression */ init_ucr(0); while((c=getc_ucr(f))!=EOF) putc_unp(c,t); break; case 6: /* Lempel-Zev plus non-repeat */ init_ucr(0); while((c=getc_ucr(f))!=EOF) putc_ncr(c,t); break; case 7: /* L-Z plus ncr with new hash */ init_ucr(1); while((c=getc_ucr(f))!=EOF) putc_ncr(c,t); break; case 8: /* dynamic Lempel-Zev */ decomp(f,t); break; default: /* unknown method */ if(warn) { printf("I don't know how to unpack file %s\n",hdr->name); printf("I think you need a newer version of ARC\n"); nerrs++; } fseek(f,hdr->size,1); /* skip over bad file */ return 1; /* note defective file */ } /* cleanups common to all methods */ if(crcval!=hdr->crc) { if(warn) { printf("WARNING: File %s fails CRC check\n",hdr->name); nerrs++; } return 1; /* note defective file */ } return 0; /* file is okay */ } /* This routine is used to put bytes in the output file. It also performs various housekeeping functions, such as maintaining the CRC check value. */ static putc_unp(c,t) /* output an unpacked byte */ char c; /* byte to output */ FILE *t; /* file to output to */ { crcval = addcrc(crcval,c); /* update the CRC check value */ putc_tst(c,t); } /* This routine is used to decode non-repeat compression. Bytes are passed one at a time in coded format, and are written out uncoded. The data is stored normally, except that runs of more than two characters are represented as: With a special case that a count of zero indicates a DLE as data, not as a repeat marker. */ putc_ncr(c,t) /* put NCR coded bytes */ unsigned char c; /* next byte of stream */ FILE *t; /* file to receive data */ { static int lastc; /* last character seen */ switch(state) /* action depends on our state */ { case NOHIST: /* no previous history */ if(c==DLE) /* if starting a series */ state = INREP; /* then remember it next time */ else putc_unp(lastc=c,t); /* else nothing unusual */ return; case INREP: /* in a repeat */ if(c) /* if count is nonzero */ while(--c) /* then repeatedly ... */ putc_unp(lastc,t); /* ... output the byte */ else putc_unp(DLE,t); /* else output DLE as data */ state = NOHIST; /* back to no history */ return; default: abort("Bad NCR unpacking state (%d)",state); } } /* This routine provides low-level byte input from an archive. This routine MUST be used, as end-of-file is simulated at the end of the archive entry. */ int getc_unp(f) /* get a byte from an archive */ FILE *f; /* archive file to read */ { if(!size) /* if no data left */ return EOF; /* then pretend end of file */ size--; /* deduct from input counter */ return code(fgetc(f)); /* and return next decoded byte */ }