]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/block_encoder.c
Remove two redundant validity checks from the LZMA decoder.
[icculus/xz.git] / src / liblzma / common / block_encoder.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       block_encoder.c
4 /// \brief      Encodes .lzma Blocks
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 "block_encoder.h"
21 #include "block_private.h"
22 #include "raw_encoder.h"
23 #include "check.h"
24
25
26 struct lzma_coder_s {
27         /// The filters in the chain; initialized with lzma_raw_decoder_init().
28         lzma_next_coder next;
29
30         /// Encoding options; we also write Total Size, Compressed Size, and
31         /// Uncompressed Size back to this structure when the encoding has
32         /// been finished.
33         lzma_options_block *options;
34
35         enum {
36                 SEQ_CODE,
37                 SEQ_CHECK_FINISH,
38                 SEQ_CHECK_COPY,
39                 SEQ_UNCOMPRESSED_SIZE,
40                 SEQ_BACKWARD_SIZE,
41                 SEQ_PADDING,
42         } sequence;
43
44         /// Position in .header and .check.
45         size_t pos;
46
47         /// Check of the uncompressed data
48         lzma_check check;
49
50         /// Total Size calculated while encoding
51         lzma_vli total_size;
52
53         /// Compressed Size calculated while encoding
54         lzma_vli compressed_size;
55
56         /// Uncompressed Size calculated while encoding
57         lzma_vli uncompressed_size;
58
59         /// Maximum allowed total_size
60         lzma_vli total_limit;
61
62         /// Maximum allowed uncompressed_size
63         lzma_vli uncompressed_limit;
64
65         /// Backward Size - This is a copy of total_size right before
66         /// the Backward Size field.
67         lzma_vli backward_size;
68 };
69
70
71 static lzma_ret
72 block_encode(lzma_coder *coder, lzma_allocator *allocator,
73                 const uint8_t *restrict in, size_t *restrict in_pos,
74                 size_t in_size, uint8_t *restrict out,
75                 size_t *restrict out_pos, size_t out_size, lzma_action action)
76 {
77         // Check that our amount of input stays in proper limits.
78         if (coder->options->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN) {
79                 if (action == LZMA_FINISH) {
80                         if (coder->options->uncompressed_size
81                                         - coder->uncompressed_size
82                                         != (lzma_vli)(in_size - *in_pos))
83                                 return LZMA_DATA_ERROR;
84                 } else {
85                         if (coder->options->uncompressed_size
86                                         - coder->uncompressed_size
87                                         <  (lzma_vli)(in_size - *in_pos))
88                                 return LZMA_DATA_ERROR;
89                 }
90         } else if (LZMA_VLI_VALUE_MAX - coder->uncompressed_size
91                         < (lzma_vli)(in_size - *in_pos)) {
92                 return LZMA_DATA_ERROR;
93         }
94
95         // Main loop
96         while (*out_pos < out_size
97                         && (*in_pos < in_size || action != LZMA_RUN))
98         switch (coder->sequence) {
99         case SEQ_CODE: {
100                 const size_t in_start = *in_pos;
101                 const size_t out_start = *out_pos;
102
103                 const lzma_ret ret = coder->next.code(coder->next.coder,
104                                 allocator, in, in_pos, in_size,
105                                 out, out_pos, out_size, action);
106
107                 const size_t in_used = *in_pos - in_start;
108                 const size_t out_used = *out_pos - out_start;
109
110                 if (update_size(&coder->total_size, out_used,
111                                         coder->total_limit)
112                                 || update_size(&coder->compressed_size,
113                                         out_used,
114                                         coder->options->compressed_size))
115                         return LZMA_DATA_ERROR;
116
117                 // No need to check for overflow because we have already
118                 // checked it at the beginning of this function.
119                 coder->uncompressed_size += in_used;
120
121                 lzma_check_update(&coder->check, coder->options->check,
122                                 in + in_start, in_used);
123
124                 if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
125                         return ret;
126
127                 assert(*in_pos == in_size);
128
129                 // Compressed and Uncompressed Sizes are now at their final
130                 // values. Verify that they match the values give to us.
131                 if (!is_size_valid(coder->compressed_size,
132                                         coder->options->compressed_size)
133                                 || !is_size_valid(coder->uncompressed_size,
134                                         coder->options->uncompressed_size))
135                         return LZMA_DATA_ERROR;
136
137                 coder->sequence = SEQ_CHECK_FINISH;
138                 break;
139         }
140
141         case SEQ_CHECK_FINISH:
142                 if (coder->options->check == LZMA_CHECK_NONE) {
143                         coder->sequence = SEQ_UNCOMPRESSED_SIZE;
144                         break;
145                 }
146
147                 lzma_check_finish(&coder->check, coder->options->check);
148                 coder->sequence = SEQ_CHECK_COPY;
149
150         // Fall through
151
152         case SEQ_CHECK_COPY:
153                 assert(lzma_check_sizes[coder->options->check] > 0);
154
155                 switch (coder->options->check) {
156                 case LZMA_CHECK_CRC32:
157                         out[*out_pos] = coder->check.crc32 >> (coder->pos * 8);
158                         break;
159
160                 case LZMA_CHECK_CRC64:
161                         out[*out_pos] = coder->check.crc64 >> (coder->pos * 8);
162                         break;
163
164                 case LZMA_CHECK_SHA256:
165                         out[*out_pos] = coder->check.sha256.buffer[coder->pos];
166                         break;
167
168                 default:
169                         assert(0);
170                         return LZMA_PROG_ERROR;
171                 }
172
173                 ++*out_pos;
174
175                 if (update_size(&coder->total_size, 1, coder->total_limit))
176                         return LZMA_DATA_ERROR;
177
178                 if (++coder->pos == lzma_check_sizes[coder->options->check]) {
179                         coder->pos = 0;
180                         coder->sequence = SEQ_UNCOMPRESSED_SIZE;
181                 }
182
183                 break;
184
185         case SEQ_UNCOMPRESSED_SIZE:
186                 if (coder->options->has_uncompressed_size_in_footer) {
187                         const size_t out_start = *out_pos;
188
189                         const lzma_ret ret = lzma_vli_encode(
190                                         coder->uncompressed_size,
191                                         &coder->pos, 1,
192                                         out, out_pos, out_size);
193
194                         // Updating the size this way instead of doing in a
195                         // single chunk using lzma_vli_size(), because this
196                         // way we detect when exactly we are going out of
197                         // our limits.
198                         if (update_size(&coder->total_size,
199                                         *out_pos - out_start,
200                                         coder->total_limit))
201                                 return LZMA_DATA_ERROR;
202
203                         if (ret != LZMA_STREAM_END)
204                                 return ret;
205
206                         coder->pos = 0;
207                 }
208
209                 coder->backward_size = coder->total_size;
210                 coder->sequence = SEQ_BACKWARD_SIZE;
211                 break;
212
213         case SEQ_BACKWARD_SIZE:
214                 if (coder->options->has_backward_size) {
215                         const size_t out_start = *out_pos;
216
217                         const lzma_ret ret = lzma_vli_encode(
218                                         coder->backward_size, &coder->pos, 1,
219                                         out, out_pos, out_size);
220
221                         if (update_size(&coder->total_size,
222                                         *out_pos - out_start,
223                                         coder->total_limit))
224                                 return LZMA_DATA_ERROR;
225
226                         if (ret != LZMA_STREAM_END)
227                                 return ret;
228                 }
229
230                 coder->sequence = SEQ_PADDING;
231                 break;
232
233         case SEQ_PADDING:
234                 if (coder->options->handle_padding) {
235                         assert(coder->options->total_size
236                                         != LZMA_VLI_VALUE_UNKNOWN);
237
238                         if (coder->total_size < coder->options->total_size) {
239                                 out[*out_pos] = 0x00;
240                                 ++*out_pos;
241
242                                 if (update_size(&coder->total_size, 1,
243                                                 coder->total_limit))
244                                         return LZMA_DATA_ERROR;
245
246                                 break;
247                         }
248                 }
249
250                 // Now also Total Size is known. Verify it.
251                 if (!is_size_valid(coder->total_size,
252                                         coder->options->total_size))
253                         return LZMA_DATA_ERROR;
254
255                 // Copy the values into coder->options. The caller
256                 // may use this information to construct Index.
257                 coder->options->total_size = coder->total_size;
258                 coder->options->compressed_size = coder->compressed_size;
259                 coder->options->uncompressed_size = coder->uncompressed_size;
260
261                 return LZMA_STREAM_END;
262
263         default:
264                 return LZMA_PROG_ERROR;
265         }
266
267         return LZMA_OK;
268 }
269
270
271 static void
272 block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
273 {
274         lzma_next_coder_end(&coder->next, allocator);
275         lzma_free(coder, allocator);
276         return;
277 }
278
279
280 static lzma_ret
281 block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
282                 lzma_options_block *options)
283 {
284         // Validate some options.
285         if (validate_options_1(options) || validate_options_2(options)
286                         || (options->handle_padding && options->total_size
287                                 == LZMA_VLI_VALUE_UNKNOWN))
288                 return LZMA_PROG_ERROR;
289
290         // Allocate and initialize *next->coder if needed.
291         if (next->coder == NULL) {
292                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
293                 if (next->coder == NULL)
294                         return LZMA_MEM_ERROR;
295
296                 next->code = &block_encode;
297                 next->end = &block_encoder_end;
298                 next->coder->next = LZMA_NEXT_CODER_INIT;
299         }
300
301         // Initialize the check.
302         return_if_error(lzma_check_init(&next->coder->check, options->check));
303
304         // If End of Payload Marker is not used and Uncompressed Size is zero,
305         // Compressed Data is empty. That is, we don't call the encoder at all.
306         // We initialize it though; it allows detecting invalid options.
307         if (!options->has_eopm && options->uncompressed_size == 0) {
308                 // Also Compressed Size must be zero if it has been
309                 // given to us.
310                 if (!is_size_valid(0, options->compressed_size))
311                         return LZMA_PROG_ERROR;
312
313                 next->coder->sequence = SEQ_CHECK_FINISH;
314         } else {
315                 next->coder->sequence = SEQ_CODE;
316         }
317
318         // Other initializations
319         next->coder->options = options;
320         next->coder->pos = 0;
321         next->coder->total_size = options->header_size;
322         next->coder->compressed_size = 0;
323         next->coder->uncompressed_size = 0;
324         next->coder->total_limit
325                         = MIN(options->total_size, options->total_limit);
326         next->coder->uncompressed_limit = MIN(options->uncompressed_size,
327                         options->uncompressed_limit);
328
329         // Initialize the requested filters.
330         return lzma_raw_encoder_init(&next->coder->next, allocator,
331                         options->filters, options->has_eopm
332                                 ? LZMA_VLI_VALUE_UNKNOWN
333                                 : options->uncompressed_size,
334                         true);
335 }
336
337
338 extern lzma_ret
339 lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
340                 lzma_options_block *options)
341 {
342         lzma_next_coder_init(block_encoder_init, next, allocator, options);
343 }
344
345
346 extern LZMA_API lzma_ret
347 lzma_block_encoder(lzma_stream *strm, lzma_options_block *options)
348 {
349         lzma_next_strm_init(strm, block_encoder_init, options);
350
351         strm->internal->supported_actions[LZMA_RUN] = true;
352         strm->internal->supported_actions[LZMA_FINISH] = true;
353
354         return LZMA_OK;
355 }