]> pd.if.org Git - zpackage/blobdiff - uncompress.c
large commit of C work
[zpackage] / uncompress.c
diff --git a/uncompress.c b/uncompress.c
new file mode 100644 (file)
index 0000000..8b5d98f
--- /dev/null
@@ -0,0 +1,198 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/mman.h>
+
+#include <sqlite3.h>
+
+#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;
+}