/src/xz/src/liblzma/common/block_encoder.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: 0BSD |
2 | | |
3 | | /////////////////////////////////////////////////////////////////////////////// |
4 | | // |
5 | | /// \file block_encoder.c |
6 | | /// \brief Encodes .xz Blocks |
7 | | // |
8 | | // Author: Lasse Collin |
9 | | // |
10 | | /////////////////////////////////////////////////////////////////////////////// |
11 | | |
12 | | #include "block_encoder.h" |
13 | | #include "filter_encoder.h" |
14 | | #include "check.h" |
15 | | |
16 | | |
17 | | typedef struct { |
18 | | /// The filters in the chain; initialized with lzma_raw_decoder_init(). |
19 | | lzma_next_coder next; |
20 | | |
21 | | /// Encoding options; we also write Unpadded Size, Compressed Size, |
22 | | /// and Uncompressed Size back to this structure when the encoding |
23 | | /// has been finished. |
24 | | lzma_block *block; |
25 | | |
26 | | enum { |
27 | | SEQ_CODE, |
28 | | SEQ_PADDING, |
29 | | SEQ_CHECK, |
30 | | } sequence; |
31 | | |
32 | | /// Compressed Size calculated while encoding |
33 | | lzma_vli compressed_size; |
34 | | |
35 | | /// Uncompressed Size calculated while encoding |
36 | | lzma_vli uncompressed_size; |
37 | | |
38 | | /// Position in the Check field |
39 | | size_t pos; |
40 | | |
41 | | /// Check of the uncompressed data |
42 | | lzma_check_state check; |
43 | | } lzma_block_coder; |
44 | | |
45 | | |
46 | | static lzma_ret |
47 | | block_encode(void *coder_ptr, const lzma_allocator *allocator, |
48 | | const uint8_t *restrict in, size_t *restrict in_pos, |
49 | | size_t in_size, uint8_t *restrict out, |
50 | | size_t *restrict out_pos, size_t out_size, lzma_action action) |
51 | 211k | { |
52 | 211k | lzma_block_coder *coder = coder_ptr; |
53 | | |
54 | | // Check that our amount of input stays in proper limits. |
55 | 211k | if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos) |
56 | 0 | return LZMA_DATA_ERROR; |
57 | | |
58 | 211k | switch (coder->sequence) { |
59 | 211k | case SEQ_CODE: { |
60 | 211k | const size_t in_start = *in_pos; |
61 | 211k | const size_t out_start = *out_pos; |
62 | | |
63 | 211k | const lzma_ret ret = coder->next.code(coder->next.coder, |
64 | 211k | allocator, in, in_pos, in_size, |
65 | 211k | out, out_pos, out_size, action); |
66 | | |
67 | 211k | const size_t in_used = *in_pos - in_start; |
68 | 211k | const size_t out_used = *out_pos - out_start; |
69 | | |
70 | 211k | if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used) |
71 | 0 | return LZMA_DATA_ERROR; |
72 | | |
73 | 211k | coder->compressed_size += out_used; |
74 | | |
75 | | // No need to check for overflow because we have already |
76 | | // checked it at the beginning of this function. |
77 | 211k | coder->uncompressed_size += in_used; |
78 | | |
79 | | // Call lzma_check_update() only if input was consumed. This |
80 | | // avoids null pointer + 0 (undefined behavior) when in == 0. |
81 | 211k | if (in_used > 0) |
82 | 209k | lzma_check_update(&coder->check, coder->block->check, |
83 | 209k | in + in_start, in_used); |
84 | | |
85 | 211k | if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH) |
86 | 209k | return ret; |
87 | | |
88 | 1.66k | assert(*in_pos == in_size); |
89 | 1.66k | assert(action == LZMA_FINISH); |
90 | | |
91 | | // Copy the values into coder->block. The caller |
92 | | // may use this information to construct Index. |
93 | 1.66k | coder->block->compressed_size = coder->compressed_size; |
94 | 1.66k | coder->block->uncompressed_size = coder->uncompressed_size; |
95 | | |
96 | 1.66k | coder->sequence = SEQ_PADDING; |
97 | 1.66k | FALLTHROUGH; |
98 | 1.66k | } |
99 | | |
100 | 1.66k | case SEQ_PADDING: |
101 | | // Pad Compressed Data to a multiple of four bytes. We can |
102 | | // use coder->compressed_size for this since we don't need |
103 | | // it for anything else anymore. |
104 | 4.06k | while (coder->compressed_size & 3) { |
105 | 2.39k | if (*out_pos >= out_size) |
106 | 0 | return LZMA_OK; |
107 | | |
108 | 2.39k | out[*out_pos] = 0x00; |
109 | 2.39k | ++*out_pos; |
110 | 2.39k | ++coder->compressed_size; |
111 | 2.39k | } |
112 | | |
113 | 1.66k | if (coder->block->check == LZMA_CHECK_NONE) |
114 | 1.66k | return LZMA_STREAM_END; |
115 | | |
116 | 0 | lzma_check_finish(&coder->check, coder->block->check); |
117 | |
|
118 | 0 | coder->sequence = SEQ_CHECK; |
119 | 0 | FALLTHROUGH; |
120 | |
|
121 | 0 | case SEQ_CHECK: { |
122 | 0 | const size_t check_size = lzma_check_size(coder->block->check); |
123 | 0 | lzma_bufcpy(coder->check.buffer.u8, &coder->pos, check_size, |
124 | 0 | out, out_pos, out_size); |
125 | 0 | if (coder->pos < check_size) |
126 | 0 | return LZMA_OK; |
127 | | |
128 | 0 | memcpy(coder->block->raw_check, coder->check.buffer.u8, |
129 | 0 | check_size); |
130 | 0 | return LZMA_STREAM_END; |
131 | 0 | } |
132 | 211k | } |
133 | | |
134 | 0 | return LZMA_PROG_ERROR; |
135 | 211k | } |
136 | | |
137 | | |
138 | | static void |
139 | | block_encoder_end(void *coder_ptr, const lzma_allocator *allocator) |
140 | 1.45k | { |
141 | 1.45k | lzma_block_coder *coder = coder_ptr; |
142 | 1.45k | lzma_next_end(&coder->next, allocator); |
143 | 1.45k | lzma_free(coder, allocator); |
144 | 1.45k | return; |
145 | 1.45k | } |
146 | | |
147 | | |
148 | | static lzma_ret |
149 | | block_encoder_update(void *coder_ptr, const lzma_allocator *allocator, |
150 | | const lzma_filter *filters lzma_attribute((__unused__)), |
151 | | const lzma_filter *reversed_filters) |
152 | 0 | { |
153 | 0 | lzma_block_coder *coder = coder_ptr; |
154 | |
|
155 | 0 | if (coder->sequence != SEQ_CODE) |
156 | 0 | return LZMA_PROG_ERROR; |
157 | | |
158 | 0 | return lzma_next_filter_update( |
159 | 0 | &coder->next, allocator, reversed_filters); |
160 | 0 | } |
161 | | |
162 | | |
163 | | extern lzma_ret |
164 | | lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, |
165 | | lzma_block *block) |
166 | 1.66k | { |
167 | 1.66k | lzma_next_coder_init(&lzma_block_encoder_init, next, allocator); |
168 | | |
169 | 1.66k | if (block == NULL) |
170 | 0 | return LZMA_PROG_ERROR; |
171 | | |
172 | | // The contents of the structure may depend on the version so |
173 | | // check the version first. |
174 | 1.66k | if (block->version > 1) |
175 | 0 | return LZMA_OPTIONS_ERROR; |
176 | | |
177 | | // If the Check ID is not supported, we cannot calculate the check and |
178 | | // thus not create a proper Block. |
179 | 1.66k | if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX) |
180 | 0 | return LZMA_PROG_ERROR; |
181 | | |
182 | 1.66k | if (!lzma_check_is_supported(block->check)) |
183 | 0 | return LZMA_UNSUPPORTED_CHECK; |
184 | | |
185 | | // Allocate and initialize *next->coder if needed. |
186 | 1.66k | lzma_block_coder *coder = next->coder; |
187 | 1.66k | if (coder == NULL) { |
188 | 1.45k | coder = lzma_alloc(sizeof(lzma_block_coder), allocator); |
189 | 1.45k | if (coder == NULL) |
190 | 0 | return LZMA_MEM_ERROR; |
191 | | |
192 | 1.45k | next->coder = coder; |
193 | 1.45k | next->code = &block_encode; |
194 | 1.45k | next->end = &block_encoder_end; |
195 | 1.45k | next->update = &block_encoder_update; |
196 | 1.45k | coder->next = LZMA_NEXT_CODER_INIT; |
197 | 1.45k | } |
198 | | |
199 | | // Basic initializations |
200 | 1.66k | coder->sequence = SEQ_CODE; |
201 | 1.66k | coder->block = block; |
202 | 1.66k | coder->compressed_size = 0; |
203 | 1.66k | coder->uncompressed_size = 0; |
204 | 1.66k | coder->pos = 0; |
205 | | |
206 | | // Initialize the check |
207 | 1.66k | lzma_check_init(&coder->check, block->check); |
208 | | |
209 | | // Initialize the requested filters. |
210 | 1.66k | return lzma_raw_encoder_init(&coder->next, allocator, block->filters); |
211 | 1.66k | } |
212 | | |
213 | | |
214 | | extern LZMA_API(lzma_ret) |
215 | | lzma_block_encoder(lzma_stream *strm, lzma_block *block) |
216 | 0 | { |
217 | 0 | lzma_next_strm_init(lzma_block_encoder_init, strm, block); |
218 | | |
219 | 0 | strm->internal->supported_actions[LZMA_RUN] = true; |
220 | 0 | strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; |
221 | 0 | strm->internal->supported_actions[LZMA_FINISH] = true; |
222 | |
|
223 | 0 | return LZMA_OK; |
224 | 0 | } |