]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/index_decoder.c
Add some single-call buffer-to-buffer coding functions.
[icculus/xz.git] / src / liblzma / common / index_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       index_decoder.c
4 /// \brief      Decodes the Index field
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 "index.h"
21 #include "check.h"
22
23
24 struct lzma_coder_s {
25         enum {
26                 SEQ_INDICATOR,
27                 SEQ_COUNT,
28                 SEQ_MEMUSAGE,
29                 SEQ_UNPADDED,
30                 SEQ_UNCOMPRESSED,
31                 SEQ_PADDING_INIT,
32                 SEQ_PADDING,
33                 SEQ_CRC32,
34         } sequence;
35
36         /// Memory usage limit
37         uint64_t memlimit;
38
39         /// Target Index
40         lzma_index *index;
41
42         /// Number of Records left to decode.
43         lzma_vli count;
44
45         /// The most recent Unpadded Size field
46         lzma_vli unpadded_size;
47
48         /// The most recent Uncompressed Size field
49         lzma_vli uncompressed_size;
50
51         /// Position in integers
52         size_t pos;
53
54         /// CRC32 of the List of Records field
55         uint32_t crc32;
56 };
57
58
59 static lzma_ret
60 index_decode(lzma_coder *coder, lzma_allocator *allocator,
61                 const uint8_t *restrict in, size_t *restrict in_pos,
62                 size_t in_size, uint8_t *restrict out lzma_attribute((unused)),
63                 size_t *restrict out_pos lzma_attribute((unused)),
64                 size_t out_size lzma_attribute((unused)),
65                 lzma_action action lzma_attribute((unused)))
66 {
67         // Similar optimization as in index_encoder.c
68         const size_t in_start = *in_pos;
69         lzma_ret ret = LZMA_OK;
70
71         while (*in_pos < in_size)
72         switch (coder->sequence) {
73         case SEQ_INDICATOR:
74                 // Return LZMA_DATA_ERROR instead of e.g. LZMA_PROG_ERROR or
75                 // LZMA_FORMAT_ERROR, because a typical usage case for Index
76                 // decoder is when parsing the Stream backwards. If seeking
77                 // backward from the Stream Footer gives us something that
78                 // doesn't begin with Index Indicator, the file is considered
79                 // corrupt, not "programming error" or "unrecognized file
80                 // format". One could argue that the application should
81                 // verify the Index Indicator before trying to decode the
82                 // Index, but well, I suppose it is simpler this way.
83                 if (in[(*in_pos)++] != 0x00)
84                         return LZMA_DATA_ERROR;
85
86                 coder->sequence = SEQ_COUNT;
87                 break;
88
89         case SEQ_COUNT:
90                 ret = lzma_vli_decode(&coder->count, &coder->pos,
91                                 in, in_pos, in_size);
92                 if (ret != LZMA_STREAM_END)
93                         goto out;
94
95                 coder->pos = 0;
96                 coder->sequence = SEQ_MEMUSAGE;
97
98         // Fall through
99
100         case SEQ_MEMUSAGE:
101                 if (lzma_index_memusage(coder->count) > coder->memlimit) {
102                         ret = LZMA_MEMLIMIT_ERROR;
103                         goto out;
104                 }
105
106                 ret = LZMA_OK;
107                 coder->sequence = coder->count == 0
108                                 ? SEQ_PADDING_INIT : SEQ_UNPADDED;
109                 break;
110
111         case SEQ_UNPADDED:
112         case SEQ_UNCOMPRESSED: {
113                 lzma_vli *size = coder->sequence == SEQ_UNPADDED
114                                 ? &coder->unpadded_size
115                                 : &coder->uncompressed_size;
116
117                 ret = lzma_vli_decode(size, &coder->pos,
118                                 in, in_pos, in_size);
119                 if (ret != LZMA_STREAM_END)
120                         goto out;
121
122                 ret = LZMA_OK;
123                 coder->pos = 0;
124
125                 if (coder->sequence == SEQ_UNPADDED) {
126                         // Validate that encoded Unpadded Size isn't too small
127                         // or too big.
128                         if (coder->unpadded_size < UNPADDED_SIZE_MIN
129                                         || coder->unpadded_size
130                                                 > UNPADDED_SIZE_MAX)
131                                 return LZMA_DATA_ERROR;
132
133                         coder->sequence = SEQ_UNCOMPRESSED;
134                 } else {
135                         // Add the decoded Record to the Index.
136                         return_if_error(lzma_index_append(
137                                         coder->index, allocator,
138                                         coder->unpadded_size,
139                                         coder->uncompressed_size));
140
141                         // Check if this was the last Record.
142                         coder->sequence = --coder->count == 0
143                                         ? SEQ_PADDING_INIT
144                                         : SEQ_UNPADDED;
145                 }
146
147                 break;
148         }
149
150         case SEQ_PADDING_INIT:
151                 coder->pos = lzma_index_padding_size(coder->index);
152                 coder->sequence = SEQ_PADDING;
153
154         // Fall through
155
156         case SEQ_PADDING:
157                 if (coder->pos > 0) {
158                         --coder->pos;
159                         if (in[(*in_pos)++] != 0x00)
160                                 return LZMA_DATA_ERROR;
161
162                         break;
163                 }
164
165                 // Finish the CRC32 calculation.
166                 coder->crc32 = lzma_crc32(in + in_start,
167                                 *in_pos - in_start, coder->crc32);
168
169                 coder->sequence = SEQ_CRC32;
170
171         // Fall through
172
173         case SEQ_CRC32:
174                 do {
175                         if (*in_pos == in_size)
176                                 return LZMA_OK;
177
178                         if (((coder->crc32 >> (coder->pos * 8)) & 0xFF)
179                                         != in[(*in_pos)++])
180                                 return LZMA_DATA_ERROR;
181
182                 } while (++coder->pos < 4);
183
184                 // Make index NULL so we don't free it unintentionally.
185                 coder->index = NULL;
186
187                 return LZMA_STREAM_END;
188
189         default:
190                 assert(0);
191                 return LZMA_PROG_ERROR;
192         }
193
194 out:
195         // Update the CRC32,
196         coder->crc32 = lzma_crc32(in + in_start,
197                         *in_pos - in_start, coder->crc32);
198
199         return ret;
200 }
201
202
203 static void
204 index_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
205 {
206         lzma_index_end(coder->index, allocator);
207         lzma_free(coder, allocator);
208         return;
209 }
210
211
212 static lzma_ret
213 index_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
214                 uint64_t *old_memlimit, uint64_t new_memlimit)
215 {
216         *memusage = lzma_index_memusage(coder->count);
217
218         if (new_memlimit != 0 && new_memlimit < *memusage)
219                 return LZMA_MEMLIMIT_ERROR;
220
221         *old_memlimit = coder->memlimit;
222         coder->memlimit = new_memlimit;
223
224         return LZMA_OK;
225 }
226
227
228 static lzma_ret
229 index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator,
230                 lzma_index **i, uint64_t memlimit)
231 {
232         // We always allocate a new lzma_index.
233         *i = lzma_index_init(NULL, allocator);
234         if (*i == NULL)
235                 return LZMA_MEM_ERROR;
236
237         // Initialize the rest.
238         coder->sequence = SEQ_INDICATOR;
239         coder->memlimit = memlimit;
240         coder->index = *i;
241         coder->count = 0; // Needs to be initialized due to _memconfig().
242         coder->pos = 0;
243         coder->crc32 = 0;
244
245         return LZMA_OK;
246 }
247
248
249 static lzma_ret
250 index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
251                 lzma_index **i, uint64_t memlimit)
252 {
253         lzma_next_coder_init(index_decoder_init, next, allocator);
254
255         if (i == NULL || memlimit == 0)
256                 return LZMA_PROG_ERROR;
257
258         if (next->coder == NULL) {
259                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
260                 if (next->coder == NULL)
261                         return LZMA_MEM_ERROR;
262
263                 next->code = &index_decode;
264                 next->end = &index_decoder_end;
265                 next->memconfig = &index_decoder_memconfig;
266                 next->coder->index = NULL;
267         } else {
268                 lzma_index_end(next->coder->index, allocator);
269         }
270
271         return index_decoder_reset(next->coder, allocator, i, memlimit);
272 }
273
274
275 extern LZMA_API lzma_ret
276 lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)
277 {
278         lzma_next_strm_init(index_decoder_init, strm, i, memlimit);
279
280         strm->internal->supported_actions[LZMA_RUN] = true;
281
282         return LZMA_OK;
283 }
284
285
286 extern LZMA_API lzma_ret
287 lzma_index_buffer_decode(
288                 lzma_index **i, uint64_t *memlimit, lzma_allocator *allocator,
289                 const uint8_t *in, size_t *in_pos, size_t in_size)
290 {
291         // Sanity checks
292         if (i == NULL || in == NULL || in_pos == NULL || *in_pos > in_size)
293                 return LZMA_PROG_ERROR;
294
295         // Initialize the decoder.
296         lzma_coder coder;
297         return_if_error(index_decoder_reset(&coder, allocator, i, *memlimit));
298
299         // Store the input start position so that we can restore it in case
300         // of an error.
301         const size_t in_start = *in_pos;
302
303         // Do the actual decoding.
304         lzma_ret ret = index_decode(&coder, allocator, in, in_pos, in_size,
305                         NULL, NULL, 0, LZMA_RUN);
306
307         if (ret == LZMA_STREAM_END) {
308                 ret = LZMA_OK;
309         } else {
310                 // Something went wrong, free the Index structure and restore
311                 // the input position.
312                 lzma_index_end(*i, allocator);
313                 *i = NULL;
314                 *in_pos = in_start;
315
316                 if (ret == LZMA_OK) {
317                         // The input is truncated or otherwise corrupt.
318                         // Use LZMA_DATA_ERROR instead of LZMA_BUF_ERROR
319                         // like lzma_vli_decode() does in single-call mode.
320                         ret = LZMA_DATA_ERROR;
321
322                 } else if (ret == LZMA_MEMLIMIT_ERROR) {
323                         // Tell the caller how much memory would have
324                         // been needed.
325                         *memlimit = lzma_index_memusage(coder.count);
326                 }
327         }
328
329         return ret;
330 }