blast.c (muscle7.61) | : | blast.c (muscle7.62) | ||
---|---|---|---|---|
/* blast.c | /* blast.c | |||
* Copyright (C) 2003, 2012 Mark Adler | * Copyright (C) 2003, 2012, 2013 Mark Adler | |||
* For conditions of distribution and use, see copyright notice in blast.h | * For conditions of distribution and use, see copyright notice in blast.h | |||
* version 1.2, 24 Oct 2012 | * version 1.3, 24 Aug 2013 | |||
* | * | |||
* blast.c decompresses data compressed by the PKWare Compression Library. | * blast.c decompresses data compressed by the PKWare Compression Library. | |||
* This function provides functionality similar to the explode() function of | * This function provides functionality similar to the explode() function of | |||
* the PKWare library, hence the name "blast". | * the PKWare library, hence the name "blast". | |||
* | * | |||
* This decompressor is based on the excellent format description provided by | * This decompressor is based on the excellent format description provided by | |||
* Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the | * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the | |||
* example Ben provided in the post is incorrect. The distance 110001 should | * example Ben provided in the post is incorrect. The distance 110001 should | |||
* instead be 111000. When corrected, the example byte stream becomes: | * instead be 111000. When corrected, the example byte stream becomes: | |||
* | * | |||
skipping to change at line 27 | skipping to change at line 27 | |||
* which decompresses to "AIAIAIAIAIAIA" (without the quotes). | * which decompresses to "AIAIAIAIAIAIA" (without the quotes). | |||
*/ | */ | |||
/* | /* | |||
* Change history: | * Change history: | |||
* | * | |||
* 1.0 12 Feb 2003 - First version | * 1.0 12 Feb 2003 - First version | |||
* 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data | * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data | |||
* 1.2 24 Oct 2012 - Add note about using binary mode in stdio | * 1.2 24 Oct 2012 - Add note about using binary mode in stdio | |||
* - Fix comparisons of differently signed integers | * - Fix comparisons of differently signed integers | |||
* 1.3 24 Aug 2013 - Return unused input from blast() | ||||
* - Fix test code to correctly report unused input | ||||
* - Enable the provision of initial input to blast() | ||||
*/ | */ | |||
#include <stddef.h> /* for NULL */ | ||||
#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */ | #include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */ | |||
#include "blast.h" /* prototype for blast() */ | #include "blast.h" /* prototype for blast() */ | |||
#define local static /* for local function definitions */ | #define local static /* for local function definitions */ | |||
#define MAXBITS 13 /* maximum code length */ | #define MAXBITS 13 /* maximum code length */ | |||
#define MAXWIN 4096 /* maximum window size */ | #define MAXWIN 4096 /* maximum window size */ | |||
/* input and output state */ | /* input and output state */ | |||
struct state { | struct state { | |||
/* input state */ | /* input state */ | |||
skipping to change at line 259 | skipping to change at line 263 | |||
* - Compressed data is a combination of literals and length/distance pairs | * - Compressed data is a combination of literals and length/distance pairs | |||
* terminated by an end code. Literals are either Huffman coded or | * terminated by an end code. Literals are either Huffman coded or | |||
* uncoded bytes. A length/distance pair is a coded length followed by a | * uncoded bytes. A length/distance pair is a coded length followed by a | |||
* coded distance to represent a string that occurs earlier in the | * coded distance to represent a string that occurs earlier in the | |||
* uncompressed data that occurs again at the current location. | * uncompressed data that occurs again at the current location. | |||
* | * | |||
* - A bit preceding a literal or length/distance pair indicates which comes | * - A bit preceding a literal or length/distance pair indicates which comes | |||
* next, 0 for literals, 1 for length/distance. | * next, 0 for literals, 1 for length/distance. | |||
* | * | |||
* - If literals are uncoded, then the next eight bits are the literal, in the | * - If literals are uncoded, then the next eight bits are the literal, in the | |||
* normal bit order in th stream, i.e. no bit-reversal is needed. Similarly, | * normal bit order in the stream, i.e. no bit-reversal is needed. Similarly, | |||
* no bit reversal is needed for either the length extra bits or the distance | * no bit reversal is needed for either the length extra bits or the distance | |||
* extra bits. | * extra bits. | |||
* | * | |||
* - Literal bytes are simply written to the output. A length/distance pair is | * - Literal bytes are simply written to the output. A length/distance pair is | |||
* an instruction to copy previously uncompressed bytes to the output. The | * an instruction to copy previously uncompressed bytes to the output. The | |||
* copy is from distance bytes back in the output stream, copying for length | * copy is from distance bytes back in the output stream, copying for length | |||
* bytes. | * bytes. | |||
* | * | |||
* - Distances pointing before the beginning of the output data are not | * - Distances pointing before the beginning of the output data are not | |||
* permitted. | * permitted. | |||
skipping to change at line 379 | skipping to change at line 383 | |||
if (s->outfun(s->outhow, s->out, s->next)) return 1; | if (s->outfun(s->outhow, s->out, s->next)) return 1; | |||
s->next = 0; | s->next = 0; | |||
s->first = 0; | s->first = 0; | |||
} | } | |||
} | } | |||
} while (1); | } while (1); | |||
return 0; | return 0; | |||
} | } | |||
/* See comments in blast.h */ | /* See comments in blast.h */ | |||
int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow) | int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow, | |||
unsigned *left, unsigned char **in) | ||||
{ | { | |||
struct state s; /* input/output state */ | struct state s; /* input/output state */ | |||
int err; /* return value */ | int err; /* return value */ | |||
/* initialize input state */ | /* initialize input state */ | |||
s.infun = infun; | s.infun = infun; | |||
s.inhow = inhow; | s.inhow = inhow; | |||
s.left = 0; | if (left != NULL && *left) { | |||
s.left = *left; | ||||
s.in = *in; | ||||
} | ||||
else | ||||
s.left = 0; | ||||
s.bitbuf = 0; | s.bitbuf = 0; | |||
s.bitcnt = 0; | s.bitcnt = 0; | |||
/* initialize output state */ | /* initialize output state */ | |||
s.outfun = outfun; | s.outfun = outfun; | |||
s.outhow = outhow; | s.outhow = outhow; | |||
s.next = 0; | s.next = 0; | |||
s.first = 1; | s.first = 1; | |||
/* return if bits() or decode() tries to read past available input */ | /* return if bits() or decode() tries to read past available input */ | |||
if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ | if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ | |||
err = 2; /* then skip decomp(), return error */ | err = 2; /* then skip decomp(), return error */ | |||
else | else | |||
err = decomp(&s); /* decompress */ | 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 */ | /* 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) | if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) | |||
err = 1; | err = 1; | |||
return err; | return err; | |||
} | } | |||
#ifdef TEST | #ifdef TEST | |||
/* Example of how to use blast() */ | /* Example of how to use blast() */ | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
skipping to change at line 432 | skipping to change at line 448 | |||
} | } | |||
local int outf(void *how, unsigned char *buf, unsigned len) | local int outf(void *how, unsigned char *buf, unsigned len) | |||
{ | { | |||
return fwrite(buf, 1, len, (FILE *)how) != len; | return fwrite(buf, 1, len, (FILE *)how) != len; | |||
} | } | |||
/* Decompress a PKWare Compression Library stream from stdin to stdout */ | /* Decompress a PKWare Compression Library stream from stdin to stdout */ | |||
int main(void) | int main(void) | |||
{ | { | |||
int ret, n; | int ret; | |||
unsigned left; | ||||
/* decompress to stdout */ | /* decompress to stdout */ | |||
ret = blast(inf, stdin, outf, stdout); | left = 0; | |||
if (ret != 0) fprintf(stderr, "blast error: %d\n", ret); | ret = blast(inf, stdin, outf, stdout, &left, NULL); | |||
if (ret != 0) | ||||
/* see if there are any leftover bytes */ | fprintf(stderr, "blast error: %d\n", ret); | |||
n = 0; | ||||
while (getchar() != EOF) n++; | /* count any leftover bytes */ | |||
if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n); | while (getchar() != EOF) | |||
left++; | ||||
if (left) | ||||
fprintf(stderr, "blast warning: %u unused bytes of input\n", left); | ||||
/* return blast() error code */ | /* return blast() error code */ | |||
return ret; | return ret; | |||
} | } | |||
#endif | #endif | |||
End of changes. 10 change blocks. | ||||
13 lines changed or deleted | 33 lines changed or added |