]> pd.if.org Git - zpackage/blob - lzma/common/block_decoder.c
remove stray debug fprintf
[zpackage] / lzma / common / block_decoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       block_decoder.c
4 /// \brief      Decodes .xz Blocks
5 //
6 //  Author:     Lasse Collin
7 //
8 //  This file has been put into the public domain.
9 //  You can do whatever you want with this file.
10 //
11 ///////////////////////////////////////////////////////////////////////////////
12
13 #include "block_decoder.h"
14 #include "filter_decoder.h"
15 #include "check.h"
16
17
18 typedef struct {
19         enum {
20                 SEQ_CODE,
21                 SEQ_PADDING,
22                 SEQ_CHECK,
23         } sequence;
24
25         /// The filters in the chain; initialized with lzma_raw_decoder_init().
26         lzma_next_coder next;
27
28         /// Decoding options; we also write Compressed Size and Uncompressed
29         /// Size back to this structure when the decoding has been finished.
30         lzma_block *block;
31
32         /// Compressed Size calculated while decoding
33         lzma_vli compressed_size;
34
35         /// Uncompressed Size calculated while decoding
36         lzma_vli uncompressed_size;
37
38         /// Maximum allowed Compressed Size; this takes into account the
39         /// size of the Block Header and Check fields when Compressed Size
40         /// is unknown.
41         lzma_vli compressed_limit;
42
43         /// Position when reading the Check field
44         size_t check_pos;
45
46         /// Check of the uncompressed data
47         lzma_check_state check;
48
49         /// True if the integrity check won't be calculated and verified.
50         bool ignore_check;
51 } lzma_block_coder;
52
53
54 static inline bool
55 update_size(lzma_vli *size, lzma_vli add, lzma_vli limit)
56 {
57         if (limit > LZMA_VLI_MAX)
58                 limit = LZMA_VLI_MAX;
59
60         if (limit < *size || limit - *size < add)
61                 return true;
62
63         *size += add;
64
65         return false;
66 }
67
68
69 static inline bool
70 is_size_valid(lzma_vli size, lzma_vli reference)
71 {
72         return reference == LZMA_VLI_UNKNOWN || reference == size;
73 }
74
75
76 static lzma_ret
77 block_decode(void *coder_ptr, const lzma_allocator *allocator,
78                 const uint8_t *restrict in, size_t *restrict in_pos,
79                 size_t in_size, uint8_t *restrict out,
80                 size_t *restrict out_pos, size_t out_size, lzma_action action)
81 {
82         lzma_block_coder *coder = coder_ptr;
83
84         switch (coder->sequence) {
85         case SEQ_CODE: {
86                 const size_t in_start = *in_pos;
87                 const size_t out_start = *out_pos;
88
89                 const lzma_ret ret = coder->next.code(coder->next.coder,
90                                 allocator, in, in_pos, in_size,
91                                 out, out_pos, out_size, action);
92
93                 const size_t in_used = *in_pos - in_start;
94                 const size_t out_used = *out_pos - out_start;
95
96                 // NOTE: We compare to compressed_limit here, which prevents
97                 // the total size of the Block growing past LZMA_VLI_MAX.
98                 if (update_size(&coder->compressed_size, in_used,
99                                         coder->compressed_limit)
100                                 || update_size(&coder->uncompressed_size,
101                                         out_used,
102                                         coder->block->uncompressed_size))
103                         return LZMA_DATA_ERROR;
104
105                 if (!coder->ignore_check)
106                         lzma_check_update(&coder->check, coder->block->check,
107                                         out + out_start, out_used);
108
109                 if (ret != LZMA_STREAM_END)
110                         return ret;
111
112                 // Compressed and Uncompressed Sizes are now at their final
113                 // values. Verify that they match the values given to us.
114                 if (!is_size_valid(coder->compressed_size,
115                                         coder->block->compressed_size)
116                                 || !is_size_valid(coder->uncompressed_size,
117                                         coder->block->uncompressed_size))
118                         return LZMA_DATA_ERROR;
119
120                 // Copy the values into coder->block. The caller
121                 // may use this information to construct Index.
122                 coder->block->compressed_size = coder->compressed_size;
123                 coder->block->uncompressed_size = coder->uncompressed_size;
124
125                 coder->sequence = SEQ_PADDING;
126         }
127
128         // Fall through
129
130         case SEQ_PADDING:
131                 // Compressed Data is padded to a multiple of four bytes.
132                 while (coder->compressed_size & 3) {
133                         if (*in_pos >= in_size)
134                                 return LZMA_OK;
135
136                         // We use compressed_size here just get the Padding
137                         // right. The actual Compressed Size was stored to
138                         // coder->block already, and won't be modified by
139                         // us anymore.
140                         ++coder->compressed_size;
141
142                         if (in[(*in_pos)++] != 0x00)
143                                 return LZMA_DATA_ERROR;
144                 }
145
146                 if (coder->block->check == LZMA_CHECK_NONE)
147                         return LZMA_STREAM_END;
148
149                 if (!coder->ignore_check)
150                         lzma_check_finish(&coder->check, coder->block->check);
151
152                 coder->sequence = SEQ_CHECK;
153
154         // Fall through
155
156         case SEQ_CHECK: {
157                 const size_t check_size = lzma_check_size(coder->block->check);
158                 lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
159                                 &coder->check_pos, check_size);
160                 if (coder->check_pos < check_size)
161                         return LZMA_OK;
162
163                 // Validate the Check only if we support it.
164                 // coder->check.buffer may be uninitialized
165                 // when the Check ID is not supported.
166                 if (!coder->ignore_check
167                                 && lzma_check_is_supported(coder->block->check)
168                                 && memcmp(coder->block->raw_check,
169                                         coder->check.buffer.u8,
170                                         check_size) != 0)
171                         return LZMA_DATA_ERROR;
172
173                 return LZMA_STREAM_END;
174         }
175         }
176
177         return LZMA_PROG_ERROR;
178 }
179
180
181 static void
182 block_decoder_end(void *coder_ptr, const lzma_allocator *allocator)
183 {
184         lzma_block_coder *coder = coder_ptr;
185         lzma_next_end(&coder->next, allocator);
186         lzma_free(coder, allocator);
187         return;
188 }
189
190
191 extern lzma_ret
192 lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
193                 lzma_block *block)
194 {
195         lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
196
197         // Validate the options. lzma_block_unpadded_size() does that for us
198         // except for Uncompressed Size and filters. Filters are validated
199         // by the raw decoder.
200         if (lzma_block_unpadded_size(block) == 0
201                         || !lzma_vli_is_valid(block->uncompressed_size))
202                 return LZMA_PROG_ERROR;
203
204         // Allocate *next->coder if needed.
205         lzma_block_coder *coder = next->coder;
206         if (coder == NULL) {
207                 coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
208                 if (coder == NULL)
209                         return LZMA_MEM_ERROR;
210
211                 next->coder = coder;
212                 next->code = &block_decode;
213                 next->end = &block_decoder_end;
214                 coder->next = LZMA_NEXT_CODER_INIT;
215         }
216
217         // Basic initializations
218         coder->sequence = SEQ_CODE;
219         coder->block = block;
220         coder->compressed_size = 0;
221         coder->uncompressed_size = 0;
222
223         // If Compressed Size is not known, we calculate the maximum allowed
224         // value so that encoded size of the Block (including Block Padding)
225         // is still a valid VLI and a multiple of four.
226         coder->compressed_limit
227                         = block->compressed_size == LZMA_VLI_UNKNOWN
228                                 ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
229                                         - block->header_size
230                                         - lzma_check_size(block->check)
231                                 : block->compressed_size;
232
233         // Initialize the check. It's caller's problem if the Check ID is not
234         // supported, and the Block decoder cannot verify the Check field.
235         // Caller can test lzma_check_is_supported(block->check).
236         coder->check_pos = 0;
237         lzma_check_init(&coder->check, block->check);
238
239         coder->ignore_check = block->version >= 1
240                         ? block->ignore_check : false;
241
242         // Initialize the filter chain.
243         return lzma_raw_decoder_init(&coder->next, allocator,
244                         block->filters);
245 }
246
247
248 extern LZMA_API(lzma_ret)
249 lzma_block_decoder(lzma_stream *strm, lzma_block *block)
250 {
251         lzma_next_strm_init(lzma_block_decoder_init, strm, block);
252
253         strm->internal->supported_actions[LZMA_RUN] = true;
254         strm->internal->supported_actions[LZMA_FINISH] = true;
255
256         return LZMA_OK;
257 }