aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/liblzma/api/lzma/container.h25
-rw-r--r--src/liblzma/common/common.h7
-rw-r--r--src/liblzma/common/stream_decoder_mt.c50
3 files changed, 56 insertions, 26 deletions
diff --git a/src/liblzma/api/lzma/container.h b/src/liblzma/api/lzma/container.h
index b2b912d5..564c6aaf 100644
--- a/src/liblzma/api/lzma/container.h
+++ b/src/liblzma/api/lzma/container.h
@@ -73,7 +73,7 @@ typedef struct {
*
* Decoder: Bitwise-or of zero or more of the decoder flags:
* LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
- * LZMA_TELL_ANY_CHECK, LZMA_CONCATENATED
+ * LZMA_TELL_ANY_CHECK, LZMA_CONCATENATED, LZMA_FAIL_FAST
*/
uint32_t flags;
@@ -616,6 +616,29 @@ extern LZMA_API(lzma_ret) lzma_microlzma_encoder(
/**
+ * This flag makes the threaded decoder report errors (like LZMA_DATA_ERROR)
+ * as soon as they are detected. This saves time when the application has no
+ * interest in a partially decompressed truncated or corrupt file. Note that
+ * due to timing randomness, if the same truncated or corrupt input is
+ * decompressed multiple times with this flag, a different amount of output
+ * may be produced by different runs, and even the error code might vary.
+ *
+ * Without this flag the threaded decoder will provide as much output as
+ * possible at first and then report the pending error. This default behavior
+ * matches the single-threaded decoder and provides repeatable behavior
+ * with truncated or corrupt input. There are a few special cases where the
+ * behavior can still differ like memory allocation failures (LZMA_MEM_ERROR).
+ *
+ * Single-threaded decoders currently ignore this flag.
+ *
+ * Support for this flag was added in liblzma 5.3.3alpha. Note that in older
+ * versions this flag isn't supported (LZMA_OPTIONS_ERROR) even by functions
+ * that ignore this flag in newer liblzma versions.
+ */
+#define LZMA_FAIL_FAST UINT32_C(0x20)
+
+
+/**
* \brief Initialize .xz Stream decoder
*
* \param strm Pointer to properly prepared lzma_stream
diff --git a/src/liblzma/common/common.h b/src/liblzma/common/common.h
index 67996228..36366dbc 100644
--- a/src/liblzma/common/common.h
+++ b/src/liblzma/common/common.h
@@ -67,14 +67,15 @@
#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
-/// Supported flags that can be passed to lzma_stream_decoder()
-/// or lzma_auto_decoder().
+/// Supported flags that can be passed to lzma_stream_decoder(),
+/// lzma_auto_decoder(), or lzma_stream_decoder_mt().
#define LZMA_SUPPORTED_FLAGS \
( LZMA_TELL_NO_CHECK \
| LZMA_TELL_UNSUPPORTED_CHECK \
| LZMA_TELL_ANY_CHECK \
| LZMA_IGNORE_CHECK \
- | LZMA_CONCATENATED )
+ | LZMA_CONCATENATED \
+ | LZMA_FAIL_FAST )
/// Largest valid lzma_action value as unsigned integer.
diff --git a/src/liblzma/common/stream_decoder_mt.c b/src/liblzma/common/stream_decoder_mt.c
index 7f445982..32e0b892 100644
--- a/src/liblzma/common/stream_decoder_mt.c
+++ b/src/liblzma/common/stream_decoder_mt.c
@@ -300,6 +300,10 @@ struct lzma_stream_coder {
/// Stream Padding is a multiple of four bytes.
bool concatenated;
+ /// If true, we will return any errors immediately instead of first
+ /// producing all output before the location of the error.
+ bool fail_fast;
+
/// When decoding concatenated Streams, this is true as long as we
/// are decoding the first Stream. This is needed to avoid misleading
@@ -711,13 +715,12 @@ read_output_and_wait(struct lzma_stream_coder *coder,
coder->pending_error
= coder->thread_error;
- // FIXME? Add a flag to do this conditionally?
- // That way errors would get reported to the
- // application without a delay.
-// if (coder->fast_errors) {
-// ret = coder->thread_error;
-// break;
-// }
+ // If LZMA_FAIL_FAST was used, report errors
+ // from worker threads immediately.
+ if (coder->fail_fast) {
+ ret = coder->thread_error;
+ break;
+ }
}
// Check if decoding of the next Block can be started.
@@ -1690,22 +1693,24 @@ stream_decode_mt(void *coder_ptr, const lzma_allocator *allocator,
break;
case SEQ_ERROR:
- // Let the application get all data before the point where
- // the error was detected. This matches the behavior of
- // single-threaded use.
- //
- // FIXME? Some errors (LZMA_MEM_ERROR) don't get here,
- // they are returned immediately. Thus in rare cases the
- // output will be less than in single-threaded mode. But
- // maybe this doesn't matter much in practice.
- return_if_error(read_output_and_wait(coder, allocator,
- out, out_pos, out_size,
- NULL, true, &wait_abs, &has_blocked));
+ if (!coder->fail_fast) {
+ // Let the application get all data before the point
+ // where the error was detected. This matches the
+ // behavior of single-threaded use.
+ //
+ // FIXME? Some errors (LZMA_MEM_ERROR) don't get here,
+ // they are returned immediately. Thus in rare cases
+ // the output will be less than in the single-threaded
+ // mode. Maybe this doesn't matter much in practice.
+ return_if_error(read_output_and_wait(coder, allocator,
+ out, out_pos, out_size,
+ NULL, true, &wait_abs, &has_blocked));
- // We get here only if the error happened in the main thread,
- // for example, unsupported Block Header.
- if (!lzma_outq_is_empty(&coder->outq))
- return LZMA_OK;
+ // We get here only if the error happened in the main
+ // thread, for example, unsupported Block Header.
+ if (!lzma_outq_is_empty(&coder->outq))
+ return LZMA_OK;
+ }
return coder->pending_error;
@@ -1900,6 +1905,7 @@ stream_decoder_mt_init(lzma_next_coder *next, const lzma_allocator *allocator,
coder->tell_any_check = (options->flags & LZMA_TELL_ANY_CHECK) != 0;
coder->ignore_check = (options->flags & LZMA_IGNORE_CHECK) != 0;
coder->concatenated = (options->flags & LZMA_CONCATENATED) != 0;
+ coder->fail_fast = (options->flags & LZMA_FAIL_FAST) != 0;
coder->first_stream = true;
coder->out_was_filled = false;