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_coder
*coder
, 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 // We don't care about uncompressed_size here, because
39 // the next filter in the chain will do it for us (since
40 // we don't change the size of the data).
41 const lzma_ret ret
= coder
->next
.code(
42 coder
->next
.coder
, allocator
,
44 out
, out_pos
, out_size
, action
);
46 if (ret
== LZMA_STREAM_END
) {
47 assert(!coder
->is_encoder
48 || action
== LZMA_FINISH
);
49 coder
->end_was_reached
= true;
51 } else if (ret
!= LZMA_OK
) {
61 call_filter(lzma_coder
*coder
, uint8_t *buffer
, size_t size
)
63 const size_t filtered
= coder
->filter(coder
->simple
,
64 coder
->now_pos
, coder
->is_encoder
,
66 coder
->now_pos
+= filtered
;
72 simple_code(lzma_coder
*coder
, lzma_allocator
*allocator
,
73 const uint8_t *restrict in
, size_t *restrict in_pos
,
74 size_t in_size
, uint8_t *restrict out
,
75 size_t *restrict out_pos
, size_t out_size
, lzma_action action
)
77 // TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it
78 // in cases when the filter is able to filter everything. With most
79 // simple filters it can be done at offset that is a multiple of 2,
80 // 4, or 16. With x86 filter, it needs good luck, and thus cannot
81 // be made to work predictably.
82 if (action
== LZMA_SYNC_FLUSH
)
83 return LZMA_OPTIONS_ERROR
;
85 // Flush already filtered data from coder->buffer[] to out[].
86 if (coder
->pos
< coder
->filtered
) {
87 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
88 out
, out_pos
, out_size
);
90 // If we couldn't flush all the filtered data, return to
91 // application immediately.
92 if (coder
->pos
< coder
->filtered
)
95 if (coder
->end_was_reached
) {
96 assert(coder
->filtered
== coder
->size
);
97 return LZMA_STREAM_END
;
101 // If we get here, there is no filtered data left in the buffer.
104 assert(!coder
->end_was_reached
);
106 // If there is more output space left than there is unfiltered data
107 // in coder->buffer[], flush coder->buffer[] to out[], and copy/code
108 // more data to out[] hopefully filling it completely. Then filter
109 // the data in out[]. This step is where most of the data gets
110 // filtered if the buffer sizes used by the application are reasonable.
111 const size_t out_avail
= out_size
- *out_pos
;
112 const size_t buf_avail
= coder
->size
- coder
->pos
;
113 if (out_avail
> buf_avail
) {
114 // Store the old position so that we know from which byte
115 // to start filtering.
116 const size_t out_start
= *out_pos
;
118 // Flush data from coder->buffer[] to out[], but don't reset
119 // coder->pos and coder->size yet. This way the coder can be
120 // restarted if the next filter in the chain returns e.g.
122 memcpy(out
+ *out_pos
, coder
->buffer
+ coder
->pos
, buf_avail
);
123 *out_pos
+= buf_avail
;
125 // Copy/Encode/Decode more data to out[].
127 const lzma_ret ret
= copy_or_code(coder
, allocator
,
129 out
, out_pos
, out_size
, action
);
130 assert(ret
!= LZMA_STREAM_END
);
136 const size_t size
= *out_pos
- out_start
;
137 const size_t filtered
= call_filter(
138 coder
, out
+ out_start
, size
);
140 const size_t unfiltered
= size
- filtered
;
141 assert(unfiltered
<= coder
->allocated
/ 2);
143 // Now we can update coder->pos and coder->size, because
144 // the next coder in the chain (if any) was successful.
146 coder
->size
= unfiltered
;
148 if (coder
->end_was_reached
) {
149 // The last byte has been copied to out[] already.
150 // They are left as is.
153 } else if (unfiltered
> 0) {
154 // There is unfiltered data left in out[]. Copy it to
155 // coder->buffer[] and rewind *out_pos appropriately.
156 *out_pos
-= unfiltered
;
157 memcpy(coder
->buffer
, out
+ *out_pos
, unfiltered
);
159 } else if (coder
->pos
> 0) {
160 memmove(coder
->buffer
, coder
->buffer
+ coder
->pos
, buf_avail
);
161 coder
->size
-= coder
->pos
;
165 assert(coder
->pos
== 0);
167 // If coder->buffer[] isn't empty, try to fill it by copying/decoding
168 // more data. Then filter coder->buffer[] and copy the successfully
169 // filtered data to out[]. It is probable, that some filtered and
170 // unfiltered data will be left to coder->buffer[].
171 if (coder
->size
> 0) {
173 const lzma_ret ret
= copy_or_code(coder
, allocator
,
175 coder
->buffer
, &coder
->size
,
176 coder
->allocated
, action
);
177 assert(ret
!= LZMA_STREAM_END
);
182 coder
->filtered
= call_filter(
183 coder
, coder
->buffer
, coder
->size
);
185 // Everything is considered to be filtered if coder->buffer[]
186 // contains the last bytes of the data.
187 if (coder
->end_was_reached
)
188 coder
->filtered
= coder
->size
;
190 // Flush as much as possible.
191 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
192 out
, out_pos
, out_size
);
195 // Check if we got everything done.
196 if (coder
->end_was_reached
&& coder
->pos
== coder
->size
)
197 return LZMA_STREAM_END
;
204 simple_coder_end(lzma_coder
*coder
, lzma_allocator
*allocator
)
206 lzma_next_end(&coder
->next
, allocator
);
207 lzma_free(coder
->simple
, allocator
);
208 lzma_free(coder
, allocator
);
214 simple_coder_update(lzma_coder
*coder
, lzma_allocator
*allocator
,
215 const lzma_filter
*filters_null
lzma_attribute((__unused__
)),
216 const lzma_filter
*reversed_filters
)
218 // No update support, just call the next filter in the chain.
219 return lzma_next_filter_update(
220 &coder
->next
, allocator
, reversed_filters
+ 1);
225 lzma_simple_coder_init(lzma_next_coder
*next
, lzma_allocator
*allocator
,
226 const lzma_filter_info
*filters
,
227 size_t (*filter
)(lzma_simple
*simple
, uint32_t now_pos
,
228 bool is_encoder
, uint8_t *buffer
, size_t size
),
229 size_t simple_size
, size_t unfiltered_max
,
230 uint32_t alignment
, bool is_encoder
)
232 // Allocate memory for the lzma_coder structure if needed.
233 if (next
->coder
== NULL
) {
234 // Here we allocate space also for the temporary buffer. We
235 // need twice the size of unfiltered_max, because then it
236 // is always possible to filter at least unfiltered_max bytes
237 // more data in coder->buffer[] if it can be filled completely.
238 next
->coder
= lzma_alloc(sizeof(lzma_coder
)
239 + 2 * unfiltered_max
, allocator
);
240 if (next
->coder
== NULL
)
241 return LZMA_MEM_ERROR
;
243 next
->code
= &simple_code
;
244 next
->end
= &simple_coder_end
;
245 next
->update
= &simple_coder_update
;
247 next
->coder
->next
= LZMA_NEXT_CODER_INIT
;
248 next
->coder
->filter
= filter
;
249 next
->coder
->allocated
= 2 * unfiltered_max
;
251 // Allocate memory for filter-specific data structure.
252 if (simple_size
> 0) {
253 next
->coder
->simple
= lzma_alloc(
254 simple_size
, allocator
);
255 if (next
->coder
->simple
== NULL
)
256 return LZMA_MEM_ERROR
;
258 next
->coder
->simple
= NULL
;
262 if (filters
[0].options
!= NULL
) {
263 const lzma_options_bcj
*simple
= filters
[0].options
;
264 next
->coder
->now_pos
= simple
->start_offset
;
265 if (next
->coder
->now_pos
& (alignment
- 1))
266 return LZMA_OPTIONS_ERROR
;
268 next
->coder
->now_pos
= 0;
272 next
->coder
->is_encoder
= is_encoder
;
273 next
->coder
->end_was_reached
= false;
274 next
->coder
->pos
= 0;
275 next
->coder
->filtered
= 0;
276 next
->coder
->size
= 0;
278 return lzma_next_filter_init(
279 &next
->coder
->next
, allocator
, filters
+ 1);