]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/simple/simple_coder.c
Imported to git.
[icculus/xz.git] / src / liblzma / simple / simple_coder.c
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 //  Copyright (C) 2007 Lasse Collin
10 //
11 //  This library is free software; you can redistribute it and/or
12 //  modify it under the terms of the GNU Lesser General Public
13 //  License as published by the Free Software Foundation; either
14 //  version 2.1 of the License, or (at your option) any later version.
15 //
16 //  This library is distributed in the hope that it will be useful,
17 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 //  Lesser General Public License for more details.
20 //
21 ///////////////////////////////////////////////////////////////////////////////
22
23 #include "simple_private.h"
24
25
26 /// Copied or encodes/decodes more data to out[]. Checks and updates
27 /// uncompressed_size when we are the last coder in the chain.
28 /// If we aren't the last filter in the chain, we don't need to care about
29 /// uncompressed size, since we don't change it; the next filter in the
30 /// chain will check it anyway.
31 static lzma_ret
32 copy_or_code(lzma_coder *coder, lzma_allocator *allocator,
33                 const uint8_t *restrict in, size_t *restrict in_pos,
34                 size_t in_size, uint8_t *restrict out,
35                 size_t *restrict out_pos, size_t out_size, lzma_action action)
36 {
37         assert(!coder->end_was_reached);
38
39         if (coder->next.code == NULL) {
40                 const size_t in_avail = in_size - *in_pos;
41
42                 if (coder->is_encoder) {
43                         if (action == LZMA_FINISH) {
44                                 // If uncompressed size is known and the
45                                 // amount of available input doesn't match
46                                 // the uncompressed size, return an error.
47                                 if (coder->uncompressed_size
48                                                 != LZMA_VLI_VALUE_UNKNOWN
49                                                 && coder->uncompressed_size
50                                                         != in_avail)
51                                         return LZMA_DATA_ERROR;
52
53                         } else if (coder->uncompressed_size
54                                         < (lzma_vli)(in_avail)) {
55                                 // There is too much input available.
56                                 return LZMA_DATA_ERROR;
57                         }
58                 } else {
59                         // Limit in_size so that we don't copy too much.
60                         if ((lzma_vli)(in_avail) > coder->uncompressed_size)
61                                 in_size = *in_pos + (size_t)(
62                                                 coder->uncompressed_size);
63                 }
64
65                 // Store the old position so we can update uncompressed_size.
66                 const size_t out_start = *out_pos;
67
68                 // Copy the data
69                 bufcpy(in, in_pos, in_size, out, out_pos, out_size);
70
71                 // Update uncompressed_size.
72                 if (coder->uncompressed_size != LZMA_VLI_VALUE_UNKNOWN)
73                         coder->uncompressed_size -= *out_pos - out_start;
74
75                 // Check if end of stream was reached.
76                 if (coder->is_encoder) {
77                         if (action == LZMA_FINISH && *in_pos == in_size)
78                                 coder->end_was_reached = true;
79                 } else {
80                         if (coder->uncompressed_size == 0)
81                                 coder->end_was_reached = true;
82                 }
83
84         } else {
85                 // Call the next coder in the chain to provide us some data.
86                 // We don't care about uncompressed_size here, because
87                 // the next filter in the chain will do it for us (since
88                 // we don't change the size of the data).
89                 const lzma_ret ret = coder->next.code(
90                                 coder->next.coder, allocator,
91                                 in, in_pos, in_size,
92                                 out, out_pos, out_size, action);
93
94                 if (ret == LZMA_STREAM_END) {
95                         assert(!coder->is_encoder
96                                         || action == LZMA_FINISH);
97                         coder->end_was_reached = true;
98
99                 } else if (ret != LZMA_OK) {
100                         return ret;
101                 }
102         }
103
104         return LZMA_OK;
105 }
106
107
108 static size_t
109 call_filter(lzma_coder *coder, uint8_t *buffer, size_t size)
110 {
111         const size_t filtered = coder->filter(coder->simple,
112                         coder->now_pos, coder->is_encoder,
113                         buffer, size);
114         coder->now_pos += filtered;
115         return filtered;
116 }
117
118
119 static lzma_ret
120 simple_code(lzma_coder *coder, lzma_allocator *allocator,
121                 const uint8_t *restrict in, size_t *restrict in_pos,
122                 size_t in_size, uint8_t *restrict out,
123                 size_t *restrict out_pos, size_t out_size, lzma_action action)
124 {
125         // Flush already filtered data from coder->buffer[] to out[].
126         if (coder->pos < coder->filtered) {
127                 bufcpy(coder->buffer, &coder->pos, coder->filtered,
128                                 out, out_pos, out_size);
129
130                 // If we couldn't flush all the filtered data, return to
131                 // application immediatelly.
132                 if (coder->pos < coder->filtered)
133                         return LZMA_OK;
134
135                 if (coder->end_was_reached) {
136                         assert(coder->filtered == coder->size);
137                         return LZMA_STREAM_END;
138                 }
139         }
140
141         // If we get here, there is no filtered data left in the buffer.
142         coder->filtered = 0;
143
144         assert(!coder->end_was_reached);
145
146         // If there is more output space left than there is unfiltered data
147         // in coder->buffer[], flush coder->buffer[] to out[], and copy/code
148         // more data to out[] hopefully filling it completely. Then filter
149         // the data in out[]. This step is where most of the data gets
150         // filtered if the buffer sizes used by the application are reasonable.
151         const size_t out_avail = out_size - *out_pos;
152         const size_t buf_avail = coder->size - coder->pos;
153         if (out_avail > buf_avail) {
154                 // Store the old position so that we know from which byte
155                 // to start filtering.
156                 const size_t out_start = *out_pos;
157
158                 // Flush data from coder->buffer[] to out[], but don't reset
159                 // coder->pos and coder->size yet. This way the coder can be
160                 // restarted if the next filter in the chain returns e.g.
161                 // LZMA_MEM_ERROR.
162                 memcpy(out + *out_pos, coder->buffer + coder->pos, buf_avail);
163                 *out_pos += buf_avail;
164
165                 // Copy/Encode/Decode more data to out[].
166                 {
167                         const lzma_ret ret = copy_or_code(coder, allocator,
168                                         in, in_pos, in_size,
169                                         out, out_pos, out_size, action);
170                         assert(ret != LZMA_STREAM_END);
171                         if (ret != LZMA_OK)
172                                 return ret;
173                 }
174
175                 // Filter out[].
176                 const size_t size = *out_pos - out_start;
177                 const size_t filtered = call_filter(
178                                 coder, out + out_start, size);
179
180                 const size_t unfiltered = size - filtered;
181                 assert(unfiltered <= coder->allocated / 2);
182
183                 // Now we can update coder->pos and coder->size, because
184                 // the next coder in the chain (if any) was successful.
185                 coder->pos = 0;
186                 coder->size = unfiltered;
187
188                 if (coder->end_was_reached) {
189                         // The last byte has been copied to out[] already.
190                         // They are left as is.
191                         coder->size = 0;
192
193                 } else if (unfiltered > 0) {
194                         // There is unfiltered data left in out[]. Copy it to
195                         // coder->buffer[] and rewind *out_pos appropriately.
196                         *out_pos -= unfiltered;
197                         memcpy(coder->buffer, out + *out_pos, unfiltered);
198                 }
199         } else if (coder->pos > 0) {
200                 memmove(coder->buffer, coder->buffer + coder->pos, buf_avail);
201                 coder->size -= coder->pos;
202                 coder->pos = 0;
203         }
204
205         assert(coder->pos == 0);
206
207         // If coder->buffer[] isn't empty, try to fill it by copying/decoding
208         // more data. Then filter coder->buffer[] and copy the successfully
209         // filtered data to out[]. It is probable, that some filtered and
210         // unfiltered data will be left to coder->buffer[].
211         if (coder->size > 0) {
212                 {
213                         const lzma_ret ret = copy_or_code(coder, allocator,
214                                         in, in_pos, in_size,
215                                         coder->buffer, &coder->size,
216                                         coder->allocated, action);
217                         assert(ret != LZMA_STREAM_END);
218                         if (ret != LZMA_OK)
219                                 return ret;
220                 }
221
222                 coder->filtered = call_filter(
223                                 coder, coder->buffer, coder->size);
224
225                 // Everything is considered to be filtered if coder->buffer[]
226                 // contains the last bytes of the data.
227                 if (coder->end_was_reached)
228                         coder->filtered = coder->size;
229
230                 // Flush as much as possible.
231                 bufcpy(coder->buffer, &coder->pos, coder->filtered,
232                                 out, out_pos, out_size);
233         }
234
235         // Check if we got everything done.
236         if (coder->end_was_reached && coder->pos == coder->size)
237                 return LZMA_STREAM_END;
238
239         return LZMA_OK;
240 }
241
242
243 static void
244 simple_coder_end(lzma_coder *coder, lzma_allocator *allocator)
245 {
246         lzma_next_coder_end(&coder->next, allocator);
247         lzma_free(coder->simple, allocator);
248         lzma_free(coder, allocator);
249         return;
250 }
251
252
253 extern lzma_ret
254 lzma_simple_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
255                 const lzma_filter_info *filters,
256                 size_t (*filter)(lzma_simple *simple, uint32_t now_pos,
257                         bool is_encoder, uint8_t *buffer, size_t size),
258                 size_t simple_size, size_t unfiltered_max, bool is_encoder)
259 {
260         // Allocate memory for the lzma_coder structure if needed.
261         if (next->coder == NULL) {
262                 // Here we allocate space also for the temporary buffer. We
263                 // need twice the size of unfiltered_max, because then it
264                 // is always possible to filter at least unfiltered_max bytes
265                 // more data in coder->buffer[] if it can be filled completely.
266                 next->coder = lzma_alloc(sizeof(lzma_coder)
267                                 + 2 * unfiltered_max, allocator);
268                 if (next->coder == NULL)
269                         return LZMA_MEM_ERROR;
270
271                 next->code = &simple_code;
272                 next->end = &simple_coder_end;
273
274                 next->coder->next = LZMA_NEXT_CODER_INIT;
275                 next->coder->filter = filter;
276                 next->coder->allocated = 2 * unfiltered_max;
277
278                 // Allocate memory for filter-specific data structure.
279                 if (simple_size > 0) {
280                         next->coder->simple = lzma_alloc(
281                                         simple_size, allocator);
282                         if (next->coder->simple == NULL)
283                                 return LZMA_MEM_ERROR;
284                 } else {
285                         next->coder->simple = NULL;
286                 }
287         }
288
289         if (filters[0].options != NULL) {
290                 const lzma_options_simple *simple = filters[0].options;
291                 next->coder->now_pos = simple->start_offset;
292         } else {
293                 next->coder->now_pos = 0;
294         }
295
296         // Reset variables.
297         next->coder->is_encoder = is_encoder;
298         next->coder->end_was_reached = false;
299         next->coder->uncompressed_size = filters[0].uncompressed_size;
300         next->coder->pos = 0;
301         next->coder->filtered = 0;
302         next->coder->size = 0;
303
304         return lzma_next_filter_init(
305                         &next->coder->next, allocator, filters + 1);
306 }