aboutsummaryrefslogtreecommitdiffstats
path: root/inflate.c
diff options
context:
space:
mode:
Diffstat (limited to 'inflate.c')
-rw-r--r--inflate.c201
1 files changed, 156 insertions, 45 deletions
diff --git a/inflate.c b/inflate.c
index 9b58101..571a1b3 100644
--- a/inflate.c
+++ b/inflate.c
@@ -1,63 +1,174 @@
-/* $Id: inflate.c,v 1.4 2002/01/31 09:43:15 ukai Exp $ */
+#include <errno.h>
#include <stdio.h>
+#include <string.h>
#include <stdlib.h>
#include <zlib.h>
-#undef BUFSIZE
-#define BUFSIZE 4096
+#define MYBUFSIZ (BUFSIZ * 0x10)
+
+/* cf. rfc1950.txt */
+static char dummy_head[1 + 1] = {
+ 0x8 + 0x7 * 0x10,
+ (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
+};
int
-main(int argc, char **argv)
+main(int argc, char *argv[])
{
- z_stream s;
- FILE *f;
- char inbuf[BUFSIZE], outbuf[BUFSIZE];
- int status, flush;
+ int err, nfiles, i, nin, inrest, eoin, nout, outrest, eoout, ninflates,
+ raw;
+ z_stream d_stream;
+ char *me = argv[0];
+ char *inbuf, *outbuf, **filev;
+
+ if (!(inbuf = malloc(MYBUFSIZ))) {
+ fprintf(stderr, "%s: inbuf = malloc(%lu): %s\n", me,
+ (unsigned long)MYBUFSIZ, strerror(errno));
+ exit(1);
+ }
+
+ if (!(outbuf = malloc(MYBUFSIZ))) {
+ fprintf(stderr, "%s: outbuf = malloc(%lu): %s\n", me,
+ (unsigned long)MYBUFSIZ, strerror(errno));
+ exit(1);
+ }
+
+ d_stream.zalloc = NULL;
+ d_stream.zfree = NULL;
+ d_stream.opaque = NULL;
if (argc > 1) {
- f = fopen(argv[1], "rb");
- if (!f) {
- fprintf(stderr, "%s: cannot open %s\n", argv[0], argv[1]);
- exit(1);
- }
+ nfiles = argc - 1;
+ filev = &argv[1];
}
- else
- f = stdin;
+ else {
+ static char *myargv[] = { "-", NULL };
- s.zalloc = Z_NULL;
- s.zfree = Z_NULL;
- s.opaque = Z_NULL;
- status = inflateInit(&s);
- if (status != Z_OK) {
- fprintf(stderr, "%s: inflateInit() %s\n", argv[0], zError(status));
+ nfiles = 1;
+ filev = myargv;
+ }
+
+ if ((err = inflateInit(&d_stream)) != Z_OK) {
+ fprintf(stderr, "%s: inflateInit(&d_stream): %d\n", me, err);
exit(1);
}
- s.avail_in = 0;
- s.next_out = (Bytef *) outbuf;
- s.avail_out = sizeof(outbuf);
- flush = Z_NO_FLUSH;
- while (1) {
- if (s.avail_in == 0) {
- s.next_in = (Bytef *) inbuf;
- s.avail_in = fread(inbuf, 1, sizeof(inbuf), f);
- }
- status = inflate(&s, flush);
- if (status == Z_STREAM_END) {
- if (sizeof(outbuf) - s.avail_out)
- fwrite(outbuf, 1, sizeof(outbuf) - s.avail_out, stdout);
- break;
- }
- if (status != Z_OK) {
- fprintf(stderr, "%s: inflate() %s\n", argv[0], zError(status));
- exit(1);
+
+ for (raw = ninflates = i = inrest = outrest = 0, eoout = 1; i < nfiles;
+ ++i) {
+ FILE *in;
+
+ if (strcmp(filev[i], "-")) {
+ if (!(in = fopen(filev[i], "rb"))) {
+ fprintf(stderr, "%s: fopen(\"%s\", \"rb\"): %s\n", me,
+ filev[i], strerror(errno));
+ exit(1);
+ }
}
- if (s.avail_out == 0) {
- fwrite(outbuf, 1, sizeof(outbuf), stdout);
- s.next_out = (Bytef *) outbuf;
- s.avail_out = sizeof(outbuf);
+ else
+ in = stdin;
+
+ for (eoin = 0;;) {
+ if ((nin =
+ fread(&inbuf[inrest], 1, MYBUFSIZ - inrest,
+ in)) < MYBUFSIZ - inrest) {
+ if (ferror(in)) {
+ fprintf(stderr, "%s: fread(&inbuf[%d], 1, %d, in): %s\n",
+ me, inrest, MYBUFSIZ - inrest, strerror(errno));
+ exit(1);
+ }
+
+ eoin = 1;
+ }
+
+ if (nin > 0) {
+ retry:
+ d_stream.next_in = inbuf;
+ d_stream.avail_in = inrest + nin;
+
+ for (eoout = 0;;) {
+ d_stream.next_out = &outbuf[outrest];
+ d_stream.avail_out = MYBUFSIZ - outrest;
+
+ switch (err = inflate(&d_stream, Z_NO_FLUSH)) {
+ case Z_OK:
+ if (!
+ ((nout =
+ fwrite(outbuf, 1, MYBUFSIZ - d_stream.avail_out,
+ stdout)) > 0)) {
+ fprintf(stderr,
+ "%s: fwrite(outbuf, 1, %d, stdout): %s\n",
+ me, MYBUFSIZ - d_stream.avail_out,
+ strerror(errno));
+ exit(1);
+ }
+
+ memmove(outbuf, &outbuf[nout],
+ MYBUFSIZ - d_stream.avail_out - nout);
+ outrest = MYBUFSIZ - d_stream.avail_out - nout;
+ ++ninflates;
+ break;
+ case Z_STREAM_END:
+ case Z_BUF_ERROR:
+ ninflates = 0;
+ outrest = MYBUFSIZ - d_stream.avail_out;
+ eoout = 1;
+ goto next_fread;
+ case Z_DATA_ERROR:
+ if (!ninflates) {
+ if ((err = inflateReset(&d_stream)) != Z_OK) {
+ fprintf(stderr,
+ "%s: inflateReset(&d_stream): %d\n",
+ me, err);
+ exit(1);
+ }
+
+ d_stream.next_in = dummy_head;
+ d_stream.avail_in = sizeof(dummy_head);
+
+ if ((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_OK) {
+ raw = ninflates = 1;
+ goto retry;
+ }
+ }
+ default:
+ fprintf(stderr,
+ "%s: inflate(&d_stream, Z_NO_FLUSH): %d\n", me,
+ err);
+ exit(1);
+ }
+ }
+ }
+
+ next_fread:
+ if (d_stream.avail_in) {
+ memmove(inbuf, &inbuf[inrest + nin - d_stream.avail_in],
+ d_stream.avail_in);
+ inrest = d_stream.avail_in;
+ }
+ else
+ inrest = 0;
+
+ if (eoin)
+ break;
}
+
+ if (in != stdin)
+ fclose(in);
}
- inflateEnd(&s);
- fclose(f);
+
+ if (!eoout && !raw) {
+ fprintf(stderr, "%s: short input\n", me);
+ exit(1);
+ }
+
+ if (inrest)
+ fprintf(stderr, "%s: trailing garbages are ignored\n", me);
+
+ if (outrest && fwrite(outbuf, 1, outrest, stdout) < outrest) {
+ fprintf(stderr, "%s: fwrite(outbuf, 1, %d, stdout): %s\n", me, outrest,
+ strerror(errno));
+ exit(1);
+ }
+
return 0;
}