1 #ifndef lint 2 static char sccsid[] = "@(#)compact.c 4.8 (Berkeley) 02/28/91"; 3 #endif 4 5 /* 6 * Adaptive Huffman code input to output 7 * 8 * On - line algorithm 9 * 10 * Does not prepend decoding tree 11 * 12 * Written by Colin L. Mc Master (UCB) February 28, 1979 13 */ 14 #include <strings.h> 15 #include "compact.h" 16 17 union cio d; 18 union cio c; 19 int bits; 20 char *infname; /* input file's name */ 21 char fname[MAXPATHLEN+1]; /* output file's name */ 22 struct stat ucfstatus; /* uncompacted file status */ 23 24 int verbose = 0; 25 26 main(argc, argv) 27 int argc; 28 char *argv[]; 29 { 30 register short j; 31 32 argc--, argv++; 33 if (argc > 0 && strcmp(*argv, "-v") == 0) { 34 verbose++; 35 argc--, argv++; 36 } 37 dir[513].next = NULL; 38 for (head = dir + (j = 513); j--; ) { 39 dirp = head--; 40 head->next = dirp; 41 } 42 bottom = dirp->pt = dict; 43 dict[0].sons[LEFT].top = dict[0].sons[RIGHT].top = dirp; 44 dirq = dirp->next; 45 in[EF].flags = FBIT | SEEN; 46 if (argc == 0) 47 exit(compact("-")); 48 for (j = 0; j < argc; j++) { 49 if (verbose && argc > 0) 50 printf("%s: ", argv[j]); 51 if (compact(argv[j])) 52 exit(1); 53 } 54 exit(0); 55 } 56 57 /* 58 * Compact a single file ("-" implies stdin). 59 */ 60 compact(file) 61 char *file; 62 { 63 int j, ignore; 64 FILE *setup(); 65 66 for (j = 256; j--; ) 67 in[j].flags = 0; 68 bottom->sons[RIGHT].top->next = flist; 69 bottom->sons[RIGHT].top = dirp; 70 flist = dirq; 71 cfp = uncfp = NULL; 72 if (strcmp(file, "-") != 0) { 73 char *cp, *tp; 74 75 /* verify .C suffix fits */ 76 cp = rindex(file, '/'); 77 if (cp == 0) 78 cp = file; 79 else 80 cp++; 81 tp = index(cp, '\0'); 82 if (tp - cp > MAXNAMLEN || strlen(file) + 2 >= MAXPATHLEN) { 83 fprintf(stderr, "%s: File name too long\n", file); 84 goto bad; 85 } 86 uncfp = fopen(file, "r"); 87 if (uncfp == NULL) { 88 fprintf(stderr, "compact: "), perror(file); 89 goto bad; 90 } 91 fstat(fileno(uncfp), &ucfstatus); 92 if ((ucfstatus.st_mode & S_IFMT) != S_IFREG) { 93 fprintf(stderr, "%s: Not a regular file.\n", file); 94 goto bad; 95 } 96 } else 97 uncfp = stdin; 98 infname = file; 99 100 cfp = setup(uncfp, &ignore); 101 if (cfp == NULL) { 102 if (ignore) 103 goto done; 104 goto bad; 105 } 106 if (compress(uncfp, cfp)) { 107 if (cfp != stdout) 108 (void) unlink(fname); 109 goto bad2; 110 } 111 encode(EF); 112 if (bits) { 113 d.integ <<= 16 - bits; 114 putc(d.chars.hib, cfp); 115 if (bits > 8) 116 putc(d.chars.lob, cfp); 117 bits = 0; 118 } 119 fflush(cfp); 120 if (ferror(uncfp) || ferror(cfp)) { 121 if (cfp != stdout) { 122 fprintf(stderr, "compact: "); 123 if (ferror(cfp)) 124 perror(fname); 125 else 126 perror(infname); 127 (void) unlink(fname); 128 } 129 goto bad; 130 } 131 if (cfp != stdout) { 132 struct stat cfstatus; 133 longint csize, ucsize; 134 135 (void) fstat(fileno(cfp), &cfstatus); 136 csize = cfstatus.st_size; 137 ucsize = ucfstatus.st_size; 138 if (csize >= ucsize) { 139 printf("%s: ", infname); 140 (void) unlink(fname); 141 printf("Not compacted, does not save bytes.\n"); 142 goto done; 143 } 144 if (verbose) { 145 FILE *fd; 146 longint n, m; 147 148 while (ucsize - csize > 21474) { 149 ucsize /= 10; 150 csize /= 10; 151 } 152 n = 100000 * (ucsize - csize) / ucsize + 5; 153 m = (n % 1000) / 10; 154 bits = m % 10 + '0'; 155 c.integ = m / 10 + '0'; 156 printf("%ld.%c%c%% compression\n", 157 n / 1000, c.chars.lob, bits); 158 } 159 if (unlink(infname) < 0) 160 fprintf(stderr, "compact: "), perror(infname); 161 } 162 done: 163 if (cfp != NULL && cfp != stdout) 164 fclose(cfp); 165 if (uncfp != NULL) 166 fclose(uncfp); 167 return (0); 168 bad2: 169 fprintf(stderr, "compact: "); 170 if (cfp != stdout) 171 perror(infname); 172 else 173 fprintf(stderr, 174 "Unsuccessful compact of standard input to standard output.\n"); 175 bad: 176 if (cfp != NULL && cfp != stdout) 177 fclose(cfp); 178 if (uncfp != NULL) 179 fclose(uncfp); 180 return (1); 181 } 182 183 encode(ch) 184 int ch; 185 { 186 register struct node *pp; 187 int stack[17]; 188 register int stbits = 1, *sp = &stack[0], rbits = bits; 189 register union cio *dp = &d; 190 union cio c; 191 192 c.integ = ch; 193 *sp = in[ch].flags & FBIT; 194 pp = in[ch].fp; 195 196 while (pp->fath.fp) { 197 *sp <<= 1; 198 if (pp->fath.flags & FBIT) 199 (*sp)++; 200 stbits++; 201 if ((stbits &= 017) == 0) 202 sp++; 203 pp = pp->fath.fp; 204 } 205 206 /* pop the output stack */ 207 do { 208 while (stbits-- > 0) { 209 dp->integ <<= 1; 210 if (*sp & 01) 211 dp->integ++; 212 ++rbits; 213 if ((rbits &= 017) == 0) { 214 putc(dp->chars.hib, cfp); 215 putc(dp->chars.lob, cfp); 216 if (ferror(cfp)) 217 goto done; 218 } 219 *sp >>= 1; 220 } 221 stbits = 16; 222 } while (--sp >= &stack[0]); 223 done: 224 bits = rbits; 225 } 226 227 compress(uncfp, cfp) 228 register FILE *uncfp, *cfp; 229 { 230 register union cio *dp = &d; 231 register union cio *cp = &c; 232 233 cp->integ = (dp->integ >> 8) & 0377; 234 for (; cp->integ != EOF; cp->integ = getc(uncfp)) { 235 if ((in[cp->integ].flags & SEEN) == 0) { 236 register short j, m; 237 238 encode(NC); 239 uptree(NC); 240 insert(cp->integ); 241 242 m = 0200; 243 for (j = 8; j--; m >>= 1) { 244 dp->integ <<= 1; 245 if (m & cp->integ) 246 dp->integ++; 247 ++bits; 248 if ((bits &= 017) == 0) { 249 putc(dp->chars.hib, cfp); 250 putc(dp->chars.lob, cfp); 251 } 252 } 253 } else 254 encode(cp->integ); 255 if (ferror(cfp)) { 256 perror(fname); 257 return (1); 258 } 259 uptree(cp->integ); 260 } 261 if (ferror(uncfp)) { 262 perror(infname); 263 return (1); 264 } 265 return (0); 266 } 267 268 FILE * 269 setup(uncfp, ignore) 270 FILE *uncfp; 271 int *ignore; 272 { 273 FILE *cfp = NULL; 274 register union cio *dp = &d; 275 register union cio *cp = &c; 276 277 dp->integ = getc(uncfp); 278 if (*ignore = (dp->integ == EOF)) 279 goto bad; 280 cp->integ = getc(uncfp); 281 if (*ignore = (cp->integ == EOF)) 282 goto bad; 283 dp->chars.hib = cp->integ & 0377; 284 if ((dp->integ &= 0177777) == COMPACTED) { 285 fprintf(stderr, "%s: Already compacted.\n", infname); 286 *ignore = 1; 287 goto bad; 288 } 289 if (dp->integ == PACKED) { 290 fprintf(stderr, 291 "%s: Already packed using pack program, use unpack.\n", 292 infname); 293 *ignore = 1; 294 goto bad; 295 } 296 if (strcmp(infname, "-") != 0) { 297 sprintf(fname, "%s.C", infname); 298 cfp = fopen(fname, "w"); 299 if (cfp == NULL) 300 goto bad2; 301 (void) fchmod(fileno(cfp), ucfstatus.st_mode); 302 } else 303 cfp = stdout; 304 cp->integ = COMPACTED; 305 putc(cp->chars.lob, cfp); 306 putc(cp->chars.hib, cfp); 307 if (ferror(cfp)) 308 goto bad2; 309 bits = 8; 310 cp->integ = dp->integ & 0377; 311 312 in[NC].fp = in[EF].fp = dict[0].sons[LEFT].sp.p = bottom = dict + 1; 313 bottom->sons[LEFT].count = bottom->sons[RIGHT].count = 314 dict[0].sons[RIGHT].count = 1; 315 dirp->next = dict[0].sons[RIGHT].top = bottom->sons[LEFT].top = 316 bottom->sons[RIGHT].top = dirq = NEW; 317 dirq->next = NULL; 318 dict[0].fath.fp = NULL; 319 dirq->pt = bottom->fath.fp = in[cp->integ].fp = dict; 320 in[cp->integ].flags = (FBIT | SEEN); 321 in[NC].flags = SEEN; 322 dict[0].fath.flags = RLEAF; 323 bottom->fath.flags = (LLEAF | RLEAF); 324 dict[0].sons[LEFT].count = 2; 325 326 dict[0].sons[RIGHT].sp.ch = cp->integ; 327 bottom->sons[LEFT].sp.ch = NC; 328 bottom->sons[RIGHT].sp.ch = EF; 329 return (cfp); 330 bad2: 331 if (cfp && cfp != stdout) { 332 fprintf(stderr, "compact: "), perror(fname); 333 (void) unlink(fname); 334 } 335 bad: 336 if (cfp && cfp != stdout) 337 fclose(cfp); 338 return (NULL); 339 } 340