summaryrefslogtreecommitdiffstats
path: root/depends/lzma/elzma.c
diff options
context:
space:
mode:
Diffstat (limited to 'depends/lzma/elzma.c')
-rw-r--r--depends/lzma/elzma.c557
1 files changed, 557 insertions, 0 deletions
diff --git a/depends/lzma/elzma.c b/depends/lzma/elzma.c
new file mode 100644
index 00000000..f715a7b2
--- /dev/null
+++ b/depends/lzma/elzma.c
@@ -0,0 +1,557 @@
+/*
+ * Written in 2009 by Lloyd Hilaiel
+ *
+ * License
+ *
+ * All the cruft you find here is public domain. You don't have to credit
+ * anyone to use this code, but my personal request is that you mention
+ * Igor Pavlov for his hard, high quality work.
+ *
+ * command line elzma tool for lzma compression
+ *
+ * At time of writing, the primary purpose of this tool is to test the
+ * easylzma library.
+ *
+ * TODO:
+ * - stdin/stdout support
+ * - multiple file support
+ * - much more
+ */
+
+#include "include/compress.h"
+#include "include/decompress.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef WIN32
+#include <stdio.h>
+#define unlink _unlink
+#else
+#include <unistd.h>
+#endif
+
+int deleteFile(const char *path)
+{
+ return unlink(path);
+}
+
+/* a utility to open a pair of files */
+/* XXX: respect overwrite flag */
+static int openFiles(const char *ifname, FILE **inFile, const char *ofname, FILE **outFile,
+ int overwrite)
+{
+ *inFile = fopen(ifname, "rb");
+ if (*inFile == NULL)
+ {
+ fprintf(stderr, "couldn't open '%s' for reading\n", ifname);
+ return 1;
+ }
+
+ *outFile = fopen(ofname, "wb");
+ if (*outFile == NULL)
+ {
+ fprintf(stderr, "couldn't open '%s' for writing\n", ofname);
+ return 1;
+ }
+
+ return 0;
+}
+
+#define ELZMA_COMPRESS_USAGE \
+ "Compress files using the LZMA algorithm (in place by default).\n" \
+ "\n" \
+ "Usage: elzma [options] [file]\n" \
+ " -1 .. -9 compression level, -1 is fast, -9 is best (default 5)\n" \
+ " -f, --force overwrite output files if they exist\n" \
+ " -h, --help output this message and exit\n" \
+ " -k, --keep don't delete input files\n" \
+ " --lzip compress to lzip disk format (.lz extension)\n" \
+ " --lzma compress to LZMA-Alone disk format (.lzma extension)\n" \
+ " -v, --verbose output verbose status information while compressing\n" \
+ " -z, --compress compress files (default when invoking elzma program)\n" \
+ " -d, --decompress decompress files (default when invoking unelzma program)\n" \
+ "\n" \
+ "Advanced Options:\n" \
+ " -s --set-max-dict (advanced) specify maximum dictionary size in bytes\n"
+
+/* parse arguments populating output parameters, return nonzero on failure */
+static int parseCompressArgs(int argc, char **argv, unsigned char *level, char **fname,
+ unsigned int *maxDictSize, unsigned int *verbose,
+ unsigned int *keep, unsigned int *overwrite,
+ elzma_file_format *format)
+{
+ int i;
+
+ if (argc < 2)
+ return 1;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ char *val = NULL;
+ char *arg = &(argv[i][1]);
+ if (arg[0] == '-')
+ arg++;
+
+ /* now see what argument this is */
+ if (!strcmp(arg, "h") || !strcmp(arg, "help"))
+ {
+ return 1;
+ }
+ else if (!strcmp(arg, "s") || !strcmp(arg, "set-max-dict"))
+ {
+ unsigned int j = 0;
+ val = argv[++i];
+
+ /* validate argument is numeric */
+ for (j = 0; j < strlen(val); j++)
+ {
+ if (val[j] < '0' || val[j] > '9')
+ return 1;
+ }
+
+ *maxDictSize = strtoul(val, (char **)NULL, 10);
+
+ /* don't allow dictionary sizes less than 8k */
+ if (*maxDictSize < (1 < 13))
+ *maxDictSize = 1 < 13;
+ else
+ {
+ /* make sure dict size is compatible with lzip,
+ * this will effectively collapse it to a close power
+ * of 2 */
+ *maxDictSize = elzma_get_dict_size(*maxDictSize);
+ }
+ }
+ else if (!strcmp(arg, "v") || !strcmp(arg, "verbose"))
+ {
+ *verbose = 1;
+ }
+ else if (!strcmp(arg, "f") || !strcmp(arg, "force"))
+ {
+ *overwrite = 1;
+ }
+ else if (!strcmp(arg, "k") || !strcmp(arg, "keep"))
+ {
+ *keep = 1;
+ }
+ else if (strlen(arg) == 1 && arg[0] >= '1' && arg[0] <= '9')
+ {
+ *level = arg[0] - '0';
+ }
+ else if (!strcmp(arg, "lzma"))
+ {
+ *format = ELZMA_lzma;
+ }
+ else if (!strcmp(arg, "lzip"))
+ {
+ *format = ELZMA_lzip;
+ }
+ else if (!strcmp(arg, "z") || !strcmp(arg, "d") || !strcmp(arg, "compress") ||
+ !strcmp(arg, "decompress"))
+ {
+ /* noop */
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ *fname = argv[i];
+ break;
+ }
+ }
+
+ /* proper number of arguments? */
+ if (i != argc - 1 || *fname == NULL)
+ return 1;
+
+ return 0;
+}
+
+/* callbacks for streamed input and output */
+static size_t elzmaWriteFunc(void *ctx, const void *buf, size_t size)
+{
+ size_t wt;
+ FILE *f = (FILE *)ctx;
+ assert(f != NULL);
+
+ wt = fwrite(buf, 1, size, f);
+
+ return wt;
+}
+
+static int elzmaReadFunc(void *ctx, void *buf, size_t *size)
+{
+ FILE *f = (FILE *)ctx;
+ assert(f != NULL);
+ *size = fread(buf, 1, *size, f);
+
+ return 0;
+}
+
+static void printProgressHeader(void)
+{
+ printf("|0%% 50%% 100%%|\n");
+}
+
+static void endProgress(int pCtx)
+{
+ while (pCtx++ < 64)
+ {
+ printf(".");
+ }
+ printf("|\n");
+}
+
+static void elzmaProgressFunc(void *ctx, size_t complete, size_t total)
+{
+ int *dots = (int *)ctx;
+ int wantDots = (int)(64 * (double)complete / (double)total);
+ if (*dots == 0)
+ {
+ printf("|");
+ (*dots)++;
+ }
+ while (wantDots > *dots)
+ {
+ printf(".");
+ (*dots)++;
+ }
+ fflush(stdout);
+}
+
+static int doCompress(int argc, char **argv)
+{
+ /* default compression parameters, some of which may be overridded by
+ * command line arguments */
+ unsigned char level = 5;
+ unsigned char lc = ELZMA_LC_DEFAULT;
+ unsigned char lp = ELZMA_LP_DEFAULT;
+ unsigned char pb = ELZMA_PB_DEFAULT;
+ unsigned int maxDictSize = ELZMA_DICT_SIZE_DEFAULT_MAX;
+ unsigned int dictSize = 0;
+ elzma_file_format format = ELZMA_lzma;
+ char *ext = ".lzma";
+ char *ifname = NULL;
+ char *ofname = NULL;
+ unsigned int verbose = 0;
+ FILE *inFile = NULL;
+ FILE *outFile = NULL;
+ elzma_compress_handle hand = NULL;
+ /* XXX: large file support */
+ unsigned int uncompressedSize = 0;
+ unsigned int keep = 0;
+ unsigned int overwrite = 0;
+
+ if (0 != parseCompressArgs(argc, argv, &level, &ifname, &maxDictSize, &verbose, &keep,
+ &overwrite, &format))
+ {
+ fprintf(stderr, ELZMA_COMPRESS_USAGE);
+ return 1;
+ }
+
+ /* extension switching based on compression type*/
+ if (format == ELZMA_lzip)
+ ext = ".lz";
+
+ /* generate output file name */
+ {
+ ofname = malloc(strlen(ifname) + strlen(ext) + 1);
+ ofname[0] = 0;
+ strcat(ofname, ifname);
+ strcat(ofname, ext);
+ }
+
+ /* now attempt to open input and ouput files */
+ /* XXX: stdin/stdout support */
+ if (0 != openFiles(ifname, &inFile, ofname, &outFile, overwrite))
+ {
+ return 1;
+ }
+
+ /* set uncompressed size */
+ if (0 != fseek(inFile, 0, SEEK_END) || 0 == (uncompressedSize = ftell(inFile)) ||
+ 0 != fseek(inFile, 0, SEEK_SET))
+ {
+ fprintf(stderr, "error seeking input file (%s) - zero length?\n", ifname);
+ deleteFile(ofname);
+ return 1;
+ }
+
+ /* determine a reasonable dictionary size given input size */
+ dictSize = elzma_get_dict_size(uncompressedSize);
+ if (dictSize > maxDictSize)
+ dictSize = maxDictSize;
+
+ if (verbose)
+ {
+ printf("compressing '%s' to '%s'\n", ifname, ofname);
+ printf("lc/lp/pb = %u/%u/%u | dictionary size = %u bytes\n", lc, lp, pb, dictSize);
+ printf("input file is %u bytes\n", uncompressedSize);
+ }
+
+ /* allocate a compression handle */
+ hand = elzma_compress_alloc();
+ if (hand == NULL)
+ {
+ fprintf(stderr, "couldn't allocate compression object\n");
+ deleteFile(ofname);
+ return 1;
+ }
+
+ if (ELZMA_E_OK !=
+ elzma_compress_config(hand, lc, lp, pb, level, dictSize, format, uncompressedSize))
+ {
+ fprintf(stderr, "couldn't configure compression with "
+ "provided parameters\n");
+ deleteFile(ofname);
+ return 1;
+ }
+
+ {
+ int rv;
+ int pCtx = 0;
+
+ if (verbose)
+ printProgressHeader();
+
+ rv = elzma_compress_run(hand, elzmaReadFunc, (void *)inFile, elzmaWriteFunc,
+ (void *)outFile, (verbose ? elzmaProgressFunc : NULL), &pCtx);
+
+ if (verbose)
+ endProgress(pCtx);
+
+ if (ELZMA_E_OK != rv)
+ {
+ fprintf(stderr, "error compressing\n");
+ deleteFile(ofname);
+ return 1;
+ }
+ }
+
+ /* clean up */
+ elzma_compress_free(&hand);
+ fclose(inFile);
+ fclose(outFile);
+ free(ofname);
+
+ if (!keep)
+ deleteFile(ifname);
+
+ return 0;
+}
+
+#define ELZMA_DECOMPRESS_USAGE \
+ "Decompress files compressed using the LZMA algorithm (in place by default).\n" \
+ "\n" \
+ "Usage: unelzma [options] [file]\n" \
+ " -f, --force overwrite output files if they exist\n" \
+ " -h, --help output this message and exit\n" \
+ " -k, --keep don't delete input files\n" \
+ " -v, --verbose output verbose status information while decompressing\n" \
+ " -z, --compress compress files (default when invoking elzma program)\n" \
+ " -d, --decompress decompress files (default when invoking unelzma program)\n" \
+ "\n"
+/* parse arguments populating output parameters, return nonzero on failure */
+static int parseDecompressArgs(int argc, char **argv, char **fname, unsigned int *verbose,
+ unsigned int *keep, unsigned int *overwrite)
+{
+ int i;
+
+ if (argc < 2)
+ return 1;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ char *arg = &(argv[i][1]);
+ if (arg[0] == '-')
+ arg++;
+
+ /* now see what argument this is */
+ if (!strcmp(arg, "h") || !strcmp(arg, "help"))
+ {
+ return 1;
+ }
+ else if (!strcmp(arg, "v") || !strcmp(arg, "verbose"))
+ {
+ *verbose = 1;
+ }
+ else if (!strcmp(arg, "k") || !strcmp(arg, "keep"))
+ {
+ *keep = 1;
+ }
+ else if (!strcmp(arg, "f") || !strcmp(arg, "force"))
+ {
+ *overwrite = 1;
+ }
+ else if (!strcmp(arg, "z") || !strcmp(arg, "d") || !strcmp(arg, "compress") ||
+ !strcmp(arg, "decompress"))
+ {
+ /* noop */
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ *fname = argv[i];
+ break;
+ }
+ }
+
+ /* proper number of arguments? */
+ if (i != argc - 1 || *fname == NULL)
+ return 1;
+
+ return 0;
+}
+
+static int doDecompress(int argc, char **argv)
+{
+ char *ifname = NULL;
+ char *ofname = NULL;
+ unsigned int verbose = 0;
+ FILE *inFile = NULL;
+ FILE *outFile = NULL;
+ elzma_decompress_handle hand = NULL;
+ unsigned int overwrite = 0;
+ unsigned int keep = 0;
+ elzma_file_format format;
+ const char *lzmaExt = ".lzma";
+ const char *lzipExt = ".lz";
+ const char *ext = ".lz";
+
+ if (0 != parseDecompressArgs(argc, argv, &ifname, &verbose, &keep, &overwrite))
+ {
+ fprintf(stderr, ELZMA_DECOMPRESS_USAGE);
+ return 1;
+ }
+
+ /* generate output file name */
+ if (strlen(ifname) > strlen(lzmaExt) &&
+ 0 == strcmp(lzmaExt, ifname + strlen(ifname) - strlen(lzmaExt)))
+ {
+ format = ELZMA_lzma;
+ ext = lzmaExt;
+ }
+ else if (strlen(ifname) > strlen(lzipExt) &&
+ 0 == strcmp(lzipExt, ifname + strlen(ifname) - strlen(lzipExt)))
+ {
+ format = ELZMA_lzip;
+ ext = lzipExt;
+ }
+ else
+ {
+ fprintf(stderr, "input file extension not recognized (expected either "
+ "%s or %s)",
+ lzmaExt, lzipExt);
+ return 1;
+ }
+
+ ofname = malloc(strlen(ifname) - strlen(ext));
+ ofname[0] = 0;
+ strncat(ofname, ifname, strlen(ifname) - strlen(ext));
+
+ /* now attempt to open input and ouput files */
+ /* XXX: stdin/stdout support */
+ if (0 != openFiles(ifname, &inFile, ofname, &outFile, overwrite))
+ {
+ return 1;
+ }
+
+ hand = elzma_decompress_alloc();
+ if (hand == NULL)
+ {
+ fprintf(stderr, "couldn't allocate decompression object\n");
+ deleteFile(ofname);
+ return 1;
+ }
+
+ if (ELZMA_E_OK != elzma_decompress_run(hand, elzmaReadFunc, (void *)inFile, elzmaWriteFunc,
+ (void *)outFile, format))
+ {
+ fprintf(stderr, "error decompressing\n");
+ deleteFile(ofname);
+ return 1;
+ }
+
+ elzma_decompress_free(&hand);
+
+ if (!keep)
+ deleteFile(ifname);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ const char *unelzma = "unelzma";
+ const char *unelzmaLose = "unelzma.exe";
+ const char *elzma = "elzma";
+ const char *elzmaLose = "elzma.exe";
+
+ enum
+ {
+ RM_NONE,
+ RM_COMPRESS,
+ RM_DECOMPRESS
+ } runmode = RM_NONE;
+
+ /* first we'll determine the mode we're running in, indicated by
+ * the binary name (argv[0]) or by the presence of a flag:
+ * one of -z, -d, -compress, --decompress */
+ if ((strlen(argv[0]) >= strlen(unelzma) &&
+ !strcmp((argv[0] + strlen(argv[0]) - strlen(unelzma)), unelzma)) ||
+ (strlen(argv[0]) >= strlen(unelzmaLose) &&
+ !strcmp((argv[0] + strlen(argv[0]) - strlen(unelzmaLose)), unelzmaLose)))
+ {
+ runmode = RM_DECOMPRESS;
+ }
+ else if ((strlen(argv[0]) >= strlen(elzma) &&
+ !strcmp((argv[0] + strlen(argv[0]) - strlen(elzma)), elzma)) ||
+ (strlen(argv[0]) >= strlen(elzmaLose) &&
+ !strcmp((argv[0] + strlen(argv[0]) - strlen(elzmaLose)), elzmaLose)))
+ {
+ runmode = RM_COMPRESS;
+ }
+
+ /* allow runmode to be overridded by a command line flag, first flag
+ * wins */
+ {
+ int i;
+ for (i = 1; i < argc; i++)
+ {
+ if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--decompress"))
+ {
+ runmode = RM_DECOMPRESS;
+ break;
+ }
+ else if (!strcmp(argv[i], "-z") || !strcmp(argv[i], "--compress"))
+ {
+ runmode = RM_COMPRESS;
+ break;
+ }
+ }
+ }
+
+ if (runmode != RM_COMPRESS && runmode != RM_DECOMPRESS)
+ {
+ fprintf(stderr, "couldn't determine whether "
+ "you want to compress or decompress\n");
+ return 1;
+ }
+
+ if (runmode == RM_COMPRESS)
+ return doCompress(argc, argv);
+ return doDecompress(argc, argv);
+}