home *** CD-ROM | disk | FTP | other *** search
- 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 <stdio.h>
- #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(ncrlen<huflen && ncrlen<lzwlen)
- { if(kludge) /*DEBUG*/
- printf("(%ld) ",lzwlen-ncrlen);
- if(note)
- { printf("packing, ");
- fflush(stdout);} /* pack w/repeat suppression */
- hdrver = 3; /* note packing method */
- hdr->size = ncrlen; /* set data length */
- while((c=getc_ncr(f))!=EOF)
- putc_pak(c,t);
- }
-
- else if(huflen<lzwlen)
- { if(kludge) /*DEBUG*/
- printf("(%ld) ",lzwlen-huflen);
- if(note)
- { printf("squeezing, "); fflush(stdout);}
- hdrver = 4; /* note packing method */
- hdr->size = 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:
-
- <char> <DLE> <count>
-
- 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 */
- {
- 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 */
- {
- 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 */
- }
-