compress.c

来自「早期freebsd实现」· C语言 代码 · 共 900 行 · 第 1/2 页

C
900
字号
/* * Copyright (c) 1989, 1993 *	The Regents of the University of California.  All rights reserved. * * This code is derived from software contributed to Berkeley by * Edward Wang at The University of California, Berkeley. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)compress.c	8.1 (Berkeley) 6/6/93";#endif /* not lint */#include "ww.h"#include "tt.h"	/* special */#include <stdio.h>#include <fcntl.h>int cc_trace = 0;FILE *cc_trace_fp;	/* tunable parameters */int cc_reverse = 1;int cc_sort = 0;int cc_chop = 0;int cc_token_max = 8;		/* <= TOKEN_MAX */int cc_token_min = 2;		/* > tt.tt_put_token_cost */int cc_npass0 = 1;int cc_npass1 = 1;int cc_bufsize = 1024 * 3;	/* XXX, or 80 * 24 * 2 */int cc_ntoken = 8192;#define cc_weight XXX#ifndef cc_weightint cc_weight = 0;#endif#define TOKEN_MAX 16struct cc {	char string[TOKEN_MAX];	char length;	char flag;#ifndef cc_weight	short weight;#endif	long time;		/* time last seen */	short bcount;		/* count in this buffer */	short ccount;		/* count in compression */	short places;		/* places in the buffer */	short code;		/* token code */	struct cc *qforw, *qback;	struct cc *hforw, **hback;};short cc_thresholds[TOKEN_MAX + 1];#define thresh(length) (cc_thresholds[length])#define threshp(code, count, length) \	((code) >= 0 || (short) (count) >= cc_thresholds[length])#ifndef cc_weightshort cc_wthresholds[TOKEN_MAX + 1];#define wthresh(length) (cc_wthresholds[length])#define wthreshp(weight, length) ((short) (weight) >= cc_wthresholds[length])#else#define wthreshp(weight, length) (0)#endif#ifndef cc_weightshort cc_wlimits[TOKEN_MAX + 1];#define wlimit(length) (cc_wlimits[length])#endif#define put_token_score(length) ((length) - tt.tt_put_token_cost)int cc_score_adjustments[TOKEN_MAX + 1][8]; /* XXX, 8 > max of cc_thresholds */#define score_adjust(score, p) \	do { \		int length = (p)->length; \		int ccount = (p)->ccount; \		if (threshp((p)->code, ccount, length) || \		    wthreshp((p)->weight, length)) /* XXX */ \			(score) -= length - tt.tt_put_token_cost; \		else \			(score) += cc_score_adjustments[length][ccount]; \	} while (0)int cc_initial_scores[TOKEN_MAX + 1][8]; /* XXX, 8 > max of cc_thresholds */struct cc cc_q0a, cc_q0b, cc_q1a, cc_q1b;#define qinsert(p1, p2) \	do { \		register struct cc *forw = (p1)->qforw; \		register struct cc *back = (p1)->qback; \		back->qforw = forw; \		forw->qback = back; \		forw = (p2)->qforw; \		(p1)->qforw = forw; \		forw->qback = (p1); \		(p2)->qforw = (p1); \		(p1)->qback = (p2); \	} while (0)#define qinsertq(q, p) \	((q)->qforw == (q) ? 0 : \	 ((q)->qback->qforw = (p)->qforw, \	  (p)->qforw->qback = (q)->qback, \	  (q)->qforw->qback = (p), \	  (p)->qforw = (q)->qforw, \	  (q)->qforw = (q), \	  (q)->qback = (q)))#define H		(14)#define HSIZE		(1 << H)#define hash(h, c)	((((h) >> H - 8 | (h) << 8) ^ (c)) & HSIZE - 1)char *cc_buffer;struct cc **cc_output;			/* the output array */short *cc_places[TOKEN_MAX + 1];short *cc_hashcodes;			/* for computing hashcodes */struct cc **cc_htab;			/* the hash table */struct cc **cc_tokens;			/* holds all the active tokens */struct cc_undo {	struct cc **pos;	struct cc *val;} *cc_undo;long cc_time, cc_time0;char *cc_tt_ob, *cc_tt_obe;ccinit(){	register i, j;	register struct cc *p;	if (tt.tt_token_max > cc_token_max)		tt.tt_token_max = cc_token_max;	if (tt.tt_token_min < cc_token_min)		tt.tt_token_min = cc_token_min;	if (tt.tt_token_min > tt.tt_token_max) {		tt.tt_ntoken = 0;		return 0;	}	if (tt.tt_ntoken > cc_ntoken / 2)	/* not likely */		tt.tt_ntoken = cc_ntoken / 2;#define C(x) (sizeof (x) / sizeof *(x))	for (i = 0; i < C(cc_thresholds); i++) {		int h = i - tt.tt_put_token_cost;		if (h > 0)			cc_thresholds[i] =				(tt.tt_set_token_cost + 1 + h - 1) / h + 1;		else			cc_thresholds[i] = 0;	}	for (i = 0; i < C(cc_score_adjustments); i++) {		int t = cc_thresholds[i];		for (j = 0; j < C(*cc_score_adjustments); j++) {			if (j >= t)				cc_score_adjustments[i][j] =					- (i - tt.tt_put_token_cost);			else if (j < t - 1)				cc_score_adjustments[i][j] = 0;			else				/*				 * cost now is				 *	length * (ccount + 1)		a				 * cost before was				 *	set-token-cost + length +				 *		ccount * put-token-cost	b				 * the score adjustment is (b - a)				 */				cc_score_adjustments[i][j] =					tt.tt_set_token_cost + i +						j * tt.tt_put_token_cost -							i * (j + 1);			if (j >= t)				cc_initial_scores[i][j] = 0;			else				/*				 * - (set-token-cost +				 *	(length - put-token-cost) -				 *	(length - put-token-cost) * ccount)				 */				cc_initial_scores[i][j] =					- (tt.tt_set_token_cost +					   (i - tt.tt_put_token_cost) -					   (i - tt.tt_put_token_cost) * j);		}	}#ifndef cc_weight	for (i = 1; i < C(cc_wthresholds); i++) {		cc_wthresholds[i] =			((tt.tt_set_token_cost + tt.tt_put_token_cost) / i +				i / 5 + 1) *				cc_weight + 1;		cc_wlimits[i] = cc_wthresholds[i] + cc_weight;	}#endif#undef C	if ((cc_output = (struct cc **)	     malloc((unsigned) cc_bufsize * sizeof *cc_output)) == 0)		goto nomem;	if ((cc_hashcodes = (short *)	     malloc((unsigned) cc_bufsize * sizeof *cc_hashcodes)) == 0)		goto nomem;	if ((cc_htab = (struct cc **) malloc(HSIZE * sizeof *cc_htab)) == 0)		goto nomem;	if ((cc_tokens = (struct cc **)	     malloc((unsigned)	            (cc_ntoken + tt.tt_token_max - tt.tt_token_min + 1) *		    sizeof *cc_tokens)) == 0)		goto nomem;	if ((cc_undo = (struct cc_undo *)	     malloc((unsigned) cc_bufsize * sizeof *cc_undo)) == 0)		goto nomem;	for (i = tt.tt_token_min; i <= tt.tt_token_max; i++)		if ((cc_places[i] = (short *)		     malloc((unsigned) cc_bufsize * sizeof **cc_places)) == 0)			goto nomem;	cc_q0a.qforw = cc_q0a.qback = &cc_q0a;	cc_q0b.qforw = cc_q0b.qback = &cc_q0b;	cc_q1a.qforw = cc_q1a.qback = &cc_q1a;	cc_q1b.qforw = cc_q1b.qback = &cc_q1b;	if ((p = (struct cc *) malloc((unsigned) cc_ntoken * sizeof *p)) == 0)		goto nomem;	for (i = 0; i < tt.tt_ntoken; i++) {		p->code = i;		p->time = -1;		p->qback = cc_q0a.qback;		p->qforw = &cc_q0a;		p->qback->qforw = p;		cc_q0a.qback = p;		p++;	}	for (; i < cc_ntoken; i++) {		p->code = -1;		p->time = -1;		p->qback = cc_q1a.qback;		p->qforw = &cc_q1a;		p->qback->qforw = p;		cc_q1a.qback = p;		p++;	}	cc_tt_ob = tt_ob;	cc_tt_obe = tt_obe;	if ((cc_buffer = malloc((unsigned) cc_bufsize)) == 0)		goto nomem;	return 0;nomem:	wwerrno = WWE_NOMEM;	return -1;}ccstart(){	int ccflush();	ttflush();	tt_obp = tt_ob = cc_buffer;	tt_obe = tt_ob + cc_bufsize;	tt.tt_flush = ccflush;	if (cc_trace) {		cc_trace_fp = fopen("window-trace", "a");		(void) fcntl(fileno(cc_trace_fp), F_SETFD, 1);	}	ccreset();}ccreset(){	register struct cc *p;	bzero((char *) cc_htab, HSIZE * sizeof *cc_htab);	for (p = cc_q0a.qforw; p != &cc_q0a; p = p->qforw)		p->hback = 0;	for (p = cc_q1a.qforw; p != &cc_q1a; p = p->qforw)		p->hback = 0;}ccend(){	ttflush();	tt_obp = tt_ob = cc_tt_ob;	tt_obe = cc_tt_obe;	tt.tt_flush = 0;	if (cc_trace_fp != NULL) {		(void) fclose(cc_trace_fp);		cc_trace_fp = NULL;	}}ccflush(){	int bufsize = tt_obp - tt_ob;	int n;	if (tt_ob != cc_buffer)		abort();	if (cc_trace_fp != NULL) {		(void) fwrite(tt_ob, 1, bufsize, cc_trace_fp);		(void) putc(-1, cc_trace_fp);	}	tt.tt_flush = 0;	(*tt.tt_compress)(1);	if (bufsize < tt.tt_token_min) {		ttflush();		goto out;	}	tt_obp = tt_ob = cc_tt_ob;	tt_obe = cc_tt_obe;	cc_time0 = cc_time;	cc_time += bufsize;	n = cc_sweep_phase(cc_buffer, bufsize, cc_tokens);	cc_compress_phase(cc_output, bufsize, cc_tokens, n);	cc_output_phase(cc_buffer, cc_output, bufsize);	ttflush();	tt_obp = tt_ob = cc_buffer;	tt_obe = cc_buffer + cc_bufsize;out:	(*tt.tt_compress)(0);	tt.tt_flush = ccflush;}cc_sweep_phase(buffer, bufsize, tokens)	char *buffer;	struct cc **tokens;{	register struct cc **pp = tokens;	register i, n;#ifdef STATS	int nn, ii;#endif#ifdef STATS	if (verbose >= 0)		time_begin();	if (verbose > 0)		printf("Sweep:");#endif	cc_sweep0(buffer, bufsize, tt.tt_token_min - 1);#ifdef STATS	ntoken_stat = 0;	nn = 0;	ii = 0;#endif	for (i = tt.tt_token_min; i <= tt.tt_token_max; i++) {#ifdef STATS		if (verbose > 0) {			if (ii > 7) {				printf("\n      ");				ii = 0;			}			ii++;			printf(" (%d", i);			(void) fflush(stdout);		}#endif		n = cc_sweep(buffer, bufsize, pp, i);		pp += n;#ifdef STATS		if (verbose > 0) {			if (--n > 0) {				printf(" %d", n);				nn += n;			}			putchar(')');		}#endif	}	qinsertq(&cc_q1b, &cc_q1a);#ifdef STATS	if (verbose > 0)		printf("\n       %d tokens, %d candidates\n",			ntoken_stat, nn);	if (verbose >= 0)		time_end();#endif	return pp - tokens;}cc_sweep0(buffer, n, length)	char *buffer;{	register char *p;	register short *hc;	register i;	register short c;	register short pc = tt.tt_padc;	/* n and length are at least 1 */	p = buffer++;	hc = cc_hashcodes;	i = n;	do {		if ((*hc++ = *p++) == pc)			hc[-1] = -1;	} while (--i);	while (--length) {		p = buffer++;		hc = cc_hashcodes;		for (i = n--; --i;) {			if ((c = *p++) == pc || *hc < 0)				c = -1;			else				c = hash(*hc, c);			*hc++ = c;		}	}}cc_sweep(buffer, bufsize, tokens, length)	char *buffer;	struct cc **tokens;	register length;{

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?