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

📄 unsac.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include "sac.h"typedef struct Huff	Huff;typedef struct Mtf	Mtf;typedef struct Decode	Decode;enum{	ZBase		= 2,			/* base of code to encode 0 runs */	LitBase		= ZBase-1,		/* base of literal values */	MaxLit		= 256,	MaxLeaf		= MaxLit+LitBase,	MaxHuffBits	= 16,			/* max bits in a huffman code */	MaxFlatbits	= 5,			/* max bits decoded in flat table */	CombLog		= 4,	CombSpace	= 1 << CombLog,		/* mtf speedup indices spacing */	CombMask	= CombSpace - 1,};struct Mtf{	int	maxcomb;		/* index of last valid comb */	uchar	prev[MaxLit];	uchar	next[MaxLit];	uchar	comb[MaxLit / CombSpace + 1];};struct Huff{	int	maxbits;	int	flatbits;	ulong	flat[1<<MaxFlatbits];	ulong	maxcode[MaxHuffBits];	ulong	last[MaxHuffBits];	ulong	decode[MaxLeaf];};struct Decode{	Huff	tab;	Mtf	mtf;	int	nbits;	ulong	bits;	int	nzero;	int	base;	ulong	maxblocksym;	jmp_buf	errjmp;	uchar	*src;				/* input buffer */	uchar	*smax;				/* limit */};static	void	fatal(Decode *dec, char*);static	int	hdec(Decode*);static	void	recvtab(Decode*, Huff*, int, ushort*);static	ulong	bitget(Decode*, int);static	int	mtf(uchar*, int);#define FORWARD 0static voidmtflistinit(Mtf *m, uchar *front, int n){	int last, me, f, i, comb;	if(n == 0)		return;	/*	 * add all entries to free list	 */	last = MaxLit - 1;	for(i = 0; i < MaxLit; i++){		m->prev[i] = last;		m->next[i] = i + 1;		last = i;	}	m->next[last] = 0;	f = 0;	/*	 * pull valid entries off free list and enter into mtf list	 */	comb = 0;	last = front[0];	for(i = 0; i < n; i++){		me = front[i];		f = m->next[me];		m->prev[f] = m->prev[me];		m->next[m->prev[f]] = f;		m->next[last] = me;		m->prev[me] = last;		last = me;		if((i & CombMask) == 0)			m->comb[comb++] = me;	}	/*	 * pad out the list with dummies to the next comb,	 * using free entries	 */	for(; i & CombMask; i++){		me = f;		f = m->next[me];		m->prev[f] = m->prev[me];		m->next[m->prev[f]] = f;		m->next[last] = me;		m->prev[me] = last;		last = me;	}	me = front[0];	m->next[last] = me;	m->prev[me] = last;	m->comb[comb] = me;	m->maxcomb = comb;}static intmtflist(Mtf *m, int pos){	uchar *next, *prev, *mycomb;	int c, c0, pc, nc, off;	if(pos == 0)		return m->comb[0];	next = m->next;	prev = m->prev;	mycomb = &m->comb[pos >> CombLog];	off = pos & CombMask;	if(off >= CombSpace / 2){		c = mycomb[1];		for(; off < CombSpace; off++)			c = prev[c];	}else{		c = *mycomb;		for(; off; off--)			c = next[c];	}	nc = next[c];	pc = prev[c];	prev[nc] = pc;	next[pc] = nc;	for(; mycomb > m->comb; mycomb--)		*mycomb = prev[*mycomb];	c0 = *mycomb;	*mycomb = c;	mycomb[m->maxcomb] = c;	next[c] = c0;	pc = prev[c0];	prev[c] = pc;	prev[c0] = c;	next[pc] = c;	return c;}static voidhdecblock(Decode *dec, ulong n, ulong I, uchar *buf, ulong *sums, ulong *prev){	ulong i, nn, sum;	int m, z, zz, c;	nn = I;	n--;	i = 0;again:	for(; i < nn; i++){		while((m = hdec(dec)) == 0 && i + dec->nzero < n)			;		if(z = dec->nzero){			dec->nzero = 0;			c = dec->mtf.comb[0];			sum = sums[c];			sums[c] = sum + z;			z += i;			zz = z;			if(i < I && z > I){				zz = I;				z++;			}		zagain:			for(; i < zz; i++){				buf[i] = c;				prev[i] = sum++;			}			if(i != z){				zz = z;				nn = ++n;				i++;				goto zagain;			}			if(i == nn){				if(i == n)					return;				nn = ++n;				i++;			}		}		c = mtflist(&dec->mtf, m);		buf[i] = c;		sum = sums[c];		prev[i] = sum++;		sums[c] = sum;	}	if(i == n)		return;	nn = ++n;	i++;	goto again;}intunsac(uchar *dst, uchar *src, int n, int nsrc){	Decode *dec;	uchar *buf, *front;	ulong *prev, *sums;	ulong sum, i, I;	int m, j, c;	dec = malloc(sizeof *dec);	buf = malloc(n+2);	prev = malloc((n+2) * sizeof *prev);	front = malloc(MaxLit * sizeof *front);	sums = malloc(MaxLit * sizeof *sums);	if(dec == nil || buf == nil || prev == nil || front == nil || sums == nil || setjmp(dec->errjmp)){		free(dec);		free(buf);		free(prev);		free(front);		free(sums);		return -1;	}	dec->src = src;	dec->smax = src + nsrc;	dec->nbits = 0;	dec->bits = 0;	dec->nzero = 0;	for(i = 0; i < MaxLit; i++)		front[i] = i;	n++;	I = bitget(dec, 16);	if(I >= n)		fatal(dec, "corrupted input");	/*	 * decode the character usage map	 */	for(i = 0; i < MaxLit; i++)		sums[i] = 0;	c = bitget(dec, 1);	for(i = 0; i < MaxLit; ){		m = bitget(dec, 8) + 1;		while(m--){			if(i >= MaxLit)				fatal(dec, "corrupted char map");			front[i++] = c;		}		c = c ^ 1;	}	/*	 * initialize mtf state	 */	c = 0;	for(i = 0; i < MaxLit; i++)		if(front[i])			front[c++] = i;	mtflistinit(&dec->mtf, front, c);	dec->maxblocksym = c + LitBase;	/*	 * huffman decoding, move to front decoding,	 * along with character counting	 */	dec->base = 1;	recvtab(dec, &dec->tab, MaxLeaf, nil);	hdecblock(dec, n, I, buf, sums, prev);	sum = 1;	for(i = 0; i < MaxLit; i++){		c = sums[i];		sums[i] = sum;		sum += c;	}	i = 0;	for(j = n - 2; j >= 0; j--){		if(i > n || i < 0 || i == I)			fatal(dec, "corrupted data");		c = buf[i];		dst[j] = c;		i = prev[i] + sums[c];	}	free(dec);	free(buf);	free(prev);	free(front);	free(sums);	return n;}static ulongbitget(Decode *dec, int nb){	int c;	while(dec->nbits < nb){		if(dec->src >= dec->smax)			fatal(dec, "premature eof 1");		c = *dec->src++;		dec->bits <<= 8;		dec->bits |= c;		dec->nbits += 8;	}	dec->nbits -= nb;	return (dec->bits >> dec->nbits) & ((1 << nb) - 1);}static voidfillbits(Decode *dec){	int c;	while(dec->nbits < 24){		if(dec->src >= dec->smax)			fatal(dec, "premature eof 2");		c = *dec->src++;		dec->bits <<= 8;		dec->bits |= c;		dec->nbits += 8;	}}/* * decode one symbol */static inthdecsym(Decode *dec, Huff *h, int b){	long c;	ulong bits;	int nbits;	bits = dec->bits;	nbits = dec->nbits;	for(; (c = bits >> (nbits - b)) > h->maxcode[b]; b++)		;	if(b > h->maxbits)		fatal(dec, "too many bits consumed");	dec->nbits = nbits - b;	return h->decode[h->last[b] - c];}static inthdec(Decode *dec){	ulong c;	int nbits, nb;	if(dec->nbits < dec->tab.maxbits)		fillbits(dec);	nbits = dec->nbits;	dec->bits &= (1 << nbits) - 1;	c = dec->tab.flat[dec->bits >> (nbits - dec->tab.flatbits)];	nb = c & 0xff;	c >>= 8;	if(nb == 0xff)		c = hdecsym(dec, &dec->tab, c);	else		dec->nbits = nbits - nb;	/*	 * reverse funny run-length coding	 */	if(c < ZBase){		dec->nzero += dec->base << c;		dec->base <<= 1;		return 0;	}	dec->base = 1;	c -= LitBase;	return c;}static voidhufftab(Decode *dec, Huff *h, char *hb, ulong *bitcount, int maxleaf, int maxbits, int flatbits){	ulong c, mincode, code, nc[MaxHuffBits];	int i, b, ec;	h->maxbits = maxbits;	if(maxbits < 0)		return;	code = 0;	c = 0;	for(b = 0; b <= maxbits; b++){		h->last[b] = c;		c += bitcount[b];		mincode = code << 1;		nc[b] = mincode;		code = mincode + bitcount[b];		if(code > (1 << b))			fatal(dec, "corrupted huffman table");		h->maxcode[b] = code - 1;		h->last[b] += code - 1;	}	if(code != (1 << maxbits))		fatal(dec, "huffman table not full");	if(flatbits > maxbits)		flatbits = maxbits;	h->flatbits = flatbits;	b = 1 << flatbits;	for(i = 0; i < b; i++)		h->flat[i] = ~0;	/*	 * initialize the flat table to include the minimum possible	 * bit length for each code prefix	 */	for(b = maxbits; b > flatbits; b--){		code = h->maxcode[b];		if(code == -1)			break;		mincode = code + 1 - bitcount[b];		mincode >>= b - flatbits;		code >>= b - flatbits;		for(; mincode <= code; mincode++)			h->flat[mincode] = (b << 8) | 0xff;	}	for(i = 0; i < maxleaf; i++){		b = hb[i];		if(b == -1)			continue;		c = nc[b]++;		if(b <= flatbits){			code = (i << 8) | b;			ec = (c + 1) << (flatbits - b);			if(ec > (1<<flatbits))				fatal(dec, "flat code too big");			for(c <<= (flatbits - b); c < ec; c++)				h->flat[c] = code;		}else{			c = h->last[b] - c;			if(c >= maxleaf)				fatal(dec, "corrupted huffman table");			h->decode[c] = i;		}	}}static voidelimBit(int b, char *tmtf, int maxbits){	int bb;	for(bb = 0; bb < maxbits; bb++)		if(tmtf[bb] == b)			break;	while(++bb <= maxbits)		tmtf[bb - 1] = tmtf[bb];}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 voidrecvtab(Decode *dec, Huff *tab, int maxleaf, ushort *map){	ulong bitcount[MaxHuffBits+1], bused[MaxHuffBits+1];	char tmtf[MaxHuffBits+1], *hb;	int i, b, ttb, m, maxbits, max, elim;	hb = malloc(MaxLeaf * sizeof *hb);	if(hb == nil)		fatal(dec, "out of memory");	/*	 * read the tables for the tables	 */	max = 8;	for(i = 0; i <= MaxHuffBits; i++){		bitcount[i] = 0;		tmtf[i] = i;		bused[i] = 0;	}	tmtf[0] = -1;	tmtf[max] = 0;	elim = 0;	maxbits = -1;	for(i = 0; i <= MaxHuffBits && elim != max; i++){		ttb = 4;		while(max - elim < (1 << (ttb-1)))			ttb--;		b = bitget(dec, ttb);		if(b > max - elim)			fatal(dec, "corrupted huffman table table");		b = tmtf[b];		hb[i] = b;		bitcount[b]++;		if(b > maxbits)			maxbits = b;		elim += elimBits(b, bused, tmtf, max);	}	if(elim != max)		fatal(dec, "incomplete huffman table table");	hufftab(dec, tab, hb, bitcount, i, maxbits, MaxFlatbits);	for(i = 0; i <= MaxHuffBits; i++){		tmtf[i] = i;		bitcount[i] = 0;		bused[i] = 0;	}	tmtf[0] = -1;	tmtf[MaxHuffBits] = 0;	elim = 0;	maxbits = -1;	for(i = 0; i < maxleaf && elim != MaxHuffBits; i++){		if(dec->nbits <= tab->maxbits)			fillbits(dec);		dec->bits &= (1 << dec->nbits) - 1;		m = tab->flat[dec->bits >> (dec->nbits - tab->flatbits)];		b = m & 0xff;		m >>= 8;		if(b == 0xff)			m = hdecsym(dec, tab, m);		else			dec->nbits -= b;		b = tmtf[m];		for(; m > 0; m--)			tmtf[m] = tmtf[m-1];		tmtf[0] = b;		if(b > MaxHuffBits)			fatal(dec, "bit length too big");		m = i;		if(map != nil)			m = map[m];		hb[m] = b;		bitcount[b]++;		if(b > maxbits)			maxbits = b;		elim += elimBits(b, bused, tmtf, MaxHuffBits);	}	if(elim != MaxHuffBits && elim != 0)		fatal(dec, "incomplete huffman table");	if(map != nil)		for(; i < maxleaf; i++)			hb[map[i]] = -1;	hufftab(dec, tab, hb, bitcount, i, maxbits, MaxFlatbits);	free(hb);}static voidfatal(Decode *dec, char *msg){	print("%s: %s\n", argv0, msg);	longjmp(dec->errjmp, 1);}

⌨️ 快捷键说明

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