]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/stream_decoder.c
Update the code to mostly match the new simpler file format
[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 "stream_decoder.h"
22 #include "check.h"
23 #include "stream_flags_decoder.h"
24 #include "block_decoder.h"
25
26
27 struct lzma_coder_s {
28         enum {
29                 SEQ_STREAM_HEADER,
30                 SEQ_BLOCK_HEADER,
31                 SEQ_BLOCK,
32                 SEQ_INDEX,
33                 SEQ_STREAM_FOOTER,
34         } sequence;
35
36         /// Block or Metadata decoder. This takes little memory and the same
37         /// data structure can be used to decode every Block Header, so it's
38         /// a good idea to have a separate lzma_next_coder structure for it.
39         lzma_next_coder block_decoder;
40
41         /// Block options decoded by the Block Header decoder and used by
42         /// the Block decoder.
43         lzma_options_block block_options;
44
45         /// Stream Flags from Stream Header
46         lzma_stream_flags stream_flags;
47
48         /// Index is hashed so that it can be compared to the sizes of Blocks
49         /// with O(1) memory usage.
50         lzma_index_hash *index_hash;
51
52         /// Write position in buffer[]
53         size_t buffer_pos;
54
55         /// Buffer to hold Stream Header, Block Header, and Stream Footer.
56         /// Block Header has biggest maximum size.
57         uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
58 };
59
60
61 static lzma_ret
62 stream_decode(lzma_coder *coder, lzma_allocator *allocator,
63                 const uint8_t *restrict in, size_t *restrict in_pos,
64                 size_t in_size, uint8_t *restrict out,
65                 size_t *restrict out_pos, size_t out_size, lzma_action action)
66 {
67         // When decoding the actual Block, it may be able to produce more
68         // output even if we don't give it any new input.
69         while (*out_pos < out_size && (*in_pos < in_size
70                         || coder->sequence == SEQ_BLOCK))
71         switch (coder->sequence) {
72         case SEQ_STREAM_HEADER: {
73                 // Copy the Stream Header to the internal buffer.
74                 bufcpy(in, in_pos, in_size, coder->buffer, &coder->buffer_pos,
75                                 LZMA_STREAM_HEADER_SIZE);
76
77                 // Return if we didn't get the whole Stream Header yet.
78                 if (coder->buffer_pos < LZMA_STREAM_HEADER_SIZE)
79                         return LZMA_OK;
80
81                 coder->buffer_pos = 0;
82
83                 // Decode the Stream Header.
84                 return_if_error(lzma_stream_header_decode(
85                                 &coder->stream_flags, coder->buffer));
86
87                 // Copy the type of the Check so that Block Header and Block
88                 // decoders see it.
89                 coder->block_options.check = coder->stream_flags.check;
90
91                 // Even if we return LZMA_UNSUPPORTED_CHECK below, we want
92                 // to continue from Block Header decoding.
93                 coder->sequence = SEQ_BLOCK_HEADER;
94
95                 // Detect if the Check type is supported and give appropriate
96                 // warning if it isn't. We don't warn every time a new Block
97                 // is started.
98                 if (!lzma_available_checks[coder->block_options.check])
99                         return LZMA_UNSUPPORTED_CHECK;
100
101                 break;
102         }
103
104         case SEQ_BLOCK_HEADER: {
105                 if (coder->buffer_pos == 0) {
106                         // Detect if it's Index.
107                         if (in[*in_pos] == 0x00) {
108                                 coder->sequence = SEQ_INDEX;
109                                 break;
110                         }
111
112                         // Calculate the size of the Block Header. Note that
113                         // Block Header decoder wants to see this byte too
114                         // so don't advance *in_pos.
115                         coder->block_options.header_size
116                                         = lzma_block_header_size_decode(
117                                                 in[*in_pos]);
118                 }
119
120                 // Copy the Block Header to the internal buffer.
121                 bufcpy(in, in_pos, in_size, coder->buffer, &coder->buffer_pos,
122                                 coder->block_options.header_size);
123
124                 // Return if we didn't get the whole Block Header yet.
125                 if (coder->buffer_pos < coder->block_options.header_size)
126                         return LZMA_OK;
127
128                 coder->buffer_pos = 0;
129
130                 // Set up a buffer to hold the filter chain. Block Header
131                 // decoder will initialize all members of this array so
132                 // we don't need to do it here.
133                 lzma_options_filter filters[LZMA_BLOCK_FILTERS_MAX + 1];
134                 coder->block_options.filters = filters;
135
136                 // Decode the Block Header.
137                 return_if_error(lzma_block_header_decode(&coder->block_options,
138                                 allocator, coder->buffer));
139
140                 // Initialize the Block decoder.
141                 const lzma_ret ret = lzma_block_decoder_init(
142                                 &coder->block_decoder,
143                                 allocator, &coder->block_options);
144
145                 // Free the allocated filter options since they are needed
146                 // only to initialize the Block decoder.
147                 for (size_t i = 0; i < LZMA_BLOCK_FILTERS_MAX; ++i)
148                         lzma_free(filters[i].options, allocator);
149
150                 coder->block_options.filters = NULL;
151
152                 // Check if Block enocoder initialization succeeded. Don't
153                 // warn about unsupported check anymore since we did it
154                 // earlier if it was needed.
155                 if (ret != LZMA_OK && ret != LZMA_UNSUPPORTED_CHECK)
156                         return ret;
157
158                 coder->sequence = SEQ_BLOCK;
159                 break;
160         }
161
162         case SEQ_BLOCK: {
163                 lzma_ret ret = coder->block_decoder.code(
164                                 coder->block_decoder.coder, allocator,
165                                 in, in_pos, in_size, out, out_pos, out_size,
166                                 action);
167
168                 if (ret != LZMA_STREAM_END)
169                         return ret;
170
171                 // Block decoded successfully. Add the new size pair to
172                 // the Index hash.
173                 return_if_error(lzma_index_hash_append(coder->index_hash,
174                                 lzma_block_total_size_get(
175                                         &coder->block_options),
176                                 coder->block_options.uncompressed_size));
177
178                 coder->sequence = SEQ_BLOCK_HEADER;
179                 break;
180         }
181
182         case SEQ_INDEX: {
183                 // Decode the Index and compare it to the hash calculated
184                 // from the sizes of the Blocks (if any).
185                 const lzma_ret ret = lzma_index_hash_decode(coder->index_hash,
186                                 in, in_pos, in_size);
187                 if (ret != LZMA_STREAM_END)
188                         return ret;
189
190                 coder->sequence = SEQ_STREAM_FOOTER;
191                 break;
192         }
193
194         case SEQ_STREAM_FOOTER:
195                 // Copy the Stream Footer to the internal buffer.
196                 bufcpy(in, in_pos, in_size, coder->buffer, &coder->buffer_pos,
197                                 LZMA_STREAM_HEADER_SIZE);
198
199                 // Return if we didn't get the whole Stream Footer yet.
200                 if (coder->buffer_pos < LZMA_STREAM_HEADER_SIZE)
201                         return LZMA_OK;
202
203                 // Decode the Stream Footer.
204                 lzma_stream_flags footer_flags;
205                 return_if_error(lzma_stream_footer_decode(
206                                 &footer_flags, coder->buffer));
207
208                 // Check that Index Size stored in the Stream Footer matches
209                 // the real size of the Index field.
210                 if (lzma_index_hash_size(coder->index_hash)
211                                 != footer_flags.backward_size)
212                         return LZMA_DATA_ERROR;
213
214                 // Compare that the Stream Flags fields are identical in
215                 // both Stream Header and Stream Footer.
216                 if (!lzma_stream_flags_equal(&coder->stream_flags,
217                                 &footer_flags))
218                         return LZMA_DATA_ERROR;
219
220                 return LZMA_STREAM_END;
221
222         default:
223                 assert(0);
224                 return LZMA_PROG_ERROR;
225         }
226
227         return LZMA_OK;
228 }
229
230
231 static void
232 stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
233 {
234         lzma_next_coder_end(&coder->block_decoder, allocator);
235         lzma_index_hash_end(coder->index_hash, allocator);
236         lzma_free(coder, allocator);
237         return;
238 }
239
240
241 static lzma_ret
242 stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
243 {
244         if (next->coder == NULL) {
245                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
246                 if (next->coder == NULL)
247                         return LZMA_MEM_ERROR;
248
249                 next->code = &stream_decode;
250                 next->end = &stream_decoder_end;
251
252                 next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
253                 next->coder->index_hash = NULL;
254         }
255
256         // Initialize the Index hash used to verify the Index.
257         next->coder->index_hash = lzma_index_hash_init(
258                         next->coder->index_hash, allocator);
259         if (next->coder->index_hash == NULL)
260                 return LZMA_MEM_ERROR;
261
262         // Reset the rest of the variables.
263         next->coder->sequence = SEQ_STREAM_HEADER;
264         next->coder->block_options.filters = NULL;
265         next->coder->buffer_pos = 0;
266
267         return LZMA_OK;
268 }
269
270
271 extern lzma_ret
272 lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator)
273 {
274         lzma_next_coder_init0(stream_decoder_init, next, allocator);
275 }
276
277
278 extern LZMA_API lzma_ret
279 lzma_stream_decoder(lzma_stream *strm)
280 {
281         lzma_next_strm_init0(strm, stream_decoder_init);
282
283         strm->internal->supported_actions[LZMA_RUN] = true;
284         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
285
286         return LZMA_OK;
287 }