aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2017-04-24 19:48:23 +0300
committerLasse Collin <lasse.collin@tukaani.org>2017-04-24 19:48:23 +0300
commit8269782283806c90a8509c2ac2a308344f70e171 (patch)
tree0cc02f552eb974f7b12901eb757a4aa77212abd3
parentliblzma: Add lzma_file_info_decoder(). (diff)
downloadxz-8269782283806c90a8509c2ac2a308344f70e171.tar.xz
xz: Use lzma_file_info_decoder() for --list.
-rw-r--r--src/xz/list.c254
1 files changed, 44 insertions, 210 deletions
diff --git a/src/xz/list.c b/src/xz/list.c
index 449c2bc4..c297d2e3 100644
--- a/src/xz/list.c
+++ b/src/xz/list.c
@@ -143,9 +143,6 @@ xz_ver_to_str(uint32_t ver)
///
/// \return On success, false is returned. On error, true is returned.
///
-// TODO: This function is pretty big. liblzma should have a function that
-// takes a callback function to parse the Index(es) from a .xz file to make
-// it easy for applications.
static bool
parse_indexes(xz_file_info *xfi, file_pair *pair)
{
@@ -161,238 +158,75 @@ parse_indexes(xz_file_info *xfi, file_pair *pair)
}
io_buf buf;
- lzma_stream_flags header_flags;
- lzma_stream_flags footer_flags;
- lzma_ret ret;
-
- // lzma_stream for the Index decoder
lzma_stream strm = LZMA_STREAM_INIT;
+ lzma_index *idx = NULL;
- // All Indexes decoded so far
- lzma_index *combined_index = NULL;
-
- // The Index currently being decoded
- lzma_index *this_index = NULL;
-
- // Current position in the file. We parse the file backwards so
- // initialize it to point to the end of the file.
- off_t pos = pair->src_st.st_size;
-
- // Each loop iteration decodes one Index.
- do {
- // Check that there is enough data left to contain at least
- // the Stream Header and Stream Footer. This check cannot
- // fail in the first pass of this loop.
- if (pos < 2 * LZMA_STREAM_HEADER_SIZE) {
- message_error("%s: %s", pair->src_name,
- message_strm(LZMA_DATA_ERROR));
- goto error;
- }
-
- pos -= LZMA_STREAM_HEADER_SIZE;
- lzma_vli stream_padding = 0;
-
- // Locate the Stream Footer. There may be Stream Padding which
- // we must skip when reading backwards.
- while (true) {
- if (pos < LZMA_STREAM_HEADER_SIZE) {
- message_error("%s: %s", pair->src_name,
- message_strm(
- LZMA_DATA_ERROR));
- goto error;
- }
+ lzma_ret ret = lzma_file_info_decoder(&strm, &idx,
+ hardware_memlimit_get(MODE_LIST),
+ (uint64_t)(pair->src_st.st_size));
+ if (ret != LZMA_OK) {
+ message_error("%s: %s", pair->src_name, message_strm(ret));
+ return true;
+ }
- if (io_pread(pair, &buf,
- LZMA_STREAM_HEADER_SIZE, pos))
+ while (true) {
+ if (strm.avail_in == 0) {
+ strm.next_in = buf.u8;
+ strm.avail_in = io_read(pair, &buf, IO_BUFFER_SIZE);
+ if (strm.avail_in == SIZE_MAX)
goto error;
-
- // Stream Padding is always a multiple of four bytes.
- int i = 2;
- if (buf.u32[i] != 0)
- break;
-
- // To avoid calling io_pread() for every four bytes
- // of Stream Padding, take advantage that we read
- // 12 bytes (LZMA_STREAM_HEADER_SIZE) already and
- // check them too before calling io_pread() again.
- do {
- stream_padding += 4;
- pos -= 4;
- --i;
- } while (i >= 0 && buf.u32[i] == 0);
}
- // Decode the Stream Footer.
- ret = lzma_stream_footer_decode(&footer_flags, buf.u8);
- if (ret != LZMA_OK) {
- message_error("%s: %s", pair->src_name,
- message_strm(ret));
- goto error;
- }
+ ret = lzma_code(&strm, LZMA_RUN);
- // Check that the Stream Footer doesn't specify something
- // that we don't support. This can only happen if the xz
- // version is older than liblzma and liblzma supports
- // something new.
- //
- // It is enough to check Stream Footer. Stream Header must
- // match when it is compared against Stream Footer with
- // lzma_stream_flags_compare().
- if (footer_flags.version != 0) {
- message_error("%s: %s", pair->src_name,
- message_strm(LZMA_OPTIONS_ERROR));
- goto error;
- }
+ switch (ret) {
+ case LZMA_OK:
+ break;
- // Check that the size of the Index field looks sane.
- lzma_vli index_size = footer_flags.backward_size;
- if ((lzma_vli)(pos) < index_size + LZMA_STREAM_HEADER_SIZE) {
- message_error("%s: %s", pair->src_name,
- message_strm(LZMA_DATA_ERROR));
- goto error;
- }
+ case LZMA_SEEK_NEEDED:
+ // The cast is safe because liblzma won't ask us to
+ // seek past the known size of the input file which
+ // did fit into off_t.
+ assert(strm.seek_pos
+ <= (uint64_t)(pair->src_st.st_size));
+ if (io_seek_src(pair, (off_t)(strm.seek_pos)))
+ goto error;
- // Set pos to the beginning of the Index.
- pos -= index_size;
+ // avail_in must be zero so that we will read new
+ // input.
+ strm.avail_in = 0;
+ break;
- // See how much memory we can use for decoding this Index.
- uint64_t memlimit = hardware_memlimit_get(MODE_LIST);
- uint64_t memused = 0;
- if (combined_index != NULL) {
- memused = lzma_index_memused(combined_index);
- if (memused > memlimit)
- message_bug();
+ case LZMA_STREAM_END: {
+ lzma_end(&strm);
+ xfi->idx = idx;
- memlimit -= memused;
- }
+ // Calculate xfi->stream_padding.
+ lzma_index_iter iter;
+ lzma_index_iter_init(&iter, xfi->idx);
+ while (!lzma_index_iter_next(&iter,
+ LZMA_INDEX_ITER_STREAM))
+ xfi->stream_padding += iter.stream.padding;
- // Decode the Index.
- ret = lzma_index_decoder(&strm, &this_index, memlimit);
- if (ret != LZMA_OK) {
- message_error("%s: %s", pair->src_name,
- message_strm(ret));
- goto error;
+ return false;
}
- do {
- // Don't give the decoder more input than the
- // Index size.
- strm.avail_in = my_min(IO_BUFFER_SIZE, index_size);
- if (io_pread(pair, &buf, strm.avail_in, pos))
- goto error;
-
- pos += strm.avail_in;
- index_size -= strm.avail_in;
-
- strm.next_in = buf.u8;
- ret = lzma_code(&strm, LZMA_RUN);
-
- } while (ret == LZMA_OK);
-
- // If the decoding seems to be successful, check also that
- // the Index decoder consumed as much input as indicated
- // by the Backward Size field.
- if (ret == LZMA_STREAM_END)
- if (index_size != 0 || strm.avail_in != 0)
- ret = LZMA_DATA_ERROR;
-
- if (ret != LZMA_STREAM_END) {
- // LZMA_BUFFER_ERROR means that the Index decoder
- // would have liked more input than what the Index
- // size should be according to Stream Footer.
- // The message for LZMA_DATA_ERROR makes more
- // sense in that case.
- if (ret == LZMA_BUF_ERROR)
- ret = LZMA_DATA_ERROR;
-
+ default:
message_error("%s: %s", pair->src_name,
message_strm(ret));
// If the error was too low memory usage limit,
// show also how much memory would have been needed.
- if (ret == LZMA_MEMLIMIT_ERROR) {
- uint64_t needed = lzma_memusage(&strm);
- if (UINT64_MAX - needed < memused)
- needed = UINT64_MAX;
- else
- needed += memused;
-
- message_mem_needed(V_ERROR, needed);
- }
+ if (ret == LZMA_MEMLIMIT_ERROR)
+ message_mem_needed(V_ERROR,
+ lzma_memusage(&strm));
goto error;
}
-
- // Decode the Stream Header and check that its Stream Flags
- // match the Stream Footer.
- pos -= footer_flags.backward_size + LZMA_STREAM_HEADER_SIZE;
- if ((lzma_vli)(pos) < lzma_index_total_size(this_index)) {
- message_error("%s: %s", pair->src_name,
- message_strm(LZMA_DATA_ERROR));
- goto error;
- }
-
- pos -= lzma_index_total_size(this_index);
- if (io_pread(pair, &buf, LZMA_STREAM_HEADER_SIZE, pos))
- goto error;
-
- ret = lzma_stream_header_decode(&header_flags, buf.u8);
- if (ret != LZMA_OK) {
- message_error("%s: %s", pair->src_name,
- message_strm(ret));
- goto error;
- }
-
- ret = lzma_stream_flags_compare(&header_flags, &footer_flags);
- if (ret != LZMA_OK) {
- message_error("%s: %s", pair->src_name,
- message_strm(ret));
- goto error;
- }
-
- // Store the decoded Stream Flags into this_index. This is
- // needed so that we can print which Check is used in each
- // Stream.
- ret = lzma_index_stream_flags(this_index, &footer_flags);
- if (ret != LZMA_OK)
- message_bug();
-
- // Store also the size of the Stream Padding field. It is
- // needed to show the offsets of the Streams correctly.
- ret = lzma_index_stream_padding(this_index, stream_padding);
- if (ret != LZMA_OK)
- message_bug();
-
- if (combined_index != NULL) {
- // Append the earlier decoded Indexes
- // after this_index.
- ret = lzma_index_cat(
- this_index, combined_index, NULL);
- if (ret != LZMA_OK) {
- message_error("%s: %s", pair->src_name,
- message_strm(ret));
- goto error;
- }
- }
-
- combined_index = this_index;
- this_index = NULL;
-
- xfi->stream_padding += stream_padding;
-
- } while (pos > 0);
-
- lzma_end(&strm);
-
- // All OK. Make combined_index available to the caller.
- xfi->idx = combined_index;
- return false;
+ }
error:
- // Something went wrong, free the allocated memory.
lzma_end(&strm);
- lzma_index_end(combined_index, NULL);
- lzma_index_end(this_index, NULL);
return true;
}