]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/lzma/lzma2_decoder.c
Make the memusage functions of LZMA1 and LZMA2 decoders
[icculus/xz.git] / src / liblzma / lzma / lzma2_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       lzma2_decoder.c
4 /// \brief      LZMA2 decoder
5 //
6 //  Copyright (C) 1999-2008 Igor Pavlov
7 //  Copyright (C) 2008 Lasse Collin
8 //
9 //  This library is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU Lesser General Public
11 //  License as published by the Free Software Foundation; either
12 //  version 2.1 of the License, or (at your option) any later version.
13 //
14 //  This library is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 //  Lesser General Public License for more details.
18 //
19 ///////////////////////////////////////////////////////////////////////////////
20
21 #include "lzma2_decoder.h"
22 #include "lz_decoder.h"
23 #include "lzma_decoder.h"
24
25
26 struct lzma_coder_s {
27         enum sequence {
28                 SEQ_CONTROL,
29                 SEQ_UNCOMPRESSED_1,
30                 SEQ_UNCOMPRESSED_2,
31                 SEQ_COMPRESSED_0,
32                 SEQ_COMPRESSED_1,
33                 SEQ_PROPERTIES,
34                 SEQ_LZMA,
35                 SEQ_COPY,
36         } sequence;
37
38         /// Sequence after the size fields have been decoded.
39         enum sequence next_sequence;
40
41         /// LZMA decoder
42         lzma_lz_decoder lzma;
43
44         /// Uncompressed size of LZMA chunk
45         size_t uncompressed_size;
46
47         /// Compressed size of the chunk (naturally equals to uncompressed
48         /// size of uncompressed chunk)
49         size_t compressed_size;
50
51         /// True if properties are needed. This is false before the
52         /// first LZMA chunk.
53         bool need_properties;
54
55         /// True if dictionary reset is needed. This is false before the
56         /// first chunk (LZMA or uncompressed).
57         bool need_dictionary_reset;
58
59         lzma_options_lzma options;
60 };
61
62
63 static lzma_ret
64 lzma2_decode(lzma_coder *restrict coder, lzma_dict *restrict dict,
65                 const uint8_t *restrict in, size_t *restrict in_pos,
66                 size_t in_size)
67 {
68         // With SEQ_LZMA it is possible that no new input is needed to do
69         // some progress. The rest of the sequences assume that there is
70         // at least one byte of input.
71         while (*in_pos < in_size || coder->sequence == SEQ_LZMA)
72         switch (coder->sequence) {
73         case SEQ_CONTROL: {
74                 const uint32_t control = in[*in_pos];
75                 ++*in_pos;
76
77                 // Dictionary reset implies that next LZMA chunk has to set
78                 // new properties.
79                 if (control >= 0xE0 || control == 1) {
80                         dict_reset(dict);
81                         coder->need_dictionary_reset = false;
82                         coder->need_properties = true;
83                 } else if (coder->need_dictionary_reset) {
84                         return LZMA_DATA_ERROR;
85                 }
86
87                 if (control >= 0x80) {
88                         // LZMA chunk. The highest five bits of the
89                         // uncompressed size are taken from the control byte.
90                         coder->uncompressed_size = (control & 0x1F) << 16;
91                         coder->sequence = SEQ_UNCOMPRESSED_1;
92
93                         // See if there are new properties or if we need to
94                         // reset the state.
95                         if (control >= 0xC0) {
96                                 // When there are new properties, state reset
97                                 // is done at SEQ_PROPERTIES.
98                                 coder->need_properties = false;
99                                 coder->next_sequence = SEQ_PROPERTIES;
100
101                         } else if (coder->need_properties) {
102                                 return LZMA_DATA_ERROR;
103
104                         } else {
105                                 coder->next_sequence = SEQ_LZMA;
106
107                                 // If only state reset is wanted with old
108                                 // properties, do the resetting here for
109                                 // simplicity.
110                                 if (control >= 0xA0)
111                                         coder->lzma.reset(coder->lzma.coder,
112                                                         &coder->options);
113                         }
114                 } else {
115                         // End marker
116                         if (control == 0x00)
117                                 return LZMA_STREAM_END;
118
119                         // Invalid control values
120                         if (control > 2)
121                                 return LZMA_DATA_ERROR;
122
123                         // It's uncompressed chunk
124                         coder->sequence = SEQ_COMPRESSED_0;
125                         coder->next_sequence = SEQ_COPY;
126                 }
127
128                 break;
129         }
130
131         case SEQ_UNCOMPRESSED_1:
132                 coder->uncompressed_size += (uint32_t)(in[(*in_pos)++]) << 8;
133                 coder->sequence = SEQ_UNCOMPRESSED_2;
134                 break;
135
136         case SEQ_UNCOMPRESSED_2:
137                 coder->uncompressed_size += in[(*in_pos)++] + 1;
138                 coder->sequence = SEQ_COMPRESSED_0;
139                 coder->lzma.set_uncompressed(coder->lzma.coder,
140                                 coder->uncompressed_size);
141                 break;
142
143         case SEQ_COMPRESSED_0:
144                 coder->compressed_size = (uint32_t)(in[(*in_pos)++]) << 8;
145                 coder->sequence = SEQ_COMPRESSED_1;
146                 break;
147
148         case SEQ_COMPRESSED_1:
149                 coder->compressed_size += in[(*in_pos)++] + 1;
150                 coder->sequence = coder->next_sequence;
151                 break;
152
153         case SEQ_PROPERTIES:
154                 if (lzma_lzma_lclppb_decode(&coder->options, in[(*in_pos)++]))
155                         return LZMA_DATA_ERROR;
156
157                 coder->lzma.reset(coder->lzma.coder, &coder->options);
158
159                 coder->sequence = SEQ_LZMA;
160                 break;
161
162         case SEQ_LZMA: {
163                 // Store the start offset so that we can update
164                 // coder->compressed_size later.
165                 const size_t in_start = *in_pos;
166
167                 // Decode from in[] to *dict.
168                 const lzma_ret ret = coder->lzma.code(coder->lzma.coder,
169                                 dict, in, in_pos, in_size);
170
171                 // Validate and update coder->compressed_size.
172                 const size_t in_used = *in_pos - in_start;
173                 if (in_used > coder->compressed_size)
174                         return LZMA_DATA_ERROR;
175
176                 coder->compressed_size -= in_used;
177
178                 // Return if we didn't finish the chunk, or an error occurred.
179                 if (ret != LZMA_STREAM_END)
180                         return ret;
181
182                 // The LZMA decoder must have consumed the whole chunk now.
183                 // We don't need to worry about uncompressed size since it
184                 // is checked by the LZMA decoder.
185                 if (coder->compressed_size != 0)
186                         return LZMA_DATA_ERROR;
187
188                 coder->sequence = SEQ_CONTROL;
189                 break;
190         }
191
192         case SEQ_COPY: {
193                 // Copy from input to the dictionary as is.
194                 // FIXME Can copy too much?
195                 dict_write(dict, in, in_pos, in_size, &coder->compressed_size);
196                 if (coder->compressed_size != 0)
197                         return LZMA_OK;
198
199                 coder->sequence = SEQ_CONTROL;
200                 break;
201         }
202
203         default:
204                 assert(0);
205                 return LZMA_PROG_ERROR;
206         }
207
208         return LZMA_OK;
209 }
210
211
212 static void
213 lzma2_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
214 {
215         assert(coder->lzma.end == NULL);
216         lzma_free(coder->lzma.coder, allocator);
217
218         lzma_free(coder, allocator);
219
220         return;
221 }
222
223
224 static lzma_ret
225 lzma2_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
226                 const void *options, size_t *dict_size)
227 {
228         if (lz->coder == NULL) {
229                 lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
230                 if (lz->coder == NULL)
231                         return LZMA_MEM_ERROR;
232
233                 lz->code = &lzma2_decode;
234                 lz->end = &lzma2_decoder_end;
235
236                 lz->coder->lzma = LZMA_LZ_DECODER_INIT;
237         }
238
239         lz->coder->sequence = SEQ_CONTROL;
240         lz->coder->need_properties = true;
241         lz->coder->need_dictionary_reset = true;
242
243         return lzma_lzma_decoder_create(&lz->coder->lzma,
244                         allocator, options, dict_size);
245 }
246
247
248 extern lzma_ret
249 lzma_lzma2_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
250                 const lzma_filter_info *filters)
251 {
252         // LZMA2 can only be the last filter in the chain. This is enforced
253         // by the raw_decoder initialization.
254         assert(filters[1].init == NULL);
255
256         return lzma_lz_decoder_init(next, allocator, filters,
257                         &lzma2_decoder_init);
258 }
259
260
261 extern uint64_t
262 lzma_lzma2_decoder_memusage(const void *options)
263 {
264         return sizeof(lzma_coder)
265                         + lzma_lzma_decoder_memusage_nocheck(options);
266 }
267
268
269 extern lzma_ret
270 lzma_lzma2_props_decode(void **options, lzma_allocator *allocator,
271                 const uint8_t *props, size_t props_size)
272 {
273         if (props_size != 1)
274                 return LZMA_OPTIONS_ERROR;
275
276         // Check that reserved bits are unset.
277         if (props[0] & 0xC0)
278                 return LZMA_OPTIONS_ERROR;
279
280         // Decode the dictionary size.
281         if (props[0] > 40)
282                 return LZMA_OPTIONS_ERROR;
283
284         lzma_options_lzma *opt = lzma_alloc(
285                         sizeof(lzma_options_lzma), allocator);
286         if (opt == NULL)
287                 return LZMA_MEM_ERROR;
288
289         if (props[0] == 40) {
290                 opt->dict_size = UINT32_MAX;
291         } else {
292                 opt->dict_size = 2 | (props[0] & 1);
293                 opt->dict_size <<= props[0] / 2 + 11;
294         }
295
296         opt->preset_dict = NULL;
297         opt->preset_dict_size = 0;
298
299         *options = opt;
300
301         return LZMA_OK;
302 }