aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/common/raw_common.c
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2008-06-18 18:02:10 +0300
committerLasse Collin <lasse.collin@tukaani.org>2008-06-18 18:02:10 +0300
commit7d17818cec8597f847b0a2537fde991bbc3d9e96 (patch)
tree9c41502e3eb96f103fe98e13456b382fbba7a292 /src/liblzma/common/raw_common.c
parentUpdate the file format specification draft. The new one is (diff)
downloadxz-7d17818cec8597f847b0a2537fde991bbc3d9e96.tar.xz
Update the code to mostly match the new simpler file format
specification. Simplify things by removing most of the support for known uncompressed size in most places. There are some miscellaneous changes here and there too. The API of liblzma has got many changes and still some more will be done soon. While most of the code has been updated, some things are not fixed (the command line tool will choke with invalid filter chain, if nothing else). Subblock filter is somewhat broken for now. It will be updated once the encoded format of the Subblock filter has been decided.
Diffstat (limited to 'src/liblzma/common/raw_common.c')
-rw-r--r--src/liblzma/common/raw_common.c178
1 files changed, 64 insertions, 114 deletions
diff --git a/src/liblzma/common/raw_common.c b/src/liblzma/common/raw_common.c
index d45bf4de..35252fc2 100644
--- a/src/liblzma/common/raw_common.c
+++ b/src/liblzma/common/raw_common.c
@@ -20,122 +20,81 @@
#include "raw_common.h"
-/// \brief Prepares the filter chain
-///
-/// Prepares the filter chain by setting uncompressed sizes for each filter,
-/// and adding implicit Subblock filter when needed.
-///
-/// \return true if error occurred, false on success.
-///
-static bool
-prepare(lzma_vli *id, lzma_vli *uncompressed_size, bool allow_implicit)
+static lzma_ret
+validate_options(const lzma_options_filter *options, size_t *count)
{
- bool needs_end_of_input = false;
-
- switch (id[0]) {
- case LZMA_FILTER_COPY:
- case LZMA_FILTER_X86:
- case LZMA_FILTER_POWERPC:
- case LZMA_FILTER_IA64:
- case LZMA_FILTER_ARM:
- case LZMA_FILTER_ARMTHUMB:
- case LZMA_FILTER_SPARC:
- case LZMA_FILTER_DELTA:
- uncompressed_size[1] = uncompressed_size[0];
- needs_end_of_input = true;
- break;
-
- case LZMA_FILTER_SUBBLOCK:
- case LZMA_FILTER_LZMA:
- // These change the size of the data unpredictably.
- uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
- break;
-
- case LZMA_FILTER_SUBBLOCK_HELPER:
- uncompressed_size[1] = uncompressed_size[0];
- break;
-
- default:
- // Unknown filter.
- return true;
- }
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
- // Is this the last filter in the chain?
- if (id[1] == LZMA_VLI_VALUE_UNKNOWN) {
- if (needs_end_of_input && allow_implicit
- && uncompressed_size[0]
- == LZMA_VLI_VALUE_UNKNOWN) {
- // Add implicit Subblock filter.
- id[1] = LZMA_FILTER_SUBBLOCK;
- uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
- id[2] = LZMA_VLI_VALUE_UNKNOWN;
+ // Number of non-last filters that may change the size of the data
+ // significantly (that is, more than 1-2 % or so).
+ size_t change = 0;
+
+ // True if the last filter in the given chain is actually usable as
+ // the last filter. Only filters that support embedding End of Payload
+ // Marker can be used as the last filter in the chain.
+ bool last_ok = false;
+
+ size_t i;
+ for (i = 0; options[i].id != LZMA_VLI_VALUE_UNKNOWN; ++i) {
+ switch (options[i].id) {
+ // Not #ifdeffing these for simplicity.
+ case LZMA_FILTER_X86:
+ case LZMA_FILTER_POWERPC:
+ case LZMA_FILTER_IA64:
+ case LZMA_FILTER_ARM:
+ case LZMA_FILTER_ARMTHUMB:
+ case LZMA_FILTER_SPARC:
+ case LZMA_FILTER_DELTA:
+ // These don't change the size of the data and cannot
+ // be used as the last filter in the chain.
+ last_ok = false;
+ break;
+
+#ifdef HAVE_FILTER_SUBBLOCK
+ case LZMA_FILTER_SUBBLOCK:
+ last_ok = true;
+ ++change;
+ break;
+#endif
+
+#ifdef HAVE_FILTER_LZMA
+ case LZMA_FILTER_LZMA:
+ last_ok = true;
+ break;
+#endif
+
+ default:
+ return LZMA_HEADER_ERROR;
}
-
- return false;
}
- return prepare(id + 1, uncompressed_size + 1, allow_implicit);
+ // There must be 1-4 filters and the last filter must be usable as
+ // the last filter in the chain.
+ if (i == 0 || i > 4 || !last_ok)
+ return LZMA_HEADER_ERROR;
+
+ // At maximum of two non-last filters are allowed to change the
+ // size of the data.
+ if (change > 2)
+ return LZMA_HEADER_ERROR;
+
+ *count = i;
+ return LZMA_OK;
}
extern lzma_ret
lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
- const lzma_options_filter *options, lzma_vli uncompressed_size,
+ const lzma_options_filter *options,
lzma_init_function (*get_function)(lzma_vli id),
- bool allow_implicit, bool is_encoder)
+ bool is_encoder)
{
- if (options == NULL || !lzma_vli_is_valid(uncompressed_size))
- return LZMA_PROG_ERROR;
-
- // Count the number of filters in the chain.
- size_t count = 0;
- while (options[count].id != LZMA_VLI_VALUE_UNKNOWN)
- ++count;
-
- // Allocate enough space from the stack for IDs and uncompressed
- // sizes. We need two extra: possible implicit Subblock and end
- // of array indicator.
- lzma_vli ids[count + 2];
- lzma_vli uncompressed_sizes[count + 2];
- bool using_implicit = false;
-
- uncompressed_sizes[0] = uncompressed_size;
-
- if (count == 0) {
- if (!allow_implicit)
- return LZMA_PROG_ERROR;
-
- count = 1;
- using_implicit = true;
-
- // Special case: no filters were specified, so an implicit
- // Copy or Subblock filter is used.
- if (uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
- ids[0] = LZMA_FILTER_SUBBLOCK;
- else
- ids[0] = LZMA_FILTER_COPY;
+ // Do some basic validation and get the number of filters.
+ size_t count;
+ return_if_error(validate_options(options, &count));
- ids[1] = LZMA_VLI_VALUE_UNKNOWN;
-
- } else {
- // Prepare the ids[] and uncompressed_sizes[].
- for (size_t i = 0; i < count; ++i)
- ids[i] = options[i].id;
-
- ids[count] = LZMA_VLI_VALUE_UNKNOWN;
-
- if (prepare(ids, uncompressed_sizes, allow_implicit))
- return LZMA_HEADER_ERROR;
-
- // Check if implicit Subblock filter was added.
- if (ids[count] != LZMA_VLI_VALUE_UNKNOWN) {
- assert(ids[count] == LZMA_FILTER_SUBBLOCK);
- ++count;
- using_implicit = true;
- }
- }
-
- // Set the filter functions, and copy uncompressed sizes and options.
+ // Set the filter functions and copy the options pointer.
lzma_filter_info filters[count + 1];
if (is_encoder) {
for (size_t i = 0; i < count; ++i) {
@@ -144,29 +103,20 @@ lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
// of the uncompressed data.
const size_t j = count - i - 1;
- filters[j].init = get_function(ids[i]);
+ filters[j].init = get_function(options[i].id);
if (filters[j].init == NULL)
return LZMA_HEADER_ERROR;
filters[j].options = options[i].options;
- filters[j].uncompressed_size = uncompressed_sizes[i];
}
-
- if (using_implicit)
- filters[0].options = NULL;
-
} else {
for (size_t i = 0; i < count; ++i) {
- filters[i].init = get_function(ids[i]);
+ filters[i].init = get_function(options[i].id);
if (filters[i].init == NULL)
return LZMA_HEADER_ERROR;
filters[i].options = options[i].options;
- filters[i].uncompressed_size = uncompressed_sizes[i];
}
-
- if (using_implicit)
- filters[count - 1].options = NULL;
}
// Terminate the array.