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