Rev 49813 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
//////////////////////////////////////////////////////////////////////////////////// \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 boolsubblock_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 boolis_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->sequencestatic voidsubblock_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 limitstatic lzma_retsubblock_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_retsubblock_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 loopwhile (*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 throughcase 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);elsecoder->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;elsecoder->sequence = SEQ_RLE_SIZE;if (coder->rle.count > REPEAT_COUNT_MAX)coder->rle.count -= REPEAT_COUNT_MAX;elsecoder->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 throughcase 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_retsubblock_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 voidsubblock_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_retlzma_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);}