| /////////////////////////////////////////////////////////////////////////////// |
| // |
| /// \file lz_decoder.h |
| /// \brief LZ out window |
| // |
| // Copyright (C) 1999-2006 Igor Pavlov |
| // 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. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #ifndef LZMA_LZ_OUT_H |
| #define LZMA_LZ_OUT_H |
| |
| #include "common.h" |
| |
| |
| /// Get a byte from the history buffer. |
| #define lz_get_byte(lz, distance) \ |
| ((distance) < (lz).pos \ |
| ? (lz).dict[(lz).pos - (distance) - 1] \ |
| : (lz).dict[(lz).pos - (distance) - 1 + (lz).end]) |
| |
| |
| #define LZMA_LZ_DECODER_INIT \ |
| (lzma_lz_decoder){ .dict = NULL, .size = 0, .match_max_len = 0 } |
| |
| |
| typedef struct { |
| /// Function to do the actual decoding (LZMA or Inflate) |
| bool (*process)(lzma_coder *restrict coder, const uint8_t *restrict in, |
| size_t *restrict in_pos, size_t size_in, |
| bool has_safe_buffer); |
| |
| /// Pointer to dictionary (history) buffer. |
| /// \note Not 'restrict' because can alias next_out. |
| uint8_t *dict; |
| |
| /// Next write goes to dict[pos]. |
| size_t pos; |
| |
| /// Next byte to flush is buffer[start]. |
| size_t start; |
| |
| /// First byte to not flush is buffer[end]. |
| size_t end; |
| |
| /// First position to which data must not be written. |
| size_t limit; |
| |
| /// True if dictionary has needed wrapping. |
| bool is_full; |
| |
| /// True if process() has detected End of Payload Marker. |
| bool eopm_detected; |
| |
| /// True if the next coder in the chain has returned LZMA_STREAM_END. |
| bool next_finished; |
| |
| /// True if the LZ decoder (e.g. LZMA) has detected End of Payload |
| /// Marker. This may become true before next_finished becomes true. |
| bool this_finished; |
| |
| /// When pos >= must_flush_pos, we must not call process(). |
| size_t must_flush_pos; |
| |
| /// Maximum number of bytes that a single decoding loop inside |
| /// process() can produce data into dict. This amount is kept |
| /// always available at dict + pos i.e. it is safe to write a byte |
| /// to dict[pos + match_max_len - 1]. |
| size_t match_max_len; |
| |
| /// Number of bytes allocated to dict. |
| size_t size; |
| |
| /// Requested size of the dictionary. This is needed because we avoid |
| /// using extremely tiny history buffers. |
| size_t requested_size; |
| |
| /// Uncompressed Size or LZMA_VLI_VALUE_UNKNOWN if unknown. |
| lzma_vli uncompressed_size; |
| |
| /// Number of bytes currently in temp[]. |
| size_t temp_size; |
| |
| /// Temporary buffer needed when |
| /// 1) we cannot make the input buffer completely empty; or |
| /// 2) we are not the last filter in the chain. |
| uint8_t temp[LZMA_BUFFER_SIZE]; |
| |
| } lzma_lz_decoder; |
| |
| |
| ///////////////////////// |
| // Function prototypes // |
| ///////////////////////// |
| |
| extern lzma_ret lzma_lz_decoder_reset(lzma_lz_decoder *lz, |
| lzma_allocator *allocator, bool (*process)( |
| lzma_coder *restrict coder, const uint8_t *restrict in, |
| size_t *restrict in_pos, size_t in_size, |
| bool has_safe_buffer), |
| lzma_vli uncompressed_size, |
| size_t history_size, size_t match_max_len); |
| |
| extern lzma_ret lzma_lz_decode(lzma_coder *coder, lzma_allocator *allocator, |
| const uint8_t *restrict in, size_t *restrict in_pos, |
| size_t in_size, uint8_t *restrict out, |
| size_t *restrict out_pos, size_t out_size, |
| lzma_action action); |
| |
| /// Deallocates the history buffer if one exists. |
| extern void lzma_lz_decoder_end( |
| lzma_lz_decoder *lz, lzma_allocator *allocator); |
| |
| ////////////////////// |
| // Inline functions // |
| ////////////////////// |
| |
| // Repeat a block of data from the history. Because memcpy() is faster |
| // than copying byte by byte in a loop, the copying process gets split |
| // into three cases: |
| // 1. distance < length |
| // Source and target areas overlap, thus we can't use memcpy() |
| // (nor memmove()) safely. |
| // TODO: If this is common enough, it might be worth optimizing this |
| // more e.g. by checking if distance > sizeof(uint8_t*) and using |
| // memcpy in small chunks. |
| // 2. distance < pos |
| // This is the easiest and the fastest case. The block being copied |
| // is a contiguous piece in the history buffer. The buffer offset |
| // doesn't need wrapping. |
| // 3. distance >= pos |
| // We need to wrap the position, because otherwise we would try copying |
| // behind the first byte of the allocated buffer. It is possible that |
| // the block is fragmeneted into two pieces, thus we might need to call |
| // memcpy() twice. |
| // NOTE: The function using this macro must ensure that length is positive |
| // and that distance is FIXME |
| static inline bool |
| lzma_lz_out_repeat(lzma_lz_decoder *lz, size_t distance, size_t length) |
| { |
| // Validate offset of the block to be repeated. It doesn't |
| // make sense to copy data behind the beginning of the stream. |
| // Leaving this check away would lead to a security problem, |
| // in which e.g. the data of the previously decoded file(s) |
| // would be leaked (or whatever happens to be in unused |
| // part of the dictionary buffer). |
| if (distance >= lz->pos && !lz->is_full) |
| return false; |
| |
| // It also doesn't make sense to copy data farer than |
| // the dictionary size. |
| if (distance >= lz->requested_size) |
| return false; |
| |
| // The caller must have checked these! |
| assert(distance <= lz->size); |
| assert(length > 0); |
| assert(length <= lz->match_max_len); |
| |
| // Copy the amount of data requested by the decoder. |
| if (distance < length) { |
| // Source and target areas overlap, thus we can't use |
| // memcpy() nor even memmove() safely. :-( |
| // TODO: Copying byte by byte is slow. It might be |
| // worth optimizing this more if this case is common. |
| do { |
| lz->dict[lz->pos] = lz_get_byte(*lz, distance); |
| ++lz->pos; |
| } while (--length > 0); |
| |
| } else if (distance < lz->pos) { |
| // The easiest and fastest case |
| memcpy(lz->dict + lz->pos, |
| lz->dict + lz->pos - distance - 1, |
| length); |
| lz->pos += length; |
| |
| } else { |
| // The bigger the dictionary, the more rare this |
| // case occurs. We need to "wrap" the dict, thus |
| // we might need two memcpy() to copy all the data. |
| assert(lz->is_full); |
| const uint32_t copy_pos = lz->pos - distance - 1 + lz->end; |
| uint32_t copy_size = lz->end - copy_pos; |
| |
| if (copy_size < length) { |
| memcpy(lz->dict + lz->pos, lz->dict + copy_pos, |
| copy_size); |
| lz->pos += copy_size; |
| copy_size = length - copy_size; |
| memcpy(lz->dict + lz->pos, lz->dict, copy_size); |
| lz->pos += copy_size; |
| } else { |
| memcpy(lz->dict + lz->pos, lz->dict + copy_pos, |
| length); |
| lz->pos += length; |
| } |
| } |
| |
| return true; |
| } |
| |
| #endif |