]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/block_header_decoder.c
Imported to git.
[icculus/xz.git] / src / liblzma / common / block_header_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       block_header_decoder.c
4 /// \brief      Decodes Block Header from .lzma files
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 "common.h"
21 #include "check.h"
22
23
24 struct lzma_coder_s {
25         lzma_options_block *options;
26
27         enum {
28                 SEQ_FLAGS_1,
29                 SEQ_FLAGS_2,
30                 SEQ_COMPRESSED_SIZE,
31                 SEQ_UNCOMPRESSED_SIZE,
32                 SEQ_FILTER_FLAGS_INIT,
33                 SEQ_FILTER_FLAGS_DECODE,
34                 SEQ_CRC32,
35                 SEQ_PADDING
36         } sequence;
37
38         /// Position in variable-length integers
39         size_t pos;
40
41         /// CRC32 of the Block Header
42         uint32_t crc32;
43
44         lzma_next_coder filter_flags_decoder;
45 };
46
47
48 static bool
49 update_sequence(lzma_coder *coder)
50 {
51         switch (coder->sequence) {
52         case SEQ_FLAGS_2:
53                 if (coder->options->compressed_size
54                                 != LZMA_VLI_VALUE_UNKNOWN) {
55                         coder->pos = 0;
56                         coder->sequence = SEQ_COMPRESSED_SIZE;
57                         break;
58                 }
59
60         // Fall through
61
62         case SEQ_COMPRESSED_SIZE:
63                 if (coder->options->uncompressed_size
64                                 != LZMA_VLI_VALUE_UNKNOWN) {
65                         coder->pos = 0;
66                         coder->sequence = SEQ_UNCOMPRESSED_SIZE;
67                         break;
68                 }
69
70         // Fall through
71
72         case SEQ_UNCOMPRESSED_SIZE:
73                 coder->pos = 0;
74
75         // Fall through
76
77         case SEQ_FILTER_FLAGS_DECODE:
78                 if (coder->options->filters[coder->pos].id
79                                 != LZMA_VLI_VALUE_UNKNOWN) {
80                         coder->sequence = SEQ_FILTER_FLAGS_INIT;
81                         break;
82                 }
83
84                 if (coder->options->has_crc32) {
85                         coder->pos = 0;
86                         coder->sequence = SEQ_CRC32;
87                         break;
88                 }
89
90         case SEQ_CRC32:
91                 if (coder->options->padding != 0) {
92                         coder->pos = 0;
93                         coder->sequence = SEQ_PADDING;
94                         break;
95                 }
96
97                 return true;
98
99         default:
100                 assert(0);
101                 return true;
102         }
103
104         return false;
105 }
106
107
108 static lzma_ret
109 block_header_decode(lzma_coder *coder, lzma_allocator *allocator,
110                 const uint8_t *restrict in, size_t *restrict in_pos,
111                 size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
112                 size_t *restrict out_pos lzma_attribute((unused)),
113                 size_t out_size lzma_attribute((unused)),
114                 lzma_action action lzma_attribute((unused)))
115 {
116         while (*in_pos < in_size)
117         switch (coder->sequence) {
118         case SEQ_FLAGS_1:
119                 // Check that the reserved bit is unset. Use HEADER_ERROR
120                 // because newer version of liblzma may support the reserved
121                 // bit, although it is likely that this is just a broken file.
122                 if (in[*in_pos] & 0x40)
123                         return LZMA_HEADER_ERROR;
124
125                 // Number of filters: we prepare appropriate amount of
126                 // variables for variable-length integer parsing. The
127                 // initialization function has already reset the rest
128                 // of the values to LZMA_VLI_VALUE_UNKNOWN, which allows
129                 // us to later know how many filters there are.
130                 for (int i = (int)(in[*in_pos] & 0x07) - 1; i >= 0; --i)
131                         coder->options->filters[i].id = 0;
132
133                 // End of Payload Marker flag
134                 coder->options->has_eopm = (in[*in_pos] & 0x08) != 0;
135
136                 // Compressed Size: Prepare for variable-length integer
137                 // parsing if it is known.
138                 if (in[*in_pos] & 0x10)
139                         coder->options->compressed_size = 0;
140
141                 // Uncompressed Size: the same.
142                 if (in[*in_pos] & 0x20)
143                         coder->options->uncompressed_size = 0;
144
145                 // Is Metadata Block flag
146                 coder->options->is_metadata = (in[*in_pos] & 0x80) != 0;
147
148                 // We need at least one: Uncompressed Size or EOPM.
149                 if (coder->options->uncompressed_size == LZMA_VLI_VALUE_UNKNOWN
150                                 && !coder->options->has_eopm)
151                         return LZMA_DATA_ERROR;
152
153                 // Update header CRC32.
154                 coder->crc32 = lzma_crc32(in + *in_pos, 1, coder->crc32);
155
156                 ++*in_pos;
157                 coder->sequence = SEQ_FLAGS_2;
158                 break;
159
160         case SEQ_FLAGS_2:
161                 // Check that the reserved bits are unset.
162                 if (in[*in_pos] & 0xE0)
163                         return LZMA_DATA_ERROR;
164
165                 // Get the size of Header Padding.
166                 coder->options->padding = in[*in_pos] & 0x1F;
167
168                 coder->crc32 = lzma_crc32(in + *in_pos, 1, coder->crc32);
169
170                 ++*in_pos;
171
172                 if (update_sequence(coder))
173                         return LZMA_STREAM_END;
174
175                 break;
176
177         case SEQ_COMPRESSED_SIZE: {
178                 // Store the old input position to be used when
179                 // updating coder->header_crc32.
180                 const size_t in_start = *in_pos;
181
182                 const lzma_ret ret = lzma_vli_decode(
183                                 &coder->options->compressed_size,
184                                 &coder->pos, in, in_pos, in_size);
185
186                 const size_t in_used = *in_pos - in_start;
187
188                 coder->options->compressed_reserve += in_used;
189                 assert(coder->options->compressed_reserve
190                                 <= LZMA_VLI_BYTES_MAX);
191
192                 coder->options->header_size += in_used;
193
194                 coder->crc32 = lzma_crc32(in + in_start, in_used,
195                                 coder->crc32);
196
197                 if (ret != LZMA_STREAM_END)
198                         return ret;
199
200                 if (update_sequence(coder))
201                         return LZMA_STREAM_END;
202
203                 break;
204         }
205
206         case SEQ_UNCOMPRESSED_SIZE: {
207                 const size_t in_start = *in_pos;
208
209                 const lzma_ret ret = lzma_vli_decode(
210                                 &coder->options->uncompressed_size,
211                                 &coder->pos, in, in_pos, in_size);
212
213                 const size_t in_used = *in_pos - in_start;
214
215                 coder->options->uncompressed_reserve += in_used;
216                 assert(coder->options->uncompressed_reserve
217                                 <= LZMA_VLI_BYTES_MAX);
218
219                 coder->options->header_size += in_used;
220
221                 coder->crc32 = lzma_crc32(in + in_start, in_used,
222                                 coder->crc32);
223
224                 if (ret != LZMA_STREAM_END)
225                         return ret;
226
227                 if (update_sequence(coder))
228                         return LZMA_STREAM_END;
229
230                 break;
231         }
232
233         case SEQ_FILTER_FLAGS_INIT: {
234                 assert(coder->options->filters[coder->pos].id
235                                 != LZMA_VLI_VALUE_UNKNOWN);
236
237                 const lzma_ret ret = lzma_filter_flags_decoder_init(
238                                 &coder->filter_flags_decoder, allocator,
239                                 &coder->options->filters[coder->pos]);
240                 if (ret != LZMA_OK)
241                         return ret;
242
243                 coder->sequence = SEQ_FILTER_FLAGS_DECODE;
244         }
245
246         // Fall through
247
248         case SEQ_FILTER_FLAGS_DECODE: {
249                 const size_t in_start = *in_pos;
250
251                 const lzma_ret ret = coder->filter_flags_decoder.code(
252                                 coder->filter_flags_decoder.coder,
253                                 allocator, in, in_pos, in_size,
254                                 NULL, NULL, 0, LZMA_RUN);
255
256                 const size_t in_used = *in_pos - in_start;
257                 coder->options->header_size += in_used;
258                 coder->crc32 = lzma_crc32(in + in_start,
259                                 in_used, coder->crc32);
260
261                 if (ret != LZMA_STREAM_END)
262                         return ret;
263
264                 ++coder->pos;
265
266                 if (update_sequence(coder))
267                         return LZMA_STREAM_END;
268
269                 break;
270         }
271
272         case SEQ_CRC32:
273                 assert(coder->options->has_crc32);
274
275                 if (in[*in_pos] != ((coder->crc32 >> (coder->pos * 8)) & 0xFF))
276                         return LZMA_DATA_ERROR;
277
278                 ++*in_pos;
279                 ++coder->pos;
280
281                 // Check if we reached end of the CRC32 field.
282                 if (coder->pos == 4) {
283                         coder->options->header_size += 4;
284
285                         if (update_sequence(coder))
286                                 return LZMA_STREAM_END;
287                 }
288
289                 break;
290
291         case SEQ_PADDING:
292                 if (in[*in_pos] != 0x00)
293                         return LZMA_DATA_ERROR;
294
295                 ++*in_pos;
296                 ++coder->options->header_size;
297                 ++coder->pos;
298
299                 if (coder->pos < (size_t)(coder->options->padding))
300                         break;
301
302                 return LZMA_STREAM_END;
303
304         default:
305                 return LZMA_PROG_ERROR;
306         }
307
308         return LZMA_OK;
309 }
310
311
312 static void
313 block_header_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
314 {
315         lzma_next_coder_end(&coder->filter_flags_decoder, allocator);
316         lzma_free(coder, allocator);
317         return;
318 }
319
320
321 extern lzma_ret
322 lzma_block_header_decoder_init(lzma_next_coder *next,
323                 lzma_allocator *allocator, lzma_options_block *options)
324 {
325         if (next->coder == NULL) {
326                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
327                 if (next->coder == NULL)
328                         return LZMA_MEM_ERROR;
329
330                 next->code = &block_header_decode;
331                 next->end = &block_header_decoder_end;
332                 next->coder->filter_flags_decoder = LZMA_NEXT_CODER_INIT;
333         }
334
335         // Assume that Compressed Size and Uncompressed Size are unknown.
336         options->compressed_size = LZMA_VLI_VALUE_UNKNOWN;
337         options->uncompressed_size = LZMA_VLI_VALUE_UNKNOWN;
338
339         // We will calculate the sizes of these fields too so that the
340         // application may rewrite the header if it wishes so.
341         options->compressed_reserve = 0;
342         options->uncompressed_reserve = 0;
343
344         // The Block Flags field is always present, so include its size here
345         // and we don't need to worry about it in block_header_decode().
346         options->header_size = 2;
347
348         // Reset filters[] to indicate empty list of filters.
349         // See SEQ_FLAGS_1 in block_header_decode() for reasoning of this.
350         for (size_t i = 0; i < 8; ++i) {
351                 options->filters[i].id = LZMA_VLI_VALUE_UNKNOWN;
352                 options->filters[i].options = NULL;
353         }
354
355         next->coder->options = options;
356         next->coder->sequence = SEQ_FLAGS_1;
357         next->coder->pos = 0;
358         next->coder->crc32 = 0;
359
360         return LZMA_OK;
361 }
362
363
364 extern LZMA_API lzma_ret
365 lzma_block_header_decoder(lzma_stream *strm,
366                 lzma_options_block *options)
367 {
368         lzma_next_strm_init(strm, lzma_block_header_decoder_init, options);
369
370         strm->internal->supported_actions[LZMA_RUN] = true;
371
372         return LZMA_OK;
373 }