]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/xz/src/liblzma/common/block_decoder.c
MFC: xz 5.2.2.
[FreeBSD/stable/10.git] / contrib / xz / src / liblzma / 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 struct lzma_coder_s {
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 };
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(lzma_coder *coder, 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         switch (coder->sequence) {
83         case SEQ_CODE: {
84                 const size_t in_start = *in_pos;
85                 const size_t out_start = *out_pos;
86
87                 const lzma_ret ret = coder->next.code(coder->next.coder,
88                                 allocator, in, in_pos, in_size,
89                                 out, out_pos, out_size, action);
90
91                 const size_t in_used = *in_pos - in_start;
92                 const size_t out_used = *out_pos - out_start;
93
94                 // NOTE: We compare to compressed_limit here, which prevents
95                 // the total size of the Block growing past LZMA_VLI_MAX.
96                 if (update_size(&coder->compressed_size, in_used,
97                                         coder->compressed_limit)
98                                 || update_size(&coder->uncompressed_size,
99                                         out_used,
100                                         coder->block->uncompressed_size))
101                         return LZMA_DATA_ERROR;
102
103                 if (!coder->ignore_check)
104                         lzma_check_update(&coder->check, coder->block->check,
105                                         out + out_start, out_used);
106
107                 if (ret != LZMA_STREAM_END)
108                         return ret;
109
110                 // Compressed and Uncompressed Sizes are now at their final
111                 // values. Verify that they match the values given to us.
112                 if (!is_size_valid(coder->compressed_size,
113                                         coder->block->compressed_size)
114                                 || !is_size_valid(coder->uncompressed_size,
115                                         coder->block->uncompressed_size))
116                         return LZMA_DATA_ERROR;
117
118                 // Copy the values into coder->block. The caller
119                 // may use this information to construct Index.
120                 coder->block->compressed_size = coder->compressed_size;
121                 coder->block->uncompressed_size = coder->uncompressed_size;
122
123                 coder->sequence = SEQ_PADDING;
124         }
125
126         // Fall through
127
128         case SEQ_PADDING:
129                 // Compressed Data is padded to a multiple of four bytes.
130                 while (coder->compressed_size & 3) {
131                         if (*in_pos >= in_size)
132                                 return LZMA_OK;
133
134                         // We use compressed_size here just get the Padding
135                         // right. The actual Compressed Size was stored to
136                         // coder->block already, and won't be modified by
137                         // us anymore.
138                         ++coder->compressed_size;
139
140                         if (in[(*in_pos)++] != 0x00)
141                                 return LZMA_DATA_ERROR;
142                 }
143
144                 if (coder->block->check == LZMA_CHECK_NONE)
145                         return LZMA_STREAM_END;
146
147                 if (!coder->ignore_check)
148                         lzma_check_finish(&coder->check, coder->block->check);
149
150                 coder->sequence = SEQ_CHECK;
151
152         // Fall through
153
154         case SEQ_CHECK: {
155                 const size_t check_size = lzma_check_size(coder->block->check);
156                 lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
157                                 &coder->check_pos, check_size);
158                 if (coder->check_pos < check_size)
159                         return LZMA_OK;
160
161                 // Validate the Check only if we support it.
162                 // coder->check.buffer may be uninitialized
163                 // when the Check ID is not supported.
164                 if (!coder->ignore_check
165                                 && lzma_check_is_supported(coder->block->check)
166                                 && memcmp(coder->block->raw_check,
167                                         coder->check.buffer.u8,
168                                         check_size) != 0)
169                         return LZMA_DATA_ERROR;
170
171                 return LZMA_STREAM_END;
172         }
173         }
174
175         return LZMA_PROG_ERROR;
176 }
177
178
179 static void
180 block_decoder_end(lzma_coder *coder, const lzma_allocator *allocator)
181 {
182         lzma_next_end(&coder->next, allocator);
183         lzma_free(coder, allocator);
184         return;
185 }
186
187
188 extern lzma_ret
189 lzma_block_decoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
190                 lzma_block *block)
191 {
192         lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
193
194         // Validate the options. lzma_block_unpadded_size() does that for us
195         // except for Uncompressed Size and filters. Filters are validated
196         // by the raw decoder.
197         if (lzma_block_unpadded_size(block) == 0
198                         || !lzma_vli_is_valid(block->uncompressed_size))
199                 return LZMA_PROG_ERROR;
200
201         // Allocate and initialize *next->coder if needed.
202         if (next->coder == NULL) {
203                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
204                 if (next->coder == NULL)
205                         return LZMA_MEM_ERROR;
206
207                 next->code = &block_decode;
208                 next->end = &block_decoder_end;
209                 next->coder->next = LZMA_NEXT_CODER_INIT;
210         }
211
212         // Basic initializations
213         next->coder->sequence = SEQ_CODE;
214         next->coder->block = block;
215         next->coder->compressed_size = 0;
216         next->coder->uncompressed_size = 0;
217
218         // If Compressed Size is not known, we calculate the maximum allowed
219         // value so that encoded size of the Block (including Block Padding)
220         // is still a valid VLI and a multiple of four.
221         next->coder->compressed_limit
222                         = block->compressed_size == LZMA_VLI_UNKNOWN
223                                 ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
224                                         - block->header_size
225                                         - lzma_check_size(block->check)
226                                 : block->compressed_size;
227
228         // Initialize the check. It's caller's problem if the Check ID is not
229         // supported, and the Block decoder cannot verify the Check field.
230         // Caller can test lzma_check_is_supported(block->check).
231         next->coder->check_pos = 0;
232         lzma_check_init(&next->coder->check, block->check);
233
234         next->coder->ignore_check = block->version >= 1
235                         ? block->ignore_check : false;
236
237         // Initialize the filter chain.
238         return lzma_raw_decoder_init(&next->coder->next, allocator,
239                         block->filters);
240 }
241
242
243 extern LZMA_API(lzma_ret)
244 lzma_block_decoder(lzma_stream *strm, lzma_block *block)
245 {
246         lzma_next_strm_init(lzma_block_decoder_init, strm, block);
247
248         strm->internal->supported_actions[LZMA_RUN] = true;
249         strm->internal->supported_actions[LZMA_FINISH] = true;
250
251         return LZMA_OK;
252 }