123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- #include <stdio.h> /* fputs(), fprintf(), fwrite(), putc() */
- #include <stdlib.h> /* exit(), malloc(), free() */
- #include <fcntl.h> /* open() */
- #include <unistd.h> /* close(), read(), lseek() */
- #include "zlib.h"
-
- #define local static
- local int bail(char *why1, char *why2)
- {
- fprintf(stderr, "gzjoin error: %s%s, output incomplete\n", why1, why2);
- exit(1);
- return 0;
- }
- #define CHUNK 32768
- typedef struct {
- char *name;
- int fd;
- unsigned left;
- unsigned char *next;
- unsigned char *buf;
- } bin;
- local void bclose(bin *in)
- {
- if (in != NULL) {
- if (in->fd != -1)
- close(in->fd);
- if (in->buf != NULL)
- free(in->buf);
- free(in);
- }
- }
- local bin *bopen(char *name)
- {
- bin *in;
- in = malloc(sizeof(bin));
- if (in == NULL)
- return NULL;
- in->buf = malloc(CHUNK);
- in->fd = open(name, O_RDONLY, 0);
- if (in->buf == NULL || in->fd == -1) {
- bclose(in);
- return NULL;
- }
- in->left = 0;
- in->next = in->buf;
- in->name = name;
- return in;
- }
- local int bload(bin *in)
- {
- long len;
- if (in == NULL)
- return -1;
- if (in->left != 0)
- return 0;
- in->next = in->buf;
- do {
- len = (long)read(in->fd, in->buf + in->left, CHUNK - in->left);
- if (len < 0)
- return -1;
- in->left += (unsigned)len;
- } while (len != 0 && in->left < CHUNK);
- return len == 0 ? 1 : 0;
- }
- #define bget(in) (in->left ? 0 : bload(in), \
- in->left ? (in->left--, *(in->next)++) : \
- bail("unexpected end of file on ", in->name))
- local unsigned long bget4(bin *in)
- {
- unsigned long val;
- val = bget(in);
- val += (unsigned long)(bget(in)) << 8;
- val += (unsigned long)(bget(in)) << 16;
- val += (unsigned long)(bget(in)) << 24;
- return val;
- }
- local void bskip(bin *in, unsigned skip)
- {
-
- if (in == NULL)
- return;
-
- if (skip <= in->left) {
- in->left -= skip;
- in->next += skip;
- return;
- }
-
- skip -= in->left;
- in->left = 0;
-
- if (skip > CHUNK) {
- unsigned left;
- left = skip & (CHUNK - 1);
- if (left == 0) {
-
- lseek(in->fd, skip - 1, SEEK_CUR);
- if (read(in->fd, in->buf, 1) != 1)
- bail("unexpected end of file on ", in->name);
- return;
- }
-
- lseek(in->fd, skip - left, SEEK_CUR);
- skip = left;
- }
-
- bload(in);
- if (skip > in->left)
- bail("unexpected end of file on ", in->name);
- in->left -= skip;
- in->next += skip;
- }
- local void gzhead(bin *in)
- {
- int flags;
-
- if (bget(in) != 0x1f || bget(in) != 0x8b || bget(in) != 8)
- bail(in->name, " is not a valid gzip file");
-
- flags = bget(in);
- if ((flags & 0xe0) != 0)
- bail("unknown reserved bits set in ", in->name);
-
- bskip(in, 6);
-
- if (flags & 4) {
- unsigned len;
- len = bget(in);
- len += (unsigned)(bget(in)) << 8;
- bskip(in, len);
- }
-
- if (flags & 8)
- while (bget(in) != 0)
- ;
-
- if (flags & 16)
- while (bget(in) != 0)
- ;
-
- if (flags & 2)
- bskip(in, 2);
- }
- local void put4(unsigned long val, FILE *out)
- {
- putc(val & 0xff, out);
- putc((val >> 8) & 0xff, out);
- putc((val >> 16) & 0xff, out);
- putc((val >> 24) & 0xff, out);
- }
- local void zpull(z_streamp strm, bin *in)
- {
- if (in->left == 0)
- bload(in);
- if (in->left == 0)
- bail("unexpected end of file on ", in->name);
- strm->avail_in = in->left;
- strm->next_in = in->next;
- }
- local void gzinit(unsigned long *crc, unsigned long *tot, FILE *out)
- {
- fwrite("\x1f\x8b\x08\0\0\0\0\0\0\xff", 1, 10, out);
- *crc = crc32(0L, Z_NULL, 0);
- *tot = 0;
- }
- local void gzcopy(char *name, int clr, unsigned long *crc, unsigned long *tot,
- FILE *out)
- {
- int ret;
- int pos;
- int last;
- bin *in;
- unsigned char *start;
- unsigned char *junk;
- z_off_t len;
- z_stream strm;
-
- in = bopen(name);
- if (in == NULL)
- bail("could not open ", name);
- gzhead(in);
-
- junk = malloc(CHUNK);
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = 0;
- strm.next_in = Z_NULL;
- ret = inflateInit2(&strm, -15);
- if (junk == NULL || ret != Z_OK)
- bail("out of memory", "");
-
- len = 0;
- zpull(&strm, in);
- start = strm.next_in;
- last = start[0] & 1;
- if (last && clr)
- start[0] &= ~1;
- strm.avail_out = 0;
- for (;;) {
-
- if (strm.avail_in == 0 && strm.avail_out != 0) {
- fwrite(start, 1, strm.next_in - start, out);
- start = in->buf;
- in->left = 0;
- zpull(&strm, in);
- }
-
- strm.avail_out = CHUNK;
- strm.next_out = junk;
- ret = inflate(&strm, Z_BLOCK);
- switch (ret) {
- case Z_MEM_ERROR:
- bail("out of memory", "");
- case Z_DATA_ERROR:
- bail("invalid compressed data in ", in->name);
- }
-
- len += CHUNK - strm.avail_out;
-
- if (strm.data_type & 128) {
-
- if (last)
- break;
-
- pos = strm.data_type & 7;
-
- if (pos != 0) {
-
- pos = 0x100 >> pos;
- last = strm.next_in[-1] & pos;
- if (last && clr)
- strm.next_in[-1] &= ~pos;
- }
- else {
-
- if (strm.avail_in == 0) {
-
- fwrite(start, 1, strm.next_in - start, out);
- start = in->buf;
- in->left = 0;
- zpull(&strm, in);
- }
- last = strm.next_in[0] & 1;
- if (last && clr)
- strm.next_in[0] &= ~1;
- }
- }
- }
-
- in->left = strm.avail_in;
- in->next = strm.next_in;
-
- pos = strm.data_type & 7;
- fwrite(start, 1, in->next - start - 1, out);
- last = in->next[-1];
- if (pos == 0 || !clr)
-
- putc(last, out);
- else {
-
- last &= ((0x100 >> pos) - 1);
- if (pos & 1) {
-
- putc(last, out);
- if (pos == 1)
- putc(0, out);
- fwrite("\0\0\xff\xff", 1, 4, out);
- }
- else {
-
- switch (pos) {
- case 6:
- putc(last | 8, out);
- last = 0;
- case 4:
- putc(last | 0x20, out);
- last = 0;
- case 2:
- putc(last | 0x80, out);
- putc(0, out);
- }
- }
- }
-
- *crc = crc32_combine(*crc, bget4(in), len);
- *tot += (unsigned long)len;
-
- inflateEnd(&strm);
- free(junk);
- bclose(in);
-
- if (!clr) {
- put4(*crc, out);
- put4(*tot, out);
- }
- }
- int main(int argc, char **argv)
- {
- unsigned long crc, tot;
-
- argc--;
- argv++;
-
- if (argc == 0) {
- fputs("gzjoin usage: gzjoin f1.gz [f2.gz [f3.gz ...]] > fjoin.gz\n",
- stderr);
- return 0;
- }
-
- gzinit(&crc, &tot, stdout);
- while (argc--)
- gzcopy(*argv++, argc, &crc, &tot, stdout);
-
- return 0;
- }
|