X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=uncompress.c;fp=uncompress.c;h=8b5d98f59dbb6fd53cc0a7fd2bae9f8ec900f710;hb=ecdd57da7df775c039aee834e1f74172004f352b;hp=0000000000000000000000000000000000000000;hpb=fa23ca4b77cd45ed4996eafc1fa714e12a72439e;p=zpackage diff --git a/uncompress.c b/uncompress.c new file mode 100644 index 0000000..8b5d98f --- /dev/null +++ b/uncompress.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "sha256.h" + +#include "lzma.h" + +void uncompresslzma(void *buf, size_t bufsize, FILE *out) { + lzma_stream s = LZMA_STREAM_INIT; + lzma_stream *strm; + + uint8_t outbuf[BUFSIZ]; + + int ret; + + 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)"); + exit(EXIT_FAILURE); + } + + 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) { + 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); + } + + 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); + return; + } + + 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, "xz: %s\n", msg); + exit(EXIT_FAILURE); + } + } +} + +#define SQLERROR(x) fprintf(stderr, "%s %d: %s\n", __func__, __LINE__, (x)) + +int main(int ac, char **av){ + sqlite3 *db = 0; + int rc; + + int blobsize; + int64_t size; + void *xzdata; + int type; + FILE *out; + sqlite3_stmt *ifile; + + char *hash; + char *filename; + + if (ac < 3) { + fprintf(stderr, "usage: db hash file\n"); + return 1; + } + + rc = sqlite3_open(av[1], &db); + if (rc) { + SQLERROR(sqlite3_errmsg(db)); + sqlite3_close(db); + return 1; + } + + rc = sqlite3_prepare(db, "select size, content from files where hash = ?", -1, &ifile,0); + if (rc != SQLITE_OK) { + SQLERROR(sqlite3_errmsg(db)); + return 1; + } + + /* hash, filename */ + hash = av[2]; + filename = av[3]; + + sqlite3_bind_text(ifile, 1, hash, 64, SQLITE_STATIC); + + rc = sqlite3_step(ifile); + + if (rc == SQLITE_DONE) { + /* didn't find a row */ + sqlite3_finalize(ifile); + sqlite3_close(db); + fprintf(stderr, "no such hash\n"); + return 1; + } + /* either way we're done with this now */ + + if (rc != SQLITE_ROW) { + SQLERROR(sqlite3_errmsg(db)); + sqlite3_finalize(ifile); + sqlite3_close(db); + return 2; + } + + type = sqlite3_column_type(ifile, 0); + if (type == SQLITE_NULL) { + fprintf(stderr, "no file size\n"); + sqlite3_finalize(ifile); + sqlite3_close(db); + return 3; + } + type = sqlite3_column_type(ifile, 1); + if (type == SQLITE_NULL) { + fprintf(stderr, "no file data\n"); + sqlite3_finalize(ifile); + sqlite3_close(db); + return 4; + } + size = sqlite3_column_int64(ifile, 0); + xzdata = (void *)sqlite3_column_blob(ifile, 1); + blobsize = sqlite3_column_bytes(ifile, 1); + + out = fopen(filename, "w"); + if (!out) { + fprintf(stderr, "can't open output file %s\n", filename); + sqlite3_finalize(ifile); + sqlite3_close(db); + return 5; + } + //fwrite(xzdata, blobsize, 1, stdout); + + fprintf(stderr, "uncompressing %d bytes at %p, expect %lld\n", blobsize, xzdata, (long long int)size); + uncompresslzma(xzdata, blobsize, out); + fclose(out); + + sqlite3_finalize(ifile); + sqlite3_close(db); + return 0; +}