-
Notifications
You must be signed in to change notification settings - Fork 0
/
arcunp.c
255 lines (215 loc) · 4.91 KB
/
arcunp.c
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 */
short crcval; /* CRC check value */
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);
}