pbzip2 に対応

id:ichii386頼まれた件を黙々と遂行中。もうちょっとだよ。

#ifndef __GNUC__
#error ぐにゅ〜
#endif /* __GNUC__ */

#include <stdio.h>
#include <stdlib.h>
#include <bzlib.h>

#define UNUSED(def) def __attribute__((unused))

#ifndef TRUE
#   define TRUE 1
#endif /* TRUE */

#ifndef FALSE
#   define FALSE 0
#endif /* FALSE */

int doit(FILE *out_strm, FILE *in_strm)
{
    int err = 0;
    int bzerr;
    unsigned char in_buf[4096];
    unsigned char out_buf[4096];
    size_t nelems_read;
    size_t total_alloc_sz = 0;
    bz_stream bzs;
    int uninitialized = TRUE;

    void *alloc(UNUSED(void *opaque), int sz, int nelems) {
        size_t r = (size_t)sz * (size_t)nelems;
        if (r / (size_t)sz != (size_t)nelems)
            return NULL; /* ! */
        total_alloc_sz += sz;
        return malloc(r);
    }

    void release(UNUSED(void *opaque), void *ptr) {
        free(ptr);
    }

    bzs.bzalloc = alloc;
    bzs.bzfree = release;

    for (;;) {
        if (uninitialized) {
            bzerr = BZ2_bzDecompressInit(&bzs, 1, 0);
            if (bzerr)
                goto out;
            bzs.avail_in = 0;
            uninitialized = FALSE;
        }

        if (bzs.avail_in == 0) {
            nelems_read = fread(in_buf, sizeof(*in_buf),
                    sizeof(in_buf) / sizeof(*in_buf), in_strm);
            if (nelems_read == 0) {
                if (ferror(in_strm)) {
                    err = 1;
                    goto out;
                } else {
                    break; /* end of file */
                }
            }
            bzs.next_in = in_buf;
            bzs.avail_in = nelems_read * sizeof(*in_buf);
        }

        bzs.next_out = out_buf;
        bzs.avail_out = sizeof(out_buf);
        fprintf(stderr, "avail_in=%tu\n", bzs.avail_in);
        bzerr = BZ2_bzDecompress(&bzs);
        fprintf(stderr, "  bzerr=%d\n", bzerr);
        if (bzerr < 0) {
            err = 1;
            goto out;
        }
        fprintf(stderr, "  avail_in=%tu\n", bzs.avail_in);
        fprintf(stderr, "  avail_out=%tu\n", bzs.avail_out);
        {
            size_t nelems_written;
            unsigned char *p = out_buf;
            while (p < (unsigned char *)bzs.next_out) {
                nelems_written = fwrite(p, sizeof(*out_buf),
                        (unsigned char *)bzs.next_out - p, out_strm);
                if (nelems_written == 0) {
                    err = 1;
                    goto out;
                }
                p += nelems_written;
            }
        }
        /* reinitialize decompressor */
        if (bzerr == BZ_STREAM_END) {
            if (BZ2_bzDecompressEnd(&bzs))
                fprintf(stderr, "WARN: BZ2_bzDecompressEnd returned error status\n");
            uninitialized = TRUE;
        }
    }

out:
    fprintf(stderr, "Total number of bytes allocated: %tu\n", total_alloc_sz);
    if (!uninitialized) {
        if (BZ2_bzDecompressEnd(&bzs))
            fprintf(stderr, "WARN: BZ2_bzDecompressEnd returned error status\n");
    }
    return err;
}

int main(UNUSED(int argc), UNUSED(void *argv))
{
    return doit(stdout, stdin) ? 1: 0;
}