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