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