static char *RCSid = "$Header: arcpack.c,v 1.2 86/07/15 07:53:48 turner Exp $"; /* * $Log: arcpack.c,v $ * Hack-attack 1.3 86/12/20 01:23:45 wilhite@usceast.uucp * Bludgeoned into submission for VAX 11/780 BSD4.2 * (ugly code, but fewer core dumps) * * Revision 1.2 86/07/15 07:53:48 turner * * * Revision 1.1 86/06/26 15:00:37 turner * initial version * * */ /* ARC - Archive utility - ARCPACK $define(tag,$$segment(@1,$$index(@1,=)+1))# $define(version,Version $tag( TED_VERSION DB =3.37), created on $tag( TED_DATE DB =02/03/86) at $tag( TED_TIME DB =22:58:01))# $undefine(tag)# $version (C) COPYRIGHT 1985 by System Enhancement Associates; ALL RIGHTS RESERVED By: Thom Henderson Description: This file contains the routines used to compress a file when placing it in an archive. Language: Computer Innovations Optimizing C86 */ #include #include "arc.h" /* stuff for non-repeat packing */ #define DLE 0x90 /* repeat sequence marker */ static unsigned char state; /* current packing state */ /* non-repeat packing states */ #define NOHIST 0 /* don't consider previous input*/ #define SENTCHAR 1 /* lastchar set, no lookahead yet */ #define SENDNEWC 2 /* run over, send new char next */ #define SENDCNT 3 /* newchar set, send count next */ /* packing results */ static long stdlen; /* length for standard packing */ static INT crcval; /* CRC check value */ INT pack(f,t,hdr) /* pack file into an archive */ FILE *f, *t; /* source, destination */ struct heads *hdr; /* pointer to header data */ { INT c; /* one character of stream */ long ncrlen; /* length after packing */ long huflen; /* length after squeezing */ long lzwlen; /* length after crunching */ long pred_sq(), file_sq(); /* stuff for squeezing */ long pred_cm(), sqpred_cm(); /* dynamic crunching cleanup */ char tnam[STRLEN]; /* temporary name buffer */ char *makefnam(); /* filename fixer upper */ FILE *crn = NULL; /* temporary crunch file */ INT getch(); INT getc_ncr(); INT putc_pak(); /* first pass - see which method is best */ if(!nocomp) /* if storage kludge not active */ { if(note) { printf(" analyzing, "); fflush(stdout);} if(arctemp) /* use temp area if specified */ sprintf(tnam,"%s.CRN",arctemp); else makefnam("$ARCTEMP.CRN",arcname,tnam); #if MSDOS crn = fopen(tnam,"wrb"); #endif #if BSD | ST crn = fopen(tnam,"w+"); #endif state = NOHIST; /* initialize ncr packing */ stdlen = ncrlen = 0; /* reset size counters */ crcval = 0; /* initialize CRC check value */ setcode(); /* initialize encryption */ if(dosquash) sqinit_cm(f,crn); else init_cm(f,crn); /* initialize for crunching */ init_sq(); /* initialize for squeeze scan */ if(dosquash) while((c=getch(f))!=EOF) /* for each byte of file */ { ncrlen++; /* one more packed byte */ scan_sq(c); /* see what squeezing can do */ sqputc_cm(c,crn); /* see what crunching can do */ } else while((c=getc_ncr(f))!=EOF) /* for each byte of file */ { ncrlen++; /* one more packed byte */ scan_sq(c); /* see what squeezing can do */ putc_cm(c,crn); /* see what crunching can do */ } huflen = pred_sq(); /* finish up after squeezing */ if(dosquash) lzwlen = sqpred_cm(crn); else lzwlen = pred_cm(crn); /* finish up after crunching */ } else /* else kludge the method */ { stdlen = 0; /* make standard look best */ ncrlen = huflen = lzwlen = 1; } /* standard set-ups common to all methods */ fseek(f,0L,0); /* rewind input */ hdr->crc = crcval; /* note CRC check value */ hdr->length = stdlen; /* set actual file length */ state = NOHIST; /* reinitialize ncr packing */ setcode(); /* reinitialize encryption */ /* choose and use the shortest method */ if(stdlen<=ncrlen && stdlen<=huflen && stdlen<=lzwlen) { if(kludge) /*DEBUG*/ printf("(%ld) ",lzwlen-stdlen); if(note) { printf("storing, "); fflush(stdout);}/* store w/out compression */ hdrver = 2; /* note packing method */ stdlen = crcval = 0; /* recalc these for kludge */ while((c=getch(f))!=EOF) /* store it straight */ putc_pak(c,t); hdr->crc = crcval; hdr->length = hdr->size = stdlen; } else if(ncrlensize = ncrlen; /* set data length */ while((c=getc_ncr(f))!=EOF) putc_pak(c,t); } else if(huflensize = file_sq(f,t); /* note final size */ } else { if(kludge) /*DEBUG*/ printf("(%ld) ",huflen-lzwlen); if(note) { printf(dosquash ? "squashing, " : "crunching, "); fflush(stdout);} hdrver = dosquash ? 9 : 8; hdr->size = lzwlen; /* size should not change */ if(crn) /* if temp was created */ { fseek(crn,0L,0); /* then copy over crunched temp */ while((c=fgetc(crn))!=EOF) putc_tst(c,t); } else /* else re-crunch */ { if(dosquash) sqinit_cm(f, t); else init_cm(f,t); if(dosquash) while((c=getc_ncr(f))!=EOF) putc_cm(c,t); else while((c=getch(f))!=EOF) sqputc_cm(c,t); if(dosquash) sqpred_cm(t); else pred_cm(t); /* finish up after crunching */ } } /* standard cleanups common to all methods */ if(crn) /* get rid of crunch temporary */ { fclose(crn); if(unlink(tnam) && warn) { printf("Cannot delete temporary file %s\n",tnam); nerrs++; } } if(note) printf("done.\n"); } /* Non-repeat compression - text is passed through normally, except that a run of more than two is encoded as: Special case: a count of zero indicates that the DLE is really a DLE, not a repeat marker. */ INT getc_ncr(f) /* get bytes with collapsed runs */ FILE *f; /* file to get from */ { #if vaxc INT getch(); #endif static INT lastc; /* value returned on last call */ static INT repcnt; /* repetition counter */ static INT c; /* latest value seen */ switch(state) /* depends on our state */ { case NOHIST: /* no relevant history */ state = SENTCHAR; return (lastc = getch(f)); /* remember the value next time */ case SENTCHAR: /* char was sent. look ahead */ switch(lastc) /* action depends on char */ { case DLE: /* if we sent a real DLE */ state = NOHIST; /* then start over again */ return 0; /* but note that the DLE was real */ case EOF: /* EOF is always a special case */ return EOF; default: /* else test for a repeat */ for(repcnt=1; (c=getch(f))==lastc && repcnt<255; repcnt++) ; /* find end of run */ switch(repcnt) /* action depends on run size */ { case 1: /* not a repeat */ return lastc = c; /* but remember value next time */ case 2: /* a repeat, but too short */ state = SENDNEWC; /* send the second one next time */ return lastc; default: /* a run - compress it */ state = SENDCNT; /* send repeat count next time */ return DLE; /* send repeat marker this time */ } } case SENDNEWC: /* send second char of short run */ state = SENTCHAR; return lastc = c; case SENDCNT: /* sent DLE, now send count */ state = SENDNEWC; return repcnt; default: abort("Bug - bad ncr state\n"); } } static INT getch(f) /* special get char for packing */ FILE *f; /* file to get from */ { register INT c; /* a char from the file */ if((c=fgetc(f))!=EOF) /* if not the end of file */ { crcval = addcrc(crcval,c); /* then update CRC check value */ stdlen++; /* and bump length counter */ } return c; } INT putc_pak(c,f) /* put a packed byte into archive */ char c; /* byte to put */ FILE *f; /* archive to put it in */ { putc_tst(code(c),f); /* put encoded byte, with checks */ }