Commit | Line | Data |
---|---|---|
b60e6348 CMM |
1 | /* |
2 | * Adaptive Huffman code input to output | |
3 | * | |
4 | * On - line algorithm | |
5 | * | |
6 | * Does not prepend decoding tree | |
7 | * | |
8 | * Written by Colin L. Mc Master (UCB) February 28, 1979 | |
9 | */ | |
10 | ||
11 | ||
12 | #include "compact.h" | |
13 | ||
14 | union cio d; | |
15 | int bits; | |
16 | ||
17 | ||
18 | main (argc, argv) | |
19 | short argc; | |
20 | char *argv [ ]; | |
21 | { | |
22 | register short i, j; | |
23 | register int m; | |
24 | union cio c; | |
25 | short l; | |
26 | longint ic, n; | |
27 | char *cp, fname [LNAME]; | |
28 | ||
29 | dir [513] . next = NULL; | |
30 | for (head = dir + (j = 513); j--; ) { | |
31 | dirp = head--; | |
32 | head -> next = dirp; | |
33 | } | |
34 | bottom = dirp -> pt = dict; | |
35 | dict [0] . top [0] = dict [0] . top [1] = dirp; | |
36 | dirq = dirp -> next; | |
37 | in [EF] . flags = FBIT | SEEN; | |
38 | ||
39 | for (i = 1; ; i++) { | |
40 | ic = oc = 0; | |
41 | (bottom -> top [1]) -> next = flist; | |
42 | bottom -> top [1] = dirp; | |
43 | flist = dirq; | |
44 | if (i >= argc) { | |
45 | uncfp = stdin; | |
46 | cfp = stdout; | |
47 | } | |
48 | else { | |
49 | m = -1; | |
50 | cp = fname; | |
51 | for (l = 0; l < (LNAME - 3) && (*cp = argv [i][l]); l++) | |
52 | if (*cp++ == '/') m = l; | |
53 | if (l >= (LNAME - 3) || (l - m) > 13) { | |
54 | fprintf (stderr, "%s: File name too long\n", argv [i]); | |
55 | if (i == argc - 1) break; | |
56 | continue; | |
57 | } | |
58 | if ((uncfp = fopen (argv [i], "r")) == NULL) { | |
59 | perror (argv [i]); | |
60 | if (i == argc - 1) break; | |
61 | continue; | |
62 | } | |
63 | } | |
64 | ||
65 | fstat (fileno (uncfp), &status); | |
66 | if ((status.st_mode & 040000) == 040000) { | |
67 | fprintf (stderr, "%s: Can't compact a directory\n", argv [i]); | |
68 | if (i < argc) goto closein; | |
69 | break; | |
70 | } | |
71 | ||
72 | if ((d . integ = getc (uncfp)) != EOF) { | |
73 | ic++; | |
74 | if ((c . integ = getc (uncfp)) != EOF) { | |
75 | d . chars . hib = c . integ & 0377; | |
76 | if ((d . integ &= 0177777) == COMPACTED) { | |
77 | fprintf (stderr, "%s: Already compacted.\n", argv [i]); | |
78 | if (i < argc) goto closein; | |
79 | break; | |
80 | } | |
81 | if (d . integ == PACKED) { | |
82 | fprintf (stderr, "%s: Already packed using program pack. Use unpack.\n", argv [i]); | |
83 | if (i < argc) goto closein; | |
84 | break; | |
85 | } | |
86 | if (i < argc) { | |
87 | *cp++ = '.'; *cp++ = 'C'; *cp = '\0'; | |
88 | if ((cfp = fopen (fname, "w")) == NULL) { | |
89 | perror (fname); | |
90 | goto closein; | |
91 | } | |
92 | chmod (fname, status.st_mode); | |
93 | } | |
94 | c . integ = COMPACTED; | |
95 | putc (c . chars . lob, cfp); | |
96 | putc (c . chars . hib, cfp); | |
97 | if (ferror (cfp)) | |
98 | if (i < argc) { | |
99 | perror (fname); | |
100 | unlink (fname); | |
101 | goto closeboth; | |
102 | } | |
103 | else goto fail; | |
104 | bits = 8; | |
105 | oc = 2; | |
106 | c . integ = d . integ & 0377; | |
107 | ||
108 | in [NC] . fp = in [EF] . fp = dict [0] . sp [0] . p = bottom = dict + 1; | |
109 | bottom -> count [0] = bottom -> count [1] = dict [0] . count [1] = 1; | |
110 | dirp -> next = dict [0] . top [1] = bottom -> top [0] = bottom -> top [1] = dirq = NEW; | |
111 | dirq -> next = NULL; | |
112 | dict [0] . fath . fp = NULL; | |
113 | dirq -> pt = bottom -> fath . fp = in [c . integ] . fp = dict; | |
114 | in [c . integ] . flags = (FBIT | SEEN); | |
115 | in [NC] . flags = SEEN; | |
116 | dict [0] . fath . flags = RLEAF; | |
117 | bottom -> fath . flags = (LLEAF | RLEAF); | |
118 | dict [0] . count [0] = 2; | |
119 | ||
120 | dict [0] . sp [1] . ch = c . integ; | |
121 | bottom -> sp [0] . ch = NC; | |
122 | bottom -> sp [1] . ch = EF; | |
123 | ||
124 | for (c . integ = ((d . integ >> 8) & 0377); c . integ != EOF; c . integ = getc (uncfp)) { | |
125 | ic++; | |
126 | if (in [c . integ] . flags & SEEN) encode (c . integ); | |
127 | else { | |
128 | encode (NC); | |
129 | uptree (NC); | |
130 | insert (c . integ); | |
131 | ||
132 | m = 0200; | |
133 | for (j = 8; j--; m >>= 1) { | |
134 | d . integ <<= 1; | |
135 | if (m & c . integ) d . integ++; | |
136 | ++bits; | |
137 | if ((bits &= 017) == 0) { | |
138 | putc (d . chars . hib, cfp); | |
139 | putc (d . chars . lob, cfp); | |
140 | oc += 2; | |
141 | } | |
142 | } | |
143 | } | |
144 | if (ferror (cfp)) | |
145 | if (i < argc) { | |
146 | perror (fname); | |
147 | unlink (fname); | |
148 | goto closeboth; | |
149 | } | |
150 | else goto fail; | |
151 | uptree (c . integ); | |
152 | ||
153 | } | |
154 | ||
155 | if (ferror (uncfp)) | |
156 | if (i < argc) { | |
157 | perror (argv [i]); | |
158 | unlink (fname); | |
159 | goto closeboth; | |
160 | } | |
161 | else goto fail; | |
162 | ||
163 | encode (EF); | |
164 | ||
165 | if (bits) { | |
166 | d . integ <<= (16 - bits); | |
167 | oc++; | |
168 | putc (d . chars . hib, cfp); | |
169 | if (bits > 8) { | |
170 | oc++; | |
171 | putc (d . chars . lob, cfp); | |
172 | } | |
173 | bits = 0; | |
174 | } | |
175 | } | |
176 | else oc = ic; | |
177 | } | |
178 | ||
179 | if (ferror (uncfp) || ferror (cfp)) | |
180 | if (i < argc) { | |
181 | if (ferror (cfp)) | |
182 | perror (fname); | |
183 | else | |
184 | perror (argv [i]); | |
185 | if (oc > 1) { | |
186 | unlink (fname); | |
187 | goto closeboth; | |
188 | } | |
189 | goto closein; | |
190 | } | |
191 | else goto fail; | |
192 | else { | |
193 | if (oc >= ic) { | |
194 | if (i < argc) fprintf (stderr, "%s: ", argv [i]); | |
195 | if (i < argc) fprintf (stderr, "Not compacted. "); | |
196 | fprintf (stderr, "Does not save bytes.\n"); | |
197 | if (i < argc) { | |
198 | if (oc > 1) { | |
199 | unlink (fname); | |
200 | goto closeboth; | |
201 | } | |
202 | goto closein; | |
203 | } | |
204 | else break; | |
205 | } | |
206 | while ((ic - oc) > 21474) { | |
207 | ic /= 10; | |
208 | oc /= 10; | |
209 | } | |
210 | n = 100000 * (ic - oc) / ic + 5; | |
211 | m = (n % 1000) / 10; | |
212 | bits = m % 10 + '0'; | |
213 | c . integ = m / 10 + '0'; | |
214 | if (i < argc) fprintf (stderr, "%s: ", argv [i]); | |
215 | fprintf (stderr, "Compression : %4ld.%c%c%%\n", n / 1000, c . chars . lob, bits); | |
216 | } | |
217 | ||
218 | if (i >= argc) break; | |
219 | unlink (argv [i]); | |
220 | closeboth : fclose (cfp); | |
221 | closein : fclose (uncfp); | |
222 | if (i == argc - 1) break; | |
223 | for (j = 256; j--; ) in [j] . flags = 0; | |
224 | continue; | |
225 | fail : fprintf (stderr, "Unsuccessful compact of standard input to standard output.\n"); | |
226 | break; | |
227 | } | |
228 | } | |
229 | ||
230 | encode (ch) | |
231 | int ch; | |
232 | { | |
233 | ||
234 | register struct node *pp; | |
235 | register char j; | |
236 | union cio c; | |
237 | int stack [17], stp, stbits; | |
238 | ||
239 | c . integ = ch; | |
240 | stack [stp = 0] = in [c . integ] . flags & FBIT; | |
241 | stbits = 1; | |
242 | pp = in [c . integ] . fp; | |
243 | ||
244 | while (pp -> fath . fp) { | |
245 | stack [stp] <<= 1; | |
246 | if (pp -> fath . flags & FBIT) stack [stp]++; | |
247 | stbits++; | |
248 | if ((stbits &= 017) == 0) stp++; | |
249 | pp = pp -> fath . fp; | |
250 | } | |
251 | ||
252 | /* pop the output stack */ | |
253 | ||
254 | for (stp++; stp--; ) { | |
255 | for (j = 0; j < stbits; j++) { | |
256 | d . integ <<= 1; | |
257 | if (stack [stp] & 01) d . integ++; | |
258 | ++bits; | |
259 | if ((bits &= 017) == 0) { | |
260 | putc (d . chars . hib, cfp); | |
261 | putc (d . chars . lob, cfp); | |
262 | if (ferror (cfp)) return; | |
263 | oc += 2; | |
264 | } | |
265 | stack [stp] >>= 1; | |
266 | } | |
267 | stbits = 16; | |
268 | } | |
269 | } |