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
, 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_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(lzma_coder
*coder
, 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 // TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it
75 // in cases when the filter is able to filter everything. With most
76 // simple filters it can be done at offset that is a multiple of 2,
77 // 4, or 16. With x86 filter, it needs good luck, and thus cannot
78 // be made to work predictably.
79 if (action
== LZMA_SYNC_FLUSH
)
80 return LZMA_OPTIONS_ERROR
;
82 // Flush already filtered data from coder->buffer[] to out[].
83 if (coder
->pos
< coder
->filtered
) {
84 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
85 out
, out_pos
, out_size
);
87 // If we couldn't flush all the filtered data, return to
88 // application immediately.
89 if (coder
->pos
< coder
->filtered
)
92 if (coder
->end_was_reached
) {
93 assert(coder
->filtered
== coder
->size
);
94 return LZMA_STREAM_END
;
98 // If we get here, there is no filtered data left in the buffer.
101 assert(!coder
->end_was_reached
);
103 // If there is more output space left than there is unfiltered data
104 // in coder->buffer[], flush coder->buffer[] to out[], and copy/code
105 // more data to out[] hopefully filling it completely. Then filter
106 // the data in out[]. This step is where most of the data gets
107 // filtered if the buffer sizes used by the application are reasonable.
108 const size_t out_avail
= out_size
- *out_pos
;
109 const size_t buf_avail
= coder
->size
- coder
->pos
;
110 if (out_avail
> buf_avail
|| buf_avail
== 0) {
111 // Store the old position so that we know from which byte
112 // to start filtering.
113 const size_t out_start
= *out_pos
;
115 // Flush data from coder->buffer[] to out[], but don't reset
116 // coder->pos and coder->size yet. This way the coder can be
117 // restarted if the next filter in the chain returns e.g.
119 memcpy(out
+ *out_pos
, coder
->buffer
+ coder
->pos
, buf_avail
);
120 *out_pos
+= buf_avail
;
122 // Copy/Encode/Decode more data to out[].
124 const lzma_ret ret
= copy_or_code(coder
, allocator
,
126 out
, out_pos
, out_size
, action
);
127 assert(ret
!= LZMA_STREAM_END
);
133 const size_t size
= *out_pos
- out_start
;
134 const size_t filtered
= call_filter(
135 coder
, out
+ out_start
, size
);
137 const size_t unfiltered
= size
- filtered
;
138 assert(unfiltered
<= coder
->allocated
/ 2);
140 // Now we can update coder->pos and coder->size, because
141 // the next coder in the chain (if any) was successful.
143 coder
->size
= unfiltered
;
145 if (coder
->end_was_reached
) {
146 // The last byte has been copied to out[] already.
147 // They are left as is.
150 } else if (unfiltered
> 0) {
151 // There is unfiltered data left in out[]. Copy it to
152 // coder->buffer[] and rewind *out_pos appropriately.
153 *out_pos
-= unfiltered
;
154 memcpy(coder
->buffer
, out
+ *out_pos
, unfiltered
);
156 } else if (coder
->pos
> 0) {
157 memmove(coder
->buffer
, coder
->buffer
+ coder
->pos
, buf_avail
);
158 coder
->size
-= coder
->pos
;
162 assert(coder
->pos
== 0);
164 // If coder->buffer[] isn't empty, try to fill it by copying/decoding
165 // more data. Then filter coder->buffer[] and copy the successfully
166 // filtered data to out[]. It is probable, that some filtered and
167 // unfiltered data will be left to coder->buffer[].
168 if (coder
->size
> 0) {
170 const lzma_ret ret
= copy_or_code(coder
, allocator
,
172 coder
->buffer
, &coder
->size
,
173 coder
->allocated
, action
);
174 assert(ret
!= LZMA_STREAM_END
);
179 coder
->filtered
= call_filter(
180 coder
, coder
->buffer
, coder
->size
);
182 // Everything is considered to be filtered if coder->buffer[]
183 // contains the last bytes of the data.
184 if (coder
->end_was_reached
)
185 coder
->filtered
= coder
->size
;
187 // Flush as much as possible.
188 lzma_bufcpy(coder
->buffer
, &coder
->pos
, coder
->filtered
,
189 out
, out_pos
, out_size
);
192 // Check if we got everything done.
193 if (coder
->end_was_reached
&& coder
->pos
== coder
->size
)
194 return LZMA_STREAM_END
;
201 simple_coder_end(lzma_coder
*coder
, const lzma_allocator
*allocator
)
203 lzma_next_end(&coder
->next
, allocator
);
204 lzma_free(coder
->simple
, allocator
);
205 lzma_free(coder
, allocator
);
211 simple_coder_update(lzma_coder
*coder
, const lzma_allocator
*allocator
,
212 const lzma_filter
*filters_null
lzma_attribute((__unused__
)),
213 const lzma_filter
*reversed_filters
)
215 // No update support, just call the next filter in the chain.
216 return lzma_next_filter_update(
217 &coder
->next
, allocator
, reversed_filters
+ 1);
222 lzma_simple_coder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
223 const lzma_filter_info
*filters
,
224 size_t (*filter
)(lzma_simple
*simple
, uint32_t now_pos
,
225 bool is_encoder
, uint8_t *buffer
, size_t size
),
226 size_t simple_size
, size_t unfiltered_max
,
227 uint32_t alignment
, bool is_encoder
)
229 // Allocate memory for the lzma_coder structure if needed.
230 if (next
->coder
== NULL
) {
231 // Here we allocate space also for the temporary buffer. We
232 // need twice the size of unfiltered_max, because then it
233 // is always possible to filter at least unfiltered_max bytes
234 // more data in coder->buffer[] if it can be filled completely.
235 next
->coder
= lzma_alloc(sizeof(lzma_coder
)
236 + 2 * unfiltered_max
, allocator
);
237 if (next
->coder
== NULL
)
238 return LZMA_MEM_ERROR
;
240 next
->code
= &simple_code
;
241 next
->end
= &simple_coder_end
;
242 next
->update
= &simple_coder_update
;
244 next
->coder
->next
= LZMA_NEXT_CODER_INIT
;
245 next
->coder
->filter
= filter
;
246 next
->coder
->allocated
= 2 * unfiltered_max
;
248 // Allocate memory for filter-specific data structure.
249 if (simple_size
> 0) {
250 next
->coder
->simple
= lzma_alloc(
251 simple_size
, allocator
);
252 if (next
->coder
->simple
== NULL
)
253 return LZMA_MEM_ERROR
;
255 next
->coder
->simple
= NULL
;
259 if (filters
[0].options
!= NULL
) {
260 const lzma_options_bcj
*simple
= filters
[0].options
;
261 next
->coder
->now_pos
= simple
->start_offset
;
262 if (next
->coder
->now_pos
& (alignment
- 1))
263 return LZMA_OPTIONS_ERROR
;
265 next
->coder
->now_pos
= 0;
269 next
->coder
->is_encoder
= is_encoder
;
270 next
->coder
->end_was_reached
= false;
271 next
->coder
->pos
= 0;
272 next
->coder
->filtered
= 0;
273 next
->coder
->size
= 0;
275 return lzma_next_filter_init(
276 &next
->coder
->next
, allocator
, filters
+ 1);