|
|
1.1 root 1: /*
2: * Huffman decompressor
3: * Usage: pcat filename...
4: * or unpack filename...
5: */
6:
7: static char unpackvers[] = "@(#)unpack.c 1.10";
8:
9: #include <stdio.h>
10: #include <setjmp.h>
11: #include <sys/types.h>
12: #include <sys/stat.h>
13:
14: #define VOID (void)
15:
16: jmp_buf env;
17: struct stat status;
18: char *argv0, *argvk;
19: short errorm;
20:
21: #define NAMELEN 80
22: #define SUF0 '.'
23: #define SUF1 'z'
24: #define US 037
25: #define RS 036
26:
27: #define BLKSIZE BUFSIZ
28:
29:
30: /* variables associated with i/o */
31: char filename[NAMELEN+2];
32: short infile;
33: short outfile;
34: short inleft;
35: char *inp;
36: char *outp;
37: char inbuff[BUFSIZ];
38: char outbuff[BUFSIZ];
39:
40: /* the dictionary */
41: long origsize;
42: short maxlev;
43: short intnodes[25];
44: char *tree[25];
45: char characters[256];
46: char *eof;
47:
48: /* read in the dictionary portion and build decoding structures */
49: /* return 1 if successful, 0 otherwise */
50: getdict ()
51: {
52: register int c, i, nchildren;
53:
54: /*
55: * check two-byte header
56: * get size of original file,
57: * get number of levels in maxlev,
58: * get number of leaves on level i in intnodes[i],
59: * set tree[i] to point to leaves for level i
60: */
61: eof = &characters[0];
62:
63: inbuff[6] = 25;
64: inleft = read (infile, &inbuff[0], BUFSIZ);
65: if (inleft < 0) {
66: eprintf (".z: read error");
67: return (0);
68: }
69: if (inbuff[0] != US)
70: goto goof;
71:
72: if (inbuff[1] == US) { /* oldstyle packing */
73: if (setjmp (env))
74: return (0);
75: expand ();
76: return (1);
77: }
78: if (inbuff[1] != RS)
79: goto goof;
80:
81: inp = &inbuff[2];
82: origsize = 0;
83: for (i=0; i<4; i++)
84: origsize = origsize*256 + ((*inp++) & 0377);
85: maxlev = *inp++ & 0377;
86: if (maxlev > 24) {
87: goof: eprintf (".z: not in packed format");
88: return (0);
89: }
90: for (i=1; i<=maxlev; i++)
91: intnodes[i] = *inp++ & 0377;
92: for (i=1; i<=maxlev; i++) {
93: tree[i] = eof;
94: for (c=intnodes[i]; c>0; c--) {
95: if (eof >= &characters[255])
96: goto goof;
97: *eof++ = *inp++;
98: }
99: }
100: *eof++ = *inp++;
101: intnodes[maxlev] += 2;
102: inleft -= inp - &inbuff[0];
103: if (inleft < 0)
104: goto goof;
105:
106: /*
107: * convert intnodes[i] to be number of
108: * internal nodes possessed by level i
109: */
110:
111: nchildren = 0;
112: for (i=maxlev; i>=1; i--) {
113: c = intnodes[i];
114: intnodes[i] = nchildren /= 2;
115: nchildren += c;
116: }
117: return (decode ());
118: }
119:
120: /* unpack the file */
121: /* return 1 if successful, 0 otherwise */
122: decode ()
123: {
124: register int bitsleft, c, i;
125: int j, lev;
126: char *p;
127:
128: outp = &outbuff[0];
129: lev = 1;
130: i = 0;
131: while (1) {
132: if (inleft <= 0) {
133: inleft = read (infile, inp = &inbuff[0], BUFSIZ);
134: if (inleft < 0) {
135: eprintf (".z: read error");
136: return (0);
137: }
138: }
139: if (--inleft < 0) {
140: uggh: if(origsize == 0) return 1;
141: eprintf (".z: unpacking error");
142: return (0);
143: }
144: c = *inp++;
145: bitsleft = 8;
146: while (--bitsleft >= 0) {
147: i *= 2;
148: if (c & 0200)
149: i++;
150: c <<= 1;
151: if ((j = i - intnodes[lev]) >= 0) {
152: p = &tree[lev][j];
153: if (p == eof) {
154: c = outp - &outbuff[0];
155: if (write (outfile, &outbuff[0], c) != c) {
156: wrerr: eprintf (": write error");
157: return (0);
158: }
159: origsize -= c;
160: if (origsize != 0)
161: goto uggh;
162: return (1);
163: }
164: *outp++ = *p;
165: if (outp == &outbuff[BUFSIZ]) {
166: if (write (outfile, outp = &outbuff[0], BUFSIZ) != BUFSIZ)
167: goto wrerr;
168: origsize -= BUFSIZ;
169: }
170: lev = 1;
171: i = 0;
172: } else
173: lev++;
174: }
175: }
176: }
177:
178: main (argc, argv)
179: char *argv[];
180: {
181: register i, k;
182: int sep, pcat = 0;
183: register char *p1, *cp;
184: int fcount = 0; /* failure count */
185:
186: p1 = *argv;
187: while(*p1++); /* Point p1 to end of argv[0] string */
188: while(--p1 >= *argv)
189: if(*p1 == '/')break;
190: *argv = p1 + 1;
191: argv0 = argv[0];
192: if(**argv == 'p')pcat++; /* User entered pcat (or /xx/xx/pcat) */
193: if(pcat && argc == 1){
194: infile = 0;
195: outfile = 1;
196: return getdict();
197: }
198: for (k=1; k<argc; k++) {
199: errorm = 0;
200: sep = -1;
201: cp = filename;
202: argvk = argv[k];
203: for (i=0; i < (NAMELEN-3) && (*cp = argvk[i]); i++)
204: if (*cp++ == '/')
205: sep = i;
206: if (cp[-1] == SUF1 && cp[-2] == SUF0) {
207: argvk[i-2] = '\0'; /* Remove suffix and try again */
208: k--;
209: continue;
210: }
211:
212: fcount++; /* expect the worst */
213: if (i >= (NAMELEN-3) || (i - sep) > 13) {
214: eprintf (": file name too long");
215: goto done;
216: }
217: *cp++ = SUF0;
218: *cp++ = SUF1;
219: *cp = '\0';
220: if ((infile = open (filename, 0)) == -1) {
221: eprintf (".z: cannot open");
222: goto done;
223: }
224:
225: if (pcat)
226: outfile = 1; /* standard output */
227: else {
228: if (stat (argvk, &status) != -1) {
229: eprintf (": already exists");
230: goto done;
231: }
232: VOID fstat (infile, &status);
233: if (status.st_nlink != 1)
234: eprintf (".z: Warning: file has links");
235: if ((outfile = creat (argvk, status.st_mode&07777)) == -1) {
236: eprintf (": cannot create");
237: goto done;
238: }
239:
240: if (chmod (argvk, status.st_mode) != 0)
241: printf("can't change mode to %o\n", status.st_mode);
242: VOID chown (argvk, status.st_uid, status.st_gid);
243: }
244:
245: if (getdict ()) { /* unpack */
246: fcount--; /* success after all */
247: if (!pcat) {
248: eprintf (": unpacked");
249: VOID unlink (filename);
250:
251: /*
252: * preserve acc & mod dates
253: */
254: VOID utime (argvk, &status.st_atime);
255: }
256: }
257: else
258: if (!pcat)
259: VOID unlink (argvk);
260: done: if (errorm)
261: VOID fprintf (stderr, "\n");
262: VOID close (infile);
263: if (!pcat)
264: VOID close (outfile);
265: }
266: return (fcount);
267: }
268:
269: eprintf (s)
270: char *s;
271: {
272: if (!errorm) {
273: errorm = 1;
274: VOID fprintf (stderr, "%s: %s", argv0, argvk);
275: }
276: VOID fprintf (stderr, s);
277: }
278:
279: /*
280: * This code is for unpacking files that
281: * were packed using the previous algorithm.
282: */
283:
284: int Tree[1024];
285:
286: expand ()
287: {
288: register tp, bit;
289: short word;
290: int keysize, i, *t;
291:
292: outp = outbuff;
293: inp = &inbuff[2];
294: inleft -= 2;
295: origsize = ((long) (unsigned) getwd ())*256*256;
296: origsize += (unsigned) getwd ();
297: t = Tree;
298: for (keysize = getwd (); keysize--; ) {
299: if ((i = getch ()) == 0377)
300: *t++ = getwd ();
301: else
302: *t++ = i & 0377;
303: }
304:
305: bit = tp = 0;
306: for (;;) {
307: if (bit <= 0) {
308: word = getwd ();
309: bit = 16;
310: }
311: tp += Tree[tp + (word<0)];
312: word <<= 1;
313: bit--;
314: if (Tree[tp] == 0) {
315: putch (Tree[tp+1]);
316: tp = 0;
317: if ((origsize -= 1) == 0) {
318: write (outfile, outbuff, outp - outbuff);
319: return;
320: }
321: }
322: }
323: }
324:
325: getch ()
326: {
327: if (inleft <= 0) {
328: inleft = read (infile, inp = inbuff, BUFSIZ);
329: if (inleft < 0) {
330: eprintf (".z: read error");
331: longjmp (env, 1);
332: }
333: }
334: inleft--;
335: return (*inp++ & 0377);
336: }
337:
338: getwd ()
339: {
340: register char c;
341: register d;
342: c = getch ();
343: d = getch ();
344: d <<= 8;
345: d |= c & 0377;
346: return (d);
347: }
348:
349: putch (c)
350: char c;
351: {
352: register n;
353:
354: *outp++ = c;
355: if (outp == &outbuff[BUFSIZ]) {
356: n = write (outfile, outp = outbuff, BUFSIZ);
357: if (n < BUFSIZ) {
358: eprintf (": write error");
359: longjmp (env, 2);
360: }
361: }
362: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.