]> icculus.org git repositories - icculus/xz.git/blob - src/liblzma/common/code.c
Fix test_filter_flags to match the new restriction of lc+lp.
[icculus/xz.git] / src / liblzma / common / code.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       code.c
4 /// \brief      zlib-like API wrapper for liblzma's internal API
5 //
6 //  Copyright (C) 2007 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 LZMA_API const lzma_stream LZMA_STREAM_INIT_VAR = {
24         .next_in = NULL,
25         .avail_in = 0,
26         .total_in = 0,
27         .next_out = NULL,
28         .avail_out = 0,
29         .total_out = 0,
30         .allocator = NULL,
31         .internal = NULL,
32 };
33
34
35 extern lzma_ret
36 lzma_strm_init(lzma_stream *strm)
37 {
38         if (strm == NULL)
39                 return LZMA_PROG_ERROR;
40
41         if (strm->internal == NULL) {
42                 strm->internal = lzma_alloc(sizeof(lzma_internal),
43                                 strm->allocator);
44                 if (strm->internal == NULL)
45                         return LZMA_MEM_ERROR;
46
47                 strm->internal->next = LZMA_NEXT_CODER_INIT;
48         }
49
50         strm->internal->supported_actions[LZMA_RUN] = false;
51         strm->internal->supported_actions[LZMA_SYNC_FLUSH] = false;
52         strm->internal->supported_actions[LZMA_FULL_FLUSH] = false;
53         strm->internal->supported_actions[LZMA_FINISH] = false;
54         strm->internal->sequence = ISEQ_RUN;
55
56         strm->total_in = 0;
57         strm->total_out = 0;
58
59         return LZMA_OK;
60 }
61
62
63 extern LZMA_API lzma_ret
64 lzma_code(lzma_stream *strm, lzma_action action)
65 {
66         // Sanity checks
67         if ((strm->next_in == NULL && strm->avail_in != 0)
68                         || (strm->next_out == NULL && strm->avail_out != 0)
69                         || strm->internal == NULL
70                         || strm->internal->next.code == NULL
71                         || (unsigned int)(action) > LZMA_FINISH
72                         || !strm->internal->supported_actions[action])
73                 return LZMA_PROG_ERROR;
74
75         switch (strm->internal->sequence) {
76         case ISEQ_RUN:
77                 switch (action) {
78                 case LZMA_RUN:
79                         break;
80
81                 case LZMA_SYNC_FLUSH:
82                         strm->internal->sequence = ISEQ_SYNC_FLUSH;
83                         break;
84
85                 case LZMA_FULL_FLUSH:
86                         strm->internal->sequence = ISEQ_FULL_FLUSH;
87                         break;
88
89                 case LZMA_FINISH:
90                         strm->internal->sequence = ISEQ_FINISH;
91                         break;
92                 }
93
94                 break;
95
96         case ISEQ_SYNC_FLUSH:
97                 if (action != LZMA_SYNC_FLUSH)
98                         return LZMA_PROG_ERROR;
99
100                 // Check that application doesn't change avail_in once
101                 // LZMA_SYNC_FLUSH has been used.
102                 if (strm->internal->avail_in != strm->avail_in)
103                         return LZMA_DATA_ERROR;
104
105                 break;
106
107         case ISEQ_FULL_FLUSH:
108                 if (action != LZMA_FULL_FLUSH)
109                         return LZMA_PROG_ERROR;
110
111                 // Check that application doesn't change avail_in once
112                 // LZMA_FULL_FLUSH has been used.
113                 if (strm->internal->avail_in != strm->avail_in)
114                         return LZMA_DATA_ERROR;
115
116                 break;
117
118         case ISEQ_FINISH:
119                 if (action != LZMA_FINISH)
120                         return LZMA_PROG_ERROR;
121
122                 if (strm->internal->avail_in != strm->avail_in)
123                         return LZMA_DATA_ERROR;
124
125                 break;
126
127         case ISEQ_END:
128                 return LZMA_STREAM_END;
129
130         case ISEQ_ERROR:
131         default:
132                 return LZMA_PROG_ERROR;
133         }
134
135         size_t in_pos = 0;
136         size_t out_pos = 0;
137         lzma_ret ret = strm->internal->next.code(
138                         strm->internal->next.coder, strm->allocator,
139                         strm->next_in, &in_pos, strm->avail_in,
140                         strm->next_out, &out_pos, strm->avail_out, action);
141
142         strm->next_in += in_pos;
143         strm->avail_in -= in_pos;
144         strm->total_in += in_pos;
145
146         strm->next_out += out_pos;
147         strm->avail_out -= out_pos;
148         strm->total_out += out_pos;
149
150         strm->internal->avail_in = strm->avail_in;
151
152         switch (ret) {
153         case LZMA_OK:
154                 // Don't return LZMA_BUF_ERROR when it happens the first time.
155                 // This is to avoid returning LZMA_BUF_ERROR when avail_out
156                 // was zero but still there was no more data left to written
157                 // to next_out.
158                 if (out_pos == 0 && in_pos == 0) {
159                         if (strm->internal->allow_buf_error)
160                                 ret = LZMA_BUF_ERROR;
161                         else
162                                 strm->internal->allow_buf_error = true;
163                 } else {
164                         strm->internal->allow_buf_error = false;
165                 }
166                 break;
167
168         case LZMA_STREAM_END:
169                 if (strm->internal->sequence == ISEQ_SYNC_FLUSH
170                                 || strm->internal->sequence == ISEQ_FULL_FLUSH)
171                         strm->internal->sequence = ISEQ_RUN;
172                 else
173                         strm->internal->sequence = ISEQ_END;
174                 break;
175
176         case LZMA_UNSUPPORTED_CHECK:
177                 strm->internal->allow_buf_error = false;
178                 break;
179
180         default:
181                 // All the other errors are fatal; coding cannot be continued.
182                 strm->internal->sequence = ISEQ_ERROR;
183                 break;
184         }
185
186         return ret;
187 }
188
189
190 extern LZMA_API void
191 lzma_end(lzma_stream *strm)
192 {
193         if (strm != NULL && strm->internal != NULL) {
194                 if (strm->internal->next.end != NULL)
195                         strm->internal->next.end(strm->internal->next.coder,
196                                         strm->allocator);
197
198                 lzma_free(strm->internal, strm->allocator);
199                 strm->internal = NULL;
200         }
201
202         return;
203 }