static bool is_equal(const lzma_index *a, const lzma_index *b) { // Compare only the Stream and Block sizes and offsets. lzma_index_iter ra, rb; lzma_index_iter_init(&ra, a); lzma_index_iter_init(&rb, b); while (true) { bool reta = lzma_index_iter_next(&ra, LZMA_INDEX_ITER_ANY); bool retb = lzma_index_iter_next(&rb, LZMA_INDEX_ITER_ANY); if (reta) return !(reta ^ retb); if (ra.stream.number != rb.stream.number || ra.stream.block_count != rb.stream.block_count || ra.stream.compressed_offset != rb.stream.compressed_offset || ra.stream.uncompressed_offset != rb.stream.uncompressed_offset || ra.stream.compressed_size != rb.stream.compressed_size || ra.stream.uncompressed_size != rb.stream.uncompressed_size || ra.stream.padding != rb.stream.padding) return false; if (ra.stream.block_count == 0) continue; if (ra.block.number_in_file != rb.block.number_in_file || ra.block.compressed_file_offset != rb.block.compressed_file_offset || ra.block.uncompressed_file_offset != rb.block.uncompressed_file_offset || ra.block.number_in_stream != rb.block.number_in_stream || ra.block.compressed_stream_offset != rb.block.compressed_stream_offset || ra.block.uncompressed_stream_offset != rb.block.uncompressed_stream_offset || ra.block.uncompressed_size != rb.block.uncompressed_size || ra.block.unpadded_size != rb.block.unpadded_size || ra.block.total_size != rb.block.total_size) return false; } }
bool decodeFillBuffer(std::string &error) { for (;0 != strm.avail_out;) { LOG_VERBOSE("decodeFillBuffer: %i bytes to go\n", (int) strm.avail_out); if (!fill_input_buffer(error)) return false; if (0 == strm.avail_in) { error.assign("Unexpected end of file"); return false; } lzma_ret ret = lzma_code(&strm, LZMA_RUN); if (LZMA_OK != ret && LZMA_STREAM_END != ret) { errnoLzmaToStr("failed decoding data", ret, error); return false; } if (0 == strm.avail_out) return true; // done filling buffer if (LZMA_STREAM_END == ret) { if (lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY)) { error.assign("Unexepected end of file"); return false; } /* restart decoder */ if (!loadBlock(error)) return false; } } return true; }
bool decode(std::string &error) { assert(0 != strm.avail_out); const unsigned char *pos = strm.next_out; for (;;) { if (!fill_input_buffer(error)) return false; if (0 == strm.avail_in) { error.assign("Unexpected end of file"); return false; } lzma_ret ret = lzma_code(&strm, LZMA_RUN); if (LZMA_OK != ret && LZMA_STREAM_END != ret) { errnoLzmaToStr("failed decoding data", ret, error); return false; } if (LZMA_STREAM_END == ret && pos == strm.next_out) { /* end of stream AND we didn't get new data this round */ if (lzma_index_iter_next(&iter, LZMA_INDEX_ITER_ANY)) { error.assign("Unexepected end of file"); return false; } /* restart decoder */ if (!loadBlock(error)) return false; } else { return true; } } }
static void read_thread(void) { off_t offset = ftello(gInFile); wanted_t *w = gWantedFiles; lzma_index_iter iter; lzma_index_iter_init(&iter, gIndex); while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) { // Don't decode the file-index off_t boffset = iter.block.compressed_file_offset; size_t bsize = iter.block.total_size; if (gFileIndexOffset && boffset == gFileIndexOffset) continue; // Do we need this block? if (gWantedFiles && gExplicitFiles) { off_t uend = iter.block.uncompressed_file_offset + iter.block.uncompressed_size; if (!w || w->start >= uend) { debug("read: skip %llu", iter.block.number_in_file); continue; } for ( ; w && w->end < uend; w = w->next) ; } debug("read: want %llu", iter.block.number_in_file); // Seek if needed, and get the data if (offset != boffset) { fseeko(gInFile, boffset, SEEK_SET); offset = boffset; } if (iter.block.uncompressed_size > MAXSPLITSIZE) { // must stream if (gRbuf) rbuf_consume(gRbuf->insize); // clear read_block(true, iter.stream.flags->check, iter.block.uncompressed_file_offset); } else { // Get a block to work with pipeline_item_t *pi; queue_pop(gPipelineStartQ, (void**)&pi); io_block_t *ib = (io_block_t*)(pi->data); block_capacity(ib, iter.block.unpadded_size, iter.block.uncompressed_size); ib->insize = fread(ib->input, 1, bsize, gInFile); if (ib->insize < bsize) die("Error reading block contents"); offset += bsize; ib->uoffset = iter.block.uncompressed_file_offset; ib->check = iter.stream.flags->check; ib->btype = BLOCK_SIZED; // Indexed blocks always sized pipeline_split(pi); } } pipeline_stop(); }
static void set_block_sizes() { lzma_index_iter iter; lzma_index_iter_init(&iter, gIndex); while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) { // exclude the file index block lzma_vli off = iter.block.compressed_file_offset; if (gFileIndexOffset && off == gFileIndexOffset) continue; size_t in = iter.block.total_size, out = iter.block.uncompressed_size; if (out > gBlockOutSize) gBlockOutSize = out; if (in > gBlockInSize) gBlockInSize = in; } }
static void test_read(lzma_index *i) { lzma_index_iter r; lzma_index_iter_init(&r, i); // Try twice so we see that rewinding works. for (size_t j = 0; j < 2; ++j) { lzma_vli total_size = 0; lzma_vli uncompressed_size = 0; lzma_vli stream_offset = LZMA_STREAM_HEADER_SIZE; lzma_vli uncompressed_offset = 0; uint32_t count = 0; while (!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK)) { ++count; total_size += r.block.total_size; uncompressed_size += r.block.uncompressed_size; expect(r.block.compressed_file_offset == stream_offset); expect(r.block.uncompressed_file_offset == uncompressed_offset); stream_offset += r.block.total_size; uncompressed_offset += r.block.uncompressed_size; } expect(lzma_index_total_size(i) == total_size); expect(lzma_index_uncompressed_size(i) == uncompressed_size); expect(lzma_index_block_count(i) == count); lzma_index_iter_rewind(&r); } }
static void wanted_files(size_t count, char **specs) { if (!gFileIndexOffset) { if (count) die("Can't filter non-tarball"); gWantedFiles = NULL; return; } // Remove trailing slashes from specs for (char **spec = specs; spec < specs + count; ++spec) { char *c = *spec; while (*c++) ; // forward to end while (--c >= *spec && *c == '/') *c = '\0'; } bool matched[count]; // for each spec, does it match? memset(matched, 0, sizeof(matched)); wanted_t *last = NULL; // Check each file in order, to see if we want it for (file_index_t *f = gFileIndex; f->name; f = f->next) { bool match = !count; for (char **spec = specs; spec < specs + count; ++spec) { if (spec_match(*spec, f->name)) { match = true; matched[spec - specs] = true; break; } } if (match) { wanted_t *w = malloc(sizeof(wanted_t)); *w = (wanted_t){ .name = f->name, .start = f->offset, .end = f->next->offset, .next = NULL }; w->size = w->end - w->start; if (last) { last->next = w; } else { gWantedFiles = w; } last = w; } } // Make sure each spec matched for (size_t i = 0; i < count; ++i) { if (!matched[i]) die("\"%s\" not found in archive", *(specs + i)); } } #pragma mark THREADS static void read_thread(void) { off_t offset = ftello(gInFile); wanted_t *w = gWantedFiles; lzma_index_iter iter; lzma_index_iter_init(&iter, gIndex); while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) { // Don't decode the file-index off_t boffset = iter.block.compressed_file_offset; size_t bsize = iter.block.total_size; if (gFileIndexOffset && boffset == gFileIndexOffset) continue; // Do we need this block? if (gWantedFiles) { off_t uend = iter.block.uncompressed_file_offset + iter.block.uncompressed_size; if (!w || w->start >= uend) { debug("read: skip %llu", iter.block.number_in_file); continue; } for ( ; w && w->end < uend; w = w->next) ; } debug("read: want %llu", iter.block.number_in_file); // Get a block to work with pipeline_item_t *pi; queue_pop(gPipelineStartQ, (void**)&pi); io_block_t *ib = (io_block_t*)(pi->data); // Seek if needed, and get the data if (offset != boffset) { fseeko(gInFile, boffset, SEEK_SET); offset = boffset; } ib->insize = fread(ib->input, 1, bsize, gInFile); if (ib->insize < bsize) die("Error reading block contents"); offset += bsize; ib->uoffset = iter.block.uncompressed_file_offset; pipeline_split(pi); } pipeline_stop(); }
static bool print_info_robot(xz_file_info *xfi, file_pair *pair) { char checks[CHECKS_STR_SIZE]; get_check_names(checks, lzma_index_checks(xfi->idx), false); printf("name\t%s\n", pair->src_name); printf("file\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s\t%" PRIu64 "\n", lzma_index_stream_count(xfi->idx), lzma_index_block_count(xfi->idx), lzma_index_file_size(xfi->idx), lzma_index_uncompressed_size(xfi->idx), get_ratio(lzma_index_file_size(xfi->idx), lzma_index_uncompressed_size(xfi->idx)), checks, xfi->stream_padding); if (message_verbosity_get() >= V_VERBOSE) { lzma_index_iter iter; lzma_index_iter_init(&iter, xfi->idx); while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) printf("stream\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s\t%" PRIu64 "\n", iter.stream.number, iter.stream.block_count, iter.stream.compressed_offset, iter.stream.uncompressed_offset, iter.stream.compressed_size, iter.stream.uncompressed_size, get_ratio(iter.stream.compressed_size, iter.stream.uncompressed_size), check_names[iter.stream.flags->check], iter.stream.padding); lzma_index_iter_rewind(&iter); block_header_info bhi; while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) { if (message_verbosity_get() >= V_DEBUG && parse_details( pair, &iter, &bhi, xfi)) return true; printf("block\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%" PRIu64 "\t%s\t%s", iter.stream.number, iter.block.number_in_stream, iter.block.number_in_file, iter.block.compressed_file_offset, iter.block.uncompressed_file_offset, iter.block.total_size, iter.block.uncompressed_size, get_ratio(iter.block.total_size, iter.block.uncompressed_size), check_names[iter.stream.flags->check]); if (message_verbosity_get() >= V_DEBUG) printf("\t%s\t%" PRIu32 "\t%s\t%" PRIu64 "\t%" PRIu64 "\t%s", check_value, bhi.header_size, bhi.flags, bhi.compressed_size, bhi.memusage, bhi.filter_chain); putchar('\n'); } } if (message_verbosity_get() >= V_DEBUG) printf("summary\t%" PRIu64 "\t%s\t%" PRIu32 "\n", xfi->memusage_max, xfi->all_have_sizes ? "yes" : "no", xfi->min_version); return false; }
static bool print_info_adv(xz_file_info *xfi, file_pair *pair) { // Print the overall information. print_adv_helper(lzma_index_stream_count(xfi->idx), lzma_index_block_count(xfi->idx), lzma_index_file_size(xfi->idx), lzma_index_uncompressed_size(xfi->idx), lzma_index_checks(xfi->idx), xfi->stream_padding); // Size of the biggest Check. This is used to calculate the width // of the CheckVal field. The table would get insanely wide if // we always reserved space for 64-byte Check (128 chars as hex). uint32_t check_max = 0; // Print information about the Streams. // // TRANSLATORS: The second line is column headings. All except // Check are right aligned; Check is left aligned. Test with // "xz -lv foo.xz". puts(_(" Streams:\n Stream Blocks" " CompOffset UncompOffset" " CompSize UncompSize Ratio" " Check Padding")); lzma_index_iter iter; lzma_index_iter_init(&iter, xfi->idx); while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_STREAM)) { const char *cols1[4] = { uint64_to_str(iter.stream.number, 0), uint64_to_str(iter.stream.block_count, 1), uint64_to_str(iter.stream.compressed_offset, 2), uint64_to_str(iter.stream.uncompressed_offset, 3), }; printf(" %*s %*s %*s %*s ", tuklib_mbstr_fw(cols1[0], 6), cols1[0], tuklib_mbstr_fw(cols1[1], 9), cols1[1], tuklib_mbstr_fw(cols1[2], 15), cols1[2], tuklib_mbstr_fw(cols1[3], 15), cols1[3]); const char *cols2[5] = { uint64_to_str(iter.stream.compressed_size, 0), uint64_to_str(iter.stream.uncompressed_size, 1), get_ratio(iter.stream.compressed_size, iter.stream.uncompressed_size), _(check_names[iter.stream.flags->check]), uint64_to_str(iter.stream.padding, 2), }; printf("%*s %*s %*s %-*s %*s\n", tuklib_mbstr_fw(cols2[0], 15), cols2[0], tuklib_mbstr_fw(cols2[1], 15), cols2[1], tuklib_mbstr_fw(cols2[2], 5), cols2[2], tuklib_mbstr_fw(cols2[3], 10), cols2[3], tuklib_mbstr_fw(cols2[4], 7), cols2[4]); // Update the maximum Check size. if (lzma_check_size(iter.stream.flags->check) > check_max) check_max = lzma_check_size(iter.stream.flags->check); } // Cache the verbosity level to a local variable. const bool detailed = message_verbosity_get() >= V_DEBUG; // Information collected from Block Headers block_header_info bhi; // Print information about the Blocks but only if there is // at least one Block. if (lzma_index_block_count(xfi->idx) > 0) { // Calculate the width of the CheckVal field. const int checkval_width = my_max(8, 2 * check_max); // TRANSLATORS: The second line is column headings. All // except Check are right aligned; Check is left aligned. printf(_(" Blocks:\n Stream Block" " CompOffset UncompOffset" " TotalSize UncompSize Ratio Check")); if (detailed) { // TRANSLATORS: These are additional column headings // for the most verbose listing mode. CheckVal // (Check value), Flags, and Filters are left aligned. // Header (Block Header Size), CompSize, and MemUsage // are right aligned. %*s is replaced with 0-120 // spaces to make the CheckVal column wide enough. // Test with "xz -lvv foo.xz". printf(_(" CheckVal %*s Header Flags " "CompSize MemUsage Filters"), checkval_width - 8, ""); } putchar('\n'); lzma_index_iter_init(&iter, xfi->idx); // Iterate over the Blocks. while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) { if (detailed && parse_details(pair, &iter, &bhi, xfi)) return true; const char *cols1[4] = { uint64_to_str(iter.stream.number, 0), uint64_to_str( iter.block.number_in_stream, 1), uint64_to_str( iter.block.compressed_file_offset, 2), uint64_to_str( iter.block.uncompressed_file_offset, 3) }; printf(" %*s %*s %*s %*s ", tuklib_mbstr_fw(cols1[0], 6), cols1[0], tuklib_mbstr_fw(cols1[1], 9), cols1[1], tuklib_mbstr_fw(cols1[2], 15), cols1[2], tuklib_mbstr_fw(cols1[3], 15), cols1[3]); const char *cols2[4] = { uint64_to_str(iter.block.total_size, 0), uint64_to_str(iter.block.uncompressed_size, 1), get_ratio(iter.block.total_size, iter.block.uncompressed_size), _(check_names[iter.stream.flags->check]) }; printf("%*s %*s %*s %-*s", tuklib_mbstr_fw(cols2[0], 15), cols2[0], tuklib_mbstr_fw(cols2[1], 15), cols2[1], tuklib_mbstr_fw(cols2[2], 5), cols2[2], tuklib_mbstr_fw(cols2[3], detailed ? 11 : 1), cols2[3]); if (detailed) { const lzma_vli compressed_size = iter.block.unpadded_size - bhi.header_size - lzma_check_size( iter.stream.flags->check); const char *cols3[6] = { check_value, uint64_to_str(bhi.header_size, 0), bhi.flags, uint64_to_str(compressed_size, 1), uint64_to_str( round_up_to_mib(bhi.memusage), 2), bhi.filter_chain }; // Show MiB for memory usage, because it // is the only size which is not in bytes. printf("%-*s %*s %-5s %*s %*s MiB %s", checkval_width, cols3[0], tuklib_mbstr_fw(cols3[1], 6), cols3[1], cols3[2], tuklib_mbstr_fw(cols3[3], 15), cols3[3], tuklib_mbstr_fw(cols3[4], 7), cols3[4], cols3[5]); } putchar('\n'); } } if (detailed) { printf(_(" Memory needed: %s MiB\n"), uint64_to_str( round_up_to_mib(xfi->memusage_max), 0)); printf(_(" Sizes in headers: %s\n"), xfi->all_have_sizes ? _("Yes") : _("No")); printf(_(" Minimum XZ Utils version: %s\n"), xz_ver_to_str(xfi->min_version)); } return false; }
static void test_locate(void) { lzma_index *i = lzma_index_init(NULL); expect(i != NULL); lzma_index_iter r; lzma_index_iter_init(&r, i); // Cannot locate anything from an empty Index. expect(lzma_index_iter_locate(&r, 0)); expect(lzma_index_iter_locate(&r, 555)); // One empty Record: nothing is found since there's no uncompressed // data. expect(lzma_index_append(i, NULL, 16, 0) == LZMA_OK); expect(lzma_index_iter_locate(&r, 0)); // Non-empty Record and we can find something. expect(lzma_index_append(i, NULL, 32, 5) == LZMA_OK); expect(!lzma_index_iter_locate(&r, 0)); expect(r.block.total_size == 32); expect(r.block.uncompressed_size == 5); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + 16); expect(r.block.uncompressed_file_offset == 0); // Still cannot find anything past the end. expect(lzma_index_iter_locate(&r, 5)); // Add the third Record. expect(lzma_index_append(i, NULL, 40, 11) == LZMA_OK); expect(!lzma_index_iter_locate(&r, 0)); expect(r.block.total_size == 32); expect(r.block.uncompressed_size == 5); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + 16); expect(r.block.uncompressed_file_offset == 0); expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK)); expect(r.block.total_size == 40); expect(r.block.uncompressed_size == 11); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + 16 + 32); expect(r.block.uncompressed_file_offset == 5); expect(!lzma_index_iter_locate(&r, 2)); expect(r.block.total_size == 32); expect(r.block.uncompressed_size == 5); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + 16); expect(r.block.uncompressed_file_offset == 0); expect(!lzma_index_iter_locate(&r, 5)); expect(r.block.total_size == 40); expect(r.block.uncompressed_size == 11); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + 16 + 32); expect(r.block.uncompressed_file_offset == 5); expect(!lzma_index_iter_locate(&r, 5 + 11 - 1)); expect(r.block.total_size == 40); expect(r.block.uncompressed_size == 11); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + 16 + 32); expect(r.block.uncompressed_file_offset == 5); expect(lzma_index_iter_locate(&r, 5 + 11)); expect(lzma_index_iter_locate(&r, 5 + 15)); // Large Index lzma_index_end(i, NULL); i = lzma_index_init(NULL); expect(i != NULL); lzma_index_iter_init(&r, i); for (size_t n = 4; n <= 4 * 5555; n += 4) expect(lzma_index_append(i, NULL, n + 8, n) == LZMA_OK); expect(lzma_index_block_count(i) == 5555); // First Record expect(!lzma_index_iter_locate(&r, 0)); expect(r.block.total_size == 4 + 8); expect(r.block.uncompressed_size == 4); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE); expect(r.block.uncompressed_file_offset == 0); expect(!lzma_index_iter_locate(&r, 3)); expect(r.block.total_size == 4 + 8); expect(r.block.uncompressed_size == 4); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE); expect(r.block.uncompressed_file_offset == 0); // Second Record expect(!lzma_index_iter_locate(&r, 4)); expect(r.block.total_size == 2 * 4 + 8); expect(r.block.uncompressed_size == 2 * 4); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + 4 + 8); expect(r.block.uncompressed_file_offset == 4); // Last Record expect(!lzma_index_iter_locate( &r, lzma_index_uncompressed_size(i) - 1)); expect(r.block.total_size == 4 * 5555 + 8); expect(r.block.uncompressed_size == 4 * 5555); expect(r.block.compressed_file_offset == lzma_index_total_size(i) + LZMA_STREAM_HEADER_SIZE - 4 * 5555 - 8); expect(r.block.uncompressed_file_offset == lzma_index_uncompressed_size(i) - 4 * 5555); // Allocation chunk boundaries. See INDEX_GROUP_SIZE in // liblzma/common/index.c. const size_t group_multiple = 256 * 4; const size_t radius = 8; const size_t start = group_multiple - radius; lzma_vli ubase = 0; lzma_vli tbase = 0; size_t n; for (n = 1; n < start; ++n) { ubase += n * 4; tbase += n * 4 + 8; } while (n < start + 2 * radius) { expect(!lzma_index_iter_locate(&r, ubase + n * 4)); expect(r.block.compressed_file_offset == tbase + n * 4 + 8 + LZMA_STREAM_HEADER_SIZE); expect(r.block.uncompressed_file_offset == ubase + n * 4); tbase += n * 4 + 8; ubase += n * 4; ++n; expect(r.block.total_size == n * 4 + 8); expect(r.block.uncompressed_size == n * 4); } // Do it also backwards. while (n > start) { expect(!lzma_index_iter_locate(&r, ubase + (n - 1) * 4)); expect(r.block.total_size == n * 4 + 8); expect(r.block.uncompressed_size == n * 4); --n; tbase -= n * 4 + 8; ubase -= n * 4; expect(r.block.compressed_file_offset == tbase + n * 4 + 8 + LZMA_STREAM_HEADER_SIZE); expect(r.block.uncompressed_file_offset == ubase + n * 4); } // Test locating in concatenated Index. lzma_index_end(i, NULL); i = lzma_index_init(NULL); expect(i != NULL); lzma_index_iter_init(&r, i); for (n = 0; n < group_multiple; ++n) expect(lzma_index_append(i, NULL, 8, 0) == LZMA_OK); expect(lzma_index_append(i, NULL, 16, 1) == LZMA_OK); expect(!lzma_index_iter_locate(&r, 0)); expect(r.block.total_size == 16); expect(r.block.uncompressed_size == 1); expect(r.block.compressed_file_offset == LZMA_STREAM_HEADER_SIZE + group_multiple * 8); expect(r.block.uncompressed_file_offset == 0); lzma_index_end(i, NULL); }
static void test_cat(void) { lzma_index *a, *b, *c; lzma_index_iter r; // Empty Indexes a = create_empty(); b = create_empty(); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); expect(lzma_index_block_count(a) == 0); expect(lzma_index_stream_size(a) == 2 * LZMA_STREAM_HEADER_SIZE + 8); expect(lzma_index_file_size(a) == 2 * (2 * LZMA_STREAM_HEADER_SIZE + 8)); lzma_index_iter_init(&r, a); expect(lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK)); b = create_empty(); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); expect(lzma_index_block_count(a) == 0); expect(lzma_index_stream_size(a) == 2 * LZMA_STREAM_HEADER_SIZE + 8); expect(lzma_index_file_size(a) == 3 * (2 * LZMA_STREAM_HEADER_SIZE + 8)); b = create_empty(); c = create_empty(); expect(lzma_index_stream_padding(b, 4) == LZMA_OK); expect(lzma_index_cat(b, c, NULL) == LZMA_OK); expect(lzma_index_block_count(b) == 0); expect(lzma_index_stream_size(b) == 2 * LZMA_STREAM_HEADER_SIZE + 8); expect(lzma_index_file_size(b) == 2 * (2 * LZMA_STREAM_HEADER_SIZE + 8) + 4); expect(lzma_index_stream_padding(a, 8) == LZMA_OK); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); expect(lzma_index_block_count(a) == 0); expect(lzma_index_stream_size(a) == 2 * LZMA_STREAM_HEADER_SIZE + 8); expect(lzma_index_file_size(a) == 5 * (2 * LZMA_STREAM_HEADER_SIZE + 8) + 4 + 8); expect(lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK)); lzma_index_iter_rewind(&r); expect(lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK)); lzma_index_end(a, NULL); // Small Indexes a = create_small(); lzma_vli stream_size = lzma_index_stream_size(a); lzma_index_iter_init(&r, a); for (int i = SMALL_COUNT; i >= 0; --i) expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK) ^ (i == 0)); b = create_small(); expect(lzma_index_stream_padding(a, 4) == LZMA_OK); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); expect(lzma_index_file_size(a) == stream_size * 2 + 4); expect(lzma_index_stream_size(a) > stream_size); expect(lzma_index_stream_size(a) < stream_size * 2); for (int i = SMALL_COUNT; i >= 0; --i) expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK) ^ (i == 0)); lzma_index_iter_rewind(&r); for (int i = SMALL_COUNT * 2; i >= 0; --i) expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK) ^ (i == 0)); b = create_small(); c = create_small(); expect(lzma_index_stream_padding(b, 8) == LZMA_OK); expect(lzma_index_cat(b, c, NULL) == LZMA_OK); expect(lzma_index_stream_padding(a, 12) == LZMA_OK); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); expect(lzma_index_file_size(a) == stream_size * 4 + 4 + 8 + 12); expect(lzma_index_block_count(a) == SMALL_COUNT * 4); for (int i = SMALL_COUNT * 2; i >= 0; --i) expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK) ^ (i == 0)); lzma_index_iter_rewind(&r); for (int i = SMALL_COUNT * 4; i >= 0; --i) expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK) ^ (i == 0)); lzma_index_end(a, NULL); // Mix of empty and small a = create_empty(); b = create_small(); expect(lzma_index_stream_padding(a, 4) == LZMA_OK); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); lzma_index_iter_init(&r, a); for (int i = SMALL_COUNT; i >= 0; --i) expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK) ^ (i == 0)); lzma_index_end(a, NULL); // Big Indexes a = create_big(); stream_size = lzma_index_stream_size(a); b = create_big(); expect(lzma_index_stream_padding(a, 4) == LZMA_OK); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); expect(lzma_index_file_size(a) == stream_size * 2 + 4); expect(lzma_index_stream_size(a) > stream_size); expect(lzma_index_stream_size(a) < stream_size * 2); b = create_big(); c = create_big(); expect(lzma_index_stream_padding(b, 8) == LZMA_OK); expect(lzma_index_cat(b, c, NULL) == LZMA_OK); expect(lzma_index_stream_padding(a, 12) == LZMA_OK); expect(lzma_index_cat(a, b, NULL) == LZMA_OK); expect(lzma_index_file_size(a) == stream_size * 4 + 4 + 8 + 12); lzma_index_iter_init(&r, a); for (int i = BIG_COUNT * 4; i >= 0; --i) expect(!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK) ^ (i == 0)); lzma_index_end(a, NULL); }
static void test_code(lzma_index *i) { const size_t alloc_size = 128 * 1024; uint8_t *buf = malloc(alloc_size); expect(buf != NULL); // Encode lzma_stream strm = LZMA_STREAM_INIT; expect(lzma_index_encoder(&strm, i) == LZMA_OK); const lzma_vli index_size = lzma_index_size(i); succeed(coder_loop(&strm, NULL, 0, buf, index_size, LZMA_STREAM_END, LZMA_RUN)); // Decode lzma_index *d; expect(lzma_index_decoder(&strm, &d, MEMLIMIT) == LZMA_OK); expect(d == NULL); succeed(decoder_loop(&strm, buf, index_size)); expect(is_equal(i, d)); lzma_index_end(d, NULL); lzma_end(&strm); // Decode with hashing lzma_index_hash *h = lzma_index_hash_init(NULL, NULL); expect(h != NULL); lzma_index_iter r; lzma_index_iter_init(&r, i); while (!lzma_index_iter_next(&r, LZMA_INDEX_ITER_BLOCK)) expect(lzma_index_hash_append(h, r.block.unpadded_size, r.block.uncompressed_size) == LZMA_OK); size_t pos = 0; while (pos < index_size - 1) expect(lzma_index_hash_decode(h, buf, &pos, pos + 1) == LZMA_OK); expect(lzma_index_hash_decode(h, buf, &pos, pos + 1) == LZMA_STREAM_END); lzma_index_hash_end(h, NULL); // Encode buffer size_t buf_pos = 1; expect(lzma_index_buffer_encode(i, buf, &buf_pos, index_size) == LZMA_BUF_ERROR); expect(buf_pos == 1); succeed(lzma_index_buffer_encode(i, buf, &buf_pos, index_size + 1)); expect(buf_pos == index_size + 1); // Decode buffer buf_pos = 1; uint64_t memlimit = MEMLIMIT; expect(lzma_index_buffer_decode(&d, &memlimit, NULL, buf, &buf_pos, index_size) == LZMA_DATA_ERROR); expect(buf_pos == 1); expect(d == NULL); succeed(lzma_index_buffer_decode(&d, &memlimit, NULL, buf, &buf_pos, index_size + 1)); expect(buf_pos == index_size + 1); expect(is_equal(i, d)); lzma_index_end(d, NULL); free(buf); }