/src/CMake/Utilities/cmliblzma/liblzma/common/block_encoder.c
Line | Count | Source |
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 | 0 | { |
52 | 0 | lzma_block_coder *coder = coder_ptr; |
53 | | |
54 | | // Check that our amount of input stays in proper limits. |
55 | 0 | if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos) |
56 | 0 | return LZMA_DATA_ERROR; |
57 | | |
58 | 0 | switch (coder->sequence) { |
59 | 0 | case SEQ_CODE: { |
60 | 0 | const size_t in_start = *in_pos; |
61 | 0 | const size_t out_start = *out_pos; |
62 | |
|
63 | 0 | const lzma_ret ret = coder->next.code(coder->next.coder, |
64 | 0 | allocator, in, in_pos, in_size, |
65 | 0 | out, out_pos, out_size, action); |
66 | |
|
67 | 0 | const size_t in_used = *in_pos - in_start; |
68 | 0 | const size_t out_used = *out_pos - out_start; |
69 | |
|
70 | 0 | if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used) |
71 | 0 | return LZMA_DATA_ERROR; |
72 | | |
73 | 0 | 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 | 0 | 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 | 0 | if (in_used > 0) |
82 | 0 | lzma_check_update(&coder->check, coder->block->check, |
83 | 0 | in + in_start, in_used); |
84 | |
|
85 | 0 | if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH) |
86 | 0 | return ret; |
87 | | |
88 | 0 | assert(*in_pos == in_size); |
89 | 0 | assert(action == LZMA_FINISH); |
90 | | |
91 | | // Copy the values into coder->block. The caller |
92 | | // may use this information to construct Index. |
93 | 0 | coder->block->compressed_size = coder->compressed_size; |
94 | 0 | coder->block->uncompressed_size = coder->uncompressed_size; |
95 | |
|
96 | 0 | coder->sequence = SEQ_PADDING; |
97 | 0 | } |
98 | | |
99 | | // Fall through |
100 | | |
101 | 0 | case SEQ_PADDING: |
102 | | // Pad Compressed Data to a multiple of four bytes. We can |
103 | | // use coder->compressed_size for this since we don't need |
104 | | // it for anything else anymore. |
105 | 0 | while (coder->compressed_size & 3) { |
106 | 0 | if (*out_pos >= out_size) |
107 | 0 | return LZMA_OK; |
108 | | |
109 | 0 | out[*out_pos] = 0x00; |
110 | 0 | ++*out_pos; |
111 | 0 | ++coder->compressed_size; |
112 | 0 | } |
113 | | |
114 | 0 | if (coder->block->check == LZMA_CHECK_NONE) |
115 | 0 | return LZMA_STREAM_END; |
116 | | |
117 | 0 | lzma_check_finish(&coder->check, coder->block->check); |
118 | |
|
119 | 0 | coder->sequence = SEQ_CHECK; |
120 | | |
121 | | // Fall through |
122 | |
|
123 | 0 | case SEQ_CHECK: { |
124 | 0 | const size_t check_size = lzma_check_size(coder->block->check); |
125 | 0 | lzma_bufcpy(coder->check.buffer.u8, &coder->pos, check_size, |
126 | 0 | out, out_pos, out_size); |
127 | 0 | if (coder->pos < check_size) |
128 | 0 | return LZMA_OK; |
129 | | |
130 | 0 | memcpy(coder->block->raw_check, coder->check.buffer.u8, |
131 | 0 | check_size); |
132 | 0 | return LZMA_STREAM_END; |
133 | 0 | } |
134 | 0 | } |
135 | | |
136 | 0 | return LZMA_PROG_ERROR; |
137 | 0 | } |
138 | | |
139 | | |
140 | | static void |
141 | | block_encoder_end(void *coder_ptr, const lzma_allocator *allocator) |
142 | 0 | { |
143 | 0 | lzma_block_coder *coder = coder_ptr; |
144 | 0 | lzma_next_end(&coder->next, allocator); |
145 | 0 | lzma_free(coder, allocator); |
146 | 0 | return; |
147 | 0 | } |
148 | | |
149 | | |
150 | | static lzma_ret |
151 | | block_encoder_update(void *coder_ptr, const lzma_allocator *allocator, |
152 | | const lzma_filter *filters lzma_attribute((__unused__)), |
153 | | const lzma_filter *reversed_filters) |
154 | 0 | { |
155 | 0 | lzma_block_coder *coder = coder_ptr; |
156 | |
|
157 | 0 | if (coder->sequence != SEQ_CODE) |
158 | 0 | return LZMA_PROG_ERROR; |
159 | | |
160 | 0 | return lzma_next_filter_update( |
161 | 0 | &coder->next, allocator, reversed_filters); |
162 | 0 | } |
163 | | |
164 | | |
165 | | extern lzma_ret |
166 | | lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, |
167 | | lzma_block *block) |
168 | 0 | { |
169 | 0 | lzma_next_coder_init(&lzma_block_encoder_init, next, allocator); |
170 | |
|
171 | 0 | if (block == NULL) |
172 | 0 | return LZMA_PROG_ERROR; |
173 | | |
174 | | // The contents of the structure may depend on the version so |
175 | | // check the version first. |
176 | 0 | if (block->version > 1) |
177 | 0 | return LZMA_OPTIONS_ERROR; |
178 | | |
179 | | // If the Check ID is not supported, we cannot calculate the check and |
180 | | // thus not create a proper Block. |
181 | 0 | if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX) |
182 | 0 | return LZMA_PROG_ERROR; |
183 | | |
184 | 0 | if (!lzma_check_is_supported(block->check)) |
185 | 0 | return LZMA_UNSUPPORTED_CHECK; |
186 | | |
187 | | // Allocate and initialize *next->coder if needed. |
188 | 0 | lzma_block_coder *coder = next->coder; |
189 | 0 | if (coder == NULL) { |
190 | 0 | coder = lzma_alloc(sizeof(lzma_block_coder), allocator); |
191 | 0 | if (coder == NULL) |
192 | 0 | return LZMA_MEM_ERROR; |
193 | | |
194 | 0 | next->coder = coder; |
195 | 0 | next->code = &block_encode; |
196 | 0 | next->end = &block_encoder_end; |
197 | 0 | next->update = &block_encoder_update; |
198 | 0 | coder->next = LZMA_NEXT_CODER_INIT; |
199 | 0 | } |
200 | | |
201 | | // Basic initializations |
202 | 0 | coder->sequence = SEQ_CODE; |
203 | 0 | coder->block = block; |
204 | 0 | coder->compressed_size = 0; |
205 | 0 | coder->uncompressed_size = 0; |
206 | 0 | coder->pos = 0; |
207 | | |
208 | | // Initialize the check |
209 | 0 | lzma_check_init(&coder->check, block->check); |
210 | | |
211 | | // Initialize the requested filters. |
212 | 0 | return lzma_raw_encoder_init(&coder->next, allocator, block->filters); |
213 | 0 | } |
214 | | |
215 | | |
216 | | extern LZMA_API(lzma_ret) |
217 | | lzma_block_encoder(lzma_stream *strm, lzma_block *block) |
218 | 0 | { |
219 | 0 | lzma_next_strm_init(lzma_block_encoder_init, strm, block); |
220 | | |
221 | 0 | strm->internal->supported_actions[LZMA_RUN] = true; |
222 | 0 | strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true; |
223 | 0 | strm->internal->supported_actions[LZMA_FINISH] = true; |
224 | |
|
225 | 0 | return LZMA_OK; |
226 | 0 | } |