]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/filter_encoder.c
The LZMA2 decoder fix introduced a bug to LZ decoder,
[icculus/xz.git] / src / liblzma / common / filter_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       filter_decoder.c
4 /// \brief      Filter ID mapping to filter-specific functions
5 //
6 //  Copyright (C) 2008 Lasse Collin
7 //
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.
12 //
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.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "filter_encoder.h"
21 #include "filter_common.h"
22 #include "lzma_encoder.h"
23 #include "lzma2_encoder.h"
24 #include "subblock_encoder.h"
25 #include "simple_encoder.h"
26 #include "delta_encoder.h"
27
28
29 typedef struct {
30         /// Filter ID
31         lzma_vli id;
32
33         /// Initializes the filter encoder and calls lzma_next_filter_init()
34         /// for filters + 1.
35         lzma_init_function init;
36
37         /// Calculates memory usage of the encoder. If the options are
38         /// invalid, UINT64_MAX is returned.
39         uint64_t (*memusage)(const void *options);
40
41         /// Calculates the minimum sane size for Blocks (or other types of
42         /// chunks) to which the input data can be splitted to make
43         /// multithreaded encoding possible. If this is NULL, it is assumed
44         /// that the encoder is fast enough with single thread.
45         lzma_vli (*chunk_size)(const void *options);
46
47         /// Tells the size of the Filter Properties field. If options are
48         /// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed
49         /// is used.
50         lzma_ret (*props_size_get)(uint32_t *size, const void *options);
51         uint32_t props_size_fixed;
52
53         /// Encodes Filter Properties.
54         ///
55         /// \return     - LZMA_OK: Properties encoded sucessfully.
56         ///             - LZMA_OPTIONS_ERROR: Unsupported options
57         ///             - LZMA_PROG_ERROR: Invalid options or not enough
58         ///               output space
59         lzma_ret (*props_encode)(const void *options, uint8_t *out);
60
61 } lzma_filter_encoder;
62
63
64 static const lzma_filter_encoder encoders[] = {
65 #ifdef HAVE_ENCODER_LZMA1
66         {
67                 .id = LZMA_FILTER_LZMA1,
68                 .init = &lzma_lzma_encoder_init,
69                 .memusage = &lzma_lzma_encoder_memusage,
70                 .chunk_size = NULL, // FIXME
71                 .props_size_get = NULL,
72                 .props_size_fixed = 5,
73                 .props_encode = &lzma_lzma_props_encode,
74         },
75 #endif
76 #ifdef HAVE_ENCODER_LZMA2
77         {
78                 .id = LZMA_FILTER_LZMA2,
79                 .init = &lzma_lzma2_encoder_init,
80                 .memusage = &lzma_lzma2_encoder_memusage,
81                 .chunk_size = NULL, // FIXME
82                 .props_size_get = NULL,
83                 .props_size_fixed = 1,
84                 .props_encode = &lzma_lzma2_props_encode,
85         },
86 #endif
87 #ifdef HAVE_ENCODER_SUBBLOCK
88         {
89                 .id = LZMA_FILTER_SUBBLOCK,
90                 .init = &lzma_subblock_encoder_init,
91 //              .memusage = &lzma_subblock_encoder_memusage,
92                 .chunk_size = NULL,
93                 .props_size_get = NULL,
94                 .props_size_fixed = 0,
95                 .props_encode = NULL,
96         },
97 #endif
98 #ifdef HAVE_ENCODER_X86
99         {
100                 .id = LZMA_FILTER_X86,
101                 .init = &lzma_simple_x86_encoder_init,
102                 .memusage = NULL,
103                 .chunk_size = NULL,
104                 .props_size_get = &lzma_simple_props_size,
105                 .props_encode = &lzma_simple_props_encode,
106         },
107 #endif
108 #ifdef HAVE_ENCODER_POWERPC
109         {
110                 .id = LZMA_FILTER_POWERPC,
111                 .init = &lzma_simple_powerpc_encoder_init,
112                 .memusage = NULL,
113                 .chunk_size = NULL,
114                 .props_size_get = &lzma_simple_props_size,
115                 .props_encode = &lzma_simple_props_encode,
116         },
117 #endif
118 #ifdef HAVE_ENCODER_IA64
119         {
120                 .id = LZMA_FILTER_IA64,
121                 .init = &lzma_simple_ia64_encoder_init,
122                 .memusage = NULL,
123                 .chunk_size = NULL,
124                 .props_size_get = &lzma_simple_props_size,
125                 .props_encode = &lzma_simple_props_encode,
126         },
127 #endif
128 #ifdef HAVE_ENCODER_ARM
129         {
130                 .id = LZMA_FILTER_ARM,
131                 .init = &lzma_simple_arm_encoder_init,
132                 .memusage = NULL,
133                 .chunk_size = NULL,
134                 .props_size_get = &lzma_simple_props_size,
135                 .props_encode = &lzma_simple_props_encode,
136         },
137 #endif
138 #ifdef HAVE_ENCODER_ARMTHUMB
139         {
140                 .id = LZMA_FILTER_ARMTHUMB,
141                 .init = &lzma_simple_armthumb_encoder_init,
142                 .memusage = NULL,
143                 .chunk_size = NULL,
144                 .props_size_get = &lzma_simple_props_size,
145                 .props_encode = &lzma_simple_props_encode,
146         },
147 #endif
148 #ifdef HAVE_ENCODER_SPARC
149         {
150                 .id = LZMA_FILTER_SPARC,
151                 .init = &lzma_simple_sparc_encoder_init,
152                 .memusage = NULL,
153                 .chunk_size = NULL,
154                 .props_size_get = &lzma_simple_props_size,
155                 .props_encode = &lzma_simple_props_encode,
156         },
157 #endif
158 #ifdef HAVE_ENCODER_DELTA
159         {
160                 .id = LZMA_FILTER_DELTA,
161                 .init = &lzma_delta_encoder_init,
162                 .memusage = &lzma_delta_coder_memusage,
163                 .chunk_size = NULL,
164                 .props_size_get = NULL,
165                 .props_size_fixed = 1,
166                 .props_encode = &lzma_delta_props_encode,
167         },
168 #endif
169 };
170
171
172 static const lzma_filter_encoder *
173 encoder_find(lzma_vli id)
174 {
175         for (size_t i = 0; i < ARRAY_SIZE(encoders); ++i)
176                 if (encoders[i].id == id)
177                         return encoders + i;
178
179         return NULL;
180 }
181
182
183 extern LZMA_API lzma_bool
184 lzma_filter_encoder_is_supported(lzma_vli id)
185 {
186         return encoder_find(id) != NULL;
187 }
188
189
190 extern lzma_ret
191 lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
192                 const lzma_filter *options)
193 {
194         return lzma_raw_coder_init(next, allocator,
195                         options, (lzma_filter_find)(&encoder_find), true);
196 }
197
198
199 extern LZMA_API lzma_ret
200 lzma_raw_encoder(lzma_stream *strm, const lzma_filter *options)
201 {
202         lzma_next_strm_init(lzma_raw_coder_init, strm, options,
203                         (lzma_filter_find)(&encoder_find), true);
204
205         strm->internal->supported_actions[LZMA_RUN] = true;
206         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
207         strm->internal->supported_actions[LZMA_FINISH] = true;
208
209         return LZMA_OK;
210 }
211
212
213 extern LZMA_API uint64_t
214 lzma_memusage_encoder(const lzma_filter *filters)
215 {
216         return lzma_memusage_coder(
217                         (lzma_filter_find)(&encoder_find), filters);
218 }
219
220
221 extern LZMA_API lzma_vli
222 lzma_chunk_size(const lzma_filter *filters)
223 {
224         lzma_vli max = 0;
225
226         for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
227                 const lzma_filter_encoder *const fe
228                                 = encoder_find(filters[i].id);
229                 if (fe->chunk_size != NULL) {
230                         const lzma_vli size
231                                         = fe->chunk_size(filters[i].options);
232                         if (size == LZMA_VLI_UNKNOWN)
233                                 return LZMA_VLI_UNKNOWN;
234
235                         if (size > max)
236                                 max = size;
237                 }
238         }
239
240         return max;
241 }
242
243
244 extern LZMA_API lzma_ret
245 lzma_properties_size(uint32_t *size, const lzma_filter *filter)
246 {
247         const lzma_filter_encoder *const fe = encoder_find(filter->id);
248         if (fe == NULL) {
249                 // Unknown filter - if the Filter ID is a proper VLI,
250                 // return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
251                 // because it's possible that we just don't have support
252                 // compiled in for the requested filter.
253                 return filter->id <= LZMA_VLI_MAX
254                                 ? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
255         }
256
257         if (fe->props_size_get == NULL) {
258                 // No props_size_get() function, use props_size_fixed.
259                 *size = fe->props_size_fixed;
260                 return LZMA_OK;
261         }
262
263         return fe->props_size_get(size, filter->options);
264 }
265
266
267 extern LZMA_API lzma_ret
268 lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
269 {
270         const lzma_filter_encoder *const fe = encoder_find(filter->id);
271         if (fe == NULL)
272                 return LZMA_PROG_ERROR;
273
274         if (fe->props_encode == NULL)
275                 return LZMA_OK;
276
277         return fe->props_encode(filter->options, props);
278 }