| /////////////////////////////////////////////////////////////////////////////// |
| // |
| /// \file code.c |
| /// \brief zlib-like API wrapper for liblzma's internal API |
| // |
| // Copyright (C) 2007 Lasse Collin |
| // |
| // This library is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Lesser General Public |
| // License as published by the Free Software Foundation; either |
| // version 2.1 of the License, or (at your option) any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Lesser General Public License for more details. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "common.h" |
| |
| |
| LZMA_API const lzma_stream LZMA_STREAM_INIT_VAR = { |
| .next_in = NULL, |
| .avail_in = 0, |
| .total_in = 0, |
| .next_out = NULL, |
| .avail_out = 0, |
| .total_out = 0, |
| .allocator = NULL, |
| .internal = NULL, |
| }; |
| |
| |
| extern lzma_ret |
| lzma_strm_init(lzma_stream *strm) |
| { |
| if (strm == NULL) |
| return LZMA_PROG_ERROR; |
| |
| if (strm->internal == NULL) { |
| strm->internal = lzma_alloc(sizeof(lzma_internal), |
| strm->allocator); |
| if (strm->internal == NULL) |
| return LZMA_MEM_ERROR; |
| |
| strm->internal->next = LZMA_NEXT_CODER_INIT; |
| } |
| |
| strm->internal->supported_actions[LZMA_RUN] = false; |
| strm->internal->supported_actions[LZMA_SYNC_FLUSH] = false; |
| strm->internal->supported_actions[LZMA_FULL_FLUSH] = false; |
| strm->internal->supported_actions[LZMA_FINISH] = false; |
| strm->internal->sequence = ISEQ_RUN; |
| |
| strm->total_in = 0; |
| strm->total_out = 0; |
| |
| return LZMA_OK; |
| } |
| |
| |
| extern LZMA_API lzma_ret |
| lzma_code(lzma_stream *strm, lzma_action action) |
| { |
| // Sanity checks |
| if ((strm->next_in == NULL && strm->avail_in != 0) |
| || (strm->next_out == NULL && strm->avail_out != 0) |
| || strm->internal == NULL |
| || strm->internal->next.code == NULL |
| || (unsigned int)(action) > LZMA_FINISH |
| || !strm->internal->supported_actions[action]) |
| return LZMA_PROG_ERROR; |
| |
| switch (strm->internal->sequence) { |
| case ISEQ_RUN: |
| switch (action) { |
| case LZMA_RUN: |
| break; |
| |
| case LZMA_SYNC_FLUSH: |
| strm->internal->sequence = ISEQ_SYNC_FLUSH; |
| break; |
| |
| case LZMA_FULL_FLUSH: |
| strm->internal->sequence = ISEQ_FULL_FLUSH; |
| break; |
| |
| case LZMA_FINISH: |
| strm->internal->sequence = ISEQ_FINISH; |
| break; |
| } |
| |
| break; |
| |
| case ISEQ_SYNC_FLUSH: |
| if (action != LZMA_SYNC_FLUSH) |
| return LZMA_PROG_ERROR; |
| |
| // Check that application doesn't change avail_in once |
| // LZMA_SYNC_FLUSH has been used. |
| if (strm->internal->avail_in != strm->avail_in) |
| return LZMA_DATA_ERROR; |
| |
| break; |
| |
| case ISEQ_FULL_FLUSH: |
| if (action != LZMA_FULL_FLUSH) |
| return LZMA_PROG_ERROR; |
| |
| // Check that application doesn't change avail_in once |
| // LZMA_FULL_FLUSH has been used. |
| if (strm->internal->avail_in != strm->avail_in) |
| return LZMA_DATA_ERROR; |
| |
| break; |
| |
| case ISEQ_FINISH: |
| if (action != LZMA_FINISH) |
| return LZMA_PROG_ERROR; |
| |
| if (strm->internal->avail_in != strm->avail_in) |
| return LZMA_DATA_ERROR; |
| |
| break; |
| |
| case ISEQ_END: |
| return LZMA_STREAM_END; |
| |
| case ISEQ_ERROR: |
| default: |
| return LZMA_PROG_ERROR; |
| } |
| |
| size_t in_pos = 0; |
| size_t out_pos = 0; |
| lzma_ret ret = strm->internal->next.code( |
| strm->internal->next.coder, strm->allocator, |
| strm->next_in, &in_pos, strm->avail_in, |
| strm->next_out, &out_pos, strm->avail_out, action); |
| |
| strm->next_in += in_pos; |
| strm->avail_in -= in_pos; |
| strm->total_in += in_pos; |
| |
| strm->next_out += out_pos; |
| strm->avail_out -= out_pos; |
| strm->total_out += out_pos; |
| |
| strm->internal->avail_in = strm->avail_in; |
| |
| switch (ret) { |
| case LZMA_OK: |
| // Don't return LZMA_BUF_ERROR when it happens the first time. |
| // This is to avoid returning LZMA_BUF_ERROR when avail_out |
| // was zero but still there was no more data left to written |
| // to next_out. |
| if (out_pos == 0 && in_pos == 0) { |
| if (strm->internal->allow_buf_error) |
| ret = LZMA_BUF_ERROR; |
| else |
| strm->internal->allow_buf_error = true; |
| } else { |
| strm->internal->allow_buf_error = false; |
| } |
| break; |
| |
| case LZMA_STREAM_END: |
| if (strm->internal->sequence == ISEQ_SYNC_FLUSH |
| || strm->internal->sequence == ISEQ_FULL_FLUSH) |
| strm->internal->sequence = ISEQ_RUN; |
| else |
| strm->internal->sequence = ISEQ_END; |
| break; |
| |
| case LZMA_UNSUPPORTED_CHECK: |
| strm->internal->allow_buf_error = false; |
| break; |
| |
| default: |
| // All the other errors are fatal; coding cannot be continued. |
| strm->internal->sequence = ISEQ_ERROR; |
| break; |
| } |
| |
| return ret; |
| } |
| |
| |
| extern LZMA_API void |
| lzma_end(lzma_stream *strm) |
| { |
| if (strm != NULL && strm->internal != NULL) { |
| if (strm->internal->next.end != NULL) |
| strm->internal->next.end(strm->internal->next.coder, |
| strm->allocator); |
| |
| lzma_free(strm->internal, strm->allocator); |
| strm->internal = NULL; |
| } |
| |
| return; |
| } |