aboutsummaryrefslogtreecommitdiff
path: root/src/lzmadec/lzmadec.c
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2008-08-28 22:53:15 +0300
committerLasse Collin <lasse.collin@tukaani.org>2008-08-28 22:53:15 +0300
commit3b34851de1eaf358cf9268922fa0eeed8278d680 (patch)
tree7bab212af647541df64227a8d350d17a2e789f6b /src/lzmadec/lzmadec.c
parentFix test_filter_flags to match the new restriction of lc+lp. (diff)
downloadxz-3b34851de1eaf358cf9268922fa0eeed8278d680.tar.xz
Sort of garbage collection commit. :-| Many things are still
broken. API has changed a lot and it will still change a little more here and there. The command line tool doesn't have all the required changes to reflect the API changes, so it's easy to get "internal error" or trigger assertions.
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;