home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume1
/
8707
/
66
/
arcpack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-13
|
11KB
|
294 lines
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 */
}