1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file simple_coder.c
6 /// \brief Wrapper for simple filters
8 /// Simple filters don't change the size of the data i.e. number of bytes
9 /// in equals the number of bytes out.
11 // Author: Lasse Collin
13 ///////////////////////////////////////////////////////////////////////////////
15 #include "simple_private.h"
18 /// Copied or encodes/decodes more data to out[].
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
)
25 assert(!coder
->end_was_reached
);
27 if (coder
->next
.code
== NULL
) {
28 lzma_bufcpy(in
, in_pos
, in_size
, out
, out_pos
, out_size
);
30 // Check if end of stream was reached.
31 if (coder
->is_encoder
&& action
== LZMA_FINISH
32 && *in_pos
== in_size
)
33 coder
->end_was_reached
= true;
36 // Call the next coder in the chain to provide us some data.
37 const lzma_ret ret
= coder
->next
.code(
38 coder
->next
.coder
, allocator
,
40 out
, out_pos
, out_size
, action
);
42 if (ret
== LZMA_STREAM_END
) {
43 assert(!coder
->is_encoder
44 || action
== LZMA_FINISH
);
45 coder
->end_was_reached
= true;
47 } else if (ret
!= LZMA_OK
) {
57 call_filter(lzma_simple_coder
*coder
, uint8_t *buffer
, size_t size
)
59 const size_t filtered
= coder
->filter(coder
->simple
,
60 coder
->now_pos
, coder
->is_encoder
,
62 coder
->now_pos
+= filtered
;
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
)
73 lzma_simple_coder
*coder
= coder_ptr
;
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 if (action
== LZMA_SYNC_FLUSH
)
81 return LZMA_OPTIONS_ERROR
;
83 // Flush already filtered data from coder->buffer[] to out[].
84 if (coder
->pos
< coder
->filtered
) {
85 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
86 out
, out_pos
, out_size
);
88 // If we couldn't flush all the filtered data, return to
89 // application immediately.
90 if (coder
->pos
< coder
->filtered
)
93 if (coder
->end_was_reached
) {
94 assert(coder
->filtered
== coder
->size
);
95 return LZMA_STREAM_END
;
99 // If we get here, there is no filtered data left in the buffer.
102 assert(!coder
->end_was_reached
);
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 const size_t out_avail
= out_size
- *out_pos
;
110 const size_t buf_avail
= coder
->size
- coder
->pos
;
111 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 const size_t out_start
= *out_pos
;
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.
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
126 memcpy(out
+ *out_pos
, coder
->buffer
+ coder
->pos
,
129 *out_pos
+= buf_avail
;
131 // Copy/Encode/Decode more data to out[].
133 const lzma_ret ret
= copy_or_code(coder
, allocator
,
135 out
, out_pos
, out_size
, action
);
136 assert(ret
!= LZMA_STREAM_END
);
141 // Filter out[] unless there is nothing to filter.
142 // This way we avoid null pointer + 0 (undefined behavior)
144 const size_t size
= *out_pos
- out_start
;
145 const size_t filtered
= size
== 0 ? 0 : call_filter(
146 coder
, out
+ out_start
, size
);
148 const size_t unfiltered
= size
- filtered
;
149 assert(unfiltered
<= coder
->allocated
/ 2);
151 // Now we can update coder->pos and coder->size, because
152 // the next coder in the chain (if any) was successful.
154 coder
->size
= unfiltered
;
156 if (coder
->end_was_reached
) {
157 // The last byte has been copied to out[] already.
158 // They are left as is.
161 } else if (unfiltered
> 0) {
162 // There is unfiltered data left in out[]. Copy it to
163 // coder->buffer[] and rewind *out_pos appropriately.
164 *out_pos
-= unfiltered
;
165 memcpy(coder
->buffer
, out
+ *out_pos
, unfiltered
);
167 } else if (coder
->pos
> 0) {
168 memmove(coder
->buffer
, coder
->buffer
+ coder
->pos
, buf_avail
);
169 coder
->size
-= coder
->pos
;
173 assert(coder
->pos
== 0);
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 if (coder
->size
> 0) {
181 const lzma_ret ret
= copy_or_code(coder
, allocator
,
183 coder
->buffer
, &coder
->size
,
184 coder
->allocated
, action
);
185 assert(ret
!= LZMA_STREAM_END
);
190 coder
->filtered
= call_filter(
191 coder
, coder
->buffer
, coder
->size
);
193 // Everything is considered to be filtered if coder->buffer[]
194 // contains the last bytes of the data.
195 if (coder
->end_was_reached
)
196 coder
->filtered
= coder
->size
;
198 // Flush as much as possible.
199 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
200 out
, out_pos
, out_size
);
203 // Check if we got everything done.
204 if (coder
->end_was_reached
&& coder
->pos
== coder
->size
)
205 return LZMA_STREAM_END
;
212 simple_coder_end(void *coder_ptr
, const lzma_allocator
*allocator
)
214 lzma_simple_coder
*coder
= coder_ptr
;
215 lzma_next_end(&coder
->next
, allocator
);
216 lzma_free(coder
->simple
, allocator
);
217 lzma_free(coder
, allocator
);
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
)
227 lzma_simple_coder
*coder
= coder_ptr
;
229 // No update support, just call the next filter in the chain.
230 return lzma_next_filter_update(
231 &coder
->next
, allocator
, reversed_filters
+ 1);
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
)
243 // Allocate memory for the lzma_simple_coder structure if needed.
244 lzma_simple_coder
*coder
= next
->coder
;
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 coder
= lzma_alloc(sizeof(lzma_simple_coder
)
251 + 2 * unfiltered_max
, allocator
);
253 return LZMA_MEM_ERROR
;
256 next
->code
= &simple_code
;
257 next
->end
= &simple_coder_end
;
258 next
->update
= &simple_coder_update
;
260 coder
->next
= LZMA_NEXT_CODER_INIT
;
261 coder
->filter
= filter
;
262 coder
->allocated
= 2 * unfiltered_max
;
264 // Allocate memory for filter-specific data structure.
265 if (simple_size
> 0) {
266 coder
->simple
= lzma_alloc(simple_size
, allocator
);
267 if (coder
->simple
== NULL
)
268 return LZMA_MEM_ERROR
;
270 coder
->simple
= NULL
;
274 if (filters
[0].options
!= NULL
) {
275 const lzma_options_bcj
*simple
= filters
[0].options
;
276 coder
->now_pos
= simple
->start_offset
;
277 if (coder
->now_pos
& (alignment
- 1))
278 return LZMA_OPTIONS_ERROR
;
284 coder
->is_encoder
= is_encoder
;
285 coder
->end_was_reached
= false;
290 return lzma_next_filter_init(&coder
->next
, allocator
, filters
+ 1);