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 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 || !implicit || uncompressed_size[0]
66 != LZMA_VLI_VALUE_UNKNOWN)
69 // Add implicit Subblock filter.
70 id[1] = LZMA_FILTER_SUBBLOCK;
71 uncompressed_size[1] = LZMA_VLI_VALUE_UNKNOWN;
72 id[2] = LZMA_VLI_VALUE_UNKNOWN;
75 return prepare(id + 1, uncompressed_size + 1, implicit);
80 lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
81 const lzma_options_filter *options, lzma_vli uncompressed_size,
82 lzma_init_function (*get_function)(lzma_vli id),
83 bool allow_implicit, bool is_encoder)
85 if (options == NULL || !lzma_vli_is_valid(uncompressed_size))
86 return LZMA_PROG_ERROR;
88 // Count the number of filters in the chain.
90 while (options[count].id != LZMA_VLI_VALUE_UNKNOWN)
93 // Allocate enough space from the stack for IDs and uncompressed
94 // sizes. We need two extra: possible implicit Subblock and end
95 // of array indicator.
96 lzma_vli ids[count + 2];
97 lzma_vli uncompressed_sizes[count + 2];
98 bool using_implicit = false;
100 uncompressed_sizes[0] = uncompressed_size;
104 return LZMA_PROG_ERROR;
107 using_implicit = true;
109 // Special case: no filters were specified, so an implicit
110 // Copy or Subblock filter is used.
111 if (uncompressed_size == LZMA_VLI_VALUE_UNKNOWN)
112 ids[0] = LZMA_FILTER_SUBBLOCK;
114 ids[0] = LZMA_FILTER_COPY;
116 ids[1] = LZMA_VLI_VALUE_UNKNOWN;
119 // Prepare the ids[] and uncompressed_sizes[].
120 for (size_t i = 0; i < count; ++i)
121 ids[i] = options[i].id;
123 ids[count] = LZMA_VLI_VALUE_UNKNOWN;
125 if (prepare(ids, uncompressed_sizes, allow_implicit))
126 return LZMA_HEADER_ERROR;
128 // Check if implicit Subblock filter was added.
129 if (ids[count] != LZMA_VLI_VALUE_UNKNOWN) {
130 assert(ids[count] == LZMA_FILTER_SUBBLOCK);
132 using_implicit = true;
136 // Set the filter functions, and copy uncompressed sizes and options.
137 lzma_filter_info filters[count + 1];
139 for (size_t i = 0; i < count; ++i) {
140 // The order of the filters is reversed in the
141 // encoder. It allows more efficient handling
142 // of the uncompressed data.
143 const size_t j = count - i - 1;
145 filters[j].init = get_function(ids[i]);
146 if (filters[j].init == NULL)
147 return LZMA_HEADER_ERROR;
149 filters[j].options = options[i].options;
150 filters[j].uncompressed_size = uncompressed_sizes[i];
154 filters[0].options = NULL;
157 for (size_t i = 0; i < count; ++i) {
158 filters[i].init = get_function(ids[i]);
159 if (filters[i].init == NULL)
160 return LZMA_HEADER_ERROR;
162 filters[i].options = options[i].options;
163 filters[i].uncompressed_size = uncompressed_sizes[i];
167 filters[count - 1].options = NULL;
170 // Terminate the array.
171 filters[count].init = NULL;
173 // Initialize the filters.
174 return lzma_next_filter_init(next, allocator, filters);