1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief Stuff shared between raw encoder and raw decoder
6 // Copyright (C) 2007 Lasse Collin
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
18 ///////////////////////////////////////////////////////////////////////////////
20 #include "raw_common.h"
23 /// \brief Prepares the filter chain
25 /// Prepares the filter chain by setting uncompressed sizes for each filter,
26 /// and adding implicit Subblock filter when needed.
28 /// \return true if error occurred, false on success.
31 prepare(lzma_vli *id, lzma_vli *uncompressed_size, bool allow_implicit)
33 bool needs_end_of_input = false;
36 case LZMA_FILTER_COPY:
38 case LZMA_FILTER_POWERPC:
39 case LZMA_FILTER_IA64:
41 case LZMA_FILTER_ARMTHUMB:
42 case LZMA_FILTER_SPARC:
43 case LZMA_FILTER_DELTA:
44 uncompressed_size[1] = uncompressed_size[0];
45 needs_end_of_input = true;
48 case LZMA_FILTER_SUBBLOCK:
49 case LZMA_FILTER_LZMA:
50 // These change the size of the data unpredictably.
51 uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
54 case LZMA_FILTER_SUBBLOCK_HELPER:
55 uncompressed_size[1] = uncompressed_size[0];
63 // Is this the last filter in the chain?
64 if (id[1] == LZMA_VLI_VALUE_UNKNOWN) {
65 if (needs_end_of_input && allow_implicit
66 && uncompressed_size[0]
67 == LZMA_VLI_VALUE_UNKNOWN) {
68 // Add implicit Subblock filter.
69 id[1] = LZMA_FILTER_SUBBLOCK;
70 uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
71 id[2] = LZMA_VLI_VALUE_UNKNOWN;
77 return prepare(id + 1, uncompressed_size + 1, allow_implicit);
82 lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
83 const lzma_options_filter *options, lzma_vli uncompressed_size,
84 lzma_init_function (*get_function)(lzma_vli id),
85 bool allow_implicit, bool is_encoder)
87 if (options == NULL || !lzma_vli_is_valid(uncompressed_size))
88 return LZMA_PROG_ERROR;
90 // Count the number of filters in the chain.
92 while (options[count].id != LZMA_VLI_VALUE_UNKNOWN)
95 // Allocate enough space from the stack for IDs and uncompressed
96 // sizes. We need two extra: possible implicit Subblock and end
97 // of array indicator.
98 lzma_vli ids[count + 2];
99 lzma_vli uncompressed_sizes[count + 2];
100 bool using_implicit = false;
102 uncompressed_sizes[0] = uncompressed_size;
106 return LZMA_PROG_ERROR;
109 using_implicit = true;
111 // Special case: no filters were specified, so an implicit
112 // Copy or Subblock filter is used.
113 if (uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
114 ids[0] = LZMA_FILTER_SUBBLOCK;
116 ids[0] = LZMA_FILTER_COPY;
118 ids[1] = LZMA_VLI_VALUE_UNKNOWN;
121 // Prepare the ids[] and uncompressed_sizes[].
122 for (size_t i = 0; i < count; ++i)
123 ids[i] = options[i].id;
125 ids[count] = LZMA_VLI_VALUE_UNKNOWN;
127 if (prepare(ids, uncompressed_sizes, allow_implicit))
128 return LZMA_HEADER_ERROR;
130 // Check if implicit Subblock filter was added.
131 if (ids[count] != LZMA_VLI_VALUE_UNKNOWN) {
132 assert(ids[count] == LZMA_FILTER_SUBBLOCK);
134 using_implicit = true;
138 // Set the filter functions, and copy uncompressed sizes and options.
139 lzma_filter_info filters[count + 1];
141 for (size_t i = 0; i < count; ++i) {
142 // The order of the filters is reversed in the
143 // encoder. It allows more efficient handling
144 // of the uncompressed data.
145 const size_t j = count - i - 1;
147 filters[j].init = get_function(ids[i]);
148 if (filters[j].init == NULL)
149 return LZMA_HEADER_ERROR;
151 filters[j].options = options[i].options;
152 filters[j].uncompressed_size = uncompressed_sizes[i];
156 filters[0].options = NULL;
159 for (size_t i = 0; i < count; ++i) {
160 filters[i].init = get_function(ids[i]);
161 if (filters[i].init == NULL)
162 return LZMA_HEADER_ERROR;
164 filters[i].options = options[i].options;
165 filters[i].uncompressed_size = uncompressed_sizes[i];
169 filters[count - 1].options = NULL;
172 // Terminate the array.
173 filters[count].init = NULL;
175 // Initialize the filters.
176 return lzma_next_filter_init(next, allocator, filters);