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