181ad8388SMartin Matuska /////////////////////////////////////////////////////////////////////////////// 281ad8388SMartin Matuska // 381ad8388SMartin Matuska /// \file stream_decoder.c 481ad8388SMartin Matuska /// \brief Decodes .xz Streams 581ad8388SMartin Matuska // 681ad8388SMartin Matuska // Author: Lasse Collin 781ad8388SMartin Matuska // 881ad8388SMartin Matuska // This file has been put into the public domain. 981ad8388SMartin Matuska // You can do whatever you want with this file. 1081ad8388SMartin Matuska // 1181ad8388SMartin Matuska /////////////////////////////////////////////////////////////////////////////// 1281ad8388SMartin Matuska 1381ad8388SMartin Matuska #include "stream_decoder.h" 1481ad8388SMartin Matuska #include "block_decoder.h" 1581ad8388SMartin Matuska 1681ad8388SMartin Matuska 1781ad8388SMartin Matuska struct lzma_coder_s { 1881ad8388SMartin Matuska enum { 1981ad8388SMartin Matuska SEQ_STREAM_HEADER, 2081ad8388SMartin Matuska SEQ_BLOCK_HEADER, 2181ad8388SMartin Matuska SEQ_BLOCK, 2281ad8388SMartin Matuska SEQ_INDEX, 2381ad8388SMartin Matuska SEQ_STREAM_FOOTER, 2481ad8388SMartin Matuska SEQ_STREAM_PADDING, 2581ad8388SMartin Matuska } sequence; 2681ad8388SMartin Matuska 2781ad8388SMartin Matuska /// Block or Metadata decoder. This takes little memory and the same 2881ad8388SMartin Matuska /// data structure can be used to decode every Block Header, so it's 2981ad8388SMartin Matuska /// a good idea to have a separate lzma_next_coder structure for it. 3081ad8388SMartin Matuska lzma_next_coder block_decoder; 3181ad8388SMartin Matuska 3281ad8388SMartin Matuska /// Block options decoded by the Block Header decoder and used by 3381ad8388SMartin Matuska /// the Block decoder. 3481ad8388SMartin Matuska lzma_block block_options; 3581ad8388SMartin Matuska 3681ad8388SMartin Matuska /// Stream Flags from Stream Header 3781ad8388SMartin Matuska lzma_stream_flags stream_flags; 3881ad8388SMartin Matuska 3981ad8388SMartin Matuska /// Index is hashed so that it can be compared to the sizes of Blocks 4081ad8388SMartin Matuska /// with O(1) memory usage. 4181ad8388SMartin Matuska lzma_index_hash *index_hash; 4281ad8388SMartin Matuska 4381ad8388SMartin Matuska /// Memory usage limit 4481ad8388SMartin Matuska uint64_t memlimit; 4581ad8388SMartin Matuska 4681ad8388SMartin Matuska /// Amount of memory actually needed (only an estimate) 4781ad8388SMartin Matuska uint64_t memusage; 4881ad8388SMartin Matuska 4981ad8388SMartin Matuska /// If true, LZMA_NO_CHECK is returned if the Stream has 5081ad8388SMartin Matuska /// no integrity check. 5181ad8388SMartin Matuska bool tell_no_check; 5281ad8388SMartin Matuska 5381ad8388SMartin Matuska /// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has 5481ad8388SMartin Matuska /// an integrity check that isn't supported by this liblzma build. 5581ad8388SMartin Matuska bool tell_unsupported_check; 5681ad8388SMartin Matuska 5781ad8388SMartin Matuska /// If true, LZMA_GET_CHECK is returned after decoding Stream Header. 5881ad8388SMartin Matuska bool tell_any_check; 5981ad8388SMartin Matuska 60*53200025SRui Paulo /// If true, we will tell the Block decoder to skip calculating 61*53200025SRui Paulo /// and verifying the integrity check. 62*53200025SRui Paulo bool ignore_check; 63*53200025SRui Paulo 6481ad8388SMartin Matuska /// If true, we will decode concatenated Streams that possibly have 6581ad8388SMartin Matuska /// Stream Padding between or after them. LZMA_STREAM_END is returned 6681ad8388SMartin Matuska /// once the application isn't giving us any new input, and we aren't 6781ad8388SMartin Matuska /// in the middle of a Stream, and possible Stream Padding is a 6881ad8388SMartin Matuska /// multiple of four bytes. 6981ad8388SMartin Matuska bool concatenated; 7081ad8388SMartin Matuska 7181ad8388SMartin Matuska /// When decoding concatenated Streams, this is true as long as we 7281ad8388SMartin Matuska /// are decoding the first Stream. This is needed to avoid misleading 7381ad8388SMartin Matuska /// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic 7481ad8388SMartin Matuska /// bytes. 7581ad8388SMartin Matuska bool first_stream; 7681ad8388SMartin Matuska 7781ad8388SMartin Matuska /// Write position in buffer[] and position in Stream Padding 7881ad8388SMartin Matuska size_t pos; 7981ad8388SMartin Matuska 8081ad8388SMartin Matuska /// Buffer to hold Stream Header, Block Header, and Stream Footer. 8181ad8388SMartin Matuska /// Block Header has biggest maximum size. 8281ad8388SMartin Matuska uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX]; 8381ad8388SMartin Matuska }; 8481ad8388SMartin Matuska 8581ad8388SMartin Matuska 8681ad8388SMartin Matuska static lzma_ret 87*53200025SRui Paulo stream_decoder_reset(lzma_coder *coder, const lzma_allocator *allocator) 8881ad8388SMartin Matuska { 8981ad8388SMartin Matuska // Initialize the Index hash used to verify the Index. 9081ad8388SMartin Matuska coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator); 9181ad8388SMartin Matuska if (coder->index_hash == NULL) 9281ad8388SMartin Matuska return LZMA_MEM_ERROR; 9381ad8388SMartin Matuska 9481ad8388SMartin Matuska // Reset the rest of the variables. 9581ad8388SMartin Matuska coder->sequence = SEQ_STREAM_HEADER; 9681ad8388SMartin Matuska coder->pos = 0; 9781ad8388SMartin Matuska 9881ad8388SMartin Matuska return LZMA_OK; 9981ad8388SMartin Matuska } 10081ad8388SMartin Matuska 10181ad8388SMartin Matuska 10281ad8388SMartin Matuska static lzma_ret 103*53200025SRui Paulo stream_decode(lzma_coder *coder, const lzma_allocator *allocator, 10481ad8388SMartin Matuska const uint8_t *restrict in, size_t *restrict in_pos, 10581ad8388SMartin Matuska size_t in_size, uint8_t *restrict out, 10681ad8388SMartin Matuska size_t *restrict out_pos, size_t out_size, lzma_action action) 10781ad8388SMartin Matuska { 10881ad8388SMartin Matuska // When decoding the actual Block, it may be able to produce more 10981ad8388SMartin Matuska // output even if we don't give it any new input. 11081ad8388SMartin Matuska while (true) 11181ad8388SMartin Matuska switch (coder->sequence) { 11281ad8388SMartin Matuska case SEQ_STREAM_HEADER: { 11381ad8388SMartin Matuska // Copy the Stream Header to the internal buffer. 11481ad8388SMartin Matuska lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, 11581ad8388SMartin Matuska LZMA_STREAM_HEADER_SIZE); 11681ad8388SMartin Matuska 11781ad8388SMartin Matuska // Return if we didn't get the whole Stream Header yet. 11881ad8388SMartin Matuska if (coder->pos < LZMA_STREAM_HEADER_SIZE) 11981ad8388SMartin Matuska return LZMA_OK; 12081ad8388SMartin Matuska 12181ad8388SMartin Matuska coder->pos = 0; 12281ad8388SMartin Matuska 12381ad8388SMartin Matuska // Decode the Stream Header. 12481ad8388SMartin Matuska const lzma_ret ret = lzma_stream_header_decode( 12581ad8388SMartin Matuska &coder->stream_flags, coder->buffer); 12681ad8388SMartin Matuska if (ret != LZMA_OK) 12781ad8388SMartin Matuska return ret == LZMA_FORMAT_ERROR && !coder->first_stream 12881ad8388SMartin Matuska ? LZMA_DATA_ERROR : ret; 12981ad8388SMartin Matuska 13081ad8388SMartin Matuska // If we are decoding concatenated Streams, and the later 13181ad8388SMartin Matuska // Streams have invalid Header Magic Bytes, we give 13281ad8388SMartin Matuska // LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR. 13381ad8388SMartin Matuska coder->first_stream = false; 13481ad8388SMartin Matuska 13581ad8388SMartin Matuska // Copy the type of the Check so that Block Header and Block 13681ad8388SMartin Matuska // decoders see it. 13781ad8388SMartin Matuska coder->block_options.check = coder->stream_flags.check; 13881ad8388SMartin Matuska 13981ad8388SMartin Matuska // Even if we return LZMA_*_CHECK below, we want 14081ad8388SMartin Matuska // to continue from Block Header decoding. 14181ad8388SMartin Matuska coder->sequence = SEQ_BLOCK_HEADER; 14281ad8388SMartin Matuska 14381ad8388SMartin Matuska // Detect if there's no integrity check or if it is 14481ad8388SMartin Matuska // unsupported if those were requested by the application. 14581ad8388SMartin Matuska if (coder->tell_no_check && coder->stream_flags.check 14681ad8388SMartin Matuska == LZMA_CHECK_NONE) 14781ad8388SMartin Matuska return LZMA_NO_CHECK; 14881ad8388SMartin Matuska 14981ad8388SMartin Matuska if (coder->tell_unsupported_check 15081ad8388SMartin Matuska && !lzma_check_is_supported( 15181ad8388SMartin Matuska coder->stream_flags.check)) 15281ad8388SMartin Matuska return LZMA_UNSUPPORTED_CHECK; 15381ad8388SMartin Matuska 15481ad8388SMartin Matuska if (coder->tell_any_check) 15581ad8388SMartin Matuska return LZMA_GET_CHECK; 15681ad8388SMartin Matuska } 15781ad8388SMartin Matuska 15881ad8388SMartin Matuska // Fall through 15981ad8388SMartin Matuska 16081ad8388SMartin Matuska case SEQ_BLOCK_HEADER: { 16181ad8388SMartin Matuska if (*in_pos >= in_size) 16281ad8388SMartin Matuska return LZMA_OK; 16381ad8388SMartin Matuska 16481ad8388SMartin Matuska if (coder->pos == 0) { 16581ad8388SMartin Matuska // Detect if it's Index. 16681ad8388SMartin Matuska if (in[*in_pos] == 0x00) { 16781ad8388SMartin Matuska coder->sequence = SEQ_INDEX; 16881ad8388SMartin Matuska break; 16981ad8388SMartin Matuska } 17081ad8388SMartin Matuska 17181ad8388SMartin Matuska // Calculate the size of the Block Header. Note that 17281ad8388SMartin Matuska // Block Header decoder wants to see this byte too 17381ad8388SMartin Matuska // so don't advance *in_pos. 17481ad8388SMartin Matuska coder->block_options.header_size 17581ad8388SMartin Matuska = lzma_block_header_size_decode( 17681ad8388SMartin Matuska in[*in_pos]); 17781ad8388SMartin Matuska } 17881ad8388SMartin Matuska 17981ad8388SMartin Matuska // Copy the Block Header to the internal buffer. 18081ad8388SMartin Matuska lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, 18181ad8388SMartin Matuska coder->block_options.header_size); 18281ad8388SMartin Matuska 18381ad8388SMartin Matuska // Return if we didn't get the whole Block Header yet. 18481ad8388SMartin Matuska if (coder->pos < coder->block_options.header_size) 18581ad8388SMartin Matuska return LZMA_OK; 18681ad8388SMartin Matuska 18781ad8388SMartin Matuska coder->pos = 0; 18881ad8388SMartin Matuska 189*53200025SRui Paulo // Version 1 is needed to support the .ignore_check option. 190*53200025SRui Paulo coder->block_options.version = 1; 19181ad8388SMartin Matuska 19281ad8388SMartin Matuska // Set up a buffer to hold the filter chain. Block Header 19381ad8388SMartin Matuska // decoder will initialize all members of this array so 19481ad8388SMartin Matuska // we don't need to do it here. 19581ad8388SMartin Matuska lzma_filter filters[LZMA_FILTERS_MAX + 1]; 19681ad8388SMartin Matuska coder->block_options.filters = filters; 19781ad8388SMartin Matuska 19881ad8388SMartin Matuska // Decode the Block Header. 19981ad8388SMartin Matuska return_if_error(lzma_block_header_decode(&coder->block_options, 20081ad8388SMartin Matuska allocator, coder->buffer)); 20181ad8388SMartin Matuska 202*53200025SRui Paulo // If LZMA_IGNORE_CHECK was used, this flag needs to be set. 203*53200025SRui Paulo // It has to be set after lzma_block_header_decode() because 204*53200025SRui Paulo // it always resets this to false. 205*53200025SRui Paulo coder->block_options.ignore_check = coder->ignore_check; 206*53200025SRui Paulo 20781ad8388SMartin Matuska // Check the memory usage limit. 20881ad8388SMartin Matuska const uint64_t memusage = lzma_raw_decoder_memusage(filters); 20981ad8388SMartin Matuska lzma_ret ret; 21081ad8388SMartin Matuska 21181ad8388SMartin Matuska if (memusage == UINT64_MAX) { 21281ad8388SMartin Matuska // One or more unknown Filter IDs. 21381ad8388SMartin Matuska ret = LZMA_OPTIONS_ERROR; 21481ad8388SMartin Matuska } else { 21581ad8388SMartin Matuska // Now we can set coder->memusage since we know that 21681ad8388SMartin Matuska // the filter chain is valid. We don't want 21781ad8388SMartin Matuska // lzma_memusage() to return UINT64_MAX in case of 21881ad8388SMartin Matuska // invalid filter chain. 21981ad8388SMartin Matuska coder->memusage = memusage; 22081ad8388SMartin Matuska 22181ad8388SMartin Matuska if (memusage > coder->memlimit) { 22281ad8388SMartin Matuska // The chain would need too much memory. 22381ad8388SMartin Matuska ret = LZMA_MEMLIMIT_ERROR; 22481ad8388SMartin Matuska } else { 22581ad8388SMartin Matuska // Memory usage is OK. 22681ad8388SMartin Matuska // Initialize the Block decoder. 22781ad8388SMartin Matuska ret = lzma_block_decoder_init( 22881ad8388SMartin Matuska &coder->block_decoder, 22981ad8388SMartin Matuska allocator, 23081ad8388SMartin Matuska &coder->block_options); 23181ad8388SMartin Matuska } 23281ad8388SMartin Matuska } 23381ad8388SMartin Matuska 23481ad8388SMartin Matuska // Free the allocated filter options since they are needed 23581ad8388SMartin Matuska // only to initialize the Block decoder. 23681ad8388SMartin Matuska for (size_t i = 0; i < LZMA_FILTERS_MAX; ++i) 23781ad8388SMartin Matuska lzma_free(filters[i].options, allocator); 23881ad8388SMartin Matuska 23981ad8388SMartin Matuska coder->block_options.filters = NULL; 24081ad8388SMartin Matuska 24181ad8388SMartin Matuska // Check if memory usage calculation and Block enocoder 24281ad8388SMartin Matuska // initialization succeeded. 24381ad8388SMartin Matuska if (ret != LZMA_OK) 24481ad8388SMartin Matuska return ret; 24581ad8388SMartin Matuska 24681ad8388SMartin Matuska coder->sequence = SEQ_BLOCK; 24781ad8388SMartin Matuska } 24881ad8388SMartin Matuska 24981ad8388SMartin Matuska // Fall through 25081ad8388SMartin Matuska 25181ad8388SMartin Matuska case SEQ_BLOCK: { 25281ad8388SMartin Matuska const lzma_ret ret = coder->block_decoder.code( 25381ad8388SMartin Matuska coder->block_decoder.coder, allocator, 25481ad8388SMartin Matuska in, in_pos, in_size, out, out_pos, out_size, 25581ad8388SMartin Matuska action); 25681ad8388SMartin Matuska 25781ad8388SMartin Matuska if (ret != LZMA_STREAM_END) 25881ad8388SMartin Matuska return ret; 25981ad8388SMartin Matuska 26081ad8388SMartin Matuska // Block decoded successfully. Add the new size pair to 26181ad8388SMartin Matuska // the Index hash. 26281ad8388SMartin Matuska return_if_error(lzma_index_hash_append(coder->index_hash, 26381ad8388SMartin Matuska lzma_block_unpadded_size( 26481ad8388SMartin Matuska &coder->block_options), 26581ad8388SMartin Matuska coder->block_options.uncompressed_size)); 26681ad8388SMartin Matuska 26781ad8388SMartin Matuska coder->sequence = SEQ_BLOCK_HEADER; 26881ad8388SMartin Matuska break; 26981ad8388SMartin Matuska } 27081ad8388SMartin Matuska 27181ad8388SMartin Matuska case SEQ_INDEX: { 27281ad8388SMartin Matuska // If we don't have any input, don't call 27381ad8388SMartin Matuska // lzma_index_hash_decode() since it would return 27481ad8388SMartin Matuska // LZMA_BUF_ERROR, which we must not do here. 27581ad8388SMartin Matuska if (*in_pos >= in_size) 27681ad8388SMartin Matuska return LZMA_OK; 27781ad8388SMartin Matuska 27881ad8388SMartin Matuska // Decode the Index and compare it to the hash calculated 27981ad8388SMartin Matuska // from the sizes of the Blocks (if any). 28081ad8388SMartin Matuska const lzma_ret ret = lzma_index_hash_decode(coder->index_hash, 28181ad8388SMartin Matuska in, in_pos, in_size); 28281ad8388SMartin Matuska if (ret != LZMA_STREAM_END) 28381ad8388SMartin Matuska return ret; 28481ad8388SMartin Matuska 28581ad8388SMartin Matuska coder->sequence = SEQ_STREAM_FOOTER; 28681ad8388SMartin Matuska } 28781ad8388SMartin Matuska 28881ad8388SMartin Matuska // Fall through 28981ad8388SMartin Matuska 29081ad8388SMartin Matuska case SEQ_STREAM_FOOTER: { 29181ad8388SMartin Matuska // Copy the Stream Footer to the internal buffer. 29281ad8388SMartin Matuska lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos, 29381ad8388SMartin Matuska LZMA_STREAM_HEADER_SIZE); 29481ad8388SMartin Matuska 29581ad8388SMartin Matuska // Return if we didn't get the whole Stream Footer yet. 29681ad8388SMartin Matuska if (coder->pos < LZMA_STREAM_HEADER_SIZE) 29781ad8388SMartin Matuska return LZMA_OK; 29881ad8388SMartin Matuska 29981ad8388SMartin Matuska coder->pos = 0; 30081ad8388SMartin Matuska 30181ad8388SMartin Matuska // Decode the Stream Footer. The decoder gives 30281ad8388SMartin Matuska // LZMA_FORMAT_ERROR if the magic bytes don't match, 30381ad8388SMartin Matuska // so convert that return code to LZMA_DATA_ERROR. 30481ad8388SMartin Matuska lzma_stream_flags footer_flags; 30581ad8388SMartin Matuska const lzma_ret ret = lzma_stream_footer_decode( 30681ad8388SMartin Matuska &footer_flags, coder->buffer); 30781ad8388SMartin Matuska if (ret != LZMA_OK) 30881ad8388SMartin Matuska return ret == LZMA_FORMAT_ERROR 30981ad8388SMartin Matuska ? LZMA_DATA_ERROR : ret; 31081ad8388SMartin Matuska 31181ad8388SMartin Matuska // Check that Index Size stored in the Stream Footer matches 31281ad8388SMartin Matuska // the real size of the Index field. 31381ad8388SMartin Matuska if (lzma_index_hash_size(coder->index_hash) 31481ad8388SMartin Matuska != footer_flags.backward_size) 31581ad8388SMartin Matuska return LZMA_DATA_ERROR; 31681ad8388SMartin Matuska 31781ad8388SMartin Matuska // Compare that the Stream Flags fields are identical in 31881ad8388SMartin Matuska // both Stream Header and Stream Footer. 31981ad8388SMartin Matuska return_if_error(lzma_stream_flags_compare( 32081ad8388SMartin Matuska &coder->stream_flags, &footer_flags)); 32181ad8388SMartin Matuska 32281ad8388SMartin Matuska if (!coder->concatenated) 32381ad8388SMartin Matuska return LZMA_STREAM_END; 32481ad8388SMartin Matuska 32581ad8388SMartin Matuska coder->sequence = SEQ_STREAM_PADDING; 32681ad8388SMartin Matuska } 32781ad8388SMartin Matuska 32881ad8388SMartin Matuska // Fall through 32981ad8388SMartin Matuska 33081ad8388SMartin Matuska case SEQ_STREAM_PADDING: 33181ad8388SMartin Matuska assert(coder->concatenated); 33281ad8388SMartin Matuska 33381ad8388SMartin Matuska // Skip over possible Stream Padding. 33481ad8388SMartin Matuska while (true) { 33581ad8388SMartin Matuska if (*in_pos >= in_size) { 33681ad8388SMartin Matuska // Unless LZMA_FINISH was used, we cannot 33781ad8388SMartin Matuska // know if there's more input coming later. 33881ad8388SMartin Matuska if (action != LZMA_FINISH) 33981ad8388SMartin Matuska return LZMA_OK; 34081ad8388SMartin Matuska 34181ad8388SMartin Matuska // Stream Padding must be a multiple of 34281ad8388SMartin Matuska // four bytes. 34381ad8388SMartin Matuska return coder->pos == 0 34481ad8388SMartin Matuska ? LZMA_STREAM_END 34581ad8388SMartin Matuska : LZMA_DATA_ERROR; 34681ad8388SMartin Matuska } 34781ad8388SMartin Matuska 34881ad8388SMartin Matuska // If the byte is not zero, it probably indicates 34981ad8388SMartin Matuska // beginning of a new Stream (or the file is corrupt). 35081ad8388SMartin Matuska if (in[*in_pos] != 0x00) 35181ad8388SMartin Matuska break; 35281ad8388SMartin Matuska 35381ad8388SMartin Matuska ++*in_pos; 35481ad8388SMartin Matuska coder->pos = (coder->pos + 1) & 3; 35581ad8388SMartin Matuska } 35681ad8388SMartin Matuska 35781ad8388SMartin Matuska // Stream Padding must be a multiple of four bytes (empty 35881ad8388SMartin Matuska // Stream Padding is OK). 35981ad8388SMartin Matuska if (coder->pos != 0) { 36081ad8388SMartin Matuska ++*in_pos; 36181ad8388SMartin Matuska return LZMA_DATA_ERROR; 36281ad8388SMartin Matuska } 36381ad8388SMartin Matuska 36481ad8388SMartin Matuska // Prepare to decode the next Stream. 36581ad8388SMartin Matuska return_if_error(stream_decoder_reset(coder, allocator)); 36681ad8388SMartin Matuska break; 36781ad8388SMartin Matuska 36881ad8388SMartin Matuska default: 36981ad8388SMartin Matuska assert(0); 37081ad8388SMartin Matuska return LZMA_PROG_ERROR; 37181ad8388SMartin Matuska } 37281ad8388SMartin Matuska 37381ad8388SMartin Matuska // Never reached 37481ad8388SMartin Matuska } 37581ad8388SMartin Matuska 37681ad8388SMartin Matuska 37781ad8388SMartin Matuska static void 378*53200025SRui Paulo stream_decoder_end(lzma_coder *coder, const lzma_allocator *allocator) 37981ad8388SMartin Matuska { 38081ad8388SMartin Matuska lzma_next_end(&coder->block_decoder, allocator); 38181ad8388SMartin Matuska lzma_index_hash_end(coder->index_hash, allocator); 38281ad8388SMartin Matuska lzma_free(coder, allocator); 38381ad8388SMartin Matuska return; 38481ad8388SMartin Matuska } 38581ad8388SMartin Matuska 38681ad8388SMartin Matuska 38781ad8388SMartin Matuska static lzma_check 38881ad8388SMartin Matuska stream_decoder_get_check(const lzma_coder *coder) 38981ad8388SMartin Matuska { 39081ad8388SMartin Matuska return coder->stream_flags.check; 39181ad8388SMartin Matuska } 39281ad8388SMartin Matuska 39381ad8388SMartin Matuska 39481ad8388SMartin Matuska static lzma_ret 39581ad8388SMartin Matuska stream_decoder_memconfig(lzma_coder *coder, uint64_t *memusage, 39681ad8388SMartin Matuska uint64_t *old_memlimit, uint64_t new_memlimit) 39781ad8388SMartin Matuska { 39881ad8388SMartin Matuska *memusage = coder->memusage; 39981ad8388SMartin Matuska *old_memlimit = coder->memlimit; 40081ad8388SMartin Matuska 40181ad8388SMartin Matuska if (new_memlimit != 0) { 40281ad8388SMartin Matuska if (new_memlimit < coder->memusage) 40381ad8388SMartin Matuska return LZMA_MEMLIMIT_ERROR; 40481ad8388SMartin Matuska 40581ad8388SMartin Matuska coder->memlimit = new_memlimit; 40681ad8388SMartin Matuska } 40781ad8388SMartin Matuska 40881ad8388SMartin Matuska return LZMA_OK; 40981ad8388SMartin Matuska } 41081ad8388SMartin Matuska 41181ad8388SMartin Matuska 41281ad8388SMartin Matuska extern lzma_ret 413*53200025SRui Paulo lzma_stream_decoder_init( 414*53200025SRui Paulo lzma_next_coder *next, const lzma_allocator *allocator, 41581ad8388SMartin Matuska uint64_t memlimit, uint32_t flags) 41681ad8388SMartin Matuska { 41781ad8388SMartin Matuska lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator); 41881ad8388SMartin Matuska 41981ad8388SMartin Matuska if (memlimit == 0) 42081ad8388SMartin Matuska return LZMA_PROG_ERROR; 42181ad8388SMartin Matuska 42281ad8388SMartin Matuska if (flags & ~LZMA_SUPPORTED_FLAGS) 42381ad8388SMartin Matuska return LZMA_OPTIONS_ERROR; 42481ad8388SMartin Matuska 42581ad8388SMartin Matuska if (next->coder == NULL) { 42681ad8388SMartin Matuska next->coder = lzma_alloc(sizeof(lzma_coder), allocator); 42781ad8388SMartin Matuska if (next->coder == NULL) 42881ad8388SMartin Matuska return LZMA_MEM_ERROR; 42981ad8388SMartin Matuska 43081ad8388SMartin Matuska next->code = &stream_decode; 43181ad8388SMartin Matuska next->end = &stream_decoder_end; 43281ad8388SMartin Matuska next->get_check = &stream_decoder_get_check; 43381ad8388SMartin Matuska next->memconfig = &stream_decoder_memconfig; 43481ad8388SMartin Matuska 43581ad8388SMartin Matuska next->coder->block_decoder = LZMA_NEXT_CODER_INIT; 43681ad8388SMartin Matuska next->coder->index_hash = NULL; 43781ad8388SMartin Matuska } 43881ad8388SMartin Matuska 43981ad8388SMartin Matuska next->coder->memlimit = memlimit; 44081ad8388SMartin Matuska next->coder->memusage = LZMA_MEMUSAGE_BASE; 44181ad8388SMartin Matuska next->coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0; 44281ad8388SMartin Matuska next->coder->tell_unsupported_check 44381ad8388SMartin Matuska = (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0; 44481ad8388SMartin Matuska next->coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0; 445*53200025SRui Paulo next->coder->ignore_check = (flags & LZMA_IGNORE_CHECK) != 0; 44681ad8388SMartin Matuska next->coder->concatenated = (flags & LZMA_CONCATENATED) != 0; 44781ad8388SMartin Matuska next->coder->first_stream = true; 44881ad8388SMartin Matuska 44981ad8388SMartin Matuska return stream_decoder_reset(next->coder, allocator); 45081ad8388SMartin Matuska } 45181ad8388SMartin Matuska 45281ad8388SMartin Matuska 45381ad8388SMartin Matuska extern LZMA_API(lzma_ret) 45481ad8388SMartin Matuska lzma_stream_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags) 45581ad8388SMartin Matuska { 45681ad8388SMartin Matuska lzma_next_strm_init(lzma_stream_decoder_init, strm, memlimit, flags); 45781ad8388SMartin Matuska 45881ad8388SMartin Matuska strm->internal->supported_actions[LZMA_RUN] = true; 45981ad8388SMartin Matuska strm->internal->supported_actions[LZMA_FINISH] = true; 46081ad8388SMartin Matuska 46181ad8388SMartin Matuska return LZMA_OK; 46281ad8388SMartin Matuska } 463