⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sac.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include "sac.h"#include "ssort.h"typedef struct Chain	Chain;typedef struct Chains	Chains;typedef struct Huff	Huff;enum{	ZBase		= 2,			/* base of code to encode 0 runs */	LitBase		= ZBase-1,		/* base of literal values */	MaxLit		= 256,	MaxLeaf		= MaxLit+LitBase,	MaxHuffBits	= 16,			/* limit of bits in a huffman code */	ChainMem	= 2 * (MaxHuffBits - 1) * MaxHuffBits,};/* * huffman code table */struct Huff{	short	bits;				/* length of the code */	ulong	encode;				/* the code */};struct Chain{	ulong	count;				/* occurances of everything in the chain */	ushort	leaf;				/* leaves to the left of chain, or leaf value */	char	col;				/* ref count for collecting unused chains */	char	gen;				/* need to generate chains for next lower level */	Chain	*up;				/* Chain up in the lists */};struct Chains{	Chain	*lists[(MaxHuffBits - 1) * 2];	ulong	leafcount[MaxLeaf];		/* sorted list of leaf counts */	ushort	leafmap[MaxLeaf];		/* map to actual leaf number */	int	nleaf;				/* number of leaves */	Chain	chains[ChainMem];	Chain	*echains;	Chain	*free;	char	col;	int	nlists;};static	jmp_buf	errjmp;static	uchar	*bout;static	int	bmax;static	int	bpos;static	ulong	leafcount[MaxLeaf];static	ulong	nzero;static	ulong	*hbuf;static	int	hbpos;static	ulong	nzero;static	ulong	maxblocksym;static	void	henc(int);static	void	hbflush(void);static	void	mkprecode(Huff*, ulong *, int, int);static	ulong	sendtab(Huff *tab, int maxleaf, ushort *map);static	int	elimBits(int b, ulong *bused, char *tmtf, int maxbits);static	void	elimBit(int b, char *tmtf, int maxbits);static	void	nextchain(Chains*, int);static	void	hufftabinit(Huff*, int, ulong*, int);static	void	leafsort(ulong*, ushort*, int, int);static	void	bitput(int, int);static	int	mtf(uchar*, int);static	void	fatal(char*, ...);static	ulong	headerbits;static	ulong	charmapbits;static	ulong	hufftabbits;static	ulong	databits;static	ulong	nbits;static	ulong	bits;intsac(uchar *dst, uchar *src, int n){	uchar front[256];	ulong *perm, cmap[256];	long i, c, rev;	rev = 0;	perm = nil;	if(setjmp(errjmp)){		free(perm);		if(rev){			for(i = 0; i < n/2; i++){				c = src[i];				src[i] = src[n-i-1];				src[n-i-1] = c;			}		}		return -1;	}	/*	 * set up the output buffer	 */	bout = dst;	bmax = n;	bpos = 0;	perm = malloc((n+1)*sizeof *perm);	if(perm == nil)		return -1;	hbuf = perm;	hbpos = 0;	nbits = 0;	nzero = 0;	for(i = 0; i < MaxLeaf; i++)		leafcount[i] = 0;	if(rev){		for(i = 0; i < n/2; i++){			c = src[i];			src[i] = src[n-i-1];			src[n-i-1] = c;		}	}	i = ssortbyte(src, (int*)perm, nil, n);	headerbits += 16;	bitput(i, 16);	/*	 * send the map of chars which occur in this block	 */	for(i = 0; i < 256; i++)		cmap[i] = 0;	for(i = 0; i < n; i++)		cmap[src[i]] = 1;	charmapbits += 1;	bitput(cmap[0] != 0, 1);	for(i = 0; i < 256; i = c){		for(c = i + 1; c < 256 && (cmap[c] != 0) == (cmap[i] != 0); c++)			;		charmapbits += 8;		bitput(c - i - 1, 8);	}	/*	 * initialize mtf state	 */	c = 0;	for(i = 0; i < 256; i++){		if(cmap[i]){			cmap[i] = c;			front[c] = i;			c++;		}	}	maxblocksym = c + LitBase;	for(i = 0; i <= n; i++){		c = perm[i] - 1;		if(c < 0)			continue;		henc(mtf(front, src[c]));	}	hbflush();	bitput(0, 24);	bitput(0, 8 - nbits);	free(perm);	return bpos;}static voidbitput(int c, int n){	bits <<= n;	bits |= c;	for(nbits += n; nbits >= 8; nbits -= 8){		c = bits << (32 - nbits);		if(bpos >= bmax)			longjmp(errjmp, 1);		bout[bpos++] = c >> 24;	}}static intmtf(uchar *front, int c){	int i, v;	for(i = 0; front[i] != c; i++)		;	for(v = i; i > 0; i--)		front[i] = front[i - 1];	front[0] = c;	return v;}/* * encode a run of zeros * convert to funny run length coding: * add one, omit implicit top 1 bit. */static voidzenc(void){	int m;	nzero++;	while(nzero != 1){		m = nzero & 1;		hbuf[hbpos++] = m;		leafcount[m]++;		nzero >>= 1;	}	nzero = 0;}/* * encode one symbol */static voidhenc(int c){	if(c == 0){		nzero++;		return;	}	if(nzero)		zenc();	c += LitBase;	leafcount[c]++;	hbuf[hbpos++] = c;}static voidhbflush(void){	Huff tab[MaxLeaf];	int i, b, s;	if(nzero)		zenc();	if(hbpos == 0)		return;	mkprecode(tab, leafcount, maxblocksym, MaxHuffBits);	hufftabbits += sendtab(tab, maxblocksym, nil);	/*	 * send the data	 */	for(i = 0; i < hbpos; i++){		s = hbuf[i];		b = tab[s].bits;		if(b == 0)			fatal("bad tables %d", i);		databits += b;		bitput(tab[s].encode, b);	}}static ulongsendtab(Huff *tab, int maxleaf, ushort *map){	ulong ccount[MaxHuffBits+1], bused[MaxHuffBits+1];	Huff codetab[MaxHuffBits+1];	char tmtf[MaxHuffBits+1];	ulong bits;	int i, b, max, ttb, s, elim;	/*	 * make up the table table	 * over cleverness: the data is known to be a huffman table	 * check for fullness at each bit level, and wipe it out from	 * the possibilities;  when nothing exists except 0, stop.	 */	for(i = 0; i <= MaxHuffBits; i++){		tmtf[i] = i;		ccount[i] = 0;		bused[i] = 0;	}	tmtf[0] = -1;	tmtf[MaxHuffBits] = 0;	elim = 0;	for(i = 0; i < maxleaf && elim != MaxHuffBits; i++){		b = i;		if(map)			b = map[b];		b = tab[b].bits;		for(s = 0; tmtf[s] != b; s++)			if(s >= MaxHuffBits)				fatal("bitlength not found");		ccount[s]++;		for(; s > 0; s--)			tmtf[s] = tmtf[s-1];		tmtf[0] = b;		elim += elimBits(b, bused, tmtf, MaxHuffBits);	}	if(elim != MaxHuffBits && elim != 0)		fatal("incomplete huffman table");	/*	 * make up and send the table table	 */	max = 8;	mkprecode(codetab, ccount, MaxHuffBits+1, max);	for(i = 0; i <= max; i++){		tmtf[i] = i;		bused[i] = 0;	}	tmtf[0] = -1;	tmtf[max] = 0;	elim = 0;	bits = 0;	for(i = 0; i <= MaxHuffBits && elim != max; i++){		b = codetab[i].bits;		for(s = 0; tmtf[s] != b; s++)			if(s > max)				fatal("bitlength not found");		ttb = 4;		while(max - elim < (1 << (ttb-1)))			ttb--;		bits += ttb;		bitput(s, ttb);		elim += elimBits(b, bused, tmtf, max);	}	if(elim != max)		fatal("incomplete huffman table table");	/*	 * send the table	 */	for(i = 0; i <= MaxHuffBits; i++){		tmtf[i] = i;		bused[i] = 0;	}	tmtf[0] = -1;	tmtf[MaxHuffBits] = 0;	elim = 0;	for(i = 0; i < maxleaf && elim != MaxHuffBits; i++){		b = i;		if(map)			b = map[b];		b = tab[b].bits;		for(s = 0; tmtf[s] != b; s++)			if(s >= MaxHuffBits)				fatal("bitlength not found");		ttb = codetab[s].bits;		if(ttb < 0)			fatal("bad huffman table table");		bits += ttb;		bitput(codetab[s].encode, ttb);		for(; s > 0; s--)			tmtf[s] = tmtf[s-1];		tmtf[0] = b;		elim += elimBits(b, bused, tmtf, MaxHuffBits);	}	if(elim != MaxHuffBits && elim != 0)		fatal("incomplete huffman table");	return bits;}static intelimBits(int b, ulong *bused, char *tmtf, int maxbits){	int bb, elim;	if(b < 0)		return 0;	elim = 0;	/*	 * increase bits counts for all descendants	 */	for(bb = b + 1; bb < maxbits; bb++){		bused[bb] += 1 << (bb - b);		if(bused[bb] == (1 << bb)){			elim++;			elimBit(bb, tmtf, maxbits);		}	}	/*	 * steal bits from parent & check for fullness	 */	for(; b >= 0; b--){		bused[b]++;		if(bused[b] == (1 << b)){			elim++;			elimBit(b, tmtf, maxbits);		}		if((bused[b] & 1) == 0)			break;	}	return elim;}static voidelimBit(int b, char *tmtf, int maxbits){	int bb;	for(bb = 0; bb < maxbits; bb++)		if(tmtf[bb] == b)			break;	if(tmtf[bb] != b)		fatal("elim bit not found");	while(++bb <= maxbits)		tmtf[bb - 1] = tmtf[bb];}/* * fast?, in-place huffman codes * * A. Moffat, J. Katajainen, "In-Place Calculation of Minimum-Redundancy Codes", * * counts must be sorted, and may be aliased to bitlens */static intfmkprecode(ulong *bitcount, ulong *bitlen, ulong *counts, int n, int maxbits){	int leaf, tree, treet, depth, nodes, internal;	/*	 * form the internal tree structure:	 * [0, tree) are parent pointers,	 * [tree, treet) are weights of internal nodes,	 * [leaf, n) are weights of remaining leaves.	 *	 * note that at the end, there are n-1 internal nodes	 */	leaf = 0;	tree = 0;	for(treet = 0; treet != n - 1; treet++){		if(leaf >= n || tree < treet && bitlen[tree] < counts[leaf]){			bitlen[treet] = bitlen[tree];			bitlen[tree++] = treet;		}else			bitlen[treet] = counts[leaf++];		if(leaf >= n || tree < treet && bitlen[tree] < counts[leaf]){			bitlen[treet] += bitlen[tree];			bitlen[tree++] = treet;		}else			bitlen[treet] += counts[leaf++];	}	if(tree != treet - 1)		fatal("bad fast mkprecode");	/*	 * calculate depth of internal nodes	 */	bitlen[n - 2] = 0;	for(tree = n - 3; tree >= 0; tree--)		bitlen[tree] = bitlen[bitlen[tree]] + 1;	/*	 * calculate depth of leaves:	 * at each depth, leaves(depth) = nodes(depth) - internal(depth)	 * and nodes(depth+1) = 2 * internal(depth)	 */	leaf = n;	tree = n - 2;	depth = 0;	for(nodes = 1; nodes > 0; nodes = 2 * internal){		internal = 0;		while(tree >= 0 && bitlen[tree] == depth){			tree--;			internal++;		}		nodes -= internal;		if(depth < maxbits)			bitcount[depth] = nodes;		while(nodes-- > 0)			bitlen[--leaf] = depth;		depth++;	}	if(leaf != 0 || tree != -1)		fatal("bad leaves in fast mkprecode");	return depth - 1;}/* * fast, low space overhead algorithm for max depth huffman type codes * * J. Katajainen, A. Moffat and A. Turpin, "A fast and space-economical * algorithm for length-limited coding," Proc. Intl. Symp. on Algorithms * and Computation, Cairns, Australia, Dec. 1995, Lecture Notes in Computer * Science, Vol 1004, J. Staples, P. Eades, N. Katoh, and A. Moffat, eds., * pp 12-21, Springer Verlag, New York, 1995. */static voidmkprecode(Huff *tab, ulong *count, int n, int maxbits){	Chains cs;	Chain *c;	ulong bitcount[MaxHuffBits];	int i, m, em, bits;	/*	 * set up the sorted list of leaves	 */	m = 0;	for(i = 0; i < n; i++){		tab[i].bits = -1;		tab[i].encode = 0;		if(count[i] != 0){			cs.leafcount[m] = count[i];			cs.leafmap[m] = i;			m++;		}	}	if(m < 2){		if(m != 0){			m = cs.leafmap[0];			tab[m].bits = 0;			tab[m].encode = 0;		}		return;	}	cs.nleaf = m;	leafsort(cs.leafcount, cs.leafmap, 0, m);	/*	 * try fast code	 */	bits = fmkprecode(bitcount, cs.leafcount, cs.leafcount, m, maxbits);	if(bits < maxbits){		for(i = 0; i < m; i++)			tab[cs.leafmap[i]].bits = cs.leafcount[i];		bitcount[0] = 0;	}else{		for(i = 0; i < m; i++)			cs.leafcount[i] = count[cs.leafmap[i]];		/*		 * set up free list		 */		cs.free = &cs.chains[2];		cs.echains = &cs.chains[ChainMem];		cs.col = 1;		/*		 * initialize chains for each list		 */		c = &cs.chains[0];		c->count = cs.leafcount[0];		c->leaf = 1;		c->col = cs.col;		c->up = nil;		c->gen = 0;		cs.chains[1] = cs.chains[0];		cs.chains[1].leaf = 2;		cs.chains[1].count = cs.leafcount[1];		for(i = 0; i < maxbits-1; i++){			cs.lists[i * 2] = &cs.chains[0];			cs.lists[i * 2 + 1] = &cs.chains[1];		}		cs.nlists = 2 * (maxbits - 1);		m = 2 * m - 2;		for(i = 2; i < m; i++)			nextchain(&cs, cs.nlists - 2);		bits = 0;		bitcount[0] = cs.nleaf;		for(c = cs.lists[cs.nlists - 1]; c != nil; c = c->up){			m = c->leaf;			bitcount[bits++] -= m;			bitcount[bits] = m;		}		m = 0;		for(i = bits; i >= 0; i--)			for(em = m + bitcount[i]; m < em; m++)				tab[cs.leafmap[m]].bits = i;	}	hufftabinit(tab, n, bitcount, bits);}/* * calculate the next chain on the list * we can always toss out the old chain */static voidnextchain(Chains *cs, int list){	Chain *c, *oc;	int i, nleaf, sumc;	oc = cs->lists[list + 1];	cs->lists[list] = oc;	if(oc == nil)		return;	/*	 * make sure we have all chains needed to make sumc	 * note it is possible to generate only one of these,	 * use twice that value for sumc, and then generate	 * the second if that preliminary sumc would be chosen.	 * however, this appears to be slower on current tests	 */	if(oc->gen){		nextchain(cs, list - 2);		nextchain(cs, list - 2);		oc->gen = 0;	}	/*	 * pick up the chain we're going to add;	 * collect unused chains no free ones are left	 */	for(c = cs->free; ; c++){		if(c >= cs->echains){			cs->col++;			for(i = 0; i < cs->nlists; i++)				for(c = cs->lists[i]; c != nil; c = c->up)					c->col = cs->col;			c = cs->chains;		}		if(c->col != cs->col)			break;	}	/*	 * pick the cheapest of	 * 1) the next package from the previous list	 * 2) the next leaf	 */	nleaf = oc->leaf;	sumc = 0;	if(list > 0 && cs->lists[list-1] != nil)		sumc = cs->lists[list-2]->count + cs->lists[list-1]->count;	if(sumc != 0 && (nleaf >= cs->nleaf || cs->leafcount[nleaf] > sumc)){		c->count = sumc;		c->leaf = oc->leaf;		c->up = cs->lists[list-1];		c->gen = 1;	}else if(nleaf >= cs->nleaf){		cs->lists[list + 1] = nil;		return;	}else{		c->leaf = nleaf + 1;		c->count = cs->leafcount[nleaf];		c->up = oc->up;		c->gen = 0;	}	cs->free = c + 1;	cs->lists[list + 1] = c;	c->col = cs->col;}static voidhufftabinit(Huff *tab, int n, ulong *bitcount, int nbits){	ulong code, nc[MaxHuffBits];	int i, bits;	code = 0;	for(bits = 1; bits <= nbits; bits++){		code = (code + bitcount[bits-1]) << 1;		nc[bits] = code;	}	for(i = 0; i < n; i++){		bits = tab[i].bits;		if(bits > 0)			tab[i].encode = nc[bits]++;	}}static intpivot(ulong *c, int a, int n){	int j, pi, pj, pk;	j = n/6;	pi = a + j;	/* 1/6 */	j += j;	pj = pi + j;	/* 1/2 */	pk = pj + j;	/* 5/6 */	if(c[pi] < c[pj]){		if(c[pi] < c[pk]){			if(c[pj] < c[pk])				return pj;			return pk;		}		return pi;	}	if(c[pj] < c[pk]){		if(c[pi] < c[pk])			return pi;		return pk;	}	return pj;}static	voidleafsort(ulong *leafcount, ushort *leafmap, int a, int n){	ulong t;	int j, pi, pj, pn;	while(n > 1){		if(n > 10){			pi = pivot(leafcount, a, n);		}else			pi = a + (n>>1);		t = leafcount[pi];		leafcount[pi] = leafcount[a];		leafcount[a] = t;		t = leafmap[pi];		leafmap[pi] = leafmap[a];		leafmap[a] = t;		pi = a;		pn = a + n;		pj = pn;		for(;;){			do				pi++;			while(pi < pn && (leafcount[pi] < leafcount[a] || leafcount[pi] == leafcount[a] && leafmap[pi] > leafmap[a]));			do				pj--;			while(pj > a && (leafcount[pj] > leafcount[a] || leafcount[pj] == leafcount[a] && leafmap[pj] < leafmap[a]));			if(pj < pi)				break;			t = leafcount[pi];			leafcount[pi] = leafcount[pj];			leafcount[pj] = t;			t = leafmap[pi];			leafmap[pi] = leafmap[pj];			leafmap[pj] = t;		}		t = leafcount[a];		leafcount[a] = leafcount[pj];		leafcount[pj] = t;		t = leafmap[a];		leafmap[a] = leafmap[pj];		leafmap[pj] = t;		j = pj - a;		n = n-j-1;		if(j >= n){			leafsort(leafcount, leafmap, a, j);			a += j+1;		}else{			leafsort(leafcount, leafmap, a + (j+1), n);			n = j;		}	}}static voidfatal(char *fmt, ...){	char buf[512];	va_list arg;	va_start(arg, fmt);	doprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg);	longjmp(errjmp, 1);}

⌨️ 快捷键说明

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