1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
|
/*
* ARC - Archive utility - ARCUNP
*
* Version 3.17, created on 02/13/86 at 10:20:08
*
* (C) COPYRIGHT 1985-87 by System Enhancement Associates.
* You may copy and distribute this program freely,
* under the terms of the General Public License.
*
* 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 <stdio.h>
#include "arc.h"
#if _MTS
#include <mts.h>
#endif
VOID setcode(), init_usq(), init_ucr(), decomp();
VOID arcdie(), codebuf();
#include "proto.h"
/* stuff for repeat unpacking */
#define DLE 0x90 /* repeat byte flag */
extern u_char state; /* repeat unpacking state */
extern int lastc;
/* repeat unpacking states */
#define NOHIST 0 /* no relevant history */
#define INREP 1 /* sending a repeated value */
extern short crcval; /* CRC check value */
extern long stdlen; /* bytes to read */
#if !DOS
static int gotcr; /* got a carriage return? */
#endif
extern u_char *pinbuf, *pakbuf, *outbuf;
int
unpack(f, t, hdr) /* unpack an archive entry */
FILE *f, *t; /* source, destination */
struct heads *hdr; /* pointer to file header data */
{
u_int len;
/* setups common to all methods */
#if !DOS
gotcr = 0;
#endif
crcval = 0; /* reset CRC check value */
stdlen = 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:
do {
len = getb_unp(f);
putb_unp(pinbuf, len, t);
} while (len == MYBUF);
break;
case 3: /* non-repeat packing */
do {
len = getb_unp(f);
putb_ncr(pinbuf, len, t);
} while (len == MYBUF);
break;
case 4: /* Huffman squeezing */
init_usq(f);
do {
len = getb_usq(f);
putb_ncr(outbuf, len, t);
} while (len == MYBUF);
break;
case 5: /* Lempel-Zev compression */
init_ucr(0, f);
do {
len = getb_ucr(f);
putb_unp(outbuf, len, t);
} while (len == MYBUF);
break;
case 6: /* Lempel-Zev plus non-repeat */
init_ucr(0, f);
do {
len = getb_ucr(f);
putb_ncr(outbuf, len, t);
} while (len == MYBUF);
break;
case 7: /* L-Z plus ncr with new hash */
init_ucr(1, f);
do {
len = getb_ucr(f);
putb_ncr(outbuf, len, t);
} while (len == MYBUF);
break;
case 8: /* dynamic Lempel-Zev */
decomp(0, f, t);
break;
case 9: /* Squashing */
decomp(1, 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 || kludge) {
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.
*/
VOID
putb_unp(buf, len, t)
u_char *buf;
u_int len;
FILE *t;
{
u_int i, j;
crcval = crcbuf(crcval, len, buf);
if (!t)
return;
#if !DOS
if (!image) {
#if _MTS
atoe(buf, len);
#endif
if (gotcr) {
gotcr = 0;
if (buf[0] != '\n')
putc('\r', t);
}
for (i=0,j=0; i<len; i++)
if (buf[i] != '\r' || buf[i+1] != '\n')
buf[j++] = buf[i];
len = j;
if (buf[len-1] == '\r') {
len--;
gotcr = 1;
}
}
#endif /* !DOS */
i=fwrite(buf, 1, len, t);
if (i != len)
arcdie("Write fail");
}
/*
* 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:
*
* <char> <DLE> <count>
*
* With a special case that a count of zero indicates a DLE as data, not as a
* repeat marker.
*/
VOID
putb_ncr(buf, len, t) /* put NCR coded bytes */
u_char *buf;
u_int len;
FILE *t; /* file to receive data */
{
u_char *pakptr=pakbuf;
u_int i;
for (i=0; i<len; i++) {
if (state == INREP) {
if (buf[i])
while (--buf[i])
*pakptr++ = lastc;
else
*pakptr++ = DLE;
state = NOHIST;
} else {
if (buf[i] != DLE)
*pakptr++ = lastc = buf[i];
else
state = INREP;
}
if (pakptr - pakbuf > MYBUF) {
putb_unp(pakbuf, (u_int) (pakptr-pakbuf), t);
pakptr = pakbuf;
}
}
putb_unp(pakbuf, (u_int) (pakptr-pakbuf), t);
}
/*
* This routine reads a buffer of data from an archive.
*/
u_int
getb_unp(f)
FILE *f;
{
register u_int len;
if (stdlen) {
len = (stdlen < MYBUF) ? stdlen : MYBUF;
len = fread(pinbuf, 1, len, f);
if (password)
codebuf(pinbuf, len);
stdlen -= len;
} else
len = 0;
return (len);
}
|