1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file simple_coder.c
4 /// \brief Wrapper for simple filters
6 /// Simple filters don't change the size of the data i.e. number of bytes
7 /// in equals the number of bytes out.
9 // Author: Lasse Collin
11 // This file has been put into the public domain.
12 // You can do whatever you want with this file.
14 ///////////////////////////////////////////////////////////////////////////////
16 #include "simple_private.h"
19 /// Copied or encodes/decodes more data to out[].
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
)
26 assert(!coder
->end_was_reached
);
28 if (coder
->next
.code
== NULL
) {
29 lzma_bufcpy(in
, in_pos
, in_size
, out
, out_pos
, out_size
);
31 // Check if end of stream was reached.
32 if (coder
->is_encoder
&& action
== LZMA_FINISH
33 && *in_pos
== in_size
)
34 coder
->end_was_reached
= true;
37 // Call the next coder in the chain to provide us some data.
38 const lzma_ret ret
= coder
->next
.code(
39 coder
->next
.coder
, allocator
,
41 out
, out_pos
, out_size
, action
);
43 if (ret
== LZMA_STREAM_END
) {
44 assert(!coder
->is_encoder
45 || action
== LZMA_FINISH
);
46 coder
->end_was_reached
= true;
48 } else if (ret
!= LZMA_OK
) {
58 call_filter(lzma_simple_coder
*coder
, uint8_t *buffer
, size_t size
)
60 const size_t filtered
= coder
->filter(coder
->simple
,
61 coder
->now_pos
, coder
->is_encoder
,
63 coder
->now_pos
+= filtered
;
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
)
74 lzma_simple_coder
*coder
= coder_ptr
;
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 if (action
== LZMA_SYNC_FLUSH
)
82 return LZMA_OPTIONS_ERROR
;
84 // Flush already filtered data from coder->buffer[] to out[].
85 if (coder
->pos
< coder
->filtered
) {
86 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
87 out
, out_pos
, out_size
);
89 // If we couldn't flush all the filtered data, return to
90 // application immediately.
91 if (coder
->pos
< coder
->filtered
)
94 if (coder
->end_was_reached
) {
95 assert(coder
->filtered
== coder
->size
);
96 return LZMA_STREAM_END
;
100 // If we get here, there is no filtered data left in the buffer.
103 assert(!coder
->end_was_reached
);
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 const size_t out_avail
= out_size
- *out_pos
;
111 const size_t buf_avail
= coder
->size
- coder
->pos
;
112 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 const size_t out_start
= *out_pos
;
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.
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
127 memcpy(out
+ *out_pos
, coder
->buffer
+ coder
->pos
,
130 *out_pos
+= buf_avail
;
132 // Copy/Encode/Decode more data to out[].
134 const lzma_ret ret
= copy_or_code(coder
, allocator
,
136 out
, out_pos
, out_size
, action
);
137 assert(ret
!= LZMA_STREAM_END
);
142 // Filter out[] unless there is nothing to filter.
143 // This way we avoid null pointer + 0 (undefined behavior)
145 const size_t size
= *out_pos
- out_start
;
146 const size_t filtered
= size
== 0 ? 0 : call_filter(
147 coder
, out
+ out_start
, size
);
149 const size_t unfiltered
= size
- filtered
;
150 assert(unfiltered
<= coder
->allocated
/ 2);
152 // Now we can update coder->pos and coder->size, because
153 // the next coder in the chain (if any) was successful.
155 coder
->size
= unfiltered
;
157 if (coder
->end_was_reached
) {
158 // The last byte has been copied to out[] already.
159 // They are left as is.
162 } else if (unfiltered
> 0) {
163 // There is unfiltered data left in out[]. Copy it to
164 // coder->buffer[] and rewind *out_pos appropriately.
165 *out_pos
-= unfiltered
;
166 memcpy(coder
->buffer
, out
+ *out_pos
, unfiltered
);
168 } else if (coder
->pos
> 0) {
169 memmove(coder
->buffer
, coder
->buffer
+ coder
->pos
, buf_avail
);
170 coder
->size
-= coder
->pos
;
174 assert(coder
->pos
== 0);
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 if (coder
->size
> 0) {
182 const lzma_ret ret
= copy_or_code(coder
, allocator
,
184 coder
->buffer
, &coder
->size
,
185 coder
->allocated
, action
);
186 assert(ret
!= LZMA_STREAM_END
);
191 coder
->filtered
= call_filter(
192 coder
, coder
->buffer
, coder
->size
);
194 // Everything is considered to be filtered if coder->buffer[]
195 // contains the last bytes of the data.
196 if (coder
->end_was_reached
)
197 coder
->filtered
= coder
->size
;
199 // Flush as much as possible.
200 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
201 out
, out_pos
, out_size
);
204 // Check if we got everything done.
205 if (coder
->end_was_reached
&& coder
->pos
== coder
->size
)
206 return LZMA_STREAM_END
;
213 simple_coder_end(void *coder_ptr
, const lzma_allocator
*allocator
)
215 lzma_simple_coder
*coder
= coder_ptr
;
216 lzma_next_end(&coder
->next
, allocator
);
217 lzma_free(coder
->simple
, allocator
);
218 lzma_free(coder
, allocator
);
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
)
228 lzma_simple_coder
*coder
= coder_ptr
;
230 // No update support, just call the next filter in the chain.
231 return lzma_next_filter_update(
232 &coder
->next
, allocator
, reversed_filters
+ 1);
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
)
244 // Allocate memory for the lzma_simple_coder structure if needed.
245 lzma_simple_coder
*coder
= next
->coder
;
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 coder
= lzma_alloc(sizeof(lzma_simple_coder
)
252 + 2 * unfiltered_max
, allocator
);
254 return LZMA_MEM_ERROR
;
257 next
->code
= &simple_code
;
258 next
->end
= &simple_coder_end
;
259 next
->update
= &simple_coder_update
;
261 coder
->next
= LZMA_NEXT_CODER_INIT
;
262 coder
->filter
= filter
;
263 coder
->allocated
= 2 * unfiltered_max
;
265 // Allocate memory for filter-specific data structure.
266 if (simple_size
> 0) {
267 coder
->simple
= lzma_alloc(simple_size
, allocator
);
268 if (coder
->simple
== NULL
)
269 return LZMA_MEM_ERROR
;
271 coder
->simple
= NULL
;
275 if (filters
[0].options
!= NULL
) {
276 const lzma_options_bcj
*simple
= filters
[0].options
;
277 coder
->now_pos
= simple
->start_offset
;
278 if (coder
->now_pos
& (alignment
- 1))
279 return LZMA_OPTIONS_ERROR
;
285 coder
->is_encoder
= is_encoder
;
286 coder
->end_was_reached
= false;
291 return lzma_next_filter_init(&coder
->next
, allocator
, filters
+ 1);