114544Ssam #ifndef lint
2*33072Sbostic static char sccsid[] = "@(#)uncompact.c	4.8 (Berkeley) 12/21/87";
314544Ssam #endif
414544Ssam 
510922Sshannon /*
610922Sshannon  *  Uncompact adaptive Huffman code input to output
710922Sshannon  *
810922Sshannon  *  On - line algorithm
910922Sshannon  *
1010922Sshannon  *  Input file does not contain decoding tree
1110922Sshannon  *
1210922Sshannon  *  Written by Colin L. Mc Master (UCB) February 14, 1979
1310922Sshannon  */
1410922Sshannon #include "compact.h"
1517016Ssam #include <strings.h>
1610922Sshannon 
1717016Ssam union	cio c;
1817016Ssam union	cio d;
1917016Ssam char	*infname;			/* input file's name */
2017016Ssam char	fname[MAXPATHLEN+1];		/* output file's name */
2117016Ssam struct	stat status;			/* compacted file status */
2210922Sshannon 
2317016Ssam int	verbose = 0;
2417016Ssam 
main(argc,argv)2517016Ssam main(argc, argv)
2617016Ssam 	int argc;
2717016Ssam 	char *argv[];
2810922Sshannon {
2910922Sshannon 	register short j;
3010922Sshannon 
3117016Ssam 	argc--, argv++;
3217016Ssam 	if (argc > 0 && strcmp(*argv, "-v") == 0) {
3317016Ssam 		verbose++;
3417016Ssam 		argc--, argv++;
3517016Ssam 	}
3617016Ssam 	dir[513].next = NULL;
3710922Sshannon 	for (head = dir + (j = 513); j--; ) {
3810922Sshannon 		dirp = head--;
3917016Ssam 		head->next = dirp;
4010922Sshannon 	}
4117016Ssam 	bottom = dirp->pt = dict;
4217017Ssam 	dict[0].sons[LEFT].top = dict[0].sons[RIGHT].top = dirp;
4317016Ssam 	dirq = dirp->next;
4417016Ssam 	in[EF].flags = FBIT | SEEN;
4517016Ssam 	if (argc == 0)
4617016Ssam 		exit(uncompact("-"));
4717016Ssam 	for (j = 0; j < argc; j++) {
4817016Ssam 		if (uncompact(argv[j]))
4917016Ssam 			exit(1);
5017016Ssam 		if (verbose && argc > 0)
5117016Ssam 			printf("%s uncompacted to %s\n", argv[j], fname);
5217016Ssam 	}
5317016Ssam 	exit(0);
5417016Ssam }
5510922Sshannon 
uncompact(file)5617016Ssam uncompact(file)
5717016Ssam 	char *file;
5817016Ssam {
5917016Ssam 	int ignore;
6017016Ssam 	FILE *setup();
6117016Ssam 
6217017Ssam 	bottom->sons[RIGHT].top->next = flist;
6317017Ssam 	bottom->sons[RIGHT].top = dirp;
6417016Ssam 	flist = dirq;
6517017Ssam 	uncfp = cfp = NULL;
6617016Ssam 	if (strcmp(file, "-") != 0) {
6717016Ssam 		char *cp;
6817016Ssam 
6917016Ssam 		strcpy(fname, file);
7017016Ssam 		cp = rindex(fname, '.');
7117016Ssam 		if (cp == 0 || strcmp(cp, ".C") != 0) {
7217016Ssam 			fprintf(stderr,
7317016Ssam 			    "uncompact: %s: File must have .C suffix.\n", file);
7417017Ssam 			goto bad;
7510922Sshannon 		}
7617016Ssam 		*cp = '\0';
7717016Ssam 		cfp = fopen(file, "r");
7817016Ssam 		if (cfp == NULL) {
7917016Ssam 			fprintf(stderr, "uncompact: "), perror(file);
8017017Ssam 			goto bad;
8110922Sshannon 		}
8217016Ssam 		(void) fstat(fileno(cfp), &status);
8317016Ssam 	} else
8417016Ssam 		cfp = stdin;
8517016Ssam 	infname = file;
8617016Ssam 	uncfp = setup(cfp, &ignore);
8717016Ssam 	if (uncfp == NULL) {
8817016Ssam 		if (ignore)
8917016Ssam 			goto done;
9017016Ssam 		goto bad;
9117016Ssam 	}
9217016Ssam 	decompress(cfp, uncfp);
9317016Ssam 	fflush(uncfp);
9417016Ssam 	if (ferror(uncfp) || ferror(cfp)) {
9517017Ssam 		fprintf(stderr, "uncompact: ");
9617016Ssam 		if (uncfp != stdout) {
9717016Ssam 			if (ferror(uncfp))
9817016Ssam 				perror(fname);
9917016Ssam 			else
10017016Ssam 				perror(infname);
10117016Ssam 			(void) unlink(fname);
10217017Ssam 		} else
10317017Ssam 			fprintf(stderr,
10417017Ssam 	    "Unsuccessful uncompact of standard input to standard output.\n");
10517016Ssam 		goto bad;
10617016Ssam 	}
10717016Ssam 	if (uncfp != stdout && unlink(infname) < 0)
10817016Ssam 		fprintf(stderr, "uncompact: "), perror(infname);
10917016Ssam done:
11017016Ssam 	if (uncfp != NULL && uncfp != stdout)
11117016Ssam 		fclose(uncfp);
11217016Ssam 	if (cfp != NULL)
11317016Ssam 		fclose(cfp);
11417016Ssam 	return (0);
11517016Ssam bad:
11617017Ssam 	if (cfp != NULL)
11717017Ssam 		fclose(cfp);
11817016Ssam 	return (1);
11917016Ssam }
12010922Sshannon 
decompress(cfp,uncfp)12117016Ssam decompress(cfp, uncfp)
12217016Ssam 	register FILE *cfp, *uncfp;
12317016Ssam {
12417016Ssam 	register struct node *p;
12517016Ssam 	register short j;
12617016Ssam 	register int m;
127*33072Sbostic 	register union cio *dp = &d;
12817016Ssam 	char b;
12917016Ssam 
13017016Ssam 	p = dict;
13117016Ssam 	while ((c.integ = getc (cfp)) != EOF) {
13217016Ssam 		for (m = 0200; m; ) {
13317016Ssam 			b = (m & c.integ ? 1 : 0);
13417016Ssam 			m >>= 1;
13517016Ssam 			if (p->fath.flags & (b ? RLEAF : LLEAF)) {
13617017Ssam 				dp->integ = p->sons[b].sp.ch;
13717016Ssam 				if (dp->integ == EF)
13817016Ssam 					break;
13917016Ssam 				if (dp->integ == NC) {
14017016Ssam 					uptree(NC);
14117016Ssam 					dp->integ = 0;
14217016Ssam 					for (j = 8; j--; m >>= 1) {
14317016Ssam 						if (m == 0) {
14417016Ssam 							c.integ = getc(cfp);
14517016Ssam 							m = 0200;
14610922Sshannon 						}
14717016Ssam 						dp->integ <<= 1;
14817016Ssam 						if (m & c.integ)
14917016Ssam 							dp->integ++;
15010922Sshannon 					}
15117016Ssam 					insert(dp->integ);
15210922Sshannon 				}
15317016Ssam 				uptree(dp->integ);
15417016Ssam 				putc(dp->chars.lob, uncfp);
15517016Ssam 				p = dict;
15617016Ssam 			} else
15717017Ssam 				p = p->sons[b].sp.p;
15810922Sshannon 		}
15917016Ssam 	}
16017016Ssam }
16117016Ssam 
16217016Ssam FILE *
setup(cfp,ignore)16317016Ssam setup(cfp, ignore)
16417016Ssam 	FILE *cfp;
16517016Ssam 	int *ignore;
16617016Ssam {
16717016Ssam 	FILE *uncfp = NULL;
16817016Ssam 	register union cio *dp = &d;
16917016Ssam 	register union cio *cp = &c;
17017016Ssam 
17117017Ssam 	*ignore = 0;
17217016Ssam 	dp->integ = getc(cfp);
17317017Ssam 	if (dp->integ != EOF) {
17417017Ssam 		cp->integ = getc(cfp);
17517017Ssam 		if (cp->integ != EOF)
17617017Ssam 			dp->chars.hib = cp->integ & 0377;
17717017Ssam 	} else
17817017Ssam 		dp->integ = 0;
17917016Ssam 	if ((dp->integ &= 0177777) != COMPACTED) {
18017017Ssam 		fprintf(stderr, "uncompact: ");
18117016Ssam 		if (dp->integ == PACKED)
18217016Ssam 			fprintf(stderr, "%s: File is packed, use unpack.\n",
18317016Ssam 			    infname);
18417016Ssam 		else
18517016Ssam 			fprintf(stderr, "%s: Not a compacted file.\n", infname);
18617016Ssam 		*ignore = 1;
18717016Ssam 		goto bad;
18817016Ssam 	}
18917016Ssam 	if (strcmp(infname, "-") != 0) {
19017016Ssam 		uncfp = fopen(fname, "w");
19117017Ssam 		if (uncfp == NULL)
19217017Ssam 			goto bad2;
19317016Ssam 		(void) fchmod(fileno(uncfp), status.st_mode);
19417016Ssam 	} else
19517016Ssam 		uncfp = stdout;
19617016Ssam 	cp->integ = getc(cfp);
19717016Ssam 	if (cp->integ == EOF)
19817017Ssam 		goto bad2;
19917016Ssam 	putc(cp->chars.lob, uncfp);
20010922Sshannon 
20117017Ssam 	in[NC].fp = in[EF].fp = dict[0].sons[LEFT].sp.p = bottom = dict + 1;
20217017Ssam 	bottom->sons[LEFT].count = bottom->sons[RIGHT].count =
20317017Ssam 	    dict[0].sons[RIGHT].count = 1;
20417017Ssam 	dirp->next = dict[0].sons[RIGHT].top = bottom->sons[LEFT].top =
20517017Ssam 	    bottom->sons[RIGHT].top = dirq = NEW;
20617016Ssam 	dirq->next = NULL;
20717016Ssam 	dict[0].fath.fp = NULL;
20817016Ssam 	dirq->pt = bottom->fath.fp = in[cp->integ].fp = dict;
20917016Ssam 	in[cp->integ].flags = (FBIT | SEEN);
21017016Ssam 	in[NC].flags = SEEN;
21117016Ssam 	dict[0].fath.flags = RLEAF;
21217016Ssam 	bottom->fath.flags = (LLEAF | RLEAF);
21317017Ssam 	dict[0].sons[LEFT].count = 2;
21417016Ssam 
21517017Ssam 	dict[0].sons[RIGHT].sp.ch = cp->integ;
21617017Ssam 	bottom->sons[LEFT].sp.ch = NC;
21717017Ssam 	bottom->sons[RIGHT].sp.ch = EF;
21817016Ssam 	return (uncfp);
21917017Ssam bad2:
22017017Ssam 	fprintf(stderr, "uncompact: ");
22117017Ssam 	perror(fname);
22217016Ssam bad:
22317016Ssam 	if (uncfp && uncfp != stdout) {
22417016Ssam 		(void) unlink(fname);
22517016Ssam 		fclose(uncfp);
22610922Sshannon 	}
22717016Ssam 	return (NULL);
22810922Sshannon }
229