1*3b35e7eeSXin LI // SPDX-License-Identifier: 0BSD 2*3b35e7eeSXin LI 381ad8388SMartin Matuska /////////////////////////////////////////////////////////////////////////////// 481ad8388SMartin Matuska // 581ad8388SMartin Matuska /// \file stream_decoder.c 681ad8388SMartin Matuska /// \brief Decodes .xz Streams 781ad8388SMartin Matuska // 881ad8388SMartin Matuska // Author: Lasse Collin 981ad8388SMartin Matuska // 1081ad8388SMartin Matuska /////////////////////////////////////////////////////////////////////////////// 1181ad8388SMartin Matuska 1281ad8388SMartin Matuska #include "stream_decoder.h" 1381ad8388SMartin Matuska #include "block_decoder.h" 14047153b4SXin LI #include "index.h" 1581ad8388SMartin Matuska 1681ad8388SMartin Matuska 171456f0f9SXin LI typedef struct { 1881ad8388SMartin Matuska enum { 1981ad8388SMartin Matuska SEQ_STREAM_HEADER, 2081ad8388SMartin Matuska SEQ_BLOCK_HEADER, 219e6bbe47SXin LI SEQ_BLOCK_INIT, 229e6bbe47SXin LI SEQ_BLOCK_RUN, 2381ad8388SMartin Matuska SEQ_INDEX, 2481ad8388SMartin Matuska SEQ_STREAM_FOOTER, 2581ad8388SMartin Matuska SEQ_STREAM_PADDING, 2681ad8388SMartin Matuska } sequence; 2781ad8388SMartin Matuska 289e6bbe47SXin LI /// Block decoder 2981ad8388SMartin Matuska lzma_next_coder block_decoder; 3081ad8388SMartin Matuska 3181ad8388SMartin Matuska /// Block options decoded by the Block Header decoder and used by 3281ad8388SMartin Matuska /// the Block decoder. 3381ad8388SMartin Matuska lzma_block block_options; 3481ad8388SMartin Matuska 3581ad8388SMartin Matuska /// Stream Flags from Stream Header 3681ad8388SMartin Matuska lzma_stream_flags stream_flags; 3781ad8388SMartin Matuska 3881ad8388SMartin Matuska /// Index is hashed so that it can be compared to the sizes of Blocks 3981ad8388SMartin Matuska /// with O(1) memory usage. 4081ad8388SMartin Matuska lzma_index_hash *index_hash; 4181ad8388SMartin Matuska 4281ad8388SMartin Matuska /// Memory usage limit 4381ad8388SMartin Matuska uint64_t memlimit; 4481ad8388SMartin Matuska 4581ad8388SMartin Matuska /// Amount of memory actually needed (only an estimate) 4681ad8388SMartin Matuska uint64_t memusage; 4781ad8388SMartin Matuska 4881ad8388SMartin Matuska /// If true, LZMA_NO_CHECK is returned if the Stream has 4981ad8388SMartin Matuska /// no integrity check. 5081ad8388SMartin Matuska bool tell_no_check; 5181ad8388SMartin Matuska 5281ad8388SMartin Matuska /// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has 5381ad8388SMartin Matuska /// an integrity check that isn't supported by this liblzma build. 5481ad8388SMartin Matuska bool tell_unsupported_check; 5581ad8388SMartin Matuska 5681ad8388SMartin Matuska /// If true, LZMA_GET_CHECK is returned after decoding Stream Header. 5781ad8388SMartin Matuska bool tell_any_check; 5881ad8388SMartin Matuska 5953200025SRui Paulo /// If true, we will tell the Block decoder to skip calculating 6053200025SRui Paulo /// and verifying the integrity check. 6153200025SRui Paulo bool ignore_check; 6253200025SRui Paulo 6381ad8388SMartin Matuska /// If true, we will decode concatenated Streams that possibly have 6481ad8388SMartin Matuska /// Stream Padding between or after them. LZMA_STREAM_END is returned 659e6bbe47SXin LI /// once the application isn't giving us any new input (LZMA_FINISH), 669e6bbe47SXin LI /// and we aren't in the middle of a Stream, and possible 679e6bbe47SXin LI /// Stream Padding is a multiple of four bytes. 6881ad8388SMartin Matuska bool concatenated; 6981ad8388SMartin Matuska 7081ad8388SMartin Matuska /// When decoding concatenated Streams, this is true as long as we 7181ad8388SMartin Matuska /// are decoding the first Stream. This is needed to avoid misleading 7281ad8388SMartin Matuska /// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic 7381ad8388SMartin Matuska /// bytes. 7481ad8388SMartin Matuska bool first_stream; 7581ad8388SMartin Matuska 7681ad8388SMartin Matuska /// Write position in buffer[] and position in Stream Padding 7781ad8388SMartin Matuska size_t pos; 7881ad8388SMartin Matuska 7981ad8388SMartin Matuska /// Buffer to hold Stream Header, Block Header, and Stream Footer. 8081ad8388SMartin Matuska /// Block Header has biggest maximum size. 8181ad8388SMartin Matuska uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX]; 821456f0f9SXin LI } lzma_stream_coder; 8381ad8388SMartin Matuska 8481ad8388SMartin Matuska 8581ad8388SMartin Matuska static lzma_ret 861456f0f9SXin LI stream_decoder_reset(lzma_stream_coder *coder, const lzma_allocator *allocator) 8781ad8388SMartin Matuska { 8881ad8388SMartin Matuska // Initialize the Index hash used to verify the Index. 8981ad8388SMartin Matuska coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator); 9081ad8388SMartin Matuska if (coder->index_hash == NULL) 9181ad8388SMartin Matuska return LZMA_MEM_ERROR; 9281ad8388SMartin Matuska 9381ad8388SMartin Matuska // Reset the rest of the variables. 9481ad8388SMartin Matuska coder->sequence = SEQ_STREAM_HEADER; 9581ad8388SMartin Matuska coder->pos = 0; 9681ad8388SMartin Matuska 9781ad8388SMartin Matuska return LZMA_OK; 9881ad8388SMartin Matuska } 9981ad8388SMartin Matuska 10081ad8388SMartin Matuska 10181ad8388SMartin Matuska static lzma_ret 1021456f0f9SXin LI stream_decode(void *coder_ptr, const lzma_allocator *allocator, 10381ad8388SMartin Matuska const uint8_t *restrict in, size_t *restrict in_pos, 10481ad8388SMartin Matuska size_t in_size, uint8_t *restrict out, 10581ad8388SMartin Matuska size_t *restrict out_pos, size_t out_size, lzma_action action) 10681ad8388SMartin Matuska { 1071456f0f9SXin LI lzma_stream_coder *coder = coder_ptr; 1081456f0f9SXin LI 10981ad8388SMartin Matuska // When decoding the actual Block, it may be able to produce more 11081ad8388SMartin Matuska // output even if we don't give it any new input. 11181ad8388SMartin Matuska while (true) 11281ad8388SMartin Matuska switch (coder->sequence) { 11381ad8388SMartin Matuska case SEQ_STREAM_HEADER: { 11481ad8388SMartin Matuska // Copy the Stream Header to the internal buffer. 11581ad8388SMartin Matuska lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, 11681ad8388SMartin Matuska LZMA_STREAM_HEADER_SIZE); 11781ad8388SMartin Matuska 11881ad8388SMartin Matuska // Return if we didn't get the whole Stream Header yet. 11981ad8388SMartin Matuska if (coder->pos < LZMA_STREAM_HEADER_SIZE) 12081ad8388SMartin Matuska return LZMA_OK; 12181ad8388SMartin Matuska 12281ad8388SMartin Matuska coder->pos = 0; 12381ad8388SMartin Matuska 12481ad8388SMartin Matuska // Decode the Stream Header. 12581ad8388SMartin Matuska const lzma_ret ret = lzma_stream_header_decode( 12681ad8388SMartin Matuska &coder->stream_flags, coder->buffer); 12781ad8388SMartin Matuska if (ret != LZMA_OK) 12881ad8388SMartin Matuska return ret == LZMA_FORMAT_ERROR && !coder->first_stream 12981ad8388SMartin Matuska ? LZMA_DATA_ERROR : ret; 13081ad8388SMartin Matuska 13181ad8388SMartin Matuska // If we are decoding concatenated Streams, and the later 13281ad8388SMartin Matuska // Streams have invalid Header Magic Bytes, we give 13381ad8388SMartin Matuska // LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR. 13481ad8388SMartin Matuska coder->first_stream = false; 13581ad8388SMartin Matuska 13681ad8388SMartin Matuska // Copy the type of the Check so that Block Header and Block 13781ad8388SMartin Matuska // decoders see it. 13881ad8388SMartin Matuska coder->block_options.check = coder->stream_flags.check; 13981ad8388SMartin Matuska 14081ad8388SMartin Matuska // Even if we return LZMA_*_CHECK below, we want 14181ad8388SMartin Matuska // to continue from Block Header decoding. 14281ad8388SMartin Matuska coder->sequence = SEQ_BLOCK_HEADER; 14381ad8388SMartin Matuska 14481ad8388SMartin Matuska // Detect if there's no integrity check or if it is 14581ad8388SMartin Matuska // unsupported if those were requested by the application. 14681ad8388SMartin Matuska if (coder->tell_no_check && coder->stream_flags.check 14781ad8388SMartin Matuska == LZMA_CHECK_NONE) 14881ad8388SMartin Matuska return LZMA_NO_CHECK; 14981ad8388SMartin Matuska 15081ad8388SMartin Matuska if (coder->tell_unsupported_check 15181ad8388SMartin Matuska && !lzma_check_is_supported( 15281ad8388SMartin Matuska coder->stream_flags.check)) 15381ad8388SMartin Matuska return LZMA_UNSUPPORTED_CHECK; 15481ad8388SMartin Matuska 15581ad8388SMartin Matuska if (coder->tell_any_check) 15681ad8388SMartin Matuska return LZMA_GET_CHECK; 15781ad8388SMartin Matuska } 15881ad8388SMartin Matuska 15981ad8388SMartin Matuska // Fall through 16081ad8388SMartin Matuska 16181ad8388SMartin Matuska case SEQ_BLOCK_HEADER: { 16281ad8388SMartin Matuska if (*in_pos >= in_size) 16381ad8388SMartin Matuska return LZMA_OK; 16481ad8388SMartin Matuska 16581ad8388SMartin Matuska if (coder->pos == 0) { 16681ad8388SMartin Matuska // Detect if it's Index. 167047153b4SXin LI if (in[*in_pos] == INDEX_INDICATOR) { 16881ad8388SMartin Matuska coder->sequence = SEQ_INDEX; 16981ad8388SMartin Matuska break; 17081ad8388SMartin Matuska } 17181ad8388SMartin Matuska 17281ad8388SMartin Matuska // Calculate the size of the Block Header. Note that 17381ad8388SMartin Matuska // Block Header decoder wants to see this byte too 17481ad8388SMartin Matuska // so don't advance *in_pos. 17581ad8388SMartin Matuska coder->block_options.header_size 17681ad8388SMartin Matuska = lzma_block_header_size_decode( 17781ad8388SMartin Matuska in[*in_pos]); 17881ad8388SMartin Matuska } 17981ad8388SMartin Matuska 18081ad8388SMartin Matuska // Copy the Block Header to the internal buffer. 18181ad8388SMartin Matuska lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, 18281ad8388SMartin Matuska coder->block_options.header_size); 18381ad8388SMartin Matuska 18481ad8388SMartin Matuska // Return if we didn't get the whole Block Header yet. 18581ad8388SMartin Matuska if (coder->pos < coder->block_options.header_size) 18681ad8388SMartin Matuska return LZMA_OK; 18781ad8388SMartin Matuska 18881ad8388SMartin Matuska coder->pos = 0; 1899e6bbe47SXin LI coder->sequence = SEQ_BLOCK_INIT; 1909e6bbe47SXin LI } 1919e6bbe47SXin LI 1929e6bbe47SXin LI // Fall through 1939e6bbe47SXin LI 1949e6bbe47SXin LI case SEQ_BLOCK_INIT: { 1959e6bbe47SXin LI // Checking memusage and doing the initialization needs 1969e6bbe47SXin LI // its own sequence point because we need to be able to 1979e6bbe47SXin LI // retry if we return LZMA_MEMLIMIT_ERROR. 19881ad8388SMartin Matuska 19953200025SRui Paulo // Version 1 is needed to support the .ignore_check option. 20053200025SRui Paulo coder->block_options.version = 1; 20181ad8388SMartin Matuska 20281ad8388SMartin Matuska // Set up a buffer to hold the filter chain. Block Header 20381ad8388SMartin Matuska // decoder will initialize all members of this array so 20481ad8388SMartin Matuska // we don't need to do it here. 20581ad8388SMartin Matuska lzma_filter filters[LZMA_FILTERS_MAX + 1]; 20681ad8388SMartin Matuska coder->block_options.filters = filters; 20781ad8388SMartin Matuska 20881ad8388SMartin Matuska // Decode the Block Header. 20981ad8388SMartin Matuska return_if_error(lzma_block_header_decode(&coder->block_options, 21081ad8388SMartin Matuska allocator, coder->buffer)); 21181ad8388SMartin Matuska 21253200025SRui Paulo // If LZMA_IGNORE_CHECK was used, this flag needs to be set. 21353200025SRui Paulo // It has to be set after lzma_block_header_decode() because 21453200025SRui Paulo // it always resets this to false. 21553200025SRui Paulo coder->block_options.ignore_check = coder->ignore_check; 21653200025SRui Paulo 21781ad8388SMartin Matuska // Check the memory usage limit. 21881ad8388SMartin Matuska const uint64_t memusage = lzma_raw_decoder_memusage(filters); 21981ad8388SMartin Matuska lzma_ret ret; 22081ad8388SMartin Matuska 22181ad8388SMartin Matuska if (memusage == UINT64_MAX) { 22281ad8388SMartin Matuska // One or more unknown Filter IDs. 22381ad8388SMartin Matuska ret = LZMA_OPTIONS_ERROR; 22481ad8388SMartin Matuska } else { 22581ad8388SMartin Matuska // Now we can set coder->memusage since we know that 22681ad8388SMartin Matuska // the filter chain is valid. We don't want 22781ad8388SMartin Matuska // lzma_memusage() to return UINT64_MAX in case of 22881ad8388SMartin Matuska // invalid filter chain. 22981ad8388SMartin Matuska coder->memusage = memusage; 23081ad8388SMartin Matuska 23181ad8388SMartin Matuska if (memusage > coder->memlimit) { 23281ad8388SMartin Matuska // The chain would need too much memory. 23381ad8388SMartin Matuska ret = LZMA_MEMLIMIT_ERROR; 23481ad8388SMartin Matuska } else { 23581ad8388SMartin Matuska // Memory usage is OK. 23681ad8388SMartin Matuska // Initialize the Block decoder. 23781ad8388SMartin Matuska ret = lzma_block_decoder_init( 23881ad8388SMartin Matuska &coder->block_decoder, 23981ad8388SMartin Matuska allocator, 24081ad8388SMartin Matuska &coder->block_options); 24181ad8388SMartin Matuska } 24281ad8388SMartin Matuska } 24381ad8388SMartin Matuska 24481ad8388SMartin Matuska // Free the allocated filter options since they are needed 24581ad8388SMartin Matuska // only to initialize the Block decoder. 24673ed8e77SXin LI lzma_filters_free(filters, allocator); 24781ad8388SMartin Matuska coder->block_options.filters = NULL; 24881ad8388SMartin Matuska 2499e6bbe47SXin LI // Check if memory usage calculation and Block decoder 25081ad8388SMartin Matuska // initialization succeeded. 25181ad8388SMartin Matuska if (ret != LZMA_OK) 25281ad8388SMartin Matuska return ret; 25381ad8388SMartin Matuska 2549e6bbe47SXin LI coder->sequence = SEQ_BLOCK_RUN; 25581ad8388SMartin Matuska } 25681ad8388SMartin Matuska 25781ad8388SMartin Matuska // Fall through 25881ad8388SMartin Matuska 2599e6bbe47SXin LI case SEQ_BLOCK_RUN: { 26081ad8388SMartin Matuska const lzma_ret ret = coder->block_decoder.code( 26181ad8388SMartin Matuska coder->block_decoder.coder, allocator, 26281ad8388SMartin Matuska in, in_pos, in_size, out, out_pos, out_size, 26381ad8388SMartin Matuska action); 26481ad8388SMartin Matuska 26581ad8388SMartin Matuska if (ret != LZMA_STREAM_END) 26681ad8388SMartin Matuska return ret; 26781ad8388SMartin Matuska 26881ad8388SMartin Matuska // Block decoded successfully. Add the new size pair to 26981ad8388SMartin Matuska // the Index hash. 27081ad8388SMartin Matuska return_if_error(lzma_index_hash_append(coder->index_hash, 27181ad8388SMartin Matuska lzma_block_unpadded_size( 27281ad8388SMartin Matuska &coder->block_options), 27381ad8388SMartin Matuska coder->block_options.uncompressed_size)); 27481ad8388SMartin Matuska 27581ad8388SMartin Matuska coder->sequence = SEQ_BLOCK_HEADER; 27681ad8388SMartin Matuska break; 27781ad8388SMartin Matuska } 27881ad8388SMartin Matuska 27981ad8388SMartin Matuska case SEQ_INDEX: { 28081ad8388SMartin Matuska // If we don't have any input, don't call 28181ad8388SMartin Matuska // lzma_index_hash_decode() since it would return 28281ad8388SMartin Matuska // LZMA_BUF_ERROR, which we must not do here. 28381ad8388SMartin Matuska if (*in_pos >= in_size) 28481ad8388SMartin Matuska return LZMA_OK; 28581ad8388SMartin Matuska 28681ad8388SMartin Matuska // Decode the Index and compare it to the hash calculated 28781ad8388SMartin Matuska // from the sizes of the Blocks (if any). 28881ad8388SMartin Matuska const lzma_ret ret = lzma_index_hash_decode(coder->index_hash, 28981ad8388SMartin Matuska in, in_pos, in_size); 29081ad8388SMartin Matuska if (ret != LZMA_STREAM_END) 29181ad8388SMartin Matuska return ret; 29281ad8388SMartin Matuska 29381ad8388SMartin Matuska coder->sequence = SEQ_STREAM_FOOTER; 29481ad8388SMartin Matuska } 29581ad8388SMartin Matuska 29681ad8388SMartin Matuska // Fall through 29781ad8388SMartin Matuska 29881ad8388SMartin Matuska case SEQ_STREAM_FOOTER: { 29981ad8388SMartin Matuska // Copy the Stream Footer to the internal buffer. 30081ad8388SMartin Matuska lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, 30181ad8388SMartin Matuska LZMA_STREAM_HEADER_SIZE); 30281ad8388SMartin Matuska 30381ad8388SMartin Matuska // Return if we didn't get the whole Stream Footer yet. 30481ad8388SMartin Matuska if (coder->pos < LZMA_STREAM_HEADER_SIZE) 30581ad8388SMartin Matuska return LZMA_OK; 30681ad8388SMartin Matuska 30781ad8388SMartin Matuska coder->pos = 0; 30881ad8388SMartin Matuska 30981ad8388SMartin Matuska // Decode the Stream Footer. The decoder gives 31081ad8388SMartin Matuska // LZMA_FORMAT_ERROR if the magic bytes don't match, 31181ad8388SMartin Matuska // so convert that return code to LZMA_DATA_ERROR. 31281ad8388SMartin Matuska lzma_stream_flags footer_flags; 31381ad8388SMartin Matuska const lzma_ret ret = lzma_stream_footer_decode( 31481ad8388SMartin Matuska &footer_flags, coder->buffer); 31581ad8388SMartin Matuska if (ret != LZMA_OK) 31681ad8388SMartin Matuska return ret == LZMA_FORMAT_ERROR 31781ad8388SMartin Matuska ? LZMA_DATA_ERROR : ret; 31881ad8388SMartin Matuska 31981ad8388SMartin Matuska // Check that Index Size stored in the Stream Footer matches 32081ad8388SMartin Matuska // the real size of the Index field. 32181ad8388SMartin Matuska if (lzma_index_hash_size(coder->index_hash) 32281ad8388SMartin Matuska != footer_flags.backward_size) 32381ad8388SMartin Matuska return LZMA_DATA_ERROR; 32481ad8388SMartin Matuska 32581ad8388SMartin Matuska // Compare that the Stream Flags fields are identical in 32681ad8388SMartin Matuska // both Stream Header and Stream Footer. 32781ad8388SMartin Matuska return_if_error(lzma_stream_flags_compare( 32881ad8388SMartin Matuska &coder->stream_flags, &footer_flags)); 32981ad8388SMartin Matuska 33081ad8388SMartin Matuska if (!coder->concatenated) 33181ad8388SMartin Matuska return LZMA_STREAM_END; 33281ad8388SMartin Matuska 33381ad8388SMartin Matuska coder->sequence = SEQ_STREAM_PADDING; 33481ad8388SMartin Matuska } 33581ad8388SMartin Matuska 33681ad8388SMartin Matuska // Fall through 33781ad8388SMartin Matuska 33881ad8388SMartin Matuska case SEQ_STREAM_PADDING: 33981ad8388SMartin Matuska assert(coder->concatenated); 34081ad8388SMartin Matuska 34181ad8388SMartin Matuska // Skip over possible Stream Padding. 34281ad8388SMartin Matuska while (true) { 34381ad8388SMartin Matuska if (*in_pos >= in_size) { 34481ad8388SMartin Matuska // Unless LZMA_FINISH was used, we cannot 34581ad8388SMartin Matuska // know if there's more input coming later. 34681ad8388SMartin Matuska if (action != LZMA_FINISH) 34781ad8388SMartin Matuska return LZMA_OK; 34881ad8388SMartin Matuska 34981ad8388SMartin Matuska // Stream Padding must be a multiple of 35081ad8388SMartin Matuska // four bytes. 35181ad8388SMartin Matuska return coder->pos == 0 35281ad8388SMartin Matuska ? LZMA_STREAM_END 35381ad8388SMartin Matuska : LZMA_DATA_ERROR; 35481ad8388SMartin Matuska } 35581ad8388SMartin Matuska 35681ad8388SMartin Matuska // If the byte is not zero, it probably indicates 35781ad8388SMartin Matuska // beginning of a new Stream (or the file is corrupt). 35881ad8388SMartin Matuska if (in[*in_pos] != 0x00) 35981ad8388SMartin Matuska break; 36081ad8388SMartin Matuska 36181ad8388SMartin Matuska ++*in_pos; 36281ad8388SMartin Matuska coder->pos = (coder->pos + 1) & 3; 36381ad8388SMartin Matuska } 36481ad8388SMartin Matuska 36581ad8388SMartin Matuska // Stream Padding must be a multiple of four bytes (empty 36681ad8388SMartin Matuska // Stream Padding is OK). 36781ad8388SMartin Matuska if (coder->pos != 0) { 36881ad8388SMartin Matuska ++*in_pos; 36981ad8388SMartin Matuska return LZMA_DATA_ERROR; 37081ad8388SMartin Matuska } 37181ad8388SMartin Matuska 37281ad8388SMartin Matuska // Prepare to decode the next Stream. 37381ad8388SMartin Matuska return_if_error(stream_decoder_reset(coder, allocator)); 37481ad8388SMartin Matuska break; 37581ad8388SMartin Matuska 37681ad8388SMartin Matuska default: 37781ad8388SMartin Matuska assert(0); 37881ad8388SMartin Matuska return LZMA_PROG_ERROR; 37981ad8388SMartin Matuska } 38081ad8388SMartin Matuska 38181ad8388SMartin Matuska // Never reached 38281ad8388SMartin Matuska } 38381ad8388SMartin Matuska 38481ad8388SMartin Matuska 38581ad8388SMartin Matuska static void 3861456f0f9SXin LI stream_decoder_end(void *coder_ptr, const lzma_allocator *allocator) 38781ad8388SMartin Matuska { 3881456f0f9SXin LI lzma_stream_coder *coder = coder_ptr; 38981ad8388SMartin Matuska lzma_next_end(&coder->block_decoder, allocator); 39081ad8388SMartin Matuska lzma_index_hash_end(coder->index_hash, allocator); 39181ad8388SMartin Matuska lzma_free(coder, allocator); 39281ad8388SMartin Matuska return; 39381ad8388SMartin Matuska } 39481ad8388SMartin Matuska 39581ad8388SMartin Matuska 39681ad8388SMartin Matuska static lzma_check 3971456f0f9SXin LI stream_decoder_get_check(const void *coder_ptr) 39881ad8388SMartin Matuska { 3991456f0f9SXin LI const lzma_stream_coder *coder = coder_ptr; 40081ad8388SMartin Matuska return coder->stream_flags.check; 40181ad8388SMartin Matuska } 40281ad8388SMartin Matuska 40381ad8388SMartin Matuska 40481ad8388SMartin Matuska static lzma_ret 4051456f0f9SXin LI stream_decoder_memconfig(void *coder_ptr, uint64_t *memusage, 40681ad8388SMartin Matuska uint64_t *old_memlimit, uint64_t new_memlimit) 40781ad8388SMartin Matuska { 4081456f0f9SXin LI lzma_stream_coder *coder = coder_ptr; 4091456f0f9SXin LI 41081ad8388SMartin Matuska *memusage = coder->memusage; 41181ad8388SMartin Matuska *old_memlimit = coder->memlimit; 41281ad8388SMartin Matuska 41381ad8388SMartin Matuska if (new_memlimit != 0) { 41481ad8388SMartin Matuska if (new_memlimit < coder->memusage) 41581ad8388SMartin Matuska return LZMA_MEMLIMIT_ERROR; 41681ad8388SMartin Matuska 41781ad8388SMartin Matuska coder->memlimit = new_memlimit; 41881ad8388SMartin Matuska } 41981ad8388SMartin Matuska 42081ad8388SMartin Matuska return LZMA_OK; 42181ad8388SMartin Matuska } 42281ad8388SMartin Matuska 42381ad8388SMartin Matuska 42481ad8388SMartin Matuska extern lzma_ret 42553200025SRui Paulo lzma_stream_decoder_init( 42653200025SRui Paulo lzma_next_coder *next, const lzma_allocator *allocator, 42781ad8388SMartin Matuska uint64_t memlimit, uint32_t flags) 42881ad8388SMartin Matuska { 42981ad8388SMartin Matuska lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator); 43081ad8388SMartin Matuska 43181ad8388SMartin Matuska if (flags & ~LZMA_SUPPORTED_FLAGS) 43281ad8388SMartin Matuska return LZMA_OPTIONS_ERROR; 43381ad8388SMartin Matuska 4341456f0f9SXin LI lzma_stream_coder *coder = next->coder; 4351456f0f9SXin LI if (coder == NULL) { 4361456f0f9SXin LI coder = lzma_alloc(sizeof(lzma_stream_coder), allocator); 4371456f0f9SXin LI if (coder == NULL) 43881ad8388SMartin Matuska return LZMA_MEM_ERROR; 43981ad8388SMartin Matuska 4401456f0f9SXin LI next->coder = coder; 44181ad8388SMartin Matuska next->code = &stream_decode; 44281ad8388SMartin Matuska next->end = &stream_decoder_end; 44381ad8388SMartin Matuska next->get_check = &stream_decoder_get_check; 44481ad8388SMartin Matuska next->memconfig = &stream_decoder_memconfig; 44581ad8388SMartin Matuska 4461456f0f9SXin LI coder->block_decoder = LZMA_NEXT_CODER_INIT; 4471456f0f9SXin LI coder->index_hash = NULL; 44881ad8388SMartin Matuska } 44981ad8388SMartin Matuska 450b71a5db3SXin LI coder->memlimit = my_max(1, memlimit); 4511456f0f9SXin LI coder->memusage = LZMA_MEMUSAGE_BASE; 4521456f0f9SXin LI coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0; 4531456f0f9SXin LI coder->tell_unsupported_check 45481ad8388SMartin Matuska = (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0; 4551456f0f9SXin LI coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0; 4561456f0f9SXin LI coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0; 4571456f0f9SXin LI coder->concatenated = (flags & LZMA_CONCATENATED) != 0; 4581456f0f9SXin LI coder->first_stream = true; 45981ad8388SMartin Matuska 4601456f0f9SXin LI return stream_decoder_reset(coder, allocator); 46181ad8388SMartin Matuska } 46281ad8388SMartin Matuska 46381ad8388SMartin Matuska 46481ad8388SMartin Matuska extern LZMA_API(lzma_ret) 46581ad8388SMartin Matuska lzma_stream_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags) 46681ad8388SMartin Matuska { 46781ad8388SMartin Matuska lzma_next_strm_init(lzma_stream_decoder_init, strm, memlimit, flags); 46881ad8388SMartin Matuska 46981ad8388SMartin Matuska strm->internal->supported_actions[LZMA_RUN] = true; 47081ad8388SMartin Matuska strm->internal->supported_actions[LZMA_FINISH] = true; 47181ad8388SMartin Matuska 47281ad8388SMartin Matuska return LZMA_OK; 47381ad8388SMartin Matuska } 474