| /////////////////////////////////////////////////////////////////////////////// |
| // |
| /// \file subblock_encoder.c |
| /// \brief Encoder of the Subblock filter |
| // |
| // Author: Lasse Collin |
| // |
| // This file has been put into the public domain. |
| // You can do whatever you want with this file. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| #include "subblock_encoder.h" |
| #include "filter_encoder.h" |
| |
| |
| /// Maximum number of repeats that a single Repeating Data can indicate. |
| /// This is directly from the file format specification. |
| #define REPEAT_COUNT_MAX (1U << 28) |
| |
| /// Number of bytes the data chunk (not including the header part) must be |
| /// before we care about alignment. This is somewhat arbitrary. It just |
| /// doesn't make sense to waste bytes for alignment when the data chunk |
| /// is very small. |
| #define MIN_CHUNK_SIZE_FOR_ALIGN 4 |
| |
| /// Number of bytes of the header part of Subblock Type `Data'. This is |
| /// used as the `skew' argument for subblock_align(). |
| #define ALIGN_SKEW_DATA 4 |
| |
| /// Like above but for Repeating Data. |
| #define ALIGN_SKEW_REPEATING_DATA 5 |
| |
| /// Writes one byte to output buffer and updates the alignment counter. |
| #define write_byte(b) \ |
| do { \ |
| assert(*out_pos < out_size); \ |
| out[*out_pos] = b; \ |
| ++*out_pos; \ |
| ++coder->alignment.out_pos; \ |
| } while (0) |
| |
| |
| struct lzma_coder_s { |
| lzma_next_coder next; |
| bool next_finished; |
| |
| enum { |
| SEQ_FILL, |
| SEQ_FLUSH, |
| SEQ_RLE_COUNT_0, |
| SEQ_RLE_COUNT_1, |
| SEQ_RLE_COUNT_2, |
| SEQ_RLE_COUNT_3, |
| SEQ_RLE_SIZE, |
| SEQ_RLE_DATA, |
| SEQ_DATA_SIZE_0, |
| SEQ_DATA_SIZE_1, |
| SEQ_DATA_SIZE_2, |
| SEQ_DATA_SIZE_3, |
| SEQ_DATA, |
| SEQ_SUBFILTER_INIT, |
| SEQ_SUBFILTER_FLAGS, |
| } sequence; |
| |
| /// Pointer to the options given by the application. This is used |
| /// for two-way communication with the application. |
| lzma_options_subblock *options; |
| |
| /// Position in various arrays. |
| size_t pos; |
| |
| /// Holds subblock.size - 1 or rle.size - 1 when encoding size |
| /// of Data or Repeat Count. |
| uint32_t tmp; |
| |
| struct { |
| /// This is a copy of options->alignment, or |
| /// LZMA_SUBBLOCK_ALIGNMENT_DEFAULT if options is NULL. |
| uint32_t multiple; |
| |
| /// Number of input bytes which we have processed and started |
| /// writing out. 32-bit integer is enough since we care only |
| /// about the lowest bits when fixing alignment. |
| uint32_t in_pos; |
| |
| /// Number of bytes written out. |
| uint32_t out_pos; |
| } alignment; |
| |
| struct { |
| /// Pointer to allocated buffer holding the Data field |
| /// of Subblock Type "Data". |
| uint8_t *data; |
| |
| /// Number of bytes in the buffer. |
| size_t size; |
| |
| /// Allocated size of the buffer. |
| size_t limit; |
| |
| /// Number of input bytes that we have already read but |
| /// not yet started writing out. This can be different |
| /// to `size' when using Subfilter. That's why we track |
| /// in_pending separately for RLE (see below). |
| uint32_t in_pending; |
| } subblock; |
| |
| struct { |
| /// Buffer to hold the data that may be coded with |
| /// Subblock Type `Repeating Data'. |
| uint8_t buffer[LZMA_SUBBLOCK_RLE_MAX]; |
| |
| /// Number of bytes in buffer[]. |
| size_t size; |
| |
| /// Number of times the first `size' bytes of buffer[] |
| /// will be repeated. |
| uint64_t count; |
| |
| /// Like subblock.in_pending above, but for RLE. |
| uint32_t in_pending; |
| } rle; |
| |
| struct { |
| enum { |
| SUB_NONE, |
| SUB_SET, |
| SUB_RUN, |
| SUB_FLUSH, |
| SUB_FINISH, |
| SUB_END_MARKER, |
| } mode; |
| |
| /// This is a copy of options->allow_subfilters. We use |
| /// this to verify that the application doesn't change |
| /// the value of allow_subfilters. |
| bool allow; |
| |
| /// When this is true, application is not allowed to modify |
| /// options->subblock_mode. We may still modify it here. |
| bool mode_locked; |
| |
| /// True if we have encoded at least one byte of data with |
| /// the Subfilter. |
| bool got_input; |
| |
| /// Track the amount of input available once |
| /// LZMA_SUBFILTER_FINISH has been enabled. |
| /// This is needed for sanity checking (kind |
| /// of duplicating what common/code.c does). |
| size_t in_avail; |
| |
| /// Buffer for the Filter Flags field written after |
| /// the `Set Subfilter' indicator. |
| uint8_t *flags; |
| |
| /// Size of Filter Flags field. |
| uint32_t flags_size; |
| |
| /// Pointers to Subfilter. |
| lzma_next_coder subcoder; |
| |
| } subfilter; |
| |
| /// Temporary buffer used when we are not the last filter in the chain. |
| struct { |
| size_t pos; |
| size_t size; |
| uint8_t buffer[LZMA_BUFFER_SIZE]; |
| } temp; |
| }; |
| |
| |
| /// \brief Aligns the output buffer |
| /// |
| /// Aligns the output buffer so that after skew bytes the output position is |
| /// a multiple of coder->alignment.multiple. |
| static bool |
| subblock_align(lzma_coder *coder, uint8_t *restrict out, |
| size_t *restrict out_pos, size_t out_size, |
| size_t chunk_size, uint32_t skew) |
| { |
| assert(*out_pos < out_size); |
| |
| // Fix the alignment only if it makes sense at least a little. |
| if (chunk_size >= MIN_CHUNK_SIZE_FOR_ALIGN) { |
| const uint32_t target = coder->alignment.in_pos |
| % coder->alignment.multiple; |
| |
| while ((coder->alignment.out_pos + skew) |
| % coder->alignment.multiple != target) { |
| // Zero indicates padding. |
| write_byte(0x00); |
| |
| // Check if output buffer got full and indicate it to |
| // the caller. |
| if (*out_pos == out_size) |
| return true; |
| } |
| } |
| |
| // Output buffer is not full. |
| return false; |
| } |
| |
| |
| /// \brief Checks if buffer contains repeated data |
| /// |
| /// \param needle Buffer containing a single repeat chunk |
| /// \param needle_size Size of needle in bytes |
| /// \param buf Buffer to search for repeated needles |
| /// \param buf_chunks Buffer size is buf_chunks * needle_size. |
| /// |
| /// \return True if the whole buf is filled with repeated needles. |
| /// |
| static bool |
| is_repeating(const uint8_t *restrict needle, size_t needle_size, |
| const uint8_t *restrict buf, size_t buf_chunks) |
| { |
| while (buf_chunks-- != 0) { |
| if (memcmp(buf, needle, needle_size) != 0) |
| return false; |
| |
| buf += needle_size; |
| } |
| |
| return true; |
| } |
| |
| |
| /// \brief Optimizes the repeating style and updates coder->sequence |
| static void |
| subblock_rle_flush(lzma_coder *coder) |
| { |
| // The Subblock decoder can use memset() when the size of the data |
| // being repeated is one byte, so we check if the RLE buffer is |
| // filled with a single repeating byte. |
| if (coder->rle.size > 1) { |
| const uint8_t b = coder->rle.buffer[0]; |
| size_t i = 0; |
| while (true) { |
| if (coder->rle.buffer[i] != b) |
| break; |
| |
| if (++i == coder->rle.size) { |
| // TODO Integer overflow check maybe, |
| // although this needs at least 2**63 bytes |
| // of input until it gets triggered... |
| coder->rle.count *= coder->rle.size; |
| coder->rle.size = 1; |
| break; |
| } |
| } |
| } |
| |
| if (coder->rle.count == 1) { |
| // The buffer should be repeated only once. It is |
| // waste of space to use Repeating Data. Instead, |
| // write a regular Data Subblock. See SEQ_RLE_COUNT_0 |
| // in subblock_buffer() for more info. |
| coder->tmp = coder->rle.size - 1; |
| } else if (coder->rle.count > REPEAT_COUNT_MAX) { |
| // There's so much to repeat that it doesn't fit into |
| // 28-bit integer. We will write two or more Subblocks |
| // of type Repeating Data. |
| coder->tmp = REPEAT_COUNT_MAX - 1; |
| } else { |
| coder->tmp = coder->rle.count - 1; |
| } |
| |
| coder->sequence = SEQ_RLE_COUNT_0; |
| |
| return; |
| } |
| |
| |
| /// \brief Resizes coder->subblock.data for a new size limit |
| static lzma_ret |
| subblock_data_size(lzma_coder *coder, lzma_allocator *allocator, |
| size_t new_limit) |
| { |
| // Verify that the new limit is valid. |
| if (new_limit < LZMA_SUBBLOCK_DATA_SIZE_MIN |
| || new_limit > LZMA_SUBBLOCK_DATA_SIZE_MAX) |
| return LZMA_OPTIONS_ERROR; |
| |
| // Ff the new limit is different than the previous one, we need |
| // to reallocate the data buffer. |
| if (new_limit != coder->subblock.limit) { |
| lzma_free(coder->subblock.data, allocator); |
| coder->subblock.data = lzma_alloc(new_limit, allocator); |
| if (coder->subblock.data == NULL) |
| return LZMA_MEM_ERROR; |
| } |
| |
| coder->subblock.limit = new_limit; |
| |
| return LZMA_OK; |
| } |
| |
| |
| static lzma_ret |
| subblock_buffer(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) |
| { |
| // Changing allow_subfilter is not allowed. |
| if (coder->options != NULL && coder->subfilter.allow |
| != coder->options->allow_subfilters) |
| return LZMA_PROG_ERROR; |
| |
| // Check if we need to do something special with the Subfilter. |
| if (coder->subfilter.allow) { |
| assert(coder->options != NULL); |
| |
| // See if subfilter_mode has been changed. |
| switch (coder->options->subfilter_mode) { |
| case LZMA_SUBFILTER_NONE: |
| if (coder->subfilter.mode != SUB_NONE) |
| return LZMA_PROG_ERROR; |
| break; |
| |
| case LZMA_SUBFILTER_SET: |
| if (coder->subfilter.mode_locked |
| || coder->subfilter.mode != SUB_NONE) |
| return LZMA_PROG_ERROR; |
| |
| coder->subfilter.mode = SUB_SET; |
| coder->subfilter.got_input = false; |
| |
| if (coder->sequence == SEQ_FILL) |
| coder->sequence = SEQ_FLUSH; |
| |
| break; |
| |
| case LZMA_SUBFILTER_RUN: |
| if (coder->subfilter.mode != SUB_RUN) |
| return LZMA_PROG_ERROR; |
| |
| break; |
| |
| case LZMA_SUBFILTER_FINISH: { |
| const size_t in_avail = in_size - *in_pos; |
| |
| if (coder->subfilter.mode == SUB_RUN) { |
| if (coder->subfilter.mode_locked) |
| return LZMA_PROG_ERROR; |
| |
| coder->subfilter.mode = SUB_FINISH; |
| coder->subfilter.in_avail = in_avail; |
| |
| } else if (coder->subfilter.mode != SUB_FINISH |
| || coder->subfilter.in_avail |
| != in_avail) { |
| return LZMA_PROG_ERROR; |
| } |
| |
| break; |
| } |
| |
| default: |
| return LZMA_OPTIONS_ERROR; |
| } |
| |
| // If we are sync-flushing or finishing, the application may |
| // no longer change subfilter_mode. Note that this check is |
| // done after checking the new subfilter_mode above; this |
| // way the application may e.g. set LZMA_SUBFILTER_SET and |
| // LZMA_SYNC_FLUSH at the same time, but it cannot modify |
| // subfilter_mode on the later lzma_code() calls before |
| // we have returned LZMA_STREAM_END. |
| if (action != LZMA_RUN) |
| coder->subfilter.mode_locked = true; |
| } |
| |
| // Main loop |
| while (*out_pos < out_size) |
| switch (coder->sequence) { |
| case SEQ_FILL: |
| // Grab the new Subblock Data Size and reallocate the buffer. |
| if (coder->subblock.size == 0 && coder->options != NULL |
| && coder->options->subblock_data_size |
| != coder->subblock.limit) |
| return_if_error(subblock_data_size(coder, |
| allocator, coder->options |
| ->subblock_data_size)); |
| |
| if (coder->subfilter.mode == SUB_NONE) { |
| assert(coder->subfilter.subcoder.code == NULL); |
| |
| // No Subfilter is enabled, just copy the data as is. |
| coder->subblock.in_pending += lzma_bufcpy( |
| in, in_pos, in_size, |
| coder->subblock.data, |
| &coder->subblock.size, |
| coder->subblock.limit); |
| |
| // If we ran out of input before the whole buffer |
| // was filled, return to application. |
| if (coder->subblock.size < coder->subblock.limit |
| && action == LZMA_RUN) |
| return LZMA_OK; |
| |
| } else { |
| assert(coder->options->subfilter_mode |
| != LZMA_SUBFILTER_SET); |
| |
| // Using LZMA_FINISH automatically toggles |
| // LZMA_SUBFILTER_FINISH. |
| // |
| // NOTE: It is possible that application had set |
| // LZMA_SUBFILTER_SET and LZMA_FINISH at the same |
| // time. In that case it is possible that we will |
| // cycle to LZMA_SUBFILTER_RUN, LZMA_SUBFILTER_FINISH, |
| // and back to LZMA_SUBFILTER_NONE in a single |
| // Subblock encoder function call. |
| if (action == LZMA_FINISH) { |
| coder->options->subfilter_mode |
| = LZMA_SUBFILTER_FINISH; |
| coder->subfilter.mode = SUB_FINISH; |
| } |
| |
| const size_t in_start = *in_pos; |
| |
| const lzma_ret ret = coder->subfilter.subcoder.code( |
| coder->subfilter.subcoder.coder, |
| allocator, in, in_pos, in_size, |
| coder->subblock.data, |
| &coder->subblock.size, |
| coder->subblock.limit, |
| coder->subfilter.mode == SUB_FINISH |
| ? LZMA_FINISH : action); |
| |
| const size_t in_used = *in_pos - in_start; |
| coder->subblock.in_pending += in_used; |
| if (in_used > 0) |
| coder->subfilter.got_input = true; |
| |
| coder->subfilter.in_avail = in_size - *in_pos; |
| |
| if (ret == LZMA_STREAM_END) { |
| // All currently available input must have |
| // been processed. |
| assert(*in_pos == in_size); |
| |
| // Flush now. Even if coder->subblock.size |
| // happened to be zero, we still need to go |
| // to SEQ_FLUSH to possibly finish RLE or |
| // write the Subfilter Unset indicator. |
| coder->sequence = SEQ_FLUSH; |
| |
| if (coder->subfilter.mode == SUB_RUN) { |
| // Flushing with Subfilter enabled. |
| assert(action == LZMA_SYNC_FLUSH); |
| coder->subfilter.mode = SUB_FLUSH; |
| break; |
| } |
| |
| // Subfilter finished its job. |
| assert(coder->subfilter.mode == SUB_FINISH |
| || action == LZMA_FINISH); |
| |
| // At least one byte of input must have been |
| // encoded with the Subfilter. This is |
| // required by the file format specification. |
| if (!coder->subfilter.got_input) |
| return LZMA_PROG_ERROR; |
| |
| // We don't strictly need to do this, but |
| // doing it sounds like a good idea, because |
| // otherwise the Subfilter's memory could be |
| // left allocated for long time, and would |
| // just waste memory. |
| lzma_next_end(&coder->subfilter.subcoder, |
| allocator); |
| |
| // We need to flush the currently buffered |
| // data and write Unset Subfilter marker. |
| // Note that we cannot set |
| // coder->options->subfilter_mode to |
| // LZMA_SUBFILTER_NONE yet, because we |
| // haven't written the Unset Subfilter |
| // marker yet. |
| coder->subfilter.mode = SUB_END_MARKER; |
| coder->sequence = SEQ_FLUSH; |
| break; |
| } |
| |
| // Return if we couldn't fill the buffer or |
| // if an error occurred. |
| if (coder->subblock.size < coder->subblock.limit |
| || ret != LZMA_OK) |
| return ret; |
| } |
| |
| coder->sequence = SEQ_FLUSH; |
| |
| // SEQ_FILL doesn't produce any output so falling through |
| // to SEQ_FLUSH is safe. |
| assert(*out_pos < out_size); |
| |
| // Fall through |
| |
| case SEQ_FLUSH: |
| if (coder->options != NULL) { |
| // Update the alignment variable. |
| coder->alignment.multiple = coder->options->alignment; |
| if (coder->alignment.multiple |
| < LZMA_SUBBLOCK_ALIGNMENT_MIN |
| || coder->alignment.multiple |
| > LZMA_SUBBLOCK_ALIGNMENT_MAX) |
| return LZMA_OPTIONS_ERROR; |
| |
| // Run-length encoder |
| // |
| // First check if there is some data pending and we |
| // have an obvious need to flush it immediatelly. |
| if (coder->rle.count > 0 |
| && (coder->rle.size |
| != coder->options->rle |
| || coder->subblock.size |
| % coder->rle.size)) { |
| subblock_rle_flush(coder); |
| break; |
| } |
| |
| // Grab the (possibly new) RLE chunk size and |
| // validate it. |
| coder->rle.size = coder->options->rle; |
| if (coder->rle.size > LZMA_SUBBLOCK_RLE_MAX) |
| return LZMA_OPTIONS_ERROR; |
| |
| if (coder->subblock.size != 0 |
| && coder->rle.size |
| != LZMA_SUBBLOCK_RLE_OFF |
| && coder->subblock.size |
| % coder->rle.size == 0) { |
| |
| // Initialize coder->rle.buffer if we don't |
| // have RLE already running. |
| if (coder->rle.count == 0) |
| memcpy(coder->rle.buffer, |
| coder->subblock.data, |
| coder->rle.size); |
| |
| // Test if coder->subblock.data is repeating. |
| // If coder->rle.count would overflow, we |
| // force flushing. Forced flushing shouldn't |
| // really happen in real-world situations. |
| const size_t count = coder->subblock.size |
| / coder->rle.size; |
| if (UINT64_MAX - count > coder->rle.count |
| && is_repeating( |
| coder->rle.buffer, |
| coder->rle.size, |
| coder->subblock.data, |
| count)) { |
| coder->rle.count += count; |
| coder->rle.in_pending += coder |
| ->subblock.in_pending; |
| coder->subblock.in_pending = 0; |
| coder->subblock.size = 0; |
| |
| } else if (coder->rle.count > 0) { |
| // It's not repeating or at least not |
| // with the same byte sequence as the |
| // earlier Subblock Data buffers. We |
| // have some data pending in the RLE |
| // buffer already, so do a flush. |
| // Once flushed, we will check again |
| // if the Subblock Data happens to |
| // contain a different repeating |
| // sequence. |
| subblock_rle_flush(coder); |
| break; |
| } |
| } |
| } |
| |
| // If we now have some data left in coder->subblock, the RLE |
| // buffer is empty and we must write a regular Subblock Data. |
| if (coder->subblock.size > 0) { |
| assert(coder->rle.count == 0); |
| coder->tmp = coder->subblock.size - 1; |
| coder->sequence = SEQ_DATA_SIZE_0; |
| break; |
| } |
| |
| // Check if we should enable Subfilter. |
| if (coder->subfilter.mode == SUB_SET) { |
| if (coder->rle.count > 0) |
| subblock_rle_flush(coder); |
| else |
| coder->sequence = SEQ_SUBFILTER_INIT; |
| break; |
| } |
| |
| // Check if we have just finished Subfiltering. |
| if (coder->subfilter.mode == SUB_END_MARKER) { |
| if (coder->rle.count > 0) { |
| subblock_rle_flush(coder); |
| break; |
| } |
| |
| coder->options->subfilter_mode = LZMA_SUBFILTER_NONE; |
| coder->subfilter.mode = SUB_NONE; |
| |
| write_byte(0x50); |
| if (*out_pos == out_size) |
| return LZMA_OK; |
| } |
| |
| // Check if we have already written everything. |
| if (action != LZMA_RUN && *in_pos == in_size |
| && (coder->subfilter.mode == SUB_NONE |
| || coder->subfilter.mode == SUB_FLUSH)) { |
| if (coder->rle.count > 0) { |
| subblock_rle_flush(coder); |
| break; |
| } |
| |
| if (action == LZMA_SYNC_FLUSH) { |
| if (coder->subfilter.mode == SUB_FLUSH) |
| coder->subfilter.mode = SUB_RUN; |
| |
| coder->subfilter.mode_locked = false; |
| coder->sequence = SEQ_FILL; |
| |
| } else { |
| assert(action == LZMA_FINISH); |
| |
| // Write EOPM. |
| // NOTE: No need to use write_byte() here |
| // since we are finishing. |
| out[*out_pos] = 0x10; |
| ++*out_pos; |
| } |
| |
| return LZMA_STREAM_END; |
| } |
| |
| // Otherwise we have more work to do. |
| coder->sequence = SEQ_FILL; |
| break; |
| |
| case SEQ_RLE_COUNT_0: |
| assert(coder->rle.count > 0); |
| |
| if (coder->rle.count == 1) { |
| // The buffer should be repeated only once. Fix |
| // the alignment and write the first byte of |
| // Subblock Type `Data'. |
| if (subblock_align(coder, out, out_pos, out_size, |
| coder->rle.size, ALIGN_SKEW_DATA)) |
| return LZMA_OK; |
| |
| write_byte(0x20 | (coder->tmp & 0x0F)); |
| |
| } else { |
| // We have something to actually repeat, which should |
| // mean that it takes less space with run-length |
| // encoding. |
| if (subblock_align(coder, out, out_pos, out_size, |
| coder->rle.size, |
| ALIGN_SKEW_REPEATING_DATA)) |
| return LZMA_OK; |
| |
| write_byte(0x30 | (coder->tmp & 0x0F)); |
| } |
| |
| // NOTE: If we have to write more than one Repeating Data |
| // due to rle.count > REPEAT_COUNT_MAX, the subsequent |
| // Repeating Data Subblocks may get wrong alignment, because |
| // we add rle.in_pending to alignment.in_pos at once instead |
| // of adding only as much as this particular Repeating Data |
| // consumed input data. Correct alignment is always restored |
| // after all the required Repeating Data Subblocks have been |
| // written. This problem occurs in such a weird cases that |
| // it's not worth fixing. |
| coder->alignment.out_pos += coder->rle.size; |
| coder->alignment.in_pos += coder->rle.in_pending; |
| coder->rle.in_pending = 0; |
| |
| coder->sequence = SEQ_RLE_COUNT_1; |
| break; |
| |
| case SEQ_RLE_COUNT_1: |
| write_byte(coder->tmp >> 4); |
| coder->sequence = SEQ_RLE_COUNT_2; |
| break; |
| |
| case SEQ_RLE_COUNT_2: |
| write_byte(coder->tmp >> 12); |
| coder->sequence = SEQ_RLE_COUNT_3; |
| break; |
| |
| case SEQ_RLE_COUNT_3: |
| write_byte(coder->tmp >> 20); |
| |
| // Again, see if we are writing regular Data or Repeating Data. |
| // In the former case, we skip SEQ_RLE_SIZE. |
| if (coder->rle.count == 1) |
| coder->sequence = SEQ_RLE_DATA; |
| else |
| coder->sequence = SEQ_RLE_SIZE; |
| |
| if (coder->rle.count > REPEAT_COUNT_MAX) |
| coder->rle.count -= REPEAT_COUNT_MAX; |
| else |
| coder->rle.count = 0; |
| |
| break; |
| |
| case SEQ_RLE_SIZE: |
| assert(coder->rle.size >= LZMA_SUBBLOCK_RLE_MIN); |
| assert(coder->rle.size <= LZMA_SUBBLOCK_RLE_MAX); |
| write_byte(coder->rle.size - 1); |
| coder->sequence = SEQ_RLE_DATA; |
| break; |
| |
| case SEQ_RLE_DATA: |
| lzma_bufcpy(coder->rle.buffer, &coder->pos, coder->rle.size, |
| out, out_pos, out_size); |
| if (coder->pos < coder->rle.size) |
| return LZMA_OK; |
| |
| coder->pos = 0; |
| coder->sequence = SEQ_FLUSH; |
| break; |
| |
| case SEQ_DATA_SIZE_0: |
| // We need four bytes for the Size field. |
| if (subblock_align(coder, out, out_pos, out_size, |
| coder->subblock.size, ALIGN_SKEW_DATA)) |
| return LZMA_OK; |
| |
| coder->alignment.out_pos += coder->subblock.size; |
| coder->alignment.in_pos += coder->subblock.in_pending; |
| coder->subblock.in_pending = 0; |
| |
| write_byte(0x20 | (coder->tmp & 0x0F)); |
| coder->sequence = SEQ_DATA_SIZE_1; |
| break; |
| |
| case SEQ_DATA_SIZE_1: |
| write_byte(coder->tmp >> 4); |
| coder->sequence = SEQ_DATA_SIZE_2; |
| break; |
| |
| case SEQ_DATA_SIZE_2: |
| write_byte(coder->tmp >> 12); |
| coder->sequence = SEQ_DATA_SIZE_3; |
| break; |
| |
| case SEQ_DATA_SIZE_3: |
| write_byte(coder->tmp >> 20); |
| coder->sequence = SEQ_DATA; |
| break; |
| |
| case SEQ_DATA: |
| lzma_bufcpy(coder->subblock.data, &coder->pos, |
| coder->subblock.size, out, out_pos, out_size); |
| if (coder->pos < coder->subblock.size) |
| return LZMA_OK; |
| |
| coder->subblock.size = 0; |
| coder->pos = 0; |
| coder->sequence = SEQ_FLUSH; |
| break; |
| |
| case SEQ_SUBFILTER_INIT: { |
| assert(coder->subblock.size == 0); |
| assert(coder->subblock.in_pending == 0); |
| assert(coder->rle.count == 0); |
| assert(coder->rle.in_pending == 0); |
| assert(coder->subfilter.mode == SUB_SET); |
| assert(coder->options != NULL); |
| |
| // There must be a filter specified. |
| if (coder->options->subfilter_options.id == LZMA_VLI_UNKNOWN) |
| return LZMA_OPTIONS_ERROR; |
| |
| // Initialize a raw encoder to work as a Subfilter. |
| lzma_filter options[2]; |
| options[0] = coder->options->subfilter_options; |
| options[1].id = LZMA_VLI_UNKNOWN; |
| |
| return_if_error(lzma_raw_encoder_init( |
| &coder->subfilter.subcoder, allocator, |
| options)); |
| |
| // Encode the Filter Flags field into a buffer. This should |
| // never fail since we have already successfully initialized |
| // the Subfilter itself. Check it still, and return |
| // LZMA_PROG_ERROR instead of whatever the ret would say. |
| lzma_ret ret = lzma_filter_flags_size( |
| &coder->subfilter.flags_size, options); |
| assert(ret == LZMA_OK); |
| if (ret != LZMA_OK) |
| return LZMA_PROG_ERROR; |
| |
| coder->subfilter.flags = lzma_alloc( |
| coder->subfilter.flags_size, allocator); |
| if (coder->subfilter.flags == NULL) |
| return LZMA_MEM_ERROR; |
| |
| // Now we have a big-enough buffer. Encode the Filter Flags. |
| // Like above, this should never fail. |
| size_t dummy = 0; |
| ret = lzma_filter_flags_encode(options, coder->subfilter.flags, |
| &dummy, coder->subfilter.flags_size); |
| assert(ret == LZMA_OK); |
| assert(dummy == coder->subfilter.flags_size); |
| if (ret != LZMA_OK || dummy != coder->subfilter.flags_size) |
| return LZMA_PROG_ERROR; |
| |
| // Write a Subblock indicating a new Subfilter. |
| write_byte(0x40); |
| |
| coder->options->subfilter_mode = LZMA_SUBFILTER_RUN; |
| coder->subfilter.mode = SUB_RUN; |
| coder->alignment.out_pos += coder->subfilter.flags_size; |
| coder->sequence = SEQ_SUBFILTER_FLAGS; |
| |
| // It is safe to fall through because SEQ_SUBFILTER_FLAGS |
| // uses lzma_bufcpy() which doesn't write unless there is |
| // output space. |
| } |
| |
| // Fall through |
| |
| case SEQ_SUBFILTER_FLAGS: |
| // Copy the Filter Flags to the output stream. |
| lzma_bufcpy(coder->subfilter.flags, &coder->pos, |
| coder->subfilter.flags_size, |
| out, out_pos, out_size); |
| if (coder->pos < coder->subfilter.flags_size) |
| return LZMA_OK; |
| |
| lzma_free(coder->subfilter.flags, allocator); |
| coder->subfilter.flags = NULL; |
| |
| coder->pos = 0; |
| coder->sequence = SEQ_FILL; |
| break; |
| |
| default: |
| return LZMA_PROG_ERROR; |
| } |
| |
| return LZMA_OK; |
| } |
| |
| |
| static lzma_ret |
| subblock_encode(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) |
| { |
| if (coder->next.code == NULL) |
| return subblock_buffer(coder, allocator, in, in_pos, in_size, |
| out, out_pos, out_size, action); |
| |
| while (*out_pos < out_size |
| && (*in_pos < in_size || action != LZMA_RUN)) { |
| if (!coder->next_finished |
| && coder->temp.pos == coder->temp.size) { |
| coder->temp.pos = 0; |
| coder->temp.size = 0; |
| |
| const lzma_ret ret = coder->next.code(coder->next.coder, |
| allocator, in, in_pos, in_size, |
| coder->temp.buffer, &coder->temp.size, |
| LZMA_BUFFER_SIZE, action); |
| if (ret == LZMA_STREAM_END) { |
| assert(action != LZMA_RUN); |
| coder->next_finished = true; |
| } else if (coder->temp.size == 0 || ret != LZMA_OK) { |
| return ret; |
| } |
| } |
| |
| const lzma_ret ret = subblock_buffer(coder, allocator, |
| coder->temp.buffer, &coder->temp.pos, |
| coder->temp.size, out, out_pos, out_size, |
| coder->next_finished ? LZMA_FINISH : LZMA_RUN); |
| if (ret == LZMA_STREAM_END) { |
| assert(action != LZMA_RUN); |
| assert(coder->next_finished); |
| return LZMA_STREAM_END; |
| } |
| |
| if (ret != LZMA_OK) |
| return ret; |
| } |
| |
| return LZMA_OK; |
| } |
| |
| |
| static void |
| subblock_encoder_end(lzma_coder *coder, lzma_allocator *allocator) |
| { |
| lzma_next_end(&coder->next, allocator); |
| lzma_next_end(&coder->subfilter.subcoder, allocator); |
| lzma_free(coder->subblock.data, allocator); |
| lzma_free(coder->subfilter.flags, allocator); |
| lzma_free(coder, allocator); |
| return; |
| } |
| |
| |
| extern lzma_ret |
| lzma_subblock_encoder_init(lzma_next_coder *next, lzma_allocator *allocator, |
| const lzma_filter_info *filters) |
| { |
| if (next->coder == NULL) { |
| next->coder = lzma_alloc(sizeof(lzma_coder), allocator); |
| if (next->coder == NULL) |
| return LZMA_MEM_ERROR; |
| |
| next->code = &subblock_encode; |
| next->end = &subblock_encoder_end; |
| |
| next->coder->next = LZMA_NEXT_CODER_INIT; |
| next->coder->subblock.data = NULL; |
| next->coder->subblock.limit = 0; |
| next->coder->subfilter.subcoder = LZMA_NEXT_CODER_INIT; |
| } else { |
| lzma_next_end(&next->coder->subfilter.subcoder, |
| allocator); |
| lzma_free(next->coder->subfilter.flags, allocator); |
| } |
| |
| next->coder->subfilter.flags = NULL; |
| |
| next->coder->next_finished = false; |
| next->coder->sequence = SEQ_FILL; |
| next->coder->options = filters[0].options; |
| next->coder->pos = 0; |
| |
| next->coder->alignment.in_pos = 0; |
| next->coder->alignment.out_pos = 0; |
| next->coder->subblock.size = 0; |
| next->coder->subblock.in_pending = 0; |
| next->coder->rle.count = 0; |
| next->coder->rle.in_pending = 0; |
| next->coder->subfilter.mode = SUB_NONE; |
| next->coder->subfilter.mode_locked = false; |
| |
| next->coder->temp.pos = 0; |
| next->coder->temp.size = 0; |
| |
| // Grab some values from the options structure if it is available. |
| size_t subblock_size_limit; |
| if (next->coder->options != NULL) { |
| if (next->coder->options->alignment |
| < LZMA_SUBBLOCK_ALIGNMENT_MIN |
| || next->coder->options->alignment |
| > LZMA_SUBBLOCK_ALIGNMENT_MAX) { |
| subblock_encoder_end(next->coder, allocator); |
| return LZMA_OPTIONS_ERROR; |
| } |
| next->coder->alignment.multiple |
| = next->coder->options->alignment; |
| next->coder->subfilter.allow |
| = next->coder->options->allow_subfilters; |
| subblock_size_limit = next->coder->options->subblock_data_size; |
| } else { |
| next->coder->alignment.multiple |
| = LZMA_SUBBLOCK_ALIGNMENT_DEFAULT; |
| next->coder->subfilter.allow = false; |
| subblock_size_limit = LZMA_SUBBLOCK_DATA_SIZE_DEFAULT; |
| } |
| |
| return_if_error(subblock_data_size(next->coder, allocator, |
| subblock_size_limit)); |
| |
| return lzma_next_filter_init( |
| &next->coder->next, allocator, filters + 1); |
| } |