#include #include #include #define DEBUG(x) struct oed_block { ulong num; ulong unknown; ulong brktbl; ulong symc; uchar *buffer; /* start of buffer */ uchar *dictionary; /* start of dictionary = 0x10 */ uchar *breaktable; /* start of break table = dictionary + brktbl */ uchar *seektable; /* start of seek table = breaktable+0x80 */ uchar *data; /* start of data = breaktable + 0x0180 */ ulong *breakpoints; ushort *symbols; int zeros; uchar *cur; /* current byte in decompression */ uchar mask; /* current bit in decompression */ }; enum { block_size = 32 * 1024, }; Biobuf out; ulong clong(uchar *src) { ulong r; r = src[0] << 24; r |= src[1] << 16; r |= src[2] << 8; r |= src[3]; return r; } void cleanup(struct oed_block *block) { free(block->breakpoints); free(block->symbols); } int enumerate_symbols(struct oed_block *block) { unsigned char *data = block->dictionary; unsigned short *sym, *lastsym = block->symbols + block->symc; DEBUG(fprint(2,"%ld symbols\n", block->symc);) for(sym = block->symbols; sym < lastsym; sym++) { *sym = data - block->buffer; while(~*data & 0x80) data++; *data = *data & 0x7f; data++; /*DEBUG(fprint(2, "symbol %ld, %p-%p\n", sym - block->symbols, block->buffer+*sym, data);) DEBUG(write(2, block->buffer+*sym, data - (block->buffer+*sym));) DEBUG(write(2, "\n", 1);)*/ } while(data < block->breaktable && *data != '\0') data++; *sym = data - block->buffer; /* the end of the final symbol */ DEBUG(fprint(2,"%ld more bytes\n", block->breaktable - data);) return block->symc; } int enumerate_breakpoints(struct oed_block *block) { uchar *i; ulong this,next; ulong c; ulong *dst; i = (block->breaktable); dst = block->breakpoints; *dst++ = 0; *dst++ = 0; *dst++ = 0; /* initial null entry */ next=clong(i+4); DEBUG(fprint(2, "%ld breakpoints\n", clong(i));) for(c=clong(i)-1; c; c--) { i+=4; this=next; next=clong(i+4); DEBUG(fprint(2, "%ld %ld\n", this, next);) *dst=*(dst-2) * 2; dst++; *dst=*(dst-1) + next; dst++; *dst=*(dst-3) + this; dst++; } return c; } /* oed_prepare * prepare block for decompression */ int oed_prepare(struct oed_block *block) { block->num = clong(block->buffer); /* block->unknown = clong(block->buffer + 4); */ block->brktbl = clong(block->buffer + 8); block->symc = clong(block->buffer + 12); /* assignments */ block->dictionary = block->buffer + 0x10; block->breaktable = block->dictionary + block->brktbl; block->seektable = block->breaktable + 0x80; block->data = block->seektable + 0x0100; block->cur = block->data; block->mask = 0x80; block->zeros = 0; if((block->symbols = malloc((block->symc + 1) * sizeof(*block->symbols))) == nil) exits("symbol table malloc"); if(enumerate_symbols(block) < 0) exits("failed to enumerate symbols"); if((block->breakpoints = malloc((clong(block->breaktable)+1)*3*sizeof(*block->breakpoints))) == nil) exits("break point malloc"); enumerate_breakpoints(block); return 0; } inline void print_symbol(ushort which, struct oed_block *block) { /*DEBUG(print("print_symbol(%hd)\n", which);)*/ if(Bwrite(&out, block->buffer + *(block->symbols + which), *(block->symbols + which + 1) - *(block->symbols + which)) < 0) exits("Bwrite"); } ushort fetch_symbol(struct oed_block *block) { int output; ulong *curbrk; output=0; curbrk = block->breakpoints; /*DEBUG(print("fetch_symbol %ld, %hhx, %hhx\n", block->cur - block->data, *block->cur, block->mask);)*/ /* the compressionish algorithm goes like this: * append the current bit to your number, * if your number is in the correct range for this many bits, you're done. * repeat. */ while(block->cur < (uchar *)block->breakpoints) { for(;block->mask;block->mask >>= 1) { output <<= 1; if(*block->cur & block->mask) output++; if(output >= curbrk[0] && output < curbrk[1]) { output = output + curbrk[2] - curbrk[0]; if(output) { block->zeros = 0; block->mask /= 2; return output; } else { if(block->zeros > 4) { /* six zeros sounds about right */ block->cur = block->buffer + block_size; block->mask = 0x00; return 0; } block->zeros++; } output = 0; curbrk = block->breakpoints; } else curbrk+=3; } block->cur++; block->mask = 0x80; } return 0; } int main(int, char **) { struct oed_block *block; unsigned short csymbol; if((block = malloc(sizeof(*block))) == nil) exits("block malloc"); if((block->buffer = malloc(block_size)) == nil) exits("buffer malloc"); if(Binit(&out, 1, OWRITE)) exits("output alloc"); while(readn(0, block->buffer, block_size) > 0) { oed_prepare(block); while(csymbol = fetch_symbol(block)) { print_symbol(csymbol, block); } cleanup(block); } exits(""); return 0; }