]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/stream_decoder.c
Imported to git.
[icculus/xz.git] / src / liblzma / common / stream_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       stream_decoder.c
4 /// \brief      Decodes .lzma Streams
5 //
6 //  Copyright (C) 2007 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 "stream_common.h"
21 #include "check.h"
22 #include "stream_flags_decoder.h"
23 #include "block_decoder.h"
24 #include "metadata_decoder.h"
25
26
27 struct lzma_coder_s {
28         enum {
29                 SEQ_STREAM_HEADER_CODE,
30                 SEQ_BLOCK_HEADER_INIT,
31                 SEQ_BLOCK_HEADER_CODE,
32                 SEQ_METADATA_CODE,
33                 SEQ_DATA_CODE,
34                 SEQ_STREAM_TAIL_INIT,
35                 SEQ_STREAM_TAIL_CODE,
36         } sequence;
37
38         /// Position in variable-length integers and in some other things.
39         size_t pos;
40
41         /// Block or Metadata decoder. This takes little memory and the same
42         /// data structure can be used to decode every Block Header, so it's
43         /// a good idea to have a separate lzma_next_coder structure for it.
44         lzma_next_coder block_decoder;
45
46         /// Block Header decoder; this is separate
47         lzma_next_coder block_header_decoder;
48
49         lzma_options_block block_options;
50
51         /// Information about the sizes of the Blocks
52         lzma_info *info;
53
54         /// Current Block in *info
55         lzma_info_iter iter;
56
57         /// Number of bytes not yet processed from Data Blocks in the Stream.
58         /// This can be LZMA_VLI_VALUE_UNKNOWN. If it is known, it is
59         /// decremented while decoding and verified to match the reality.
60         lzma_vli total_left;
61
62         /// Like uncompressed_left above but for uncompressed data from
63         /// Data Blocks.
64         lzma_vli uncompressed_left;
65
66         /// Stream Flags from Stream Header
67         lzma_stream_flags header_flags;
68
69         /// Stream Flags from Stream tail
70         lzma_stream_flags tail_flags;
71
72         /// Decoder for Stream Header and Stream tail. This takes very
73         /// little memory and the same data structure can be used for
74         /// both Header and tail, so it's a good idea to have a separate
75         /// lzma_next_coder structure for it.
76         lzma_next_coder flags_decoder;
77
78         /// Temporary destination for the decoded Metadata.
79         lzma_metadata metadata;
80
81         /// Pointer to application-supplied pointer where to store the list
82         /// of Extra Records from the Header Metadata Block.
83         lzma_extra **header_extra;
84
85         /// Same as above but Footer Metadata Block
86         lzma_extra **footer_extra;
87 };
88
89
90 static lzma_ret
91 metadata_init(lzma_coder *coder, lzma_allocator *allocator)
92 {
93         assert(coder->metadata.index == NULL);
94         assert(coder->metadata.extra == NULL);
95
96         // Single-Block Streams don't have Metadata Blocks.
97         if (!coder->header_flags.is_multi)
98                 return LZMA_DATA_ERROR;
99
100         coder->block_options.total_limit = LZMA_VLI_VALUE_UNKNOWN;
101
102         // Limit the Uncompressed Size of a Metadata Block. This is to
103         // prevent security issues where input file would have very huge
104         // Metadata.
105         //
106         // FIXME: Hardcoded constant is ugly. Maybe we should provide
107         // some way to specify this from the application.
108         coder->block_options.uncompressed_limit = LZMA_VLI_C(1) << 23;
109
110         lzma_info_size size_type;
111         bool want_extra;
112
113         // If we haven't decoded any Data Blocks yet, this is Header
114         // Metadata Block.
115         if (lzma_info_index_count_get(coder->info) == 0) {
116                 coder->block_options.has_backward_size = false;
117                 coder->block_options.handle_padding = true;
118                 size_type = LZMA_INFO_HEADER_METADATA;
119                 want_extra = coder->header_extra != NULL;
120         } else {
121                 if (lzma_info_index_finish(coder->info))
122                         return LZMA_DATA_ERROR;
123
124                 coder->block_options.has_backward_size = true;
125                 coder->block_options.handle_padding = false;
126                 size_type = LZMA_INFO_FOOTER_METADATA;
127                 want_extra = coder->footer_extra != NULL;
128         }
129
130         coder->block_options.has_uncompressed_size_in_footer = false;
131         coder->block_options.total_size = lzma_info_size_get(
132                         coder->info, size_type);
133
134         coder->sequence = SEQ_METADATA_CODE;
135
136         return lzma_metadata_decoder_init(&coder->block_decoder, allocator,
137                         &coder->block_options, &coder->metadata, want_extra);
138 }
139
140
141 static lzma_ret
142 data_init(lzma_coder *coder, lzma_allocator *allocator)
143 {
144         lzma_ret ret = lzma_info_iter_next(&coder->iter, allocator);
145         if (ret != LZMA_OK)
146                 return ret;
147
148         ret = lzma_info_iter_set(&coder->iter, LZMA_VLI_VALUE_UNKNOWN,
149                         coder->block_options.uncompressed_size);
150         if (ret != LZMA_OK)
151                 return ret;
152
153         coder->block_options.total_size = coder->iter.total_size;
154         coder->block_options.uncompressed_size = coder->iter.uncompressed_size;
155         coder->block_options.total_limit = coder->total_left;
156         coder->block_options.uncompressed_limit = coder->uncompressed_left;
157
158         if (coder->header_flags.is_multi) {
159                 coder->block_options.has_uncompressed_size_in_footer = false;
160                 coder->block_options.has_backward_size = false;
161                 coder->block_options.handle_padding = true;
162         } else {
163                 coder->block_options.has_uncompressed_size_in_footer
164                                 = coder->iter.uncompressed_size
165                                         == LZMA_VLI_VALUE_UNKNOWN;
166                 coder->block_options.has_backward_size = true;
167                 coder->block_options.handle_padding = false;
168         }
169
170         coder->sequence = SEQ_DATA_CODE;
171
172         return lzma_block_decoder_init(&coder->block_decoder, allocator,
173                         &coder->block_options);
174 }
175
176
177 static lzma_ret
178 stream_decode(lzma_coder *coder, lzma_allocator *allocator,
179                 const uint8_t *restrict in, size_t *restrict in_pos,
180                 size_t in_size, uint8_t *restrict out,
181                 size_t *restrict out_pos, size_t out_size, lzma_action action)
182 {
183         while (*out_pos < out_size && (*in_pos < in_size
184                         || coder->sequence == SEQ_DATA_CODE))
185         switch (coder->sequence) {
186         case SEQ_STREAM_HEADER_CODE: {
187                 const lzma_ret ret = coder->flags_decoder.code(
188                                 coder->flags_decoder.coder,
189                                 allocator, in, in_pos, in_size,
190                                 NULL, NULL, 0, LZMA_RUN);
191                 if (ret != LZMA_STREAM_END)
192                         return ret;
193
194                 coder->sequence = SEQ_BLOCK_HEADER_INIT;
195
196                 // Detect if the Check type is supported and give appropriate
197                 // warning if it isn't. We don't warn every time a new Block
198                 // is started.
199                 lzma_check tmp;
200                 if (lzma_check_init(&tmp, coder->header_flags.check))
201                         return LZMA_UNSUPPORTED_CHECK;
202
203                 break;
204         }
205
206         case SEQ_BLOCK_HEADER_INIT: {
207                 coder->block_options.check = coder->header_flags.check;
208                 coder->block_options.has_crc32 = coder->header_flags.has_crc32;
209
210                 const lzma_ret ret = lzma_block_header_decoder_init(
211                                 &coder->block_header_decoder, allocator,
212                                 &coder->block_options);
213                 if (ret != LZMA_OK)
214                         return ret;
215
216                 coder->sequence = SEQ_BLOCK_HEADER_CODE;
217         }
218
219         // Fall through
220
221         case SEQ_BLOCK_HEADER_CODE: {
222                 lzma_ret ret = coder->block_header_decoder.code(
223                                 coder->block_header_decoder.coder,
224                                 allocator, in, in_pos, in_size,
225                                 NULL, NULL, 0, LZMA_RUN);
226
227                 if (ret != LZMA_STREAM_END)
228                         return ret;
229
230                 if (coder->block_options.is_metadata)
231                         ret = metadata_init(coder, allocator);
232                 else
233                         ret = data_init(coder, allocator);
234
235                 if (ret != LZMA_OK)
236                         return ret;
237
238                 break;
239         }
240
241         case SEQ_METADATA_CODE: {
242                 lzma_ret ret = coder->block_decoder.code(
243                                 coder->block_decoder.coder, allocator,
244                                 in, in_pos, in_size, NULL, NULL, 0, LZMA_RUN);
245                 if (ret != LZMA_STREAM_END)
246                         return ret;
247
248                 const bool is_header_metadata = lzma_info_index_count_get(
249                                 coder->info) == 0;
250
251                 if (is_header_metadata) {
252                         if (coder->header_extra != NULL) {
253                                 *coder->header_extra = coder->metadata.extra;
254                                 coder->metadata.extra = NULL;
255                         }
256
257                         if (lzma_info_size_set(coder->info,
258                                         LZMA_INFO_HEADER_METADATA,
259                                         coder->block_options.total_size)
260                                         != LZMA_OK)
261                                 return LZMA_PROG_ERROR;
262
263                         coder->sequence = SEQ_BLOCK_HEADER_INIT;
264                 } else {
265                         if (coder->footer_extra != NULL) {
266                                 *coder->footer_extra = coder->metadata.extra;
267                                 coder->metadata.extra = NULL;
268                         }
269
270                         coder->sequence = SEQ_STREAM_TAIL_INIT;
271                 }
272
273                 assert(coder->metadata.extra == NULL);
274
275                 ret = lzma_info_metadata_set(coder->info, allocator,
276                                 &coder->metadata, is_header_metadata, true);
277                 if (ret != LZMA_OK)
278                         return ret;
279
280                 // Intialize coder->total_size and coder->uncompressed_size
281                 // from Header Metadata.
282                 if (is_header_metadata) {
283                         coder->total_left = lzma_info_size_get(
284                                         coder->info, LZMA_INFO_TOTAL);
285                         coder->uncompressed_left = lzma_info_size_get(
286                                         coder->info, LZMA_INFO_UNCOMPRESSED);
287                 }
288
289                 break;
290         }
291
292         case SEQ_DATA_CODE: {
293                 lzma_ret ret = coder->block_decoder.code(
294                                 coder->block_decoder.coder, allocator,
295                                 in, in_pos, in_size, out, out_pos, out_size,
296                                 action);
297
298                 if (ret != LZMA_STREAM_END)
299                         return ret;
300
301                 ret = lzma_info_iter_set(&coder->iter,
302                                 coder->block_options.total_size,
303                                 coder->block_options.uncompressed_size);
304                 if (ret != LZMA_OK)
305                         return ret;
306
307                 // These won't overflow since lzma_info_iter_set() succeeded.
308                 if (coder->total_left != LZMA_VLI_VALUE_UNKNOWN)
309                         coder->total_left -= coder->block_options.total_size;
310                 if (coder->uncompressed_left != LZMA_VLI_VALUE_UNKNOWN)
311                         coder->uncompressed_left -= coder->block_options
312                                         .uncompressed_size;
313
314                 if (!coder->header_flags.is_multi) {
315                         ret = lzma_info_index_finish(coder->info);
316                         if (ret != LZMA_OK)
317                                 return ret;
318
319                         coder->sequence = SEQ_STREAM_TAIL_INIT;
320                         break;
321                 }
322
323                 coder->sequence = SEQ_BLOCK_HEADER_INIT;
324                 break;
325         }
326
327         case SEQ_STREAM_TAIL_INIT: {
328                 lzma_ret ret = lzma_info_index_finish(coder->info);
329                 if (ret != LZMA_OK)
330                         return ret;
331
332                 ret = lzma_stream_tail_decoder_init(&coder->flags_decoder,
333                                 allocator, &coder->tail_flags);
334                 if (ret != LZMA_OK)
335                         return ret;
336
337                 coder->sequence = SEQ_STREAM_TAIL_CODE;
338         }
339
340         // Fall through
341
342         case SEQ_STREAM_TAIL_CODE: {
343                 const lzma_ret ret = coder->flags_decoder.code(
344                                 coder->flags_decoder.coder, allocator,
345                                 in, in_pos, in_size, NULL, NULL, 0, LZMA_RUN);
346                 if (ret != LZMA_STREAM_END)
347                         return ret;
348
349                 if (!lzma_stream_flags_is_equal(
350                                 coder->header_flags, coder->tail_flags))
351                         return LZMA_DATA_ERROR;
352
353                 return LZMA_STREAM_END;
354         }
355
356         default:
357                 return LZMA_PROG_ERROR;
358         }
359
360         return LZMA_OK;
361 }
362
363
364 static void
365 stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
366 {
367         lzma_next_coder_end(&coder->block_decoder, allocator);
368         lzma_next_coder_end(&coder->block_header_decoder, allocator);
369         lzma_next_coder_end(&coder->flags_decoder, allocator);
370         lzma_info_free(coder->info, allocator);
371         lzma_index_free(coder->metadata.index, allocator);
372         lzma_extra_free(coder->metadata.extra, allocator);
373         lzma_free(coder, allocator);
374         return;
375 }
376
377
378 static lzma_ret
379 stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
380                 lzma_extra **header, lzma_extra **footer)
381 {
382         if (next->coder == NULL) {
383                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
384                 if (next->coder == NULL)
385                         return LZMA_MEM_ERROR;
386
387                 next->code = &stream_decode;
388                 next->end = &stream_decoder_end;
389
390                 next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
391                 next->coder->block_header_decoder = LZMA_NEXT_CODER_INIT;
392                 next->coder->info = NULL;
393                 next->coder->flags_decoder = LZMA_NEXT_CODER_INIT;
394                 next->coder->metadata.index = NULL;
395                 next->coder->metadata.extra = NULL;
396         } else {
397                 lzma_index_free(next->coder->metadata.index, allocator);
398                 next->coder->metadata.index = NULL;
399
400                 lzma_extra_free(next->coder->metadata.extra, allocator);
401                 next->coder->metadata.extra = NULL;
402         }
403
404         next->coder->info = lzma_info_init(next->coder->info, allocator);
405         if (next->coder->info == NULL)
406                 return LZMA_MEM_ERROR;
407
408         lzma_info_iter_begin(next->coder->info, &next->coder->iter);
409
410         // Initialize Stream Header decoder.
411         return_if_error(lzma_stream_header_decoder_init(
412                                 &next->coder->flags_decoder, allocator,
413                                 &next->coder->header_flags));
414
415         // Reset the *foo_extra pointers to NULL. This way the caller knows
416         // if there were no Extra Records. (We don't support appending
417         // Records to Extra list.)
418         if (header != NULL)
419                 *header = NULL;
420         if (footer != NULL)
421                 *footer = NULL;
422
423         // Reset some variables.
424         next->coder->sequence = SEQ_STREAM_HEADER_CODE;
425         next->coder->pos = 0;
426         next->coder->uncompressed_left = LZMA_VLI_VALUE_UNKNOWN;
427         next->coder->total_left = LZMA_VLI_VALUE_UNKNOWN;
428         next->coder->header_extra = header;
429         next->coder->footer_extra = footer;
430
431         return LZMA_OK;
432 }
433
434
435 extern lzma_ret
436 lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
437                 lzma_extra **header, lzma_extra **footer)
438 {
439         lzma_next_coder_init(
440                         stream_decoder_init, next, allocator, header, footer);
441 }
442
443
444 extern LZMA_API lzma_ret
445 lzma_stream_decoder(lzma_stream *strm,
446                 lzma_extra **header, lzma_extra **footer)
447 {
448         lzma_next_strm_init(strm, stream_decoder_init, header, footer);
449
450         strm->internal->supported_actions[LZMA_RUN] = true;
451         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
452
453         return LZMA_OK;
454 }