shithub: u6m

ref: 0598322524a57595eabe75295a60913dcc9bff01
dir: /u6dec.c/

View raw version
#include <u.h>
#include <libc.h>
#include <bio.h>

typedef struct Dict Dict;
struct Dict{
	uchar root;
	int word;
};
Dict dict[4096], *dictp;
int sz, top;
Biobuf *bf, *bfo;

u16int
get16(void)
{
	int n;
	uchar u[2];

	n = Bread(bf, u, sizeof u);
	if(n < 0)
		sysfatal("get16: %r");
	else if(n != sizeof u)
		exits(nil);
	return u[1] << 8 | u[0];
}

void
put8(u8int v)
{
	if(Bwrite(bfo, &v, sizeof v) != sizeof v)
		sysfatal("put8: %r");
}

uchar
putstr(int v)
{
	uchar buf[4096], *p;

	p = buf;
	while(v > 0xff){
		*p++ = dict[v].root;
		v = dict[v].word;
	}
	put8(v);
	while(--p >= buf)
		put8(*p);
	return v;
}

void
pushnode(uchar r, int u)
{
	if(dictp == dict + nelem(dict))
		sysfatal("pushnode: dict overflow");
	dictp->root = r;
	dictp->word = u;
	dictp++;
	if(++top >= 1 << sz){
		if(++sz > 12)
			sysfatal("pushnode: word size overflow");
	}
}

u16int
getword(int sz)
{
	static int nbit;
	static u32int u;
	u16int v;

	if(sz < 9 || sz > 12)
		sysfatal("getword: invalid word size");
	if(nbit < sz){
		u &= (1 << nbit) - 1;
		u |= get16() << nbit;
		nbit += 16;
	}
	v = u & (1 << sz) - 1;
	u >>= sz;
	nbit -= sz;
	return v;
}

void
init(void)
{
	sz = 9;
	top = 0x102;
	dictp = dict + 0x102;
}

void
main(int, char**)
{
	int u, v;
	uchar r;

	bf = Bfdopen(0, OREAD);
	bfo = Bfdopen(1, OWRITE);
	if(bf == nil || bfo == nil)
		sysfatal("Bfdopen: %r");
	Bseek(bf, 4, 1);
	init();
	u = 0;
	v = getword(sz);
	if(v != 0x100)
		sysfatal("unknown format");
	for(;;){
		switch(v){
		case 0x100:
			init();
			v = getword(sz);
			put8(v);
			break;
		case 0x101:
			exits(nil);
		default:
			if(v < top){
				r = putstr(v);
				pushnode(r, u);
				break;
			}
			if(v != top)
				sysfatal("invalid word");
			r = putstr(u);
			put8(r);
			pushnode(r, u);
			break;
		}
		u = v;
		v = getword(sz);
	}
}