/src/CMake/Utilities/cmliblzma/liblzma/simple/simple_coder.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: 0BSD |
2 | | |
3 | | /////////////////////////////////////////////////////////////////////////////// |
4 | | // |
5 | | /// \file simple_coder.c |
6 | | /// \brief Wrapper for simple filters |
7 | | /// |
8 | | /// Simple filters don't change the size of the data i.e. number of bytes |
9 | | /// in equals the number of bytes out. |
10 | | // |
11 | | // Author: Lasse Collin |
12 | | // |
13 | | /////////////////////////////////////////////////////////////////////////////// |
14 | | |
15 | | #include "simple_private.h" |
16 | | |
17 | | |
18 | | /// Copied or encodes/decodes more data to out[]. |
19 | | static lzma_ret |
20 | | copy_or_code(lzma_simple_coder *coder, const lzma_allocator *allocator, |
21 | | const uint8_t *restrict in, size_t *restrict in_pos, |
22 | | size_t in_size, uint8_t *restrict out, |
23 | | size_t *restrict out_pos, size_t out_size, lzma_action action) |
24 | 1.62k | { |
25 | 1.62k | assert(!coder->end_was_reached); |
26 | | |
27 | 1.62k | if (coder->next.code == NULL) { |
28 | 0 | lzma_bufcpy(in, in_pos, in_size, out, out_pos, out_size); |
29 | | |
30 | | // Check if end of stream was reached. |
31 | 0 | if (coder->is_encoder && action == LZMA_FINISH |
32 | 0 | && *in_pos == in_size) |
33 | 0 | coder->end_was_reached = true; |
34 | |
|
35 | 1.62k | } else { |
36 | | // Call the next coder in the chain to provide us some data. |
37 | 1.62k | const lzma_ret ret = coder->next.code( |
38 | 1.62k | coder->next.coder, allocator, |
39 | 1.62k | in, in_pos, in_size, |
40 | 1.62k | out, out_pos, out_size, action); |
41 | | |
42 | 1.62k | if (ret == LZMA_STREAM_END) { |
43 | 62 | assert(!coder->is_encoder |
44 | 62 | || action == LZMA_FINISH); |
45 | 62 | coder->end_was_reached = true; |
46 | | |
47 | 1.55k | } else if (ret != LZMA_OK) { |
48 | 30 | return ret; |
49 | 30 | } |
50 | 1.62k | } |
51 | | |
52 | 1.59k | return LZMA_OK; |
53 | 1.62k | } |
54 | | |
55 | | |
56 | | static size_t |
57 | | call_filter(lzma_simple_coder *coder, uint8_t *buffer, size_t size) |
58 | 1.42k | { |
59 | 1.42k | const size_t filtered = coder->filter(coder->simple, |
60 | 1.42k | coder->now_pos, coder->is_encoder, |
61 | 1.42k | buffer, size); |
62 | 1.42k | coder->now_pos += filtered; |
63 | 1.42k | return filtered; |
64 | 1.42k | } |
65 | | |
66 | | |
67 | | static lzma_ret |
68 | | simple_code(void *coder_ptr, const lzma_allocator *allocator, |
69 | | const uint8_t *restrict in, size_t *restrict in_pos, |
70 | | size_t in_size, uint8_t *restrict out, |
71 | | size_t *restrict out_pos, size_t out_size, lzma_action action) |
72 | 950 | { |
73 | 950 | lzma_simple_coder *coder = coder_ptr; |
74 | | |
75 | | // TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it |
76 | | // in cases when the filter is able to filter everything. With most |
77 | | // simple filters it can be done at offset that is a multiple of 2, |
78 | | // 4, or 16. With x86 filter, it needs good luck, and thus cannot |
79 | | // be made to work predictably. |
80 | 950 | if (action == LZMA_SYNC_FLUSH) |
81 | 0 | return LZMA_OPTIONS_ERROR; |
82 | | |
83 | | // Flush already filtered data from coder->buffer[] to out[]. |
84 | 950 | if (coder->pos < coder->filtered) { |
85 | 12 | lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered, |
86 | 12 | out, out_pos, out_size); |
87 | | |
88 | | // If we couldn't flush all the filtered data, return to |
89 | | // application immediately. |
90 | 12 | if (coder->pos < coder->filtered) |
91 | 12 | return LZMA_OK; |
92 | | |
93 | 0 | if (coder->end_was_reached) { |
94 | 0 | assert(coder->filtered == coder->size); |
95 | 0 | return LZMA_STREAM_END; |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | // If we get here, there is no filtered data left in the buffer. |
100 | 938 | coder->filtered = 0; |
101 | | |
102 | 938 | assert(!coder->end_was_reached); |
103 | | |
104 | | // If there is more output space left than there is unfiltered data |
105 | | // in coder->buffer[], flush coder->buffer[] to out[], and copy/code |
106 | | // more data to out[] hopefully filling it completely. Then filter |
107 | | // the data in out[]. This step is where most of the data gets |
108 | | // filtered if the buffer sizes used by the application are reasonable. |
109 | 938 | const size_t out_avail = out_size - *out_pos; |
110 | 938 | const size_t buf_avail = coder->size - coder->pos; |
111 | 938 | if (out_avail > buf_avail || buf_avail == 0) { |
112 | | // Store the old position so that we know from which byte |
113 | | // to start filtering. |
114 | 930 | const size_t out_start = *out_pos; |
115 | | |
116 | | // Flush data from coder->buffer[] to out[], but don't reset |
117 | | // coder->pos and coder->size yet. This way the coder can be |
118 | | // restarted if the next filter in the chain returns e.g. |
119 | | // LZMA_MEM_ERROR. |
120 | | // |
121 | | // Do the memcpy() conditionally because out can be NULL |
122 | | // (in which case buf_avail is always 0). Calling memcpy() |
123 | | // with a null-pointer is undefined even if the third |
124 | | // argument is 0. |
125 | 930 | if (buf_avail > 0) |
126 | 436 | memcpy(out + *out_pos, coder->buffer + coder->pos, |
127 | 436 | buf_avail); |
128 | | |
129 | 930 | *out_pos += buf_avail; |
130 | | |
131 | | // Copy/Encode/Decode more data to out[]. |
132 | 930 | { |
133 | 930 | const lzma_ret ret = copy_or_code(coder, allocator, |
134 | 930 | in, in_pos, in_size, |
135 | 930 | out, out_pos, out_size, action); |
136 | 930 | assert(ret != LZMA_STREAM_END); |
137 | 930 | if (ret != LZMA_OK) |
138 | 28 | return ret; |
139 | 930 | } |
140 | | |
141 | | // Filter out[] unless there is nothing to filter. |
142 | | // This way we avoid null pointer + 0 (undefined behavior) |
143 | | // when out == NULL. |
144 | 902 | const size_t size = *out_pos - out_start; |
145 | 902 | const size_t filtered = size == 0 ? 0 : call_filter( |
146 | 734 | coder, out + out_start, size); |
147 | | |
148 | 902 | const size_t unfiltered = size - filtered; |
149 | 902 | assert(unfiltered <= coder->allocated / 2); |
150 | | |
151 | | // Now we can update coder->pos and coder->size, because |
152 | | // the next coder in the chain (if any) was successful. |
153 | 902 | coder->pos = 0; |
154 | 902 | coder->size = unfiltered; |
155 | | |
156 | 902 | if (coder->end_was_reached) { |
157 | | // The last byte has been copied to out[] already. |
158 | | // They are left as is. |
159 | 62 | coder->size = 0; |
160 | | |
161 | 840 | } else if (unfiltered > 0) { |
162 | | // There is unfiltered data left in out[]. Copy it to |
163 | | // coder->buffer[] and rewind *out_pos appropriately. |
164 | 682 | *out_pos -= unfiltered; |
165 | 682 | memcpy(coder->buffer, out + *out_pos, unfiltered); |
166 | 682 | } |
167 | 902 | } else if (coder->pos > 0) { |
168 | 0 | memmove(coder->buffer, coder->buffer + coder->pos, buf_avail); |
169 | 0 | coder->size -= coder->pos; |
170 | 0 | coder->pos = 0; |
171 | 0 | } |
172 | | |
173 | 938 | assert(coder->pos == 0); |
174 | | |
175 | | // If coder->buffer[] isn't empty, try to fill it by copying/decoding |
176 | | // more data. Then filter coder->buffer[] and copy the successfully |
177 | | // filtered data to out[]. It is probable, that some filtered and |
178 | | // unfiltered data will be left to coder->buffer[]. |
179 | 910 | if (coder->size > 0) { |
180 | 690 | { |
181 | 690 | const lzma_ret ret = copy_or_code(coder, allocator, |
182 | 690 | in, in_pos, in_size, |
183 | 690 | coder->buffer, &coder->size, |
184 | 690 | coder->allocated, action); |
185 | 690 | assert(ret != LZMA_STREAM_END); |
186 | 690 | if (ret != LZMA_OK) |
187 | 2 | return ret; |
188 | 690 | } |
189 | | |
190 | 688 | coder->filtered = call_filter( |
191 | 688 | coder, coder->buffer, coder->size); |
192 | | |
193 | | // Everything is considered to be filtered if coder->buffer[] |
194 | | // contains the last bytes of the data. |
195 | 688 | if (coder->end_was_reached) |
196 | 0 | coder->filtered = coder->size; |
197 | | |
198 | | // Flush as much as possible. |
199 | 688 | lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered, |
200 | 688 | out, out_pos, out_size); |
201 | 688 | } |
202 | | |
203 | | // Check if we got everything done. |
204 | 908 | if (coder->end_was_reached && coder->pos == coder->size) |
205 | 62 | return LZMA_STREAM_END; |
206 | | |
207 | 846 | return LZMA_OK; |
208 | 908 | } |
209 | | |
210 | | |
211 | | static void |
212 | | simple_coder_end(void *coder_ptr, const lzma_allocator *allocator) |
213 | 390 | { |
214 | 390 | lzma_simple_coder *coder = coder_ptr; |
215 | 390 | lzma_next_end(&coder->next, allocator); |
216 | 390 | lzma_free(coder->simple, allocator); |
217 | 390 | lzma_free(coder, allocator); |
218 | 390 | return; |
219 | 390 | } |
220 | | |
221 | | |
222 | | static lzma_ret |
223 | | simple_coder_update(void *coder_ptr, const lzma_allocator *allocator, |
224 | | const lzma_filter *filters_null lzma_attribute((__unused__)), |
225 | | const lzma_filter *reversed_filters) |
226 | 0 | { |
227 | 0 | lzma_simple_coder *coder = coder_ptr; |
228 | | |
229 | | // No update support, just call the next filter in the chain. |
230 | 0 | return lzma_next_filter_update( |
231 | 0 | &coder->next, allocator, reversed_filters + 1); |
232 | 0 | } |
233 | | |
234 | | |
235 | | extern lzma_ret |
236 | | lzma_simple_coder_init(lzma_next_coder *next, const lzma_allocator *allocator, |
237 | | const lzma_filter_info *filters, |
238 | | size_t (*filter)(void *simple, uint32_t now_pos, |
239 | | bool is_encoder, uint8_t *buffer, size_t size), |
240 | | size_t simple_size, size_t unfiltered_max, |
241 | | uint32_t alignment, bool is_encoder) |
242 | 390 | { |
243 | | // Allocate memory for the lzma_simple_coder structure if needed. |
244 | 390 | lzma_simple_coder *coder = next->coder; |
245 | 390 | if (coder == NULL) { |
246 | | // Here we allocate space also for the temporary buffer. We |
247 | | // need twice the size of unfiltered_max, because then it |
248 | | // is always possible to filter at least unfiltered_max bytes |
249 | | // more data in coder->buffer[] if it can be filled completely. |
250 | 390 | coder = lzma_alloc(sizeof(lzma_simple_coder) |
251 | 390 | + 2 * unfiltered_max, allocator); |
252 | 390 | if (coder == NULL) |
253 | 0 | return LZMA_MEM_ERROR; |
254 | | |
255 | 390 | next->coder = coder; |
256 | 390 | next->code = &simple_code; |
257 | 390 | next->end = &simple_coder_end; |
258 | 390 | next->update = &simple_coder_update; |
259 | | |
260 | 390 | coder->next = LZMA_NEXT_CODER_INIT; |
261 | 390 | coder->filter = filter; |
262 | 390 | coder->allocated = 2 * unfiltered_max; |
263 | | |
264 | | // Allocate memory for filter-specific data structure. |
265 | 390 | if (simple_size > 0) { |
266 | 74 | coder->simple = lzma_alloc(simple_size, allocator); |
267 | 74 | if (coder->simple == NULL) |
268 | 0 | return LZMA_MEM_ERROR; |
269 | 316 | } else { |
270 | 316 | coder->simple = NULL; |
271 | 316 | } |
272 | 390 | } |
273 | | |
274 | 390 | if (filters[0].options != NULL) { |
275 | 0 | const lzma_options_bcj *simple = filters[0].options; |
276 | 0 | coder->now_pos = simple->start_offset; |
277 | 0 | if (coder->now_pos & (alignment - 1)) |
278 | 0 | return LZMA_OPTIONS_ERROR; |
279 | 390 | } else { |
280 | 390 | coder->now_pos = 0; |
281 | 390 | } |
282 | | |
283 | | // Reset variables. |
284 | 390 | coder->is_encoder = is_encoder; |
285 | 390 | coder->end_was_reached = false; |
286 | 390 | coder->pos = 0; |
287 | 390 | coder->filtered = 0; |
288 | 390 | coder->size = 0; |
289 | | |
290 | 390 | return lzma_next_filter_init(&coder->next, allocator, filters + 1); |
291 | 390 | } |