diff options
Diffstat (limited to 'src/lzmadec/lzmadec.c')
-rw-r--r-- | src/lzmadec/lzmadec.c | 492 |
1 files changed, 0 insertions, 492 deletions
diff --git a/src/lzmadec/lzmadec.c b/src/lzmadec/lzmadec.c deleted file mode 100644 index 0b2adb97..00000000 --- a/src/lzmadec/lzmadec.c +++ /dev/null @@ -1,492 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file lzmadec.c -/// \brief Simple single-threaded tool to uncompress .lzma files -// -// Copyright (C) 2007 Lasse Collin -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -/////////////////////////////////////////////////////////////////////////////// - -#include "sysdefs.h" - -#include <errno.h> -#include <stdio.h> -#include <unistd.h> - -#ifdef WIN32 -# include <fcntl.h> -#endif - -#include "getopt.h" -#include "physmem.h" - - -enum return_code { - SUCCESS, - ERROR, - WARNING, -}; - - -enum format_type { - FORMAT_AUTO, - FORMAT_NATIVE, - FORMAT_ALONE, -}; - - -enum { - OPTION_FORMAT = INT_MIN, -}; - - -/// Input buffer -static uint8_t in_buf[BUFSIZ]; - -/// Output buffer -static uint8_t out_buf[BUFSIZ]; - -/// Decoder -static lzma_stream strm = LZMA_STREAM_INIT; - -/// Number of bytes to use memory at maximum -static uint64_t memlimit; - -/// Program name to be shown in error messages -static const char *argv0; - -/// File currently being processed -static FILE *file; - -/// Name of the file currently being processed -static const char *filename; - -static enum return_code exit_status = SUCCESS; - -static enum format_type format_type = FORMAT_AUTO; - -static bool force = false; - - -static void lzma_attribute((noreturn)) -help(void) -{ - printf( -"Usage: %s [OPTION]... [FILE]...\n" -"Uncompress files in the .lzma format to the standard output.\n" -"\n" -" -c, --stdout (ignored)\n" -" -d, --decompress (ignored)\n" -" -k, --keep (ignored)\n" -" -f, --force allow reading compressed data from a terminal\n" -" -M, --memory=NUM use NUM bytes of memory at maximum (0 means default);\n" -" the suffixes k, M, G, Ki, Mi, and Gi are supported.\n" -" --format=FMT accept only files in the given file format;\n" -" possible FMTs are `auto', `native', and alone',\n" -" -h, --help display this help and exit\n" -" -V, --version display version and license information and exit\n" -"\n" -"With no FILE, or when FILE is -, read standard input.\n" -"\n" -"On this configuration, the tool will use about %" PRIu64 - " MiB of memory at maximum.\n" -"\n" -"Report bugs to <" PACKAGE_BUGREPORT "> (in English or Finnish).\n", - argv0, ((uint64_t)(memlimit) + 512 * 1024) / (1024 * 1024)); - // Using PRIu64 above instead of %zu to support pre-C99 libc. - exit(0); -} - - -static void lzma_attribute((noreturn)) -version(void) -{ - printf( -"lzmadec (LZMA Utils) " PACKAGE_VERSION "\n" -"\n" -"Copyright (C) 1999-2006 Igor Pavlov\n" -"Copyright (C) 2007 Lasse Collin\n" -"\n" -"This program is free software; you can redistribute it and/or\n" -"modify it under the terms of the GNU Lesser General Public\n" -"License as published by the Free Software Foundation; either\n" -"version 2.1 of the License, or (at your option) any later version.\n" -"\n" -"This program is distributed in the hope that it will be useful,\n" -"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" -"Lesser General Public License for more details.\n" -"\n"); - exit(0); -} - - -/// Finds out the amount of physical memory in the system, and sets -/// a default memory usage limit. -static void -set_default_memlimit(void) -{ - const uint64_t mem = physmem(); - - if (mem == 0) - // Cannot autodetect, use 10 MiB as the default limit. - memlimit = (1U << 23) + (1U << 21); - else - // Limit is 33 % of RAM. - memlimit = mem / 3; - - return; -} - - -/// \brief Converts a string to size_t -/// -/// This is rudely copied from src/lzma/util.c and modified a little. :-( -/// -static size_t -str_to_uint64(const char *value) -{ - size_t result = 0; - - if (*value < '0' || *value > '9') { - fprintf(stderr, "%s: %s: Not a number", argv0, value); - exit(ERROR); - } - - do { - // Don't overflow. - if (result > (SIZE_MAX - 9) / 10) - return SIZE_MAX; - - result *= 10; - result += *value - '0'; - ++value; - } while (*value >= '0' && *value <= '9'); - - if (*value != '\0') { - // Look for suffix. - static const struct { - const char name[4]; - size_t multiplier; - } suffixes[] = { - { "k", 1000 }, - { "kB", 1000 }, - { "M", 1000000 }, - { "MB", 1000000 }, - { "G", 1000000000 }, - { "GB", 1000000000 }, - { "Ki", 1024 }, - { "KiB", 1024 }, - { "Mi", 1048576 }, - { "MiB", 1048576 }, - { "Gi", 1073741824 }, - { "GiB", 1073741824 } - }; - - size_t multiplier = 0; - for (size_t i = 0; i < ARRAY_SIZE(suffixes); ++i) { - if (strcmp(value, suffixes[i].name) == 0) { - multiplier = suffixes[i].multiplier; - break; - } - } - - if (multiplier == 0) { - fprintf(stderr, "%s: %s: Invalid suffix", - argv0, value); - exit(ERROR); - } - - // Don't overflow here either. - if (result > SIZE_MAX / multiplier) - result = SIZE_MAX; - else - result *= multiplier; - } - - return result; -} - - -/// Parses command line options. -static void -parse_options(int argc, char **argv) -{ - static const char short_opts[] = "cdkfM:hV"; - static const struct option long_opts[] = { - { "stdout", no_argument, NULL, 'c' }, - { "to-stdout", no_argument, NULL, 'c' }, - { "decompress", no_argument, NULL, 'd' }, - { "uncompress", no_argument, NULL, 'd' }, - { "force", no_argument, NULL, 'f' }, - { "keep", no_argument, NULL, 'k' }, - { "memory", required_argument, NULL, 'M' }, - { "format", required_argument, NULL, OPTION_FORMAT }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { NULL, 0, NULL, 0 } - }; - - int c; - - while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) - != -1) { - switch (c) { - case 'c': - case 'd': - case 'k': - break; - - case 'f': - force = true; - break; - - case 'M': - memlimit = str_to_uint64(optarg); - if (memlimit == 0) - set_default_memlimit(); - - break; - - case 'h': - help(); - - case 'V': - version(); - - case OPTION_FORMAT: { - if (strcmp("auto", optarg) == 0) { - format_type = FORMAT_AUTO; - } else if (strcmp("native", optarg) == 0) { - format_type = FORMAT_NATIVE; - } else if (strcmp("alone", optarg) == 0) { - format_type = FORMAT_ALONE; - } else { - fprintf(stderr, "%s: %s: Unknown file format " - "name\n", argv0, optarg); - exit(ERROR); - } - break; - } - - default: - exit(ERROR); - } - } - - return; -} - - -/// Initializes lzma_stream structure for decoding of a new Stream. -static void -init(void) -{ - const uint32_t flags = LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED; - lzma_ret ret; - - switch (format_type) { - case FORMAT_AUTO: - ret = lzma_auto_decoder(&strm, memlimit, flags); - break; - - case FORMAT_NATIVE: - ret = lzma_stream_decoder(&strm, memlimit, flags); - break; - - case FORMAT_ALONE: - ret = lzma_alone_decoder(&strm, memlimit); - break; - - default: - assert(0); - ret = LZMA_PROG_ERROR; - } - - if (ret != LZMA_OK) { - fprintf(stderr, "%s: ", argv0); - - if (ret == LZMA_MEM_ERROR) - fprintf(stderr, "%s\n", strerror(ENOMEM)); - else - fprintf(stderr, "Internal program error (bug)\n"); - - exit(ERROR); - } - - return; -} - - -static void -uncompress(void) -{ - if (file == stdin && !force && isatty(STDIN_FILENO)) { - fprintf(stderr, "%s: Compressed data not read from " - "a terminal.\n%s: Use `-f' to force reading " - "from a terminal, or `-h' for help.\n", - argv0, argv0); - exit(ERROR); - } - - init(); - - strm.avail_in = 0; - strm.next_out = out_buf; - strm.avail_out = BUFSIZ; - - lzma_action action = LZMA_RUN; - - while (true) { - if (strm.avail_in == 0) { - strm.next_in = in_buf; - strm.avail_in = fread(in_buf, 1, BUFSIZ, file); - - if (ferror(file)) { - // POSIX says that fread() sets errno if - // an error occurred. ferror() doesn't - // touch errno. - fprintf(stderr, "%s: %s: Error reading " - "input file: %s\n", - argv0, filename, - strerror(errno)); - exit(ERROR); - } - - if (feof(file)) - action = LZMA_FINISH; - } - - const lzma_ret 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(out_buf, 1, write_size, stdout) - != 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, "%s: Cannot write to " - "standard output: %s\n", argv0, - strerror(errno)); - exit(ERROR); - } - - strm.next_out = out_buf; - strm.avail_out = BUFSIZ; - } - - if (ret != LZMA_OK) { - // FIXME !!! Doesn't work with LZMA_Alone for the - // same reason as in process.c. - if (ret == LZMA_STREAM_END) - return; - - fprintf(stderr, "%s: %s: ", argv0, filename); - - // FIXME Add LZMA_*_CHECK and LZMA_FORMAT_ERROR. - switch (ret) { - case LZMA_DATA_ERROR: - fprintf(stderr, "File is corrupt\n"); - exit(ERROR); - - case LZMA_OPTIONS_ERROR: - fprintf(stderr, "Unsupported file " - "format or filters\n"); - exit(ERROR); - - case LZMA_MEM_ERROR: - fprintf(stderr, "%s\n", strerror(ENOMEM)); - exit(ERROR); - - case LZMA_MEMLIMIT_ERROR: - fprintf(stderr, "Memory usage limit " - "reached\n"); - exit(ERROR); - - case LZMA_BUF_ERROR: - fprintf(stderr, "Unexpected end of input\n"); - exit(ERROR); - - case LZMA_UNSUPPORTED_CHECK: - fprintf(stderr, "Unsupported type of " - "integrity check; not " - "verifying file integrity\n"); - exit_status = WARNING; - break; - - case LZMA_PROG_ERROR: - default: - fprintf(stderr, "Internal program " - "error (bug)\n"); - exit(ERROR); - } - } - } -} - - -int -main(int argc, char **argv) -{ - argv0 = argv[0]; - - set_default_memlimit(); - - parse_options(argc, argv); - - lzma_init_decoder(); - -#ifdef WIN32 - setmode(fileno(stdin), O_BINARY); - setmode(fileno(stdout), O_BINARY); -#endif - - if (optind == argc) { - file = stdin; - filename = "(stdin)"; - uncompress(); - } else { - do { - if (strcmp(argv[optind], "-") == 0) { - file = stdin; - filename = "(stdin)"; - uncompress(); - } else { - filename = argv[optind]; - file = fopen(filename, "rb"); - if (file == NULL) { - fprintf(stderr, "%s: %s: %s\n", - argv0, filename, - strerror(errno)); - exit(ERROR); - } - - uncompress(); - fclose(file); - } - } while (++optind < argc); - } - -#ifndef NDEBUG - // Free the memory only when debugging. Freeing wastes some time, - // but allows detecting possible memory leaks with Valgrind. - lzma_end(&strm); -#endif - - return exit_status; -} |