#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "bzlib.h"
extern void bz_internal_error(int errcode) {
fprintf(stderr, "bzip2 hit internal error code: %d\n", errcode);
exit(1);
}
#ifdef NO_STD
void *custom_bzalloc(void *opaque, int items, int size) {
return malloc(items * size);
}
void custom_bzfree(void *opaque, void *address) {
free(address);
}
#endif
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
# include <fcntl.h>
# include <io.h>
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
# define SET_BINARY_MODE(file)
#endif
#define CHUNK 256
int def(FILE *source, FILE *dest)
{
int ret;
unsigned have;
bz_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
#ifdef NO_STD
strm.bzalloc = custom_bzalloc;
strm.bzfree = custom_bzfree;
#else
strm.bzalloc = NULL;
strm.bzfree = NULL;
#endif
strm.opaque = NULL;
ret = BZ2_bzCompressInit(&strm, 9, 0, 0);
if (ret != BZ_OK)
return ret;
int done = 0;
while (!done) {
strm.avail_in = fread(in, 1, CHUNK, source);
done = feof(source);
if (ferror(source)) {
(void)BZ2_bzCompressEnd(&strm);
return BZ_IO_ERROR;
}
strm.next_in = in;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = BZ2_bzCompress(&strm, BZ_FLUSH);
assert(ret != BZ_PARAM_ERROR);
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)BZ2_bzCompressEnd(&strm);
return BZ_IO_ERROR;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0);
}
strm.avail_out = CHUNK;
strm.next_out = out;
ret = BZ2_bzCompress(&strm, BZ_FINISH);
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)BZ2_bzCompressEnd(&strm);
return BZ_IO_ERROR;
}
assert(ret == BZ_STREAM_END);
(void)BZ2_bzCompressEnd(&strm);
return BZ_OK;
}
int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
bz_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
#ifdef NO_STD
strm.bzalloc = custom_bzalloc;
strm.bzfree = custom_bzfree;
#else
strm.bzalloc = NULL;
strm.bzfree = NULL;
#endif
strm.opaque = NULL;
strm.avail_in = 0;
strm.next_in = NULL;
ret = BZ2_bzDecompressInit(&strm, 0, 0);
if (ret != BZ_OK)
return ret;
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)BZ2_bzDecompressEnd(&strm);
return BZ_IO_ERROR;
}
if (strm.avail_in == 0)
break;
strm.next_in = in;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = BZ2_bzDecompress(&strm);
assert(ret != BZ_PARAM_ERROR);
switch (ret) {
case BZ_DATA_ERROR:
case BZ_MEM_ERROR:
(void)BZ2_bzDecompressEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)BZ2_bzDecompressEnd(&strm);
return BZ_IO_ERROR;
}
} while (strm.avail_out == 0);
} while (ret != BZ_STREAM_END);
(void)BZ2_bzDecompressEnd(&strm);
return ret == BZ_STREAM_END ? BZ_OK : BZ_DATA_ERROR;
}
void zerr(int ret)
{
fputs("bzpipe: ", stderr);
switch (ret) {
case BZ_IO_ERROR:
if (ferror(stdin))
fputs("error reading stdin\n", stderr);
if (ferror(stdout))
fputs("error writing stdout\n", stderr);
break;
case BZ_PARAM_ERROR:
fputs("invalid block size\n", stderr);
break;
case BZ_DATA_ERROR:
case BZ_DATA_ERROR_MAGIC:
fputs("invalid or incomplete data\n", stderr);
break;
case BZ_MEM_ERROR:
fputs("out of memory\n", stderr);
break;
}
}
int main(int argc, char **argv)
{
int ret;
SET_BINARY_MODE(stdin);
SET_BINARY_MODE(stdout);
if (argc == 1) {
ret = def(stdin, stdout);
if (ret != BZ_OK)
zerr(ret);
return ret;
}
else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
ret = inf(stdin, stdout);
if (ret != BZ_OK)
zerr(ret);
return ret;
}
else {
fputs("bzpipe usage: bzpipe [-d] < source > dest\n", stderr);
return 1;
}
}