#include <stddef.h> /* for NULL */ #include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */ #include"blast.h"/* prototype for blast() */
#define local static/* for local function definitions */ #define MAXBITS 13/* maximum code length */ #define MAXWIN 4096/* maximum window size */
/* input and output state */ struct state { /* input state */
blast_in infun; /* input function provided by user */ void *inhow; /* opaque information passed to infun() */ unsignedchar *in; /* next input location */ unsigned left; /* available input at in */ int bitbuf; /* bit buffer */ int bitcnt; /* number of bits in bit buffer */
/* input limit error return state for bits() and decode() */
jmp_buf env;
/* output state */
blast_out outfun; /* output function provided by user */ void *outhow; /* opaque information passed to outfun() */ unsigned next; /* index of next write location in out[] */ int first; /* true to check distances (for first 4K) */ unsignedchar out[MAXWIN]; /* output buffer and sliding window */
};
/* *Returnneedbitsfromtheinputstream.Thisalwaysleaveslessthan *eightbitsinthebuffer.bits()worksproperlyforneed==0. * *Formatnotes: * *-Bitsarestoredinbytesfromtheleastsignificantbittothemost *significantbit.Thereforebitsaredroppedfromthebottomofthebit *buffer,usingshiftright,andnewbytesareappendedtothetopofthe *bitbuffer,usingshiftleft.
*/
local int bits(struct state *s, int need)
{ int val; /* bit accumulator */
/* load at least need bits into val */
val = s->bitbuf; while (s->bitcnt < need) { if (s->left == 0) {
s->left = s->infun(s->inhow, &(s->in)); if (s->left == 0) longjmp(s->env, 1); /* out of input */
}
val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */
s->left--;
s->bitcnt += 8;
}
/* drop need bits and update buffer, always zero to seven bits left */
s->bitbuf = val >> need;
s->bitcnt -= need;
/* return need bits, zeroing the bits above that */ return val & ((1 << need) - 1);
}
/* *Huffmancodedecodingtables.count[1..MAXBITS]isthenumberofsymbolsof *eachlength,whichforacanonicalcodearesteppedthroughinorder. *symbol[]arethesymbolvaluesincanonicalorder,wherethenumberof *entriesisthesumofthecountsincount[].Thedecodingprocesscanbe *seeninthefunctiondecode()below.
*/ struct huffman { short *count; /* number of symbols of each length */ short *symbol; /* canonically ordered symbols */
};
/* *Decodeacodefromthestreamsusinghuffmantableh.Returnthesymbolor *anegativevalueifthereisanerror.Ifallofthelengthsarezero,i.e. *anemptycode,orifthecodeisincompleteandaninvalidcodeisreceived, *then-9isreturnedafterreadingMAXBITSbits. * *Formatnotes: * *-Thecodesasstoredinthecompresseddataarebit-reversedrelativeto *asimpleintegerorderingofcodesofthesamelengths.Hencebelowthe *bitsarepulledfromthecompresseddataoneatatimeandusedto *buildthecodevaluereversedfromwhatisinthestreaminorderto *permitsimpleintegercomparisonsfordecoding. * *-Thefirstcodefortheshortestlengthisallones.Subsequentcodesof *thesamelengtharesimplyintegerdecrementsofthepreviouscode.When *movingupalength,aonebitisappendedtothecode.Foracomplete *code,thelastcodeofthelongestlengthwillbeallzeros.Tosupport *thisordering,thebitspulledduringdecodingareinvertedtoapplythe *more"natural"orderingstartingwithallzerosandincrementing.
*/
local int decode(struct state *s, struct huffman *h)
{ int len; /* current number of bits in code */ int code; /* len bits being decoded */ int first; /* first code of length len */ int count; /* number of codes of length len */ int index; /* index of first code of length len in symbol table */ int bitbuf; /* bits from stream */ int left; /* bits left in next or left to process */ short *next; /* next number of codes */
bitbuf = s->bitbuf;
left = s->bitcnt;
code = first = index = 0;
len = 1;
next = h->count + 1; while (1) { while (left--) {
code |= (bitbuf & 1) ^ 1; /* invert code */
bitbuf >>= 1;
count = *next++; if (code < first + count) { /* if length len, return symbol */
s->bitbuf = bitbuf;
s->bitcnt = (s->bitcnt - len) & 7; return h->symbol[index + (code - first)];
}
index += count; /* else update for next length */
first += count;
first <<= 1;
code <<= 1;
len++;
}
left = (MAXBITS+1) - len; if (left == 0) break; if (s->left == 0) {
s->left = s->infun(s->inhow, &(s->in)); if (s->left == 0) longjmp(s->env, 1); /* out of input */
}
bitbuf = *(s->in)++;
s->left--; if (left > 8) left = 8;
} return -9; /* ran out of codes */
}
/* *Givenalistofrepeatedcodelengthsrep[0..n-1],whereeachbyteisa *count(highfourbits+1)andacodelength(lowfourbits),generatethe *listofcodelengths.Thiscompactionreducesthesizeoftheobjectcode. *Thengiventhelistofcodelengthslength[0..n-1]representingacanonical *Huffmancodefornsymbols,constructthetablesrequiredtodecodethose *codes.Thosetablesarethenumberofcodesofeachlength,andthesymbols *sortedbylength,retainingtheiroriginalorderwithineachlength.The *returnvalueiszeroforacompletecodeset,negativeforanover- *subscribedcodeset,andpositiveforanincompletecodeset.Thetables *canbeusedifthereturnvalueiszeroorpositive,buttheycannotbeused *ifthereturnvalueisnegative.Ifthereturnvalueiszero,itisnot *possiblefordecode()usingthattabletoreturnanerror--anystreamof *enoughbitswillresolvetoasymbol.Ifthereturnvalueispositive,then *itispossiblefordecode()usingthattabletoreturnanerrorforreceived *codespasttheendoftheincompletelengths.
*/
local int construct(struct huffman *h, constunsignedchar *rep, int n)
{ int symbol; /* current symbol when stepping through length[] */ int len; /* current length when stepping through h->count[] */ int left; /* number of possible codes left of current length */ short offs[MAXBITS+1]; /* offsets in symbol table for each length */ short length[256]; /* code lengths */
/* convert compact repeat counts into symbol bit length list */
symbol = 0; do {
len = *rep++;
left = (len >> 4) + 1;
len &= 15; do {
length[symbol++] = len;
} while (--left);
} while (--n);
n = symbol;
/* count number of codes of each length */ for (len = 0; len <= MAXBITS; len++)
h->count[len] = 0; for (symbol = 0; symbol < n; symbol++)
(h->count[length[symbol]])++; /* assumes lengths are within bounds */ if (h->count[0] == n) /* no codes! */ return0; /* complete, but decode() will fail */
/* check for an over-subscribed or incomplete set of lengths */
left = 1; /* one possible code of zero length */ for (len = 1; len <= MAXBITS; len++) {
left <<= 1; /* one more bit, double codes left */
left -= h->count[len]; /* deduct count from possible codes */ if (left < 0) return left; /* over-subscribed--return negative */
} /* left > 0 means incomplete */
/* generate offsets into symbol table for each length for sorting */
offs[1] = 0; for (len = 1; len < MAXBITS; len++)
offs[len + 1] = offs[len] + h->count[len];
/* *putsymbolsintablesortedbylength,bysymbolorderwithineach *length
*/ for (symbol = 0; symbol < n; symbol++) if (length[symbol] != 0)
h->symbol[offs[length[symbol]]++] = symbol;
/* return zero for complete set, positive for incomplete set */ return left;
}
/* decode literals and length/distance pairs */ do { if (bits(s, 1)) { /* get length */
symbol = decode(s, &lencode);
len = base[symbol] + bits(s, extra[symbol]); if (len == 519) break; /* end code */
/* get distance */
symbol = len == 2 ? 2 : dict;
dist = decode(s, &distcode) << symbol;
dist += bits(s, symbol);
dist++; if (s->first && dist > s->next) return -3; /* distance too far back */
/* copy length bytes from distance bytes back */ do {
to = s->out + s->next;
from = to - dist;
copy = MAXWIN; if (s->next < dist) {
from += copy;
copy = dist;
}
copy -= s->next; if (copy > len) copy = len;
len -= copy;
s->next += copy; do {
*to++ = *from++;
} while (--copy); if (s->next == MAXWIN) { if (s->outfun(s->outhow, s->out, s->next)) return1;
s->next = 0;
s->first = 0;
}
} while (len != 0);
} else { /* get literal and write it */
symbol = lit ? decode(s, &litcode) : bits(s, 8);
s->out[s->next++] = symbol; if (s->next == MAXWIN) { if (s->outfun(s->outhow, s->out, s->next)) return1;
s->next = 0;
s->first = 0;
}
}
} while (1); return0;
}
/* See comments in blast.h */ int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, unsigned *left, unsignedchar **in)
{ struct state s; /* input/output state */ int err; /* return value */
/* return if bits() or decode() tries to read past available input */ if (setjmp(s.env) != 0) /* if came back here via longjmp(), */
err = 2; /* then skip decomp(), return error */ else
err = decomp(&s); /* decompress */
/* return unused input */ if (left != NULL)
*left = s.left; if (in != NULL)
*in = s.left ? s.in : NULL;
/* write any leftover output and update the error code if needed */ if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0)
err = 1; return err;
}
#ifdef TEST /* Example of how to use blast() */ #include <stdio.h> #include <stdlib.h>
#define CHUNK 16384
local unsigned inf(void *how, unsignedchar **buf)
{ staticunsignedchar hold[CHUNK];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.