aboutsummaryrefslogtreecommitdiff
path: root/src/lzmadec/lzmadec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lzmadec/lzmadec.c')
-rw-r--r--src/lzmadec/lzmadec.c157
1 files changed, 60 insertions, 97 deletions
diff --git a/src/lzmadec/lzmadec.c b/src/lzmadec/lzmadec.c
index 1fc561b7..ed5947ad 100644
--- a/src/lzmadec/lzmadec.c
+++ b/src/lzmadec/lzmadec.c
@@ -65,14 +65,7 @@ static uint8_t out_buf[BUFSIZ];
static lzma_stream strm = LZMA_STREAM_INIT;
/// Number of bytes to use memory at maximum
-static size_t mem_limit;
-
-/// Memory allocation hooks
-static lzma_allocator allocator = {
- .alloc = (void *(*)(void *, size_t, size_t))(&lzma_memlimit_alloc),
- .free = (void (*)(void *, void *))(&lzma_memlimit_free),
- .opaque = NULL,
-};
+static size_t memlimit;
/// Program name to be shown in error messages
static const char *argv0;
@@ -116,7 +109,7 @@ help(void)
" MiB of memory at maximum.\n"
"\n"
"Report bugs to <" PACKAGE_BUGREPORT "> (in English or Finnish).\n",
- argv0, ((uint64_t)(mem_limit) + 512 * 1024) / (1024 * 1024));
+ argv0, ((uint64_t)(memlimit) + 512 * 1024) / (1024 * 1024));
// Using PRIu64 above instead of %zu to support pre-C99 libc.
exit(0);
}
@@ -148,7 +141,7 @@ version(void)
/// Finds out the amount of physical memory in the system, and sets
/// a default memory usage limit.
static void
-set_default_mem_limit(void)
+set_default_memlimit(void)
{
uint64_t mem = physmem();
if (mem != 0) {
@@ -159,10 +152,10 @@ set_default_mem_limit(void)
mem = SIZE_MAX;
#endif
- mem_limit = mem / 3;
+ memlimit = mem / 3;
} else {
// Cannot autodetect, use 10 MiB as the default limit.
- mem_limit = (1U << 23) + (1U << 21);
+ memlimit = (1U << 23) + (1U << 21);
}
return;
@@ -272,7 +265,7 @@ parse_options(int argc, char **argv)
break;
case 'M':
- mem_limit = str_to_size(optarg);
+ memlimit = str_to_size(optarg);
break;
case 'h':
@@ -309,19 +302,20 @@ parse_options(int argc, char **argv)
static void
init(void)
{
+ const uint32_t flags = LZMA_WARN_UNSUPPORTED_CHECK | LZMA_CONCATENATED;
lzma_ret ret;
switch (format_type) {
case FORMAT_AUTO:
- ret = lzma_auto_decoder(&strm);
+ ret = lzma_auto_decoder(&strm, memlimit, flags);
break;
case FORMAT_NATIVE:
- ret = lzma_stream_decoder(&strm);
+ ret = lzma_stream_decoder(&strm, memlimit, flags);
break;
case FORMAT_ALONE:
- ret = lzma_alone_decoder(&strm);
+ ret = lzma_alone_decoder(&strm, memlimit);
break;
default:
@@ -345,50 +339,6 @@ init(void)
static void
-read_input(void)
-{
- 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);
- }
-
- return;
-}
-
-
-static bool
-skip_padding(void)
-{
- // Handle concatenated Streams. There can be arbitrary number of
- // nul-byte padding between the Streams, which must be ignored.
- //
- // NOTE: Concatenating LZMA_Alone files works only if at least
- // one of lc, lp, and pb is non-zero. Using the concatenation
- // on LZMA_Alone files is strongly discouraged.
- while (true) {
- while (strm.avail_in > 0) {
- if (*strm.next_in != '\0')
- return true;
-
- ++strm.next_in;
- --strm.avail_in;
- }
-
- if (feof(file))
- return false;
-
- read_input();
- }
-}
-
-
-static void
uncompress(void)
{
if (file == stdin && !force && isatty(STDIN_FILENO)) {
@@ -400,44 +350,65 @@ uncompress(void)
}
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)
- read_input();
+ 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);
+ }
- strm.next_out = out_buf;
- strm.avail_out = BUFSIZ;
+ if (feof(file))
+ action = LZMA_FINISH;
+ }
- const lzma_ret ret = lzma_code(&strm, LZMA_RUN);
+ 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. Checking write error
- // needs to be done before checking decoder error due to
- // how concatenated Streams are handled a few lines later.
- 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);
+ // 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) {
- if (ret == LZMA_STREAM_END) {
- if (skip_padding()) {
- init();
- continue;
- }
-
+ // 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");
@@ -452,6 +423,11 @@ uncompress(void)
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);
@@ -479,23 +455,12 @@ main(int argc, char **argv)
{
argv0 = argv[0];
- set_default_mem_limit();
+ set_default_memlimit();
parse_options(argc, argv);
lzma_init_decoder();
- lzma_memlimit *mem_limiter = lzma_memlimit_create(mem_limit);
- if (mem_limiter == NULL) {
- fprintf(stderr, "%s: %s\n", argv0, strerror(ENOMEM));
- exit(ERROR);
- }
-
- assert(lzma_memlimit_count(mem_limiter) == 0);
-
- allocator.opaque = mem_limiter;
- strm.allocator = &allocator;
-
#ifdef WIN32
setmode(fileno(stdin), O_BINARY);
setmode(fileno(stdout), O_BINARY);
@@ -531,8 +496,6 @@ main(int argc, char **argv)
// Free the memory only when debugging. Freeing wastes some time,
// but allows detecting possible memory leaks with Valgrind.
lzma_end(&strm);
- assert(lzma_memlimit_count(mem_limiter) == 0);
- lzma_memlimit_end(mem_limiter, false);
#endif
return exit_status;