1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: expandtab:ts=8:sw=4:softtabstop=4:
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file common.h
6 /// \brief Common functions needed in many places in liblzma
7 //
8 // Author: Lasse Collin
9 //
10 // This file has been put into the public domain.
11 // You can do whatever you want with this file.
12 //
13 ///////////////////////////////////////////////////////////////////////////////
14
15 #include "common.h"
16
17
18 /////////////
19 // Version //
20 /////////////
21
22 extern LZMA_API(uint32_t)
lzma_version_number(void)23 lzma_version_number(void)
24 {
25 return LZMA_VERSION;
26 }
27
28
29 extern LZMA_API(const char *)
lzma_version_string(void)30 lzma_version_string(void)
31 {
32 return LZMA_VERSION_STRING;
33 }
34
35
36 ///////////////////////
37 // Memory allocation //
38 ///////////////////////
39
40 extern void * lzma_attribute((malloc))
lzma_alloc(size_t size,lzma_allocator * allocator)41 lzma_alloc(size_t size, lzma_allocator *allocator)
42 {
43 // Some malloc() variants return NULL if called with size == 0.
44 if (size == 0)
45 size = 1;
46
47 void *ptr;
48
49 if (allocator != NULL && allocator->alloc != NULL)
50 ptr = allocator->alloc(allocator->opaque, 1, size);
51 else
52 ptr = malloc(size);
53
54 return ptr;
55 }
56
57
58 extern void
lzma_free(void * ptr,lzma_allocator * allocator)59 lzma_free(void *ptr, lzma_allocator *allocator)
60 {
61 if (allocator != NULL && allocator->free != NULL)
62 allocator->free(allocator->opaque, ptr);
63 else
64 free(ptr);
65
66 return;
67 }
68
69
70 //////////
71 // Misc //
72 //////////
73
74 extern size_t
lzma_bufcpy(const uint8_t * restrict in,size_t * restrict in_pos,size_t in_size,uint8_t * restrict out,size_t * restrict out_pos,size_t out_size)75 lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
76 size_t in_size, uint8_t *restrict out,
77 size_t *restrict out_pos, size_t out_size)
78 {
79 const size_t in_avail = in_size - *in_pos;
80 const size_t out_avail = out_size - *out_pos;
81 const size_t copy_size = MIN(in_avail, out_avail);
82
83 memcpy(out + *out_pos, in + *in_pos, copy_size);
84
85 *in_pos += copy_size;
86 *out_pos += copy_size;
87
88 return copy_size;
89 }
90
91
92 extern lzma_ret
lzma_next_filter_init(lzma_next_coder * next,lzma_allocator * allocator,const lzma_filter_info * filters)93 lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator,
94 const lzma_filter_info *filters)
95 {
96 lzma_next_coder_init(filters[0].init, next, allocator);
97
98 return filters[0].init == NULL
99 ? LZMA_OK : filters[0].init(next, allocator, filters);
100 }
101
102
103 extern void
lzma_next_end(lzma_next_coder * next,lzma_allocator * allocator)104 lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator)
105 {
106 if (next->init != (uintptr_t)(NULL)) {
107 // To avoid tiny end functions that simply call
108 // lzma_free(coder, allocator), we allow leaving next->end
109 // NULL and call lzma_free() here.
110 if (next->end != NULL)
111 next->end(next->coder, allocator);
112 else
113 lzma_free(next->coder, allocator);
114
115 // Reset the variables so the we don't accidentally think
116 // that it is an already initialized coder.
117 *next = LZMA_NEXT_CODER_INIT;
118 }
119
120 return;
121 }
122
123
124 //////////////////////////////////////
125 // External to internal API wrapper //
126 //////////////////////////////////////
127
128 extern lzma_ret
lzma_strm_init(lzma_stream * strm)129 lzma_strm_init(lzma_stream *strm)
130 {
131 if (strm == NULL)
132 return LZMA_PROG_ERROR;
133
134 if (strm->internal == NULL) {
135 strm->internal = lzma_alloc(sizeof(lzma_internal),
136 strm->allocator);
137 if (strm->internal == NULL)
138 return LZMA_MEM_ERROR;
139
140 strm->internal->next = LZMA_NEXT_CODER_INIT;
141 }
142
143 strm->internal->supported_actions[LZMA_RUN] = false;
144 strm->internal->supported_actions[LZMA_SYNC_FLUSH] = false;
145 strm->internal->supported_actions[LZMA_FULL_FLUSH] = false;
146 strm->internal->supported_actions[LZMA_FINISH] = false;
147 strm->internal->sequence = ISEQ_RUN;
148
149 strm->total_in = 0;
150 strm->total_out = 0;
151
152 return LZMA_OK;
153 }
154
155
156 extern LZMA_API(lzma_ret)
lzma_code(lzma_stream * strm,lzma_action action)157 lzma_code(lzma_stream *strm, lzma_action action)
158 {
159 // Sanity checks
160 if ((strm->next_in == NULL && strm->avail_in != 0)
161 || (strm->next_out == NULL && strm->avail_out != 0)
162 || strm->internal == NULL
163 || strm->internal->next.code == NULL
164 || (unsigned int)(action) > LZMA_FINISH
165 || !strm->internal->supported_actions[action])
166 return LZMA_PROG_ERROR;
167
168 switch (strm->internal->sequence) {
169 case ISEQ_RUN:
170 switch (action) {
171 case LZMA_RUN:
172 break;
173
174 case LZMA_SYNC_FLUSH:
175 strm->internal->sequence = ISEQ_SYNC_FLUSH;
176 break;
177
178 case LZMA_FULL_FLUSH:
179 strm->internal->sequence = ISEQ_FULL_FLUSH;
180 break;
181
182 case LZMA_FINISH:
183 strm->internal->sequence = ISEQ_FINISH;
184 break;
185 }
186
187 break;
188
189 case ISEQ_SYNC_FLUSH:
190 // The same action must be used until we return
191 // LZMA_STREAM_END, and the amount of input must not change.
192 if (action != LZMA_SYNC_FLUSH
193 || strm->internal->avail_in != strm->avail_in)
194 return LZMA_PROG_ERROR;
195
196 break;
197
198 case ISEQ_FULL_FLUSH:
199 if (action != LZMA_FULL_FLUSH
200 || strm->internal->avail_in != strm->avail_in)
201 return LZMA_PROG_ERROR;
202
203 break;
204
205 case ISEQ_FINISH:
206 if (action != LZMA_FINISH
207 || strm->internal->avail_in != strm->avail_in)
208 return LZMA_PROG_ERROR;
209
210 break;
211
212 case ISEQ_END:
213 return LZMA_STREAM_END;
214
215 case ISEQ_ERROR:
216 default:
217 return LZMA_PROG_ERROR;
218 }
219
220 size_t in_pos = 0;
221 size_t out_pos = 0;
222 lzma_ret ret = strm->internal->next.code(
223 strm->internal->next.coder, strm->allocator,
224 strm->next_in, &in_pos, strm->avail_in,
225 strm->next_out, &out_pos, strm->avail_out, action);
226
227 strm->next_in += in_pos;
228 strm->avail_in -= in_pos;
229 strm->total_in += in_pos;
230
231 strm->next_out += out_pos;
232 strm->avail_out -= out_pos;
233 strm->total_out += out_pos;
234
235 strm->internal->avail_in = strm->avail_in;
236
237 switch (ret) {
238 case LZMA_OK:
239 // Don't return LZMA_BUF_ERROR when it happens the first time.
240 // This is to avoid returning LZMA_BUF_ERROR when avail_out
241 // was zero but still there was no more data left to written
242 // to next_out.
243 if (out_pos == 0 && in_pos == 0) {
244 if (strm->internal->allow_buf_error)
245 ret = LZMA_BUF_ERROR;
246 else
247 strm->internal->allow_buf_error = true;
248 } else {
249 strm->internal->allow_buf_error = false;
250 }
251 break;
252
253 case LZMA_STREAM_END:
254 if (strm->internal->sequence == ISEQ_SYNC_FLUSH
255 || strm->internal->sequence == ISEQ_FULL_FLUSH)
256 strm->internal->sequence = ISEQ_RUN;
257 else
258 strm->internal->sequence = ISEQ_END;
259
260 // Fall through
261
262 case LZMA_NO_CHECK:
263 case LZMA_UNSUPPORTED_CHECK:
264 case LZMA_GET_CHECK:
265 case LZMA_MEMLIMIT_ERROR:
266 // Something else than LZMA_OK, but not a fatal error,
267 // that is, coding may be continued (except if ISEQ_END).
268 strm->internal->allow_buf_error = false;
269 break;
270
271 default:
272 // All the other errors are fatal; coding cannot be continued.
273 assert(ret != LZMA_BUF_ERROR);
274 strm->internal->sequence = ISEQ_ERROR;
275 break;
276 }
277
278 return ret;
279 }
280
281
282 extern LZMA_API(void)
lzma_end(lzma_stream * strm)283 lzma_end(lzma_stream *strm)
284 {
285 if (strm != NULL && strm->internal != NULL) {
286 lzma_next_end(&strm->internal->next, strm->allocator);
287 lzma_free(strm->internal, strm->allocator);
288 strm->internal = NULL;
289 }
290
291 return;
292 }
293
294
295 extern LZMA_API(lzma_check)
lzma_get_check(const lzma_stream * strm)296 lzma_get_check(const lzma_stream *strm)
297 {
298 // Return LZMA_CHECK_NONE if we cannot know the check type.
299 // It's a bug in the application if this happens.
300 if (strm->internal->next.get_check == NULL)
301 return LZMA_CHECK_NONE;
302
303 return strm->internal->next.get_check(strm->internal->next.coder);
304 }
305
306
307 extern LZMA_API(uint64_t)
lzma_memusage(const lzma_stream * strm)308 lzma_memusage(const lzma_stream *strm)
309 {
310 uint64_t memusage;
311 uint64_t old_memlimit;
312
313 if (strm == NULL || strm->internal == NULL
314 || strm->internal->next.memconfig == NULL
315 || strm->internal->next.memconfig(
316 strm->internal->next.coder,
317 &memusage, &old_memlimit, 0) != LZMA_OK)
318 return 0;
319
320 return memusage;
321 }
322
323
324 extern LZMA_API(uint64_t)
lzma_memlimit_get(const lzma_stream * strm)325 lzma_memlimit_get(const lzma_stream *strm)
326 {
327 uint64_t old_memlimit;
328 uint64_t memusage;
329
330 if (strm == NULL || strm->internal == NULL
331 || strm->internal->next.memconfig == NULL
332 || strm->internal->next.memconfig(
333 strm->internal->next.coder,
334 &memusage, &old_memlimit, 0) != LZMA_OK)
335 return 0;
336
337 return old_memlimit;
338 }
339
340
341 extern LZMA_API(lzma_ret)
lzma_memlimit_set(lzma_stream * strm,uint64_t new_memlimit)342 lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
343 {
344 // Dummy variables to simplify memconfig functions
345 uint64_t old_memlimit;
346 uint64_t memusage;
347
348 if (strm == NULL || strm->internal == NULL
349 || strm->internal->next.memconfig == NULL)
350 return LZMA_PROG_ERROR;
351
352 if (new_memlimit != 0 && new_memlimit < LZMA_MEMUSAGE_BASE)
353 return LZMA_MEMLIMIT_ERROR;
354
355 return strm->internal->next.memconfig(strm->internal->next.coder,
356 &memusage, &old_memlimit, new_memlimit);
357 }
358