diff options
author | rsc <devnull@localhost> | 2005-07-12 15:23:36 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-07-12 15:23:36 +0000 |
commit | a0d146edd7a7de6236a0d60baafeeb59f8452aae (patch) | |
tree | b55baa526d9f5adfc73246e6ee2fadf455e0b7a2 /src/cmd/venti/srv/unwhack.c | |
parent | 88bb285e3d87ec2508840af33f7e0af53ec3c13c (diff) | |
download | plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.tar.gz plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.tar.bz2 plan9port-a0d146edd7a7de6236a0d60baafeeb59f8452aae.zip |
return of venti
Diffstat (limited to 'src/cmd/venti/srv/unwhack.c')
-rw-r--r-- | src/cmd/venti/srv/unwhack.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/cmd/venti/srv/unwhack.c b/src/cmd/venti/srv/unwhack.c new file mode 100644 index 00000000..5530bd07 --- /dev/null +++ b/src/cmd/venti/srv/unwhack.c @@ -0,0 +1,179 @@ +#include "stdinc.h" +#include "whack.h" + +enum +{ + DMaxFastLen = 7, + DBigLenCode = 0x3c, /* minimum code for large lenth encoding */ + DBigLenBits = 6, + DBigLenBase = 1 /* starting items to encode for big lens */ +}; + +static uchar lenval[1 << (DBigLenBits - 1)] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, + 5, + 6, + 255, + 255 +}; + +static uchar lenbits[] = +{ + 0, 0, 0, + 2, 3, 5, 5, +}; + +static uchar offbits[16] = +{ + 5, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 12, 13 +}; + +static ushort offbase[16] = +{ + 0, 0x20, + 0x40, 0x60, + 0x80, 0xc0, + 0x100, 0x180, + 0x200, 0x300, + 0x400, 0x600, + 0x800, 0xc00, + 0x1000, + 0x2000 +}; + +void +unwhackinit(Unwhack *uw) +{ + uw->err[0] = '\0'; +} + +int +unwhack(Unwhack *uw, uchar *dst, int ndst, uchar *src, int nsrc) +{ + uchar *s, *d, *dmax, *smax, lit; + ulong uwbits, lithist; + int i, off, len, bits, use, code, uwnbits, overbits; + + d = dst; + dmax = d + ndst; + + smax = src + nsrc; + uwnbits = 0; + uwbits = 0; + overbits = 0; + lithist = ~0; + while(src < smax || uwnbits - overbits >= MinDecode){ + while(uwnbits <= 24){ + uwbits <<= 8; + if(src < smax) + uwbits |= *src++; + else + overbits += 8; + uwnbits += 8; + } + + /* + * literal + */ + len = lenval[(uwbits >> (uwnbits - 5)) & 0x1f]; + if(len == 0){ + if(lithist & 0xf){ + uwnbits -= 9; + lit = (uwbits >> uwnbits) & 0xff; + lit &= 255; + }else{ + uwnbits -= 8; + lit = (uwbits >> uwnbits) & 0x7f; + if(lit < 32){ + if(lit < 24){ + uwnbits -= 2; + lit = (lit << 2) | ((uwbits >> uwnbits) & 3); + }else{ + uwnbits -= 3; + lit = (lit << 3) | ((uwbits >> uwnbits) & 7); + } + lit = (lit - 64) & 0xff; + } + } + if(d >= dmax){ + snprint(uw->err, WhackErrLen, "too much output"); + return -1; + } + *d++ = lit; + lithist = (lithist << 1) | (lit < 32) | (lit > 127); + continue; + } + + /* + * length + */ + if(len < 255) + uwnbits -= lenbits[len]; + else{ + uwnbits -= DBigLenBits; + code = ((uwbits >> uwnbits) & ((1 << DBigLenBits) - 1)) - DBigLenCode; + len = DMaxFastLen; + use = DBigLenBase; + bits = (DBigLenBits & 1) ^ 1; + while(code >= use){ + len += use; + code -= use; + code <<= 1; + uwnbits--; + if(uwnbits < 0){ + snprint(uw->err, WhackErrLen, "len out of range"); + return -1; + } + code |= (uwbits >> uwnbits) & 1; + use <<= bits; + bits ^= 1; + } + len += code; + + while(uwnbits <= 24){ + uwbits <<= 8; + if(src < smax) + uwbits |= *src++; + else + overbits += 8; + uwnbits += 8; + } + } + + /* + * offset + */ + uwnbits -= 4; + bits = (uwbits >> uwnbits) & 0xf; + off = offbase[bits]; + bits = offbits[bits]; + + uwnbits -= bits; + off |= (uwbits >> uwnbits) & ((1 << bits) - 1); + off++; + + if(off > d - dst){ + snprint(uw->err, WhackErrLen, "offset out of range: off=%d d=%ld len=%d nbits=%d", off, d - dst, len, uwnbits); + return -1; + } + if(d + len > dmax){ + snprint(uw->err, WhackErrLen, "len out of range"); + return -1; + } + s = d - off; + for(i = 0; i < len; i++) + d[i] = s[i]; + d += len; + } + if(uwnbits < overbits){ + snprint(uw->err, WhackErrLen, "compressed data overrun"); + return -1; + } + + len = d - dst; + + return len; +} |