X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=lib%2Funcompress.c;h=b8e0b674fc089512875b08e1b028fd00d12baced;hb=2ac486ab18adbbb84563eafc0d67fa8da6ca7822;hp=867e5bc265a0deee290e4935040f98c5ba30714d;hpb=ecdd57da7df775c039aee834e1f74172004f352b;p=zpackage diff --git a/lib/uncompress.c b/lib/uncompress.c index 867e5bc..b8e0b67 100644 --- a/lib/uncompress.c +++ b/lib/uncompress.c @@ -4,18 +4,122 @@ #include #include #include +#include +#include +#include #include -#include +#include "lzma.h" + +ssize_t zpm_uncompress_cb(void *buf, size_t bufsize, void *cbdata, + int (*cb)(void *ud, void *buf, size_t bufsize)) { + lzma_stream s = LZMA_STREAM_INIT; + lzma_stream *strm; + ssize_t bytes = 0; + + uint8_t outbuf[BUFSIZ]; -#include "sha256.h" + int ret; -#include "lzma.h" + strm = &s; + + ret = lzma_stream_decoder(strm, UINT64_MAX, 0); + /* The only reasonable error here is LZMA_MEM_ERROR. */ + if (ret != LZMA_OK) { + fprintf(stderr, "%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM) + : "Internal error (bug)"); + return -1; + } + + strm->avail_in = bufsize; + strm->next_in = buf; + strm->avail_out = BUFSIZ; + strm->next_out = outbuf; + + lzma_action action = LZMA_RUN; + + while (1) { + ret = lzma_code(strm, action); + + // Write and check write error before checking decoder error. + // This way as much data as possible gets written to output + // even if decoder detected an error. + if (strm->avail_out == 0 || ret != LZMA_OK) { + size_t avail = BUFSIZ - strm->avail_out; + ssize_t written = 0; + uint8_t *start; + + start = outbuf; + + while (avail > 0) { + written = cb(cbdata, outbuf, avail); + if (written == -1) { + /* Wouldn't be a surprise if writing to + * stderr would fail too but at least + * try to show an error message. + */ + return -1; + } + avail -= written; + start += written; + bytes += written; + } + + strm->next_out = outbuf; + strm->avail_out = BUFSIZ; + } + + if (ret != LZMA_OK) { + if (ret == LZMA_STREAM_END) { + // lzma_stream_decoder() already guarantees + // that there's no trailing garbage. + assert(strm->avail_in == 0); + //assert(action == LZMA_FINISH); + lzma_end(strm); + return bytes; + } + + lzma_end(strm); + const char *msg; + switch (ret) { + case LZMA_MEM_ERROR: + msg = strerror(ENOMEM); + break; + + case LZMA_FORMAT_ERROR: + msg = "File format not recognized"; + break; + + case LZMA_OPTIONS_ERROR: + // FIXME: Better message? + msg = "Unsupported compression options"; + break; + + case LZMA_DATA_ERROR: + msg = "File is corrupt"; + break; + + case LZMA_BUF_ERROR: + msg = "Unexpected end of input"; + break; + + default: + msg = "Internal error (bug)"; + break; + } + + fprintf(stderr, "zpmuncompress: %s\n", msg); + return -1; + } + } + +} -void uncompresslzma(void *buf, size_t bufsize, FILE *out) { +ssize_t uncompresslzma(void *buf, size_t bufsize, int out) { lzma_stream s = LZMA_STREAM_INIT; lzma_stream *strm; + ssize_t bytes = 0; uint8_t outbuf[BUFSIZ]; @@ -28,7 +132,7 @@ void uncompresslzma(void *buf, size_t bufsize, FILE *out) { if (ret != LZMA_OK) { fprintf(stderr, "%s", ret == LZMA_MEM_ERROR ? strerror(ENOMEM) : "Internal error (bug)"); - exit(EXIT_FAILURE); + return -1; } strm->avail_in = bufsize; @@ -45,15 +149,27 @@ void uncompresslzma(void *buf, size_t bufsize, FILE *out) { // This way as much data as possible gets written to output // even if decoder detected an error. if (strm->avail_out == 0 || ret != LZMA_OK) { - const size_t write_size = BUFSIZ - strm->avail_out; - - if (fwrite(outbuf, 1, write_size, out) != write_size) { - // Wouldn't be a surprise if writing to stderr - // would fail too but at least try to show an - // error message. - fprintf(stderr, "Cannot write to output file stream: " - "%s", strerror(errno)); - exit(EXIT_FAILURE); + size_t avail = BUFSIZ - strm->avail_out; + ssize_t written = 0; + uint8_t *start; + + start = outbuf; + + while (avail > 0) { + written = write(out, outbuf, avail); + if (written == -1) { + /* Wouldn't be a surprise if writing to + * stderr would fail too but at least + * try to show an error message. + */ + fprintf(stderr, "Cannot write to output" + " file stream: %s", + strerror(errno)); + return -1; + } + avail -= written; + start += written; + bytes += written; } strm->next_out = outbuf; @@ -66,9 +182,11 @@ void uncompresslzma(void *buf, size_t bufsize, FILE *out) { // that there's no trailing garbage. assert(strm->avail_in == 0); //assert(action == LZMA_FINISH); - return; + lzma_end(strm); + return bytes; } + lzma_end(strm); const char *msg; switch (ret) { case LZMA_MEM_ERROR: @@ -97,8 +215,8 @@ void uncompresslzma(void *buf, size_t bufsize, FILE *out) { break; } - fprintf(stderr, "xz: %s\n", msg); - exit(EXIT_FAILURE); + fprintf(stderr, "zpmuncompress: %s\n", msg); + return -1; } } }