]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/block_encoder.c
Cleaned up Block encoder and moved the no longer shared
[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 "filter_encoder.h"
22 #include "check.h"
23
24
25 /// The maximum size of a single Block is limited by the maximum size of
26 /// a Stream, which is 2^63 - 1 bytes (i.e. LZMA_VLI_VALUE_MAX). We could
27 /// take into account the headers etc. to determine the exact maximum size
28 /// of the Compressed Data field, but the complexity would give us nothing
29 /// useful. Instead, limit the size of Compressed Data so that even with
30 /// biggest possible Block Header and Check fields the total size of the
31 /// Block stays as valid VLI. This way we don't produce incorrect output
32 /// if someone will really try creating a Block of 8 EiB.
33 ///
34 /// ~LZMA_VLI_C(3) is to guarantee that if we need padding at the end of
35 /// the Compressed Data field, it will still stay in the proper limit.
36 #define COMPRESSED_SIZE_MAX ((LZMA_VLI_VALUE_MAX - LZMA_BLOCK_HEADER_SIZE_MAX \
37                 - LZMA_CHECK_SIZE_MAX) & ~LZMA_VLI_C(3))
38
39
40 struct lzma_coder_s {
41         /// The filters in the chain; initialized with lzma_raw_decoder_init().
42         lzma_next_coder next;
43
44         /// Encoding options; we also write Total Size, Compressed Size, and
45         /// Uncompressed Size back to this structure when the encoding has
46         /// been finished.
47         lzma_block *options;
48
49         enum {
50                 SEQ_CODE,
51                 SEQ_PADDING,
52                 SEQ_CHECK,
53         } sequence;
54
55         /// Compressed Size calculated while encoding
56         lzma_vli compressed_size;
57
58         /// Uncompressed Size calculated while encoding
59         lzma_vli uncompressed_size;
60
61         /// Position when writing out the Check field
62         size_t check_pos;
63
64         /// Check of the uncompressed data
65         lzma_check_state check;
66 };
67
68
69 static lzma_ret
70 block_encode(lzma_coder *coder, lzma_allocator *allocator,
71                 const uint8_t *restrict in, size_t *restrict in_pos,
72                 size_t in_size, uint8_t *restrict out,
73                 size_t *restrict out_pos, size_t out_size, lzma_action action)
74 {
75         // Check that our amount of input stays in proper limits.
76         if (LZMA_VLI_VALUE_MAX - coder->uncompressed_size < in_size - *in_pos)
77                 return LZMA_PROG_ERROR;
78
79         switch (coder->sequence) {
80         case SEQ_CODE: {
81                 const size_t in_start = *in_pos;
82                 const size_t out_start = *out_pos;
83
84                 const lzma_ret ret = coder->next.code(coder->next.coder,
85                                 allocator, in, in_pos, in_size,
86                                 out, out_pos, out_size, action);
87
88                 const size_t in_used = *in_pos - in_start;
89                 const size_t out_used = *out_pos - out_start;
90
91                 if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used)
92                         return LZMA_DATA_ERROR;
93
94                 coder->compressed_size += out_used;
95
96                 // No need to check for overflow because we have already
97                 // checked it at the beginning of this function.
98                 coder->uncompressed_size += in_used;
99
100                 lzma_check_update(&coder->check, coder->options->check,
101                                 in + in_start, in_used);
102
103                 if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
104                         return ret;
105
106                 assert(*in_pos == in_size);
107                 assert(action == LZMA_FINISH);
108
109                 coder->sequence = SEQ_PADDING;
110         }
111
112         // Fall through
113
114         case SEQ_PADDING:
115                 // Pad Compressed Data to a multiple of four bytes.
116                 while (coder->compressed_size & 3) {
117                         if (*out_pos >= out_size)
118                                 return LZMA_OK;
119
120                         out[*out_pos] = 0x00;
121                         ++*out_pos;
122
123                         // No need to use check for overflow here since we
124                         // have already checked in SEQ_CODE that Compressed
125                         // Size will stay in proper limits.
126                         ++coder->compressed_size;
127                 }
128
129                 // Copy the values into coder->options. The caller
130                 // may use this information to construct Index.
131                 coder->options->compressed_size = coder->compressed_size;
132                 coder->options->uncompressed_size = coder->uncompressed_size;
133
134                 if (coder->options->check == LZMA_CHECK_NONE)
135                         return LZMA_STREAM_END;
136
137                 lzma_check_finish(&coder->check, coder->options->check);
138                 coder->sequence = SEQ_CHECK;
139
140         // Fall through
141
142         case SEQ_CHECK: {
143                 const uint32_t check_size
144                                 = lzma_check_size(coder->options->check);
145
146                 while (*out_pos < out_size) {
147                         out[*out_pos] = coder->check.buffer.u8[
148                                         coder->check_pos];
149                         ++*out_pos;
150
151                         if (++coder->check_pos == check_size)
152                                 return LZMA_STREAM_END;
153                 }
154
155                 return LZMA_OK;
156         }
157         }
158
159         return LZMA_PROG_ERROR;
160 }
161
162
163 static void
164 block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
165 {
166         lzma_next_end(&coder->next, allocator);
167         lzma_free(coder, allocator);
168         return;
169 }
170
171
172 extern lzma_ret
173 lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
174                 lzma_block *options)
175 {
176         lzma_next_coder_init(lzma_block_encoder_init, next, allocator);
177
178         // While lzma_block_total_size_get() is meant to calculate the Total
179         // Size, it also validates the options excluding the filters.
180         if (lzma_block_total_size_get(options) == 0)
181                 return LZMA_PROG_ERROR;
182
183         // If the Check ID is not supported, we cannot calculate the check and
184         // thus not create a proper Block.
185         if ((unsigned)(options->check) > LZMA_CHECK_ID_MAX)
186                 return LZMA_PROG_ERROR;
187
188         if (!lzma_check_is_supported(options->check))
189                 return LZMA_UNSUPPORTED_CHECK;
190
191         // Allocate and initialize *next->coder if needed.
192         if (next->coder == NULL) {
193                 next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
194                 if (next->coder == NULL)
195                         return LZMA_MEM_ERROR;
196
197                 next->code = &block_encode;
198                 next->end = &block_encoder_end;
199                 next->coder->next = LZMA_NEXT_CODER_INIT;
200         }
201
202         // Basic initializations
203         next->coder->sequence = SEQ_CODE;
204         next->coder->options = options;
205         next->coder->compressed_size = 0;
206         next->coder->uncompressed_size = 0;
207
208         // Initialize the check
209         next->coder->check_pos = 0;
210         lzma_check_init(&next->coder->check, options->check);
211
212         // Initialize the requested filters.
213         return lzma_raw_encoder_init(&next->coder->next, allocator,
214                         options->filters);
215 }
216
217
218 extern LZMA_API lzma_ret
219 lzma_block_encoder(lzma_stream *strm, lzma_block *options)
220 {
221         lzma_next_strm_init(lzma_block_encoder_init, strm, options);
222
223         strm->internal->supported_actions[LZMA_RUN] = true;
224         strm->internal->supported_actions[LZMA_FINISH] = true;
225
226         return LZMA_OK;
227 }