1*3b35e7eeSXin LI // SPDX-License-Identifier: 0BSD 2*3b35e7eeSXin LI 373ed8e77SXin LI /////////////////////////////////////////////////////////////////////////////// 473ed8e77SXin LI // 573ed8e77SXin LI /// \file file_info.c 673ed8e77SXin LI /// \brief Decode .xz file information into a lzma_index structure 773ed8e77SXin LI // 873ed8e77SXin LI // Author: Lasse Collin 973ed8e77SXin LI // 1073ed8e77SXin LI /////////////////////////////////////////////////////////////////////////////// 1173ed8e77SXin LI 1273ed8e77SXin LI #include "index_decoder.h" 1373ed8e77SXin LI 1473ed8e77SXin LI 1573ed8e77SXin LI typedef struct { 1673ed8e77SXin LI enum { 1773ed8e77SXin LI SEQ_MAGIC_BYTES, 1873ed8e77SXin LI SEQ_PADDING_SEEK, 1973ed8e77SXin LI SEQ_PADDING_DECODE, 2073ed8e77SXin LI SEQ_FOOTER, 2173ed8e77SXin LI SEQ_INDEX_INIT, 2273ed8e77SXin LI SEQ_INDEX_DECODE, 2373ed8e77SXin LI SEQ_HEADER_DECODE, 2473ed8e77SXin LI SEQ_HEADER_COMPARE, 2573ed8e77SXin LI } sequence; 2673ed8e77SXin LI 2773ed8e77SXin LI /// Absolute position of in[*in_pos] in the file. All code that 2873ed8e77SXin LI /// modifies *in_pos also updates this. seek_to_pos() needs this 2973ed8e77SXin LI /// to determine if we need to request the application to seek for 3073ed8e77SXin LI /// us or if we can do the seeking internally by adjusting *in_pos. 3173ed8e77SXin LI uint64_t file_cur_pos; 3273ed8e77SXin LI 3373ed8e77SXin LI /// This refers to absolute positions of interesting parts of the 3473ed8e77SXin LI /// input file. Sometimes it points to the *beginning* of a specific 3573ed8e77SXin LI /// field and sometimes to the *end* of a field. The current target 3673ed8e77SXin LI /// position at each moment is explained in the comments. 3773ed8e77SXin LI uint64_t file_target_pos; 3873ed8e77SXin LI 3973ed8e77SXin LI /// Size of the .xz file (from the application). 4073ed8e77SXin LI uint64_t file_size; 4173ed8e77SXin LI 4273ed8e77SXin LI /// Index decoder 4373ed8e77SXin LI lzma_next_coder index_decoder; 4473ed8e77SXin LI 4573ed8e77SXin LI /// Number of bytes remaining in the Index field that is currently 4673ed8e77SXin LI /// being decoded. 4773ed8e77SXin LI lzma_vli index_remaining; 4873ed8e77SXin LI 4973ed8e77SXin LI /// The Index decoder will store the decoded Index in this pointer. 5073ed8e77SXin LI lzma_index *this_index; 5173ed8e77SXin LI 5273ed8e77SXin LI /// Amount of Stream Padding in the current Stream. 5373ed8e77SXin LI lzma_vli stream_padding; 5473ed8e77SXin LI 5573ed8e77SXin LI /// The final combined index is collected here. 5673ed8e77SXin LI lzma_index *combined_index; 5773ed8e77SXin LI 5873ed8e77SXin LI /// Pointer from the application where to store the index information 5973ed8e77SXin LI /// after successful decoding. 6073ed8e77SXin LI lzma_index **dest_index; 6173ed8e77SXin LI 6273ed8e77SXin LI /// Pointer to lzma_stream.seek_pos to be used when returning 6373ed8e77SXin LI /// LZMA_SEEK_NEEDED. This is set by seek_to_pos() when needed. 6473ed8e77SXin LI uint64_t *external_seek_pos; 6573ed8e77SXin LI 6673ed8e77SXin LI /// Memory usage limit 6773ed8e77SXin LI uint64_t memlimit; 6873ed8e77SXin LI 6973ed8e77SXin LI /// Stream Flags from the very beginning of the file. 7073ed8e77SXin LI lzma_stream_flags first_header_flags; 7173ed8e77SXin LI 7273ed8e77SXin LI /// Stream Flags from Stream Header of the current Stream. 7373ed8e77SXin LI lzma_stream_flags header_flags; 7473ed8e77SXin LI 7573ed8e77SXin LI /// Stream Flags from Stream Footer of the current Stream. 7673ed8e77SXin LI lzma_stream_flags footer_flags; 7773ed8e77SXin LI 7873ed8e77SXin LI size_t temp_pos; 7973ed8e77SXin LI size_t temp_size; 8073ed8e77SXin LI uint8_t temp[8192]; 8173ed8e77SXin LI 8273ed8e77SXin LI } lzma_file_info_coder; 8373ed8e77SXin LI 8473ed8e77SXin LI 8573ed8e77SXin LI /// Copies data from in[*in_pos] into coder->temp until 8673ed8e77SXin LI /// coder->temp_pos == coder->temp_size. This also keeps coder->file_cur_pos 8773ed8e77SXin LI /// in sync with *in_pos. Returns true if more input is needed. 8873ed8e77SXin LI static bool 8973ed8e77SXin LI fill_temp(lzma_file_info_coder *coder, const uint8_t *restrict in, 9073ed8e77SXin LI size_t *restrict in_pos, size_t in_size) 9173ed8e77SXin LI { 9273ed8e77SXin LI coder->file_cur_pos += lzma_bufcpy(in, in_pos, in_size, 9373ed8e77SXin LI coder->temp, &coder->temp_pos, coder->temp_size); 9473ed8e77SXin LI return coder->temp_pos < coder->temp_size; 9573ed8e77SXin LI } 9673ed8e77SXin LI 9773ed8e77SXin LI 9873ed8e77SXin LI /// Seeks to the absolute file position specified by target_pos. 9973ed8e77SXin LI /// This tries to do the seeking by only modifying *in_pos, if possible. 10073ed8e77SXin LI /// The main benefit of this is that if one passes the whole file at once 10173ed8e77SXin LI /// to lzma_code(), the decoder will never need to return LZMA_SEEK_NEEDED 10273ed8e77SXin LI /// as all the seeking can be done by adjusting *in_pos in this function. 10373ed8e77SXin LI /// 10473ed8e77SXin LI /// Returns true if an external seek is needed and the caller must return 10573ed8e77SXin LI /// LZMA_SEEK_NEEDED. 10673ed8e77SXin LI static bool 10773ed8e77SXin LI seek_to_pos(lzma_file_info_coder *coder, uint64_t target_pos, 10873ed8e77SXin LI size_t in_start, size_t *in_pos, size_t in_size) 10973ed8e77SXin LI { 11073ed8e77SXin LI // The input buffer doesn't extend beyond the end of the file. 11173ed8e77SXin LI // This has been checked by file_info_decode() already. 11273ed8e77SXin LI assert(coder->file_size - coder->file_cur_pos >= in_size - *in_pos); 11373ed8e77SXin LI 11473ed8e77SXin LI const uint64_t pos_min = coder->file_cur_pos - (*in_pos - in_start); 11573ed8e77SXin LI const uint64_t pos_max = coder->file_cur_pos + (in_size - *in_pos); 11673ed8e77SXin LI 11773ed8e77SXin LI bool external_seek_needed; 11873ed8e77SXin LI 11973ed8e77SXin LI if (target_pos >= pos_min && target_pos <= pos_max) { 12073ed8e77SXin LI // The requested position is available in the current input 12173ed8e77SXin LI // buffer or right after it. That is, in a corner case we 12273ed8e77SXin LI // end up setting *in_pos == in_size and thus will immediately 12373ed8e77SXin LI // need new input bytes from the application. 12473ed8e77SXin LI *in_pos += (size_t)(target_pos - coder->file_cur_pos); 12573ed8e77SXin LI external_seek_needed = false; 12673ed8e77SXin LI } else { 12773ed8e77SXin LI // Ask the application to seek the input file. 12873ed8e77SXin LI *coder->external_seek_pos = target_pos; 12973ed8e77SXin LI external_seek_needed = true; 13073ed8e77SXin LI 13173ed8e77SXin LI // Mark the whole input buffer as used. This way 13273ed8e77SXin LI // lzma_stream.total_in will have a better estimate 13373ed8e77SXin LI // of the amount of data read. It still won't be perfect 13473ed8e77SXin LI // as the value will depend on the input buffer size that 13573ed8e77SXin LI // the application uses, but it should be good enough for 13673ed8e77SXin LI // those few who want an estimate. 13773ed8e77SXin LI *in_pos = in_size; 13873ed8e77SXin LI } 13973ed8e77SXin LI 14073ed8e77SXin LI // After seeking (internal or external) the current position 14173ed8e77SXin LI // will match the requested target position. 14273ed8e77SXin LI coder->file_cur_pos = target_pos; 14373ed8e77SXin LI 14473ed8e77SXin LI return external_seek_needed; 14573ed8e77SXin LI } 14673ed8e77SXin LI 14773ed8e77SXin LI 14873ed8e77SXin LI /// The caller sets coder->file_target_pos so that it points to the *end* 14973ed8e77SXin LI /// of the desired file position. This function then determines how far 15073ed8e77SXin LI /// backwards from that position we can seek. After seeking fill_temp() 15173ed8e77SXin LI /// can be used to read data into coder->temp. When fill_temp() has finished, 15273ed8e77SXin LI /// coder->temp[coder->temp_size] will match coder->file_target_pos. 15373ed8e77SXin LI /// 15473ed8e77SXin LI /// This also validates that coder->target_file_pos is sane in sense that 15573ed8e77SXin LI /// we aren't trying to seek too far backwards (too close or beyond the 15673ed8e77SXin LI /// beginning of the file). 15773ed8e77SXin LI static lzma_ret 15873ed8e77SXin LI reverse_seek(lzma_file_info_coder *coder, 15973ed8e77SXin LI size_t in_start, size_t *in_pos, size_t in_size) 16073ed8e77SXin LI { 16173ed8e77SXin LI // Check that there is enough data before the target position 16273ed8e77SXin LI // to contain at least Stream Header and Stream Footer. If there 16373ed8e77SXin LI // isn't, the file cannot be valid. 16473ed8e77SXin LI if (coder->file_target_pos < 2 * LZMA_STREAM_HEADER_SIZE) 16573ed8e77SXin LI return LZMA_DATA_ERROR; 16673ed8e77SXin LI 16773ed8e77SXin LI coder->temp_pos = 0; 16873ed8e77SXin LI 16973ed8e77SXin LI // The Stream Header at the very beginning of the file gets handled 17073ed8e77SXin LI // specially in SEQ_MAGIC_BYTES and thus we will never need to seek 17173ed8e77SXin LI // there. By not seeking to the first LZMA_STREAM_HEADER_SIZE bytes 17273ed8e77SXin LI // we avoid a useless external seek after SEQ_MAGIC_BYTES if the 17373ed8e77SXin LI // application uses an extremely small input buffer and the input 17473ed8e77SXin LI // file is very small. 17573ed8e77SXin LI if (coder->file_target_pos - LZMA_STREAM_HEADER_SIZE 17673ed8e77SXin LI < sizeof(coder->temp)) 17773ed8e77SXin LI coder->temp_size = (size_t)(coder->file_target_pos 17873ed8e77SXin LI - LZMA_STREAM_HEADER_SIZE); 17973ed8e77SXin LI else 18073ed8e77SXin LI coder->temp_size = sizeof(coder->temp); 18173ed8e77SXin LI 18273ed8e77SXin LI // The above if-statements guarantee this. This is important because 18373ed8e77SXin LI // the Stream Header/Footer decoders assume that there's at least 18473ed8e77SXin LI // LZMA_STREAM_HEADER_SIZE bytes in coder->temp. 18573ed8e77SXin LI assert(coder->temp_size >= LZMA_STREAM_HEADER_SIZE); 18673ed8e77SXin LI 18773ed8e77SXin LI if (seek_to_pos(coder, coder->file_target_pos - coder->temp_size, 18873ed8e77SXin LI in_start, in_pos, in_size)) 18973ed8e77SXin LI return LZMA_SEEK_NEEDED; 19073ed8e77SXin LI 19173ed8e77SXin LI return LZMA_OK; 19273ed8e77SXin LI } 19373ed8e77SXin LI 19473ed8e77SXin LI 19573ed8e77SXin LI /// Gets the number of zero-bytes at the end of the buffer. 19673ed8e77SXin LI static size_t 19773ed8e77SXin LI get_padding_size(const uint8_t *buf, size_t buf_size) 19873ed8e77SXin LI { 19973ed8e77SXin LI size_t padding = 0; 20073ed8e77SXin LI while (buf_size > 0 && buf[--buf_size] == 0x00) 20173ed8e77SXin LI ++padding; 20273ed8e77SXin LI 20373ed8e77SXin LI return padding; 20473ed8e77SXin LI } 20573ed8e77SXin LI 20673ed8e77SXin LI 20773ed8e77SXin LI /// With the Stream Header at the very beginning of the file, LZMA_FORMAT_ERROR 20873ed8e77SXin LI /// is used to tell the application that Magic Bytes didn't match. In other 20973ed8e77SXin LI /// Stream Header/Footer fields (in the middle/end of the file) it could be 21073ed8e77SXin LI /// a bit confusing to return LZMA_FORMAT_ERROR as we already know that there 21173ed8e77SXin LI /// is a valid Stream Header at the beginning of the file. For those cases 21273ed8e77SXin LI /// this function is used to convert LZMA_FORMAT_ERROR to LZMA_DATA_ERROR. 21373ed8e77SXin LI static lzma_ret 21473ed8e77SXin LI hide_format_error(lzma_ret ret) 21573ed8e77SXin LI { 21673ed8e77SXin LI if (ret == LZMA_FORMAT_ERROR) 21773ed8e77SXin LI ret = LZMA_DATA_ERROR; 21873ed8e77SXin LI 21973ed8e77SXin LI return ret; 22073ed8e77SXin LI } 22173ed8e77SXin LI 22273ed8e77SXin LI 22373ed8e77SXin LI /// Calls the Index decoder and updates coder->index_remaining. 22473ed8e77SXin LI /// This is a separate function because the input can be either directly 22573ed8e77SXin LI /// from the application or from coder->temp. 22673ed8e77SXin LI static lzma_ret 22773ed8e77SXin LI decode_index(lzma_file_info_coder *coder, const lzma_allocator *allocator, 22873ed8e77SXin LI const uint8_t *restrict in, size_t *restrict in_pos, 22973ed8e77SXin LI size_t in_size, bool update_file_cur_pos) 23073ed8e77SXin LI { 23173ed8e77SXin LI const size_t in_start = *in_pos; 23273ed8e77SXin LI 23373ed8e77SXin LI const lzma_ret ret = coder->index_decoder.code( 23473ed8e77SXin LI coder->index_decoder.coder, 23573ed8e77SXin LI allocator, in, in_pos, in_size, 23673ed8e77SXin LI NULL, NULL, 0, LZMA_RUN); 23773ed8e77SXin LI 23873ed8e77SXin LI coder->index_remaining -= *in_pos - in_start; 23973ed8e77SXin LI 24073ed8e77SXin LI if (update_file_cur_pos) 24173ed8e77SXin LI coder->file_cur_pos += *in_pos - in_start; 24273ed8e77SXin LI 24373ed8e77SXin LI return ret; 24473ed8e77SXin LI } 24573ed8e77SXin LI 24673ed8e77SXin LI 24773ed8e77SXin LI static lzma_ret 24873ed8e77SXin LI file_info_decode(void *coder_ptr, const lzma_allocator *allocator, 24973ed8e77SXin LI const uint8_t *restrict in, size_t *restrict in_pos, 25073ed8e77SXin LI size_t in_size, 25173ed8e77SXin LI uint8_t *restrict out lzma_attribute((__unused__)), 25273ed8e77SXin LI size_t *restrict out_pos lzma_attribute((__unused__)), 25373ed8e77SXin LI size_t out_size lzma_attribute((__unused__)), 25473ed8e77SXin LI lzma_action action lzma_attribute((__unused__))) 25573ed8e77SXin LI { 25673ed8e77SXin LI lzma_file_info_coder *coder = coder_ptr; 25773ed8e77SXin LI const size_t in_start = *in_pos; 25873ed8e77SXin LI 25973ed8e77SXin LI // If the caller provides input past the end of the file, trim 26073ed8e77SXin LI // the extra bytes from the buffer so that we won't read too far. 26173ed8e77SXin LI assert(coder->file_size >= coder->file_cur_pos); 26273ed8e77SXin LI if (coder->file_size - coder->file_cur_pos < in_size - in_start) 26373ed8e77SXin LI in_size = in_start 26473ed8e77SXin LI + (size_t)(coder->file_size - coder->file_cur_pos); 26573ed8e77SXin LI 26673ed8e77SXin LI while (true) 26773ed8e77SXin LI switch (coder->sequence) { 26873ed8e77SXin LI case SEQ_MAGIC_BYTES: 26973ed8e77SXin LI // Decode the Stream Header at the beginning of the file 27073ed8e77SXin LI // first to check if the Magic Bytes match. The flags 27173ed8e77SXin LI // are stored in coder->first_header_flags so that we 27273ed8e77SXin LI // don't need to seek to it again. 27373ed8e77SXin LI // 27473ed8e77SXin LI // Check that the file is big enough to contain at least 27573ed8e77SXin LI // Stream Header. 27673ed8e77SXin LI if (coder->file_size < LZMA_STREAM_HEADER_SIZE) 27773ed8e77SXin LI return LZMA_FORMAT_ERROR; 27873ed8e77SXin LI 27973ed8e77SXin LI // Read the Stream Header field into coder->temp. 28073ed8e77SXin LI if (fill_temp(coder, in, in_pos, in_size)) 28173ed8e77SXin LI return LZMA_OK; 28273ed8e77SXin LI 28373ed8e77SXin LI // This is the only Stream Header/Footer decoding where we 28473ed8e77SXin LI // want to return LZMA_FORMAT_ERROR if the Magic Bytes don't 28573ed8e77SXin LI // match. Elsewhere it will be converted to LZMA_DATA_ERROR. 28673ed8e77SXin LI return_if_error(lzma_stream_header_decode( 28773ed8e77SXin LI &coder->first_header_flags, coder->temp)); 28873ed8e77SXin LI 28973ed8e77SXin LI // Now that we know that the Magic Bytes match, check the 29073ed8e77SXin LI // file size. It's better to do this here after checking the 29173ed8e77SXin LI // Magic Bytes since this way we can give LZMA_FORMAT_ERROR 29273ed8e77SXin LI // instead of LZMA_DATA_ERROR when the Magic Bytes don't 29373ed8e77SXin LI // match in a file that is too big or isn't a multiple of 29473ed8e77SXin LI // four bytes. 29573ed8e77SXin LI if (coder->file_size > LZMA_VLI_MAX || (coder->file_size & 3)) 29673ed8e77SXin LI return LZMA_DATA_ERROR; 29773ed8e77SXin LI 29873ed8e77SXin LI // Start looking for Stream Padding and Stream Footer 29973ed8e77SXin LI // at the end of the file. 30073ed8e77SXin LI coder->file_target_pos = coder->file_size; 30173ed8e77SXin LI 30273ed8e77SXin LI // Fall through 30373ed8e77SXin LI 30473ed8e77SXin LI case SEQ_PADDING_SEEK: 30573ed8e77SXin LI coder->sequence = SEQ_PADDING_DECODE; 30673ed8e77SXin LI return_if_error(reverse_seek( 30773ed8e77SXin LI coder, in_start, in_pos, in_size)); 30873ed8e77SXin LI 30973ed8e77SXin LI // Fall through 31073ed8e77SXin LI 31173ed8e77SXin LI case SEQ_PADDING_DECODE: { 31273ed8e77SXin LI // Copy to coder->temp first. This keeps the code simpler if 31373ed8e77SXin LI // the application only provides input a few bytes at a time. 31473ed8e77SXin LI if (fill_temp(coder, in, in_pos, in_size)) 31573ed8e77SXin LI return LZMA_OK; 31673ed8e77SXin LI 31773ed8e77SXin LI // Scan the buffer backwards to get the size of the 31873ed8e77SXin LI // Stream Padding field (if any). 31973ed8e77SXin LI const size_t new_padding = get_padding_size( 32073ed8e77SXin LI coder->temp, coder->temp_size); 32173ed8e77SXin LI coder->stream_padding += new_padding; 32273ed8e77SXin LI 32373ed8e77SXin LI // Set the target position to the beginning of Stream Padding 32473ed8e77SXin LI // that has been observed so far. If all Stream Padding has 32573ed8e77SXin LI // been seen, then the target position will be at the end 32673ed8e77SXin LI // of the Stream Footer field. 32773ed8e77SXin LI coder->file_target_pos -= new_padding; 32873ed8e77SXin LI 32973ed8e77SXin LI if (new_padding == coder->temp_size) { 33073ed8e77SXin LI // The whole buffer was padding. Seek backwards in 33173ed8e77SXin LI // the file to get more input. 33273ed8e77SXin LI coder->sequence = SEQ_PADDING_SEEK; 33373ed8e77SXin LI break; 33473ed8e77SXin LI } 33573ed8e77SXin LI 33673ed8e77SXin LI // Size of Stream Padding must be a multiple of 4 bytes. 33773ed8e77SXin LI if (coder->stream_padding & 3) 33873ed8e77SXin LI return LZMA_DATA_ERROR; 33973ed8e77SXin LI 34073ed8e77SXin LI coder->sequence = SEQ_FOOTER; 34173ed8e77SXin LI 34273ed8e77SXin LI // Calculate the amount of non-padding data in coder->temp. 34373ed8e77SXin LI coder->temp_size -= new_padding; 34473ed8e77SXin LI coder->temp_pos = coder->temp_size; 34573ed8e77SXin LI 34673ed8e77SXin LI // We can avoid an external seek if the whole Stream Footer 34773ed8e77SXin LI // is already in coder->temp. In that case SEQ_FOOTER won't 34873ed8e77SXin LI // read more input and will find the Stream Footer from 34973ed8e77SXin LI // coder->temp[coder->temp_size - LZMA_STREAM_HEADER_SIZE]. 35073ed8e77SXin LI // 35173ed8e77SXin LI // Otherwise we will need to seek. The seeking is done so 3521f3ced26SXin LI // that Stream Footer will be at the end of coder->temp. 35373ed8e77SXin LI // This way it's likely that we also get a complete Index 35473ed8e77SXin LI // field into coder->temp without needing a separate seek 35573ed8e77SXin LI // for that (unless the Index field is big). 35673ed8e77SXin LI if (coder->temp_size < LZMA_STREAM_HEADER_SIZE) 35773ed8e77SXin LI return_if_error(reverse_seek( 35873ed8e77SXin LI coder, in_start, in_pos, in_size)); 35973ed8e77SXin LI } 36073ed8e77SXin LI 36173ed8e77SXin LI // Fall through 36273ed8e77SXin LI 36373ed8e77SXin LI case SEQ_FOOTER: 36473ed8e77SXin LI // Copy the Stream Footer field into coder->temp. 36573ed8e77SXin LI // If Stream Footer was already available in coder->temp 36673ed8e77SXin LI // in SEQ_PADDING_DECODE, then this does nothing. 36773ed8e77SXin LI if (fill_temp(coder, in, in_pos, in_size)) 36873ed8e77SXin LI return LZMA_OK; 36973ed8e77SXin LI 37073ed8e77SXin LI // Make coder->file_target_pos and coder->temp_size point 37173ed8e77SXin LI // to the beginning of Stream Footer and thus to the end 37273ed8e77SXin LI // of the Index field. coder->temp_pos will be updated 37373ed8e77SXin LI // a bit later. 37473ed8e77SXin LI coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE; 37573ed8e77SXin LI coder->temp_size -= LZMA_STREAM_HEADER_SIZE; 37673ed8e77SXin LI 37773ed8e77SXin LI // Decode Stream Footer. 37873ed8e77SXin LI return_if_error(hide_format_error(lzma_stream_footer_decode( 37973ed8e77SXin LI &coder->footer_flags, 38073ed8e77SXin LI coder->temp + coder->temp_size))); 38173ed8e77SXin LI 38273ed8e77SXin LI // Check that we won't seek past the beginning of the file. 38373ed8e77SXin LI // 38473ed8e77SXin LI // LZMA_STREAM_HEADER_SIZE is added because there must be 38573ed8e77SXin LI // space for Stream Header too even though we won't seek 38673ed8e77SXin LI // there before decoding the Index field. 38773ed8e77SXin LI // 38873ed8e77SXin LI // There's no risk of integer overflow here because 38973ed8e77SXin LI // Backward Size cannot be greater than 2^34. 39073ed8e77SXin LI if (coder->file_target_pos < coder->footer_flags.backward_size 39173ed8e77SXin LI + LZMA_STREAM_HEADER_SIZE) 39273ed8e77SXin LI return LZMA_DATA_ERROR; 39373ed8e77SXin LI 39473ed8e77SXin LI // Set the target position to the beginning of the Index field. 39573ed8e77SXin LI coder->file_target_pos -= coder->footer_flags.backward_size; 39673ed8e77SXin LI coder->sequence = SEQ_INDEX_INIT; 39773ed8e77SXin LI 39873ed8e77SXin LI // We can avoid an external seek if the whole Index field is 39973ed8e77SXin LI // already available in coder->temp. 40073ed8e77SXin LI if (coder->temp_size >= coder->footer_flags.backward_size) { 40173ed8e77SXin LI // Set coder->temp_pos to point to the beginning 40273ed8e77SXin LI // of the Index. 40373ed8e77SXin LI coder->temp_pos = coder->temp_size 40473ed8e77SXin LI - coder->footer_flags.backward_size; 40573ed8e77SXin LI } else { 40673ed8e77SXin LI // These are set to zero to indicate that there's no 40773ed8e77SXin LI // useful data (Index or anything else) in coder->temp. 40873ed8e77SXin LI coder->temp_pos = 0; 40973ed8e77SXin LI coder->temp_size = 0; 41073ed8e77SXin LI 41173ed8e77SXin LI // Seek to the beginning of the Index field. 41273ed8e77SXin LI if (seek_to_pos(coder, coder->file_target_pos, 41373ed8e77SXin LI in_start, in_pos, in_size)) 41473ed8e77SXin LI return LZMA_SEEK_NEEDED; 41573ed8e77SXin LI } 41673ed8e77SXin LI 41773ed8e77SXin LI // Fall through 41873ed8e77SXin LI 41973ed8e77SXin LI case SEQ_INDEX_INIT: { 42073ed8e77SXin LI // Calculate the amount of memory already used by the earlier 42173ed8e77SXin LI // Indexes so that we know how big memory limit to pass to 42273ed8e77SXin LI // the Index decoder. 42373ed8e77SXin LI // 42473ed8e77SXin LI // NOTE: When there are multiple Streams, the separate 42573ed8e77SXin LI // lzma_index structures can use more RAM (as measured by 42673ed8e77SXin LI // lzma_index_memused()) than the final combined lzma_index. 42773ed8e77SXin LI // Thus memlimit may need to be slightly higher than the final 42873ed8e77SXin LI // calculated memory usage will be. This is perhaps a bit 42973ed8e77SXin LI // confusing to the application, but I think it shouldn't 43073ed8e77SXin LI // cause problems in practice. 43173ed8e77SXin LI uint64_t memused = 0; 43273ed8e77SXin LI if (coder->combined_index != NULL) { 43373ed8e77SXin LI memused = lzma_index_memused(coder->combined_index); 43473ed8e77SXin LI assert(memused <= coder->memlimit); 43573ed8e77SXin LI if (memused > coder->memlimit) // Extra sanity check 43673ed8e77SXin LI return LZMA_PROG_ERROR; 43773ed8e77SXin LI } 43873ed8e77SXin LI 43973ed8e77SXin LI // Initialize the Index decoder. 44073ed8e77SXin LI return_if_error(lzma_index_decoder_init( 44173ed8e77SXin LI &coder->index_decoder, allocator, 44273ed8e77SXin LI &coder->this_index, 44373ed8e77SXin LI coder->memlimit - memused)); 44473ed8e77SXin LI 44573ed8e77SXin LI coder->index_remaining = coder->footer_flags.backward_size; 44673ed8e77SXin LI coder->sequence = SEQ_INDEX_DECODE; 44773ed8e77SXin LI } 44873ed8e77SXin LI 44973ed8e77SXin LI // Fall through 45073ed8e77SXin LI 45173ed8e77SXin LI case SEQ_INDEX_DECODE: { 45273ed8e77SXin LI // Decode (a part of) the Index. If the whole Index is already 45373ed8e77SXin LI // in coder->temp, read it from there. Otherwise read from 45473ed8e77SXin LI // in[*in_pos] onwards. Note that index_decode() updates 45573ed8e77SXin LI // coder->index_remaining and optionally coder->file_cur_pos. 45673ed8e77SXin LI lzma_ret ret; 45773ed8e77SXin LI if (coder->temp_size != 0) { 45873ed8e77SXin LI assert(coder->temp_size - coder->temp_pos 45973ed8e77SXin LI == coder->index_remaining); 46073ed8e77SXin LI ret = decode_index(coder, allocator, coder->temp, 46173ed8e77SXin LI &coder->temp_pos, coder->temp_size, 46273ed8e77SXin LI false); 46373ed8e77SXin LI } else { 46473ed8e77SXin LI // Don't give the decoder more input than the known 46573ed8e77SXin LI // remaining size of the Index field. 46673ed8e77SXin LI size_t in_stop = in_size; 46773ed8e77SXin LI if (in_size - *in_pos > coder->index_remaining) 46873ed8e77SXin LI in_stop = *in_pos 46973ed8e77SXin LI + (size_t)(coder->index_remaining); 47073ed8e77SXin LI 47173ed8e77SXin LI ret = decode_index(coder, allocator, 47273ed8e77SXin LI in, in_pos, in_stop, true); 47373ed8e77SXin LI } 47473ed8e77SXin LI 47573ed8e77SXin LI switch (ret) { 47673ed8e77SXin LI case LZMA_OK: 47773ed8e77SXin LI // If the Index docoder asks for more input when we 47873ed8e77SXin LI // have already given it as much input as Backward Size 47973ed8e77SXin LI // indicated, the file is invalid. 48073ed8e77SXin LI if (coder->index_remaining == 0) 48173ed8e77SXin LI return LZMA_DATA_ERROR; 48273ed8e77SXin LI 48373ed8e77SXin LI // We cannot get here if we were reading Index from 48473ed8e77SXin LI // coder->temp because when reading from coder->temp 48573ed8e77SXin LI // we give the Index decoder exactly 48673ed8e77SXin LI // coder->index_remaining bytes of input. 48773ed8e77SXin LI assert(coder->temp_size == 0); 48873ed8e77SXin LI 48973ed8e77SXin LI return LZMA_OK; 49073ed8e77SXin LI 49173ed8e77SXin LI case LZMA_STREAM_END: 49273ed8e77SXin LI // If the decoding seems to be successful, check also 49373ed8e77SXin LI // that the Index decoder consumed as much input as 49473ed8e77SXin LI // indicated by the Backward Size field. 49573ed8e77SXin LI if (coder->index_remaining != 0) 49673ed8e77SXin LI return LZMA_DATA_ERROR; 49773ed8e77SXin LI 49873ed8e77SXin LI break; 49973ed8e77SXin LI 50073ed8e77SXin LI default: 50173ed8e77SXin LI return ret; 50273ed8e77SXin LI } 50373ed8e77SXin LI 50473ed8e77SXin LI // Calculate how much the Index tells us to seek backwards 50573ed8e77SXin LI // (relative to the beginning of the Index): Total size of 50673ed8e77SXin LI // all Blocks plus the size of the Stream Header field. 50773ed8e77SXin LI // No integer overflow here because lzma_index_total_size() 50873ed8e77SXin LI // cannot return a value greater than LZMA_VLI_MAX. 50973ed8e77SXin LI const uint64_t seek_amount 51073ed8e77SXin LI = lzma_index_total_size(coder->this_index) 51173ed8e77SXin LI + LZMA_STREAM_HEADER_SIZE; 51273ed8e77SXin LI 51373ed8e77SXin LI // Check that Index is sane in sense that seek_amount won't 51473ed8e77SXin LI // make us seek past the beginning of the file when locating 51573ed8e77SXin LI // the Stream Header. 51673ed8e77SXin LI // 51773ed8e77SXin LI // coder->file_target_pos still points to the beginning of 51873ed8e77SXin LI // the Index field. 51973ed8e77SXin LI if (coder->file_target_pos < seek_amount) 52073ed8e77SXin LI return LZMA_DATA_ERROR; 52173ed8e77SXin LI 52273ed8e77SXin LI // Set the target to the beginning of Stream Header. 52373ed8e77SXin LI coder->file_target_pos -= seek_amount; 52473ed8e77SXin LI 52573ed8e77SXin LI if (coder->file_target_pos == 0) { 52673ed8e77SXin LI // We would seek to the beginning of the file, but 52773ed8e77SXin LI // since we already decoded that Stream Header in 52873ed8e77SXin LI // SEQ_MAGIC_BYTES, we can use the cached value from 52973ed8e77SXin LI // coder->first_header_flags to avoid the seek. 53073ed8e77SXin LI coder->header_flags = coder->first_header_flags; 53173ed8e77SXin LI coder->sequence = SEQ_HEADER_COMPARE; 53273ed8e77SXin LI break; 53373ed8e77SXin LI } 53473ed8e77SXin LI 53573ed8e77SXin LI coder->sequence = SEQ_HEADER_DECODE; 53673ed8e77SXin LI 53773ed8e77SXin LI // Make coder->file_target_pos point to the end of 53873ed8e77SXin LI // the Stream Header field. 53973ed8e77SXin LI coder->file_target_pos += LZMA_STREAM_HEADER_SIZE; 54073ed8e77SXin LI 54173ed8e77SXin LI // If coder->temp_size is non-zero, it points to the end 54273ed8e77SXin LI // of the Index field. Then the beginning of the Index 54373ed8e77SXin LI // field is at coder->temp[coder->temp_size 54473ed8e77SXin LI // - coder->footer_flags.backward_size]. 54573ed8e77SXin LI assert(coder->temp_size == 0 || coder->temp_size 54673ed8e77SXin LI >= coder->footer_flags.backward_size); 54773ed8e77SXin LI 54873ed8e77SXin LI // If coder->temp contained the whole Index, see if it has 54973ed8e77SXin LI // enough data to contain also the Stream Header. If so, 55073ed8e77SXin LI // we avoid an external seek. 55173ed8e77SXin LI // 55273ed8e77SXin LI // NOTE: This can happen only with small .xz files and only 55373ed8e77SXin LI // for the non-first Stream as the Stream Flags of the first 55473ed8e77SXin LI // Stream are cached and already handled a few lines above. 55573ed8e77SXin LI // So this isn't as useful as the other seek-avoidance cases. 55673ed8e77SXin LI if (coder->temp_size != 0 && coder->temp_size 55773ed8e77SXin LI - coder->footer_flags.backward_size 55873ed8e77SXin LI >= seek_amount) { 55973ed8e77SXin LI // Make temp_pos and temp_size point to the *end* of 56073ed8e77SXin LI // Stream Header so that SEQ_HEADER_DECODE will find 56173ed8e77SXin LI // the start of Stream Header from coder->temp[ 56273ed8e77SXin LI // coder->temp_size - LZMA_STREAM_HEADER_SIZE]. 56373ed8e77SXin LI coder->temp_pos = coder->temp_size 56473ed8e77SXin LI - coder->footer_flags.backward_size 56573ed8e77SXin LI - seek_amount 56673ed8e77SXin LI + LZMA_STREAM_HEADER_SIZE; 56773ed8e77SXin LI coder->temp_size = coder->temp_pos; 56873ed8e77SXin LI } else { 56973ed8e77SXin LI // Seek so that Stream Header will be at the end of 57073ed8e77SXin LI // coder->temp. With typical multi-Stream files we 57173ed8e77SXin LI // will usually also get the Stream Footer and Index 57273ed8e77SXin LI // of the *previous* Stream in coder->temp and thus 57373ed8e77SXin LI // won't need a separate seek for them. 57473ed8e77SXin LI return_if_error(reverse_seek(coder, 57573ed8e77SXin LI in_start, in_pos, in_size)); 57673ed8e77SXin LI } 57773ed8e77SXin LI } 57873ed8e77SXin LI 57973ed8e77SXin LI // Fall through 58073ed8e77SXin LI 58173ed8e77SXin LI case SEQ_HEADER_DECODE: 58273ed8e77SXin LI // Copy the Stream Header field into coder->temp. 58373ed8e77SXin LI // If Stream Header was already available in coder->temp 58473ed8e77SXin LI // in SEQ_INDEX_DECODE, then this does nothing. 58573ed8e77SXin LI if (fill_temp(coder, in, in_pos, in_size)) 58673ed8e77SXin LI return LZMA_OK; 58773ed8e77SXin LI 58873ed8e77SXin LI // Make all these point to the beginning of Stream Header. 58973ed8e77SXin LI coder->file_target_pos -= LZMA_STREAM_HEADER_SIZE; 59073ed8e77SXin LI coder->temp_size -= LZMA_STREAM_HEADER_SIZE; 59173ed8e77SXin LI coder->temp_pos = coder->temp_size; 59273ed8e77SXin LI 59373ed8e77SXin LI // Decode the Stream Header. 59473ed8e77SXin LI return_if_error(hide_format_error(lzma_stream_header_decode( 59573ed8e77SXin LI &coder->header_flags, 59673ed8e77SXin LI coder->temp + coder->temp_size))); 59773ed8e77SXin LI 59873ed8e77SXin LI coder->sequence = SEQ_HEADER_COMPARE; 59973ed8e77SXin LI 60073ed8e77SXin LI // Fall through 60173ed8e77SXin LI 60273ed8e77SXin LI case SEQ_HEADER_COMPARE: 60373ed8e77SXin LI // Compare Stream Header against Stream Footer. They must 60473ed8e77SXin LI // match. 60573ed8e77SXin LI return_if_error(lzma_stream_flags_compare( 60673ed8e77SXin LI &coder->header_flags, &coder->footer_flags)); 60773ed8e77SXin LI 60873ed8e77SXin LI // Store the decoded Stream Flags into the Index. Use the 60973ed8e77SXin LI // Footer Flags because it contains Backward Size, although 61073ed8e77SXin LI // it shouldn't matter in practice. 61173ed8e77SXin LI if (lzma_index_stream_flags(coder->this_index, 61273ed8e77SXin LI &coder->footer_flags) != LZMA_OK) 61373ed8e77SXin LI return LZMA_PROG_ERROR; 61473ed8e77SXin LI 61573ed8e77SXin LI // Store also the size of the Stream Padding field. It is 61673ed8e77SXin LI // needed to calculate the offsets of the Streams correctly. 61773ed8e77SXin LI if (lzma_index_stream_padding(coder->this_index, 61873ed8e77SXin LI coder->stream_padding) != LZMA_OK) 61973ed8e77SXin LI return LZMA_PROG_ERROR; 62073ed8e77SXin LI 62173ed8e77SXin LI // Reset it so that it's ready for the next Stream. 62273ed8e77SXin LI coder->stream_padding = 0; 62373ed8e77SXin LI 62473ed8e77SXin LI // Append the earlier decoded Indexes after this_index. 62573ed8e77SXin LI if (coder->combined_index != NULL) 62673ed8e77SXin LI return_if_error(lzma_index_cat(coder->this_index, 62773ed8e77SXin LI coder->combined_index, allocator)); 62873ed8e77SXin LI 62973ed8e77SXin LI coder->combined_index = coder->this_index; 63073ed8e77SXin LI coder->this_index = NULL; 63173ed8e77SXin LI 63273ed8e77SXin LI // If the whole file was decoded, tell the caller that we 63373ed8e77SXin LI // are finished. 63473ed8e77SXin LI if (coder->file_target_pos == 0) { 63573ed8e77SXin LI // The combined index must indicate the same file 63673ed8e77SXin LI // size as was told to us at initialization. 63773ed8e77SXin LI assert(lzma_index_file_size(coder->combined_index) 63873ed8e77SXin LI == coder->file_size); 63973ed8e77SXin LI 64073ed8e77SXin LI // Make the combined index available to 64173ed8e77SXin LI // the application. 64273ed8e77SXin LI *coder->dest_index = coder->combined_index; 64373ed8e77SXin LI coder->combined_index = NULL; 64473ed8e77SXin LI 64573ed8e77SXin LI // Mark the input buffer as used since we may have 64673ed8e77SXin LI // done internal seeking and thus don't know how 64773ed8e77SXin LI // many input bytes were actually used. This way 64873ed8e77SXin LI // lzma_stream.total_in gets a slightly better 64973ed8e77SXin LI // estimate of the amount of input used. 65073ed8e77SXin LI *in_pos = in_size; 65173ed8e77SXin LI return LZMA_STREAM_END; 65273ed8e77SXin LI } 65373ed8e77SXin LI 65473ed8e77SXin LI // We didn't hit the beginning of the file yet, so continue 65573ed8e77SXin LI // reading backwards in the file. If we have unprocessed 65673ed8e77SXin LI // data in coder->temp, use it before requesting more data 65773ed8e77SXin LI // from the application. 65873ed8e77SXin LI // 65973ed8e77SXin LI // coder->file_target_pos, coder->temp_size, and 66073ed8e77SXin LI // coder->temp_pos all point to the beginning of Stream Header 66173ed8e77SXin LI // and thus the end of the previous Stream in the file. 66273ed8e77SXin LI coder->sequence = coder->temp_size > 0 66373ed8e77SXin LI ? SEQ_PADDING_DECODE : SEQ_PADDING_SEEK; 66473ed8e77SXin LI break; 66573ed8e77SXin LI 66673ed8e77SXin LI default: 66773ed8e77SXin LI assert(0); 66873ed8e77SXin LI return LZMA_PROG_ERROR; 66973ed8e77SXin LI } 67073ed8e77SXin LI } 67173ed8e77SXin LI 67273ed8e77SXin LI 67373ed8e77SXin LI static lzma_ret 67473ed8e77SXin LI file_info_decoder_memconfig(void *coder_ptr, uint64_t *memusage, 67573ed8e77SXin LI uint64_t *old_memlimit, uint64_t new_memlimit) 67673ed8e77SXin LI { 67773ed8e77SXin LI lzma_file_info_coder *coder = coder_ptr; 67873ed8e77SXin LI 67973ed8e77SXin LI // The memory usage calculation comes from three things: 68073ed8e77SXin LI // 68173ed8e77SXin LI // (1) The Indexes that have already been decoded and processed into 68273ed8e77SXin LI // coder->combined_index. 68373ed8e77SXin LI // 68473ed8e77SXin LI // (2) The latest Index in coder->this_index that has been decoded but 68573ed8e77SXin LI // not yet put into coder->combined_index. 68673ed8e77SXin LI // 68773ed8e77SXin LI // (3) The latest Index that we have started decoding but haven't 68873ed8e77SXin LI // finished and thus isn't available in coder->this_index yet. 68973ed8e77SXin LI // Memory usage and limit information needs to be communicated 69073ed8e77SXin LI // from/to coder->index_decoder. 69173ed8e77SXin LI // 69273ed8e77SXin LI // Care has to be taken to not do both (2) and (3) when calculating 69373ed8e77SXin LI // the memory usage. 69473ed8e77SXin LI uint64_t combined_index_memusage = 0; 69573ed8e77SXin LI uint64_t this_index_memusage = 0; 69673ed8e77SXin LI 69773ed8e77SXin LI // (1) If we have already successfully decoded one or more Indexes, 69873ed8e77SXin LI // get their memory usage. 69973ed8e77SXin LI if (coder->combined_index != NULL) 70073ed8e77SXin LI combined_index_memusage = lzma_index_memused( 70173ed8e77SXin LI coder->combined_index); 70273ed8e77SXin LI 70373ed8e77SXin LI // Choose between (2), (3), or neither. 70473ed8e77SXin LI if (coder->this_index != NULL) { 70573ed8e77SXin LI // (2) The latest Index is available. Use its memory usage. 70673ed8e77SXin LI this_index_memusage = lzma_index_memused(coder->this_index); 70773ed8e77SXin LI 70873ed8e77SXin LI } else if (coder->sequence == SEQ_INDEX_DECODE) { 70973ed8e77SXin LI // (3) The Index decoder is activate and hasn't yet stored 71073ed8e77SXin LI // the new index in coder->this_index. Get the memory usage 71173ed8e77SXin LI // information from the Index decoder. 71273ed8e77SXin LI // 71373ed8e77SXin LI // NOTE: If the Index decoder doesn't yet know how much memory 71473ed8e77SXin LI // it will eventually need, it will return a tiny value here. 71573ed8e77SXin LI uint64_t dummy; 71673ed8e77SXin LI if (coder->index_decoder.memconfig(coder->index_decoder.coder, 71773ed8e77SXin LI &this_index_memusage, &dummy, 0) 71873ed8e77SXin LI != LZMA_OK) { 71973ed8e77SXin LI assert(0); 72073ed8e77SXin LI return LZMA_PROG_ERROR; 72173ed8e77SXin LI } 72273ed8e77SXin LI } 72373ed8e77SXin LI 72473ed8e77SXin LI // Now we know the total memory usage/requirement. If we had neither 72573ed8e77SXin LI // old Indexes nor a new Index, this will be zero which isn't 72673ed8e77SXin LI // acceptable as lzma_memusage() has to return non-zero on success 72773ed8e77SXin LI // and even with an empty .xz file we will end up with a lzma_index 72873ed8e77SXin LI // that takes some memory. 72973ed8e77SXin LI *memusage = combined_index_memusage + this_index_memusage; 73073ed8e77SXin LI if (*memusage == 0) 73173ed8e77SXin LI *memusage = lzma_index_memusage(1, 0); 73273ed8e77SXin LI 73373ed8e77SXin LI *old_memlimit = coder->memlimit; 73473ed8e77SXin LI 73573ed8e77SXin LI // If requested, set a new memory usage limit. 73673ed8e77SXin LI if (new_memlimit != 0) { 73773ed8e77SXin LI if (new_memlimit < *memusage) 73873ed8e77SXin LI return LZMA_MEMLIMIT_ERROR; 73973ed8e77SXin LI 74073ed8e77SXin LI // In the condition (3) we need to tell the Index decoder 74173ed8e77SXin LI // its new memory usage limit. 74273ed8e77SXin LI if (coder->this_index == NULL 74373ed8e77SXin LI && coder->sequence == SEQ_INDEX_DECODE) { 74473ed8e77SXin LI const uint64_t idec_new_memlimit = new_memlimit 74573ed8e77SXin LI - combined_index_memusage; 74673ed8e77SXin LI 74773ed8e77SXin LI assert(this_index_memusage > 0); 74873ed8e77SXin LI assert(idec_new_memlimit > 0); 74973ed8e77SXin LI 75073ed8e77SXin LI uint64_t dummy1; 75173ed8e77SXin LI uint64_t dummy2; 75273ed8e77SXin LI 75373ed8e77SXin LI if (coder->index_decoder.memconfig( 75473ed8e77SXin LI coder->index_decoder.coder, 75573ed8e77SXin LI &dummy1, &dummy2, idec_new_memlimit) 75673ed8e77SXin LI != LZMA_OK) { 75773ed8e77SXin LI assert(0); 75873ed8e77SXin LI return LZMA_PROG_ERROR; 75973ed8e77SXin LI } 76073ed8e77SXin LI } 76173ed8e77SXin LI 76273ed8e77SXin LI coder->memlimit = new_memlimit; 76373ed8e77SXin LI } 76473ed8e77SXin LI 76573ed8e77SXin LI return LZMA_OK; 76673ed8e77SXin LI } 76773ed8e77SXin LI 76873ed8e77SXin LI 76973ed8e77SXin LI static void 77073ed8e77SXin LI file_info_decoder_end(void *coder_ptr, const lzma_allocator *allocator) 77173ed8e77SXin LI { 77273ed8e77SXin LI lzma_file_info_coder *coder = coder_ptr; 77373ed8e77SXin LI 77473ed8e77SXin LI lzma_next_end(&coder->index_decoder, allocator); 77573ed8e77SXin LI lzma_index_end(coder->this_index, allocator); 77673ed8e77SXin LI lzma_index_end(coder->combined_index, allocator); 77773ed8e77SXin LI 77873ed8e77SXin LI lzma_free(coder, allocator); 77973ed8e77SXin LI return; 78073ed8e77SXin LI } 78173ed8e77SXin LI 78273ed8e77SXin LI 78373ed8e77SXin LI static lzma_ret 78473ed8e77SXin LI lzma_file_info_decoder_init(lzma_next_coder *next, 78573ed8e77SXin LI const lzma_allocator *allocator, uint64_t *seek_pos, 78673ed8e77SXin LI lzma_index **dest_index, 78773ed8e77SXin LI uint64_t memlimit, uint64_t file_size) 78873ed8e77SXin LI { 78973ed8e77SXin LI lzma_next_coder_init(&lzma_file_info_decoder_init, next, allocator); 79073ed8e77SXin LI 79173ed8e77SXin LI if (dest_index == NULL) 79273ed8e77SXin LI return LZMA_PROG_ERROR; 79373ed8e77SXin LI 79473ed8e77SXin LI lzma_file_info_coder *coder = next->coder; 79573ed8e77SXin LI if (coder == NULL) { 79673ed8e77SXin LI coder = lzma_alloc(sizeof(lzma_file_info_coder), allocator); 79773ed8e77SXin LI if (coder == NULL) 79873ed8e77SXin LI return LZMA_MEM_ERROR; 79973ed8e77SXin LI 80073ed8e77SXin LI next->coder = coder; 80173ed8e77SXin LI next->code = &file_info_decode; 80273ed8e77SXin LI next->end = &file_info_decoder_end; 80373ed8e77SXin LI next->memconfig = &file_info_decoder_memconfig; 80473ed8e77SXin LI 80573ed8e77SXin LI coder->index_decoder = LZMA_NEXT_CODER_INIT; 80673ed8e77SXin LI coder->this_index = NULL; 80773ed8e77SXin LI coder->combined_index = NULL; 80873ed8e77SXin LI } 80973ed8e77SXin LI 81073ed8e77SXin LI coder->sequence = SEQ_MAGIC_BYTES; 81173ed8e77SXin LI coder->file_cur_pos = 0; 81273ed8e77SXin LI coder->file_target_pos = 0; 81373ed8e77SXin LI coder->file_size = file_size; 81473ed8e77SXin LI 81573ed8e77SXin LI lzma_index_end(coder->this_index, allocator); 81673ed8e77SXin LI coder->this_index = NULL; 81773ed8e77SXin LI 81873ed8e77SXin LI lzma_index_end(coder->combined_index, allocator); 81973ed8e77SXin LI coder->combined_index = NULL; 82073ed8e77SXin LI 82173ed8e77SXin LI coder->stream_padding = 0; 82273ed8e77SXin LI 82373ed8e77SXin LI coder->dest_index = dest_index; 82473ed8e77SXin LI coder->external_seek_pos = seek_pos; 82573ed8e77SXin LI 82673ed8e77SXin LI // If memlimit is 0, make it 1 to ensure that lzma_memlimit_get() 82773ed8e77SXin LI // won't return 0 (which would indicate an error). 82873ed8e77SXin LI coder->memlimit = my_max(1, memlimit); 82973ed8e77SXin LI 83073ed8e77SXin LI // Prepare these for reading the first Stream Header into coder->temp. 83173ed8e77SXin LI coder->temp_pos = 0; 83273ed8e77SXin LI coder->temp_size = LZMA_STREAM_HEADER_SIZE; 83373ed8e77SXin LI 83473ed8e77SXin LI return LZMA_OK; 83573ed8e77SXin LI } 83673ed8e77SXin LI 83773ed8e77SXin LI 83873ed8e77SXin LI extern LZMA_API(lzma_ret) 83973ed8e77SXin LI lzma_file_info_decoder(lzma_stream *strm, lzma_index **dest_index, 84073ed8e77SXin LI uint64_t memlimit, uint64_t file_size) 84173ed8e77SXin LI { 84273ed8e77SXin LI lzma_next_strm_init(lzma_file_info_decoder_init, strm, &strm->seek_pos, 84373ed8e77SXin LI dest_index, memlimit, file_size); 84473ed8e77SXin LI 84573ed8e77SXin LI // We allow LZMA_FINISH in addition to LZMA_RUN for convenience. 84673ed8e77SXin LI // lzma_code() is able to handle the LZMA_FINISH + LZMA_SEEK_NEEDED 84773ed8e77SXin LI // combination in a sane way. Applications still need to be careful 84873ed8e77SXin LI // if they use LZMA_FINISH so that they remember to reset it back 84973ed8e77SXin LI // to LZMA_RUN after seeking if needed. 85073ed8e77SXin LI strm->internal->supported_actions[LZMA_RUN] = true; 85173ed8e77SXin LI strm->internal->supported_actions[LZMA_FINISH] = true; 85273ed8e77SXin LI 85373ed8e77SXin LI return LZMA_OK; 85473ed8e77SXin LI } 855