]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/common.c
Sort of garbage collection commit. :-| Many things are still
[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                 if (action != LZMA_SYNC_FLUSH)
196                         return LZMA_PROG_ERROR;
197
198                 // Check that application doesn't change avail_in once
199                 // LZMA_SYNC_FLUSH has been used.
200                 if (strm->internal->avail_in != strm->avail_in)
201                         return LZMA_DATA_ERROR;
202
203                 break;
204
205         case ISEQ_FULL_FLUSH:
206                 if (action != LZMA_FULL_FLUSH)
207                         return LZMA_PROG_ERROR;
208
209                 // Check that application doesn't change avail_in once
210                 // LZMA_FULL_FLUSH has been used.
211                 if (strm->internal->avail_in != strm->avail_in)
212                         return LZMA_DATA_ERROR;
213
214                 break;
215
216         case ISEQ_FINISH:
217                 if (action != LZMA_FINISH)
218                         return LZMA_PROG_ERROR;
219
220                 if (strm->internal->avail_in != strm->avail_in)
221                         return LZMA_DATA_ERROR;
222
223                 break;
224
225         case ISEQ_END:
226                 return LZMA_STREAM_END;
227
228         case ISEQ_ERROR:
229         default:
230                 return LZMA_PROG_ERROR;
231         }
232
233         size_t in_pos = 0;
234         size_t out_pos = 0;
235         lzma_ret ret = strm->internal->next.code(
236                         strm->internal->next.coder, strm->allocator,
237                         strm->next_in, &in_pos, strm->avail_in,
238                         strm->next_out, &out_pos, strm->avail_out, action);
239
240         strm->next_in += in_pos;
241         strm->avail_in -= in_pos;
242         strm->total_in += in_pos;
243
244         strm->next_out += out_pos;
245         strm->avail_out -= out_pos;
246         strm->total_out += out_pos;
247
248         strm->internal->avail_in = strm->avail_in;
249
250         switch (ret) {
251         case LZMA_OK:
252                 // Don't return LZMA_BUF_ERROR when it happens the first time.
253                 // This is to avoid returning LZMA_BUF_ERROR when avail_out
254                 // was zero but still there was no more data left to written
255                 // to next_out.
256                 if (out_pos == 0 && in_pos == 0) {
257                         if (strm->internal->allow_buf_error)
258                                 ret = LZMA_BUF_ERROR;
259                         else
260                                 strm->internal->allow_buf_error = true;
261                 } else {
262                         strm->internal->allow_buf_error = false;
263                 }
264                 break;
265
266         case LZMA_STREAM_END:
267                 if (strm->internal->sequence == ISEQ_SYNC_FLUSH
268                                 || strm->internal->sequence == ISEQ_FULL_FLUSH)
269                         strm->internal->sequence = ISEQ_RUN;
270                 else
271                         strm->internal->sequence = ISEQ_END;
272                 break;
273
274         case LZMA_UNSUPPORTED_CHECK:
275                 strm->internal->allow_buf_error = false;
276                 break;
277
278         default:
279                 // All the other errors are fatal; coding cannot be continued.
280                 strm->internal->sequence = ISEQ_ERROR;
281                 break;
282         }
283
284         return ret;
285 }
286
287
288 extern LZMA_API void
289 lzma_end(lzma_stream *strm)
290 {
291         if (strm != NULL && strm->internal != NULL) {
292                 lzma_next_end(&strm->internal->next, strm->allocator);
293                 lzma_free(strm->internal, strm->allocator);
294                 strm->internal = NULL;
295         }
296
297         return;
298 }