1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief zlib-like API wrapper for liblzma's internal API
6 // Copyright (C) 2007 Lasse Collin
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.
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.
18 ///////////////////////////////////////////////////////////////////////////////
23 LZMA_API const lzma_stream LZMA_STREAM_INIT_VAR = {
36 lzma_strm_init(lzma_stream *strm)
39 return LZMA_PROG_ERROR;
41 if (strm->internal == NULL) {
42 strm->internal = lzma_alloc(sizeof(lzma_internal),
44 if (strm->internal == NULL)
45 return LZMA_MEM_ERROR;
47 strm->internal->next = LZMA_NEXT_CODER_INIT;
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;
63 extern LZMA_API lzma_ret
64 lzma_code(lzma_stream *strm, lzma_action action)
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;
75 switch (strm->internal->sequence) {
82 strm->internal->sequence = ISEQ_SYNC_FLUSH;
86 strm->internal->sequence = ISEQ_FULL_FLUSH;
90 strm->internal->sequence = ISEQ_FINISH;
97 if (action != LZMA_SYNC_FLUSH)
98 return LZMA_PROG_ERROR;
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;
107 case ISEQ_FULL_FLUSH:
108 if (action != LZMA_FULL_FLUSH)
109 return LZMA_PROG_ERROR;
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;
119 if (action != LZMA_FINISH)
120 return LZMA_PROG_ERROR;
122 if (strm->internal->avail_in != strm->avail_in)
123 return LZMA_DATA_ERROR;
128 return LZMA_STREAM_END;
132 return LZMA_PROG_ERROR;
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);
142 strm->next_in += in_pos;
143 strm->avail_in -= in_pos;
144 strm->total_in += in_pos;
146 strm->next_out += out_pos;
147 strm->avail_out -= out_pos;
148 strm->total_out += out_pos;
150 strm->internal->avail_in = strm->avail_in;
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
158 if (out_pos == 0 && in_pos == 0) {
159 if (strm->internal->allow_buf_error)
160 ret = LZMA_BUF_ERROR;
162 strm->internal->allow_buf_error = true;
164 strm->internal->allow_buf_error = false;
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;
173 strm->internal->sequence = ISEQ_END;
176 case LZMA_UNSUPPORTED_CHECK:
177 strm->internal->allow_buf_error = false;
181 // All the other errors are fatal; coding cannot be continued.
182 strm->internal->sequence = ISEQ_ERROR;
191 lzma_end(lzma_stream *strm)
193 if (strm != NULL && strm->internal != NULL) {
194 if (strm->internal->next.end != NULL)
195 strm->internal->next.end(strm->internal->next.coder,
198 lzma_free(strm->internal, strm->allocator);
199 strm->internal = NULL;