diff options
Diffstat (limited to 'utils/sqz')
| -rw-r--r-- | utils/sqz/NOTICE | 27 | ||||
| -rw-r--r-- | utils/sqz/mkfile | 19 | ||||
| -rw-r--r-- | utils/sqz/squeeze.h | 34 | ||||
| -rw-r--r-- | utils/sqz/sqz.c | 528 | ||||
| -rw-r--r-- | utils/sqz/zqs.c | 243 |
5 files changed, 851 insertions, 0 deletions
diff --git a/utils/sqz/NOTICE b/utils/sqz/NOTICE new file mode 100644 index 00000000..724003a1 --- /dev/null +++ b/utils/sqz/NOTICE @@ -0,0 +1,27 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 1998 C H Forsyth (forsyth@terzarima.net). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/utils/sqz/mkfile b/utils/sqz/mkfile new file mode 100644 index 00000000..430bbce5 --- /dev/null +++ b/utils/sqz/mkfile @@ -0,0 +1,19 @@ +<../../mkconfig +CFLAGS=$CFLAGS -I../include + +TARG=sqz + +OFILES= sqz.$O\ + +HFILES= \ + squeeze.h\ + ../include/a.out.h\ + ../include/mach.h\ + +LIBS= mach bio 9 + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +CFLAGS= $CFLAGS -I../include diff --git a/utils/sqz/squeeze.h b/utils/sqz/squeeze.h new file mode 100644 index 00000000..b06c1b79 --- /dev/null +++ b/utils/sqz/squeeze.h @@ -0,0 +1,34 @@ + +/* + * squeezed file format: + * Sqhdr + * original Exec header + * two Squeeze tables + * squeezed segment + * unsqueezed segment, if any + */ +#define SQMAGIC (ulong)0xFEEF0F1E + +typedef struct Sqhdr Sqhdr; +struct Sqhdr { + uchar magic[4]; /* SQMAGIC */ + uchar text[4]; /* squeezed length of text (excluding tables) */ + uchar data[4]; /* squeezed length of data (excluding tables) */ + uchar asis[4]; /* length of unsqueezed segment */ + uchar toptxt[4]; /* value for 0 encoding in text */ + uchar topdat[4]; /* value for 0 encoding in data */ + uchar sum[4]; /* simple checksum of unsqueezed data */ + uchar flags[4]; +}; +#define SQHDRLEN (8*4) + +/* + * certain power instruction types are rearranged by sqz + * so as to move the variable part of the instruction word to the + * low order bits. note that the mapping is its own inverse. + */ +#define QREMAP(X)\ + switch((X)>>26){\ + case 19: case 31: case 59: case 63:\ + (X) = (((X) & 0xFC00F801) | (((X)>>15)&0x7FE) | (((X)&0x7FE)<<15));\ + } diff --git a/utils/sqz/sqz.c b/utils/sqz/sqz.c new file mode 100644 index 00000000..cf399e45 --- /dev/null +++ b/utils/sqz/sqz.c @@ -0,0 +1,528 @@ +#include <lib9.h> +#include <a.out.h> +#include "squeeze.h" + +/* + * forsyth@vitanuova.com + */ + +typedef struct Word Word; +struct Word { + ulong v; + ushort freq; + ushort code; + Word* next; +}; + +typedef struct Squeeze Squeeze; +struct Squeeze { + int n; + /*union {*/ + ulong tab[7*256]; + Word* rep[7*256]; + /*};*/ +}; + +enum { + HMASK = 0xFFFF, + HSIZE = HMASK+1, + + Codebufsize = 3*1024*1024 +}; + +#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3]) +#define GET4L(p) (((((((p)[3]<<8)|(p)[2])<<8)|(p)[1])<<8)|(p)[0]) +#define PUT4(p,v) (((p)[0]=(v)>>24),((p)[1]=(v)>>16),((p)[2]=(v)>>8),((p)[3]=(v))) + +static uchar prog[Codebufsize]; +static uchar outbuf[Codebufsize]; +static Word* hash1[HSIZE]; +static Word* hash2[HSIZE]; +static Sqhdr sqhdr; +static ulong chksum; + +static int aflag; /* all: both text (squeezed) and data (not) */ +static int dflag; /* squeeze data, not text */ +static int tflag; /* squeeze text, leave data as-is */ +static int qflag = 1; /* enable powerpc option */ +static int wflag; /* write output */ +static int zflag; /* use top==0 for data segment */ +static int islittle; /* object code uses little-endian byte order */ +static int debug; +static char* fname; + +static void analyse(ulong*, int, Squeeze*, Squeeze*, Word**); +static Word** collate(Word**, int); +static void dumpsq(Squeeze*, int); +static void freehash(Word**); +static long Read(int, void*, long); +static void remap(Squeeze*); +static int squeeze(ulong*, int, uchar*, ulong); +static int squeezetab(int, int, Squeeze*, Word**, int); +static void squirt(int, Squeeze*); +static void Write(int, void*, long); + +static void +usage(void) +{ + fprint(2, "Usage: sqz [-w] [-t] [-d] [-q] q.out\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int fd, n, ns, nst, nsd; + long txtlen, datlen, asis; + ulong topdat, toptxt; + Exec ex; + Squeeze sq3, sq4, sq5, sq6; + Word *top; + + setbinmode(); +/* fmtinstall('f', gfltconv); */ + ARGBEGIN{ + case 'D': + debug++; + break; + case 'd': + dflag++; + break; + case 'q': + qflag = 0; + break; + case 't': + tflag++; + break; + case 'w': + wflag++; + break; + default: + usage(); + }ARGEND + fname = *argv; + if(fname == nil) + usage(); + fd = open(fname, OREAD); + if(fd < 0){ + fprint(2, "sqz: can't open %s: %r\n", fname); + exits("open"); + } + Read(fd, &ex, sizeof(Exec)); + txtlen = GET4((uchar*)&ex.text); + datlen = GET4((uchar*)&ex.data); + switch(GET4((uchar*)&ex.magic)){ + case Q_MAGIC: /* powerpc */ + islittle = 0; + break; + case E_MAGIC: /* arm */ + islittle = 1; + qflag = 0; + break; + case 0xA0E1: /* arm AIF */ + islittle = 1; + qflag = 0; + txtlen = GET4L((uchar*)&ex+(5*4))-sizeof(Exec); + datlen = GET4L((uchar*)&ex+(6*4)); + break; + default: + fprint(2, "sqz: unknown magic for sqz: %8.8ux\n", GET4((uchar*)&ex.magic)); + exits("bad magic"); + } + if(qflag) + fprint(2, "PowerPC rules\n"); + if(islittle) + fprint(2, "Little endian\n"); + if(txtlen > sizeof(prog) || datlen > sizeof(prog) || txtlen+datlen > sizeof(prog)){ + fprint(2, "sqz: executable too big: %lud+%lud; increase Codebufsize in sqz.c\n", txtlen, datlen); + exits("size"); + } + if(dflag){ + seek(fd, txtlen, 1); + Read(fd, prog, datlen); + }else{ + Read(fd, prog, txtlen); + Read(fd, prog+txtlen, datlen); + } + close(fd); + asis = 0; + if(dflag) + n = datlen; + else if(tflag){ + n = txtlen; + asis = datlen; + }else + n = txtlen+datlen; + if(dflag || tflag){ + analyse((ulong*)prog, n/4, &sq3, &sq4, &top); + nst = squeeze((ulong*)prog, n/4, outbuf, top->v); + if(nst < 0) + exits("sqz"); + nsd = 0; + remap(&sq3); + remap(&sq4); + toptxt = topdat = top->v; + }else{ + analyse((ulong*)prog, txtlen/4, &sq3, &sq4, &top); + nst = squeeze((ulong*)prog, txtlen/4, outbuf, top->v); + if(nst < 0) + exits("sqz"); + toptxt = top->v; + remap(&sq3); + remap(&sq4); + if(datlen/4){ + freehash(hash1); + freehash(hash2); + analyse((ulong*)(prog+txtlen), datlen/4, &sq5, &sq6, &top); + nsd = squeeze((ulong*)(prog+txtlen), datlen/4, outbuf+nst, top->v); + if(nsd < 0) + exits("sqz"); + topdat = top->v; + remap(&sq5); + remap(&sq6); + }else{ + nsd = 0; + topdat = 0; + } + } + ns = nst+nsd; + fprint(2, "%d/%d bytes\n", ns, n); + fprint(2, "%8.8lux csum\n", chksum); + if(!wflag) + exits(0); + PUT4(sqhdr.magic, SQMAGIC); + PUT4(sqhdr.toptxt, toptxt); + PUT4(sqhdr.sum, chksum); + PUT4(sqhdr.text, nst); + PUT4(sqhdr.topdat, topdat); + PUT4(sqhdr.data, nsd); + PUT4(sqhdr.asis, asis); + PUT4(sqhdr.flags, 0); + Write(1, &sqhdr, SQHDRLEN); + Write(1, &ex, sizeof(Exec)); + squirt(1, &sq3); + squirt(1, &sq4); + Write(1, outbuf, nst); + if(nsd){ + squirt(1, &sq5); + squirt(1, &sq6); + Write(1, outbuf+nst, nsd); + } + if(asis) + Write(1, prog+txtlen, asis); + exits(0); +} + +static void +analyse(ulong *prog, int nw, Squeeze *sq3, Squeeze *sq4, Word **top) +{ + Word *w, **hp, **sorts, **resorts; + ulong *rp, *ep; + ulong v; + int i, nv1, nv2, nv, nz; + + rp = prog; + ep = prog+nw; + nv = 0; + nz = 0; + while(rp < ep){ + if(islittle){ + v = GET4L((uchar*)rp); + }else{ + v = GET4((uchar*)rp); + } + rp++; + chksum += v; + if(v == 0){ + nz++; + if(0) + continue; + } + if(qflag){ + QREMAP(v); + } + for(hp = &hash1[v&HMASK]; (w = *hp) != nil; hp = &w->next) + if(w->v == v) + break; + if(w == nil){ + w = (Word*)malloc(sizeof(*w)); + w->v = v; + w->freq = 0; + w->code = 0; + w->next = nil; + *hp = w; + nv++; + } + w->freq++; + } + sorts = collate(hash1, nv); + fprint(2, "phase 1: %d/%d words (%d zero), %d top (%8.8lux)\n", nv, nw, nz, sorts[0]->freq, sorts[0]->v); + *top = sorts[0]; + nv1 = squeezetab(1, 0x900, sq3, sorts+1, nv-1)+1; + nv2 = 0; + for(i=nv1; i<nv; i++){ + v = sorts[i]->v >> 8; + for(hp = &hash2[v&HMASK]; (w = *hp) != nil; hp = &w->next) + if(w->v == v) + break; + if(w == nil){ + w = (Word*)malloc(sizeof(*w)); + w->v = v; + w->freq = 0; + w->code = 0; + w->next = nil; + *hp = w; + nv2++; + } + w->freq++; + } + free(sorts); + resorts = collate(hash2, nv2); + fprint(2, "phase 2: %d/%d\n", nv2, nv-nv1); + squeezetab(2, 0x200, sq4, resorts, nv2); + free(resorts); + fprint(2, "phase 3: 1 4-code, %d 12-codes, %d 20-codes, %d uncoded\n", + sq3->n, sq4->n, nv-(sq3->n+sq4->n+1)); +} + +static int +wdcmp(const void *a, const void *b) +{ + return (*(Word**)b)->freq - (*(Word**)a)->freq; +} + +static Word ** +collate(Word **tab, int nv) +{ + Word *w, **hp, **sorts; + int i; + + sorts = (Word**)malloc(nv*sizeof(Word**)); + i = 0; + for(hp = &tab[0]; hp < &tab[HSIZE]; hp++) + for(w = *hp; w != nil; w = w->next) + sorts[i++] = w; + qsort(sorts, nv, sizeof(*sorts), wdcmp); + if(debug > 1) + for(i=0; i<nv; i++) + fprint(2, "%d\t%d\t%8.8lux\n", i, sorts[i]->freq, sorts[i]->v); + return sorts; +} + +static int +tabcmp(const void *a, const void *b) +{ + ulong av, bv; + + av = (*(Word**)a)->v; + bv = (*(Word**)b)->v; + if(av > bv) + return 1; + if(av < bv) + return -1; + return 0; +} + +static int +squeezetab(int tabno, int base, Squeeze *sq, Word **sorts, int nv) +{ + int i; + + if(nv >= 7*256) + nv = 7*256; + memset(sq, 0, sizeof(*sq)); + for(i=0; i<nv; i++) + sq->rep[sq->n++] = sorts[i]; + qsort(sq->rep, sq->n, sizeof(*sq->rep), tabcmp); + for(i=0; i<sq->n; i++) + sq->rep[i]->code = base + i; + if(debug) + dumpsq(sq, tabno); + return sq->n; +} + +static void +dumpsq(Squeeze *sq, int n) +{ + int i; + + fprint(2, "table %d: %d entries\n", n, sq->n); + for(i=0; i<sq->n; i++) + fprint(2, "%.3x\t%8.8lux\t%lux\n", sq->rep[i]->code, sq->rep[i]->v, i? sq->rep[i]->v - sq->rep[i-1]->v: 0); +} + +static void +remap(Squeeze *sq) +{ + int i; + ulong v; + + if(sq->n){ + v = 0; + for(i=0; i<sq->n; i++){ + sq->tab[i] = sq->rep[i]->v - v; + v += sq->tab[i]; + } + } +} + +static Word * +squash(Word **tab, ulong v) +{ + Word *w, **hp; + + for(hp = &tab[v&0xFFFF]; (w = *hp) != nil; hp = &w->next) + if(w->v == v) + return w; + return nil; +} + +static void +freehash(Word **tab) +{ + Word *w, **hp; + + for(hp = &tab[0]; hp < &tab[HSIZE]; hp++) + while((w = *hp) != nil){ + *hp = w->next; + free(w); + } +} + +static int +squeeze(ulong *prog, int nw, uchar *out, ulong top) +{ + ulong *rp, *ep; + ulong v, bits; + ulong e1, e2, e3, e4; + Word *w; + uchar bytes[8], *bp, *wp; + int ctl, n; + + rp = prog; + ep = prog+nw; + bits = 0; + e1 = e2 = e3 = e4 = 0; + wp = out; + n = 0; + ctl = 0; + bp = bytes; + for(;;){ + if(n == 2){ + *wp++ = ctl; + if(0) + fprint(2, "%x\n", ctl); + memmove(wp, bytes, bp-bytes); + wp += bp-bytes; + bp = bytes; + ctl = 0; + n = 0; + } + ctl <<= 4; + n++; + if(rp >= ep){ + if(n == 1) + break; + continue; + } + if(islittle){ + v = GET4L((uchar*)rp); + }else{ + v = GET4((uchar*)rp); + } + rp++; + if(qflag){ + QREMAP(v); + } + if(v == top){ + e1++; + bits += 4; + ctl |= 0; + continue; + } + w = squash(hash1, v); + if(w && w->code){ + e2++; + bits += 4+8; + ctl |= w->code>>8; + *bp++ = w->code; + continue; + } + w = squash(hash2, v>>8); + if(w && w->code){ + e3++; + bits += 4+8+8; + ctl |= w->code>>8; + *bp++ = w->code; + *bp++ = v & 0xFF; + if(debug > 2) + fprint(2, "%x %8.8lux %8.8lux\n", w->code, w->v, v); + continue; + } + e4++; + bits += 4+32; + ctl |= 0x1; + bp[0] = v; + bp[1] = v>>8; + bp[2] = v>>16; + bp[3] = v>>24; + bp += 4; + } + fprint(2, "enc: %lud 4-bits, %lud 12-bits %lud 20-bits %lud 36-bits -- %ld bytes\n", + e1, e2, e3, e4, wp-out); + return wp-out; +} + +static void +squirt(int fd, Squeeze *sq) +{ + uchar b[7*256*5 + 2], rep[5], *p, *q; + ulong v; + int i; + + p = b+2; + for(i=0; i<sq->n; i++){ + v = sq->tab[i]; + q = rep; + do { + *q++ = v & 0x7F; + }while((v >>= 7) != 0); + do { + *p++ = *--q | 0x80; + }while(q != rep); + p[-1] &= ~0x80; + } + if(p > b+sizeof(b)) + abort(); + i = p-b; + b[0] = i>>8; + b[1] = i; + Write(fd, b, i); + fprint(2, "table: %d/%d\n", i, (sq->n+1)*4); +} + +static long +Read(int fd, void *buf, long nb) +{ + long n; + + n = read(fd, buf, nb); + if(n < 0){ + fprint(2, "sqz: %s: read error: %r\n", fname); + exits("read"); + } + if(n < nb){ + fprint(2, "sqz: %s: unexpected end-of-file\n", fname); + exits("read"); + } + return n; +} + +static void +Write(int fd, void *buf, long nb) +{ + if(write(fd, buf, nb) != nb){ + fprint(2, "sqz: write error: %r\n"); + exits("write err"); + } +} diff --git a/utils/sqz/zqs.c b/utils/sqz/zqs.c new file mode 100644 index 00000000..b9b2a163 --- /dev/null +++ b/utils/sqz/zqs.c @@ -0,0 +1,243 @@ +#include <lib9.h> +#include <a.out.h> +#include "squeeze.h" + +/* + * forsyth@vitanuova.com + */ + +/* + * for details of `unsqueeze' see: + * + * %A Mark Taunton + * %T Compressed Executables: An Exercise in Thinking Small + * %P 385-404 + * %I USENIX + * %B USENIX Conference Proceedings + * %D Summer 1991 + * %C Nashville, TN + * + * several of the unimplemented improvements described in the paper + * have been implemented here + * + * there is a further transformation on the powerpc (QFLAG!=0) to shuffle bits + * in certain instructions so as to push the fixed bits to the top of the word. + */ + +typedef struct Squeeze Squeeze; +struct Squeeze { + int n; + ulong tab[7*256]; +}; + +enum { + CHECK = 1 /* check precise bounds in Squeeze array */ +}; + +#define GET4(p) (((((((p)[0]<<8)|(p)[1])<<8)|(p)[2])<<8)|(p)[3]) + +static uchar out[3*1024*1024]; +static uchar bigb[1024*1024]; +static ulong top; +static int qflag = 1; +static int islittle = 0; +static ulong chksum, oldsum; +static int rdtab(int, Squeeze*, int); +static long unsqueezefd(int, void*); +static uchar* unsqueeze(uchar*, uchar*, uchar*, Squeeze*, Squeeze*, ulong); +static uchar* unsqzseg(int, uchar*, long, ulong); + +void +main(int argc, char **argv) +{ + int fd; + long n; + + if(argc < 2) + exits("args"); + fd = open(argv[1], OREAD); + if(fd < 0) + exits("open"); + n = unsqueezefd(fd, out); + if(n < 0){ + fprint(2, "zqs: can't unsqueeze\n"); + exits("err"); + } + if(write(1, out, n) != n){ + fprint(2, "zqs: write error: %r\n"); + exits("err"); + } + fprint(2, "%ld bytes, %8.8lux csum\n", n, chksum); + exits(0); +} + +static long +unsqueezefd(int fd, void *v) +{ + uchar *wp, *out; + ulong toptxt, topdat; + long asis, nst, nsd; + Sqhdr sqh; + Exec ex; + + out = (uchar*)v; + if(read(fd, &sqh, SQHDRLEN) != SQHDRLEN) + return -1; + if(GET4(sqh.magic) != SQMAGIC) + return -1; + if(read(fd, &ex, sizeof(Exec)) != sizeof(Exec)) + return -1; + toptxt = GET4(sqh.toptxt); + topdat = GET4(sqh.topdat); + oldsum = GET4(sqh.sum); + asis = GET4(sqh.asis); + if(asis < 0) + asis = 0; + nst = GET4(sqh.text); + nsd = GET4(sqh.data); + switch(GET4((uchar*)&ex.magic)){ + case Q_MAGIC: + if(qflag) + fprint(2, "PowerPC mode\n"); + islittle = 0; + break; + case E_MAGIC: + case 0xA0E1: /* arm AIF */ + islittle = 1; + qflag = 0; + break; + default: + fprint(2, "Unknown magic: %8.8ux\n", GET4((uchar*)&ex.magic)); + qflag = 0; + break; + } + memmove(out, &ex, sizeof(ex)); + wp = unsqzseg(fd, out + sizeof(ex), nst, toptxt); + if(wp == nil) + return -1; + wp = unsqzseg(fd, wp, nsd, topdat); + if(wp == nil) + return -1; + if(asis){ + if(read(fd, wp, asis) != asis) + return -1; + wp += asis; + } + return wp-out; +} + +static uchar* +unsqzseg(int fd, uchar *wp, long ns, ulong top) +{ + Squeeze sq3, sq4; + + if(ns == 0) + return wp; + if(rdtab(fd, &sq3, 0) < 0) + return nil; + if(rdtab(fd, &sq4, 8) < 0) + return nil; + fprint(2, "tables: %d %d\n", sq3.n, sq4.n); + if(read(fd, bigb, ns) != ns) + return nil; + return unsqueeze(wp, bigb, bigb+ns, &sq3, &sq4, top); +} + +static uchar* +unsqueeze(uchar *wp, uchar *rp, uchar *ep, Squeeze *sq3, Squeeze *sq4, ulong top) +{ + ulong nx; + int code, n; + + if(qflag){ + QREMAP(top); /* adjust top just once, outside the loop */ + } + while(rp < ep){ + code = *rp++; + n = 0; + nx = code>>4; + do{ + if(nx == 0){ + nx = top; + }else{ + if(nx==1){ + if(rp+3 >= ep) + return nil; + nx = (((((rp[3]<<8)|rp[2])<<8)|rp[1])<<8)|rp[0]; + rp += 4; + }else if(nx <= 8){ /* 2 to 8 */ + if(rp+1 >= ep) + return nil; + nx = ((nx-2)<<8) | rp[0]; + if(CHECK && nx >= sq4->n) + return nil; /* corrupted file */ + nx = sq4->tab[nx] | rp[1]; + rp += 2; + }else{ /* 9 to 15 */ + if(rp >= ep) + return nil; /* corrupted file */ + nx = ((nx-9)<<8) | rp[0]; + if(CHECK && nx >= sq3->n) + return nil; /* corrupted file */ + nx = sq3->tab[nx]; + rp++; + } + if(rp > ep) + return nil; /* corrupted file */ + if(qflag){ + QREMAP(nx); + } + } + if(islittle){ + wp[0] = nx; + wp[1] = nx>>8; + wp[2] = nx>>16; + wp[3] = nx>>24; + }else{ + wp[0] = nx>>24; + wp[1] = nx>>16; + wp[2] = nx>>8; + wp[3] = nx; + } + wp += 4; + chksum += nx; + nx = code & 0xF; + }while(++n == 1); + } + return wp; +} + +static int +rdtab(int fd, Squeeze *sq, int shift) +{ + uchar b[7*256*5], *p, *ep; + ulong v, w; + int i; + + if(read(fd, b, 2) != 2) + return -1; + i = (b[0]<<8) | b[1]; + if(1) + fprint(2, "table: %d\n", i); + if((i -= 2) > 0){ + if(read(fd, b, i) != i) + return -1; + } + sq->n = 0; + p = b; + ep = b+i; + v = 0; + while(p < ep){ + w = 0; + do{ + if(p >= ep) + return -1; + w = (w<<7) | (*p & 0x7F); + }while(*p++ & 0x80); + v += w; + if(0) + fprint(2, "%d %8.8lux %8.8lux\n", sq->n, v, w); + sq->tab[sq->n++] = v << shift; + } + return 0; +} |
