summaryrefslogtreecommitdiffstats
path: root/tests/test_index.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tests/test_index.c736
1 files changed, 736 insertions, 0 deletions
diff --git a/tests/test_index.c b/tests/test_index.c
new file mode 100644
index 0000000..31b958d
--- /dev/null
+++ b/tests/test_index.c
@@ -0,0 +1,736 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file test_index.c
+/// \brief Tests functions handling the lzma_index structure
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "tests.h"
+
+#define MEMLIMIT (LZMA_VLI_C(1) << 20)
+
+#define SMALL_COUNT 3
+#define BIG_COUNT 5555
+
+
+static lzma_index *
+create_empty(void)
+{
+ lzma_index *i = lzma_index_init(NULL);
+ expect(i != NULL);
+ return i;
+}
+
+
+static lzma_index *
+create_small(void)
+{
+ lzma_index *i = lzma_index_init(NULL);
+ expect(i != NULL);
+ expect(lzma_index_append(i, NULL, 101, 555) == LZMA_OK);
+ expect(lzma_index_append(i, NULL, 602, 777) == LZMA_OK);
+ expect(lzma_index_append(i, NULL, 804, 999) == LZMA_OK);
+ return i;
+}
+
+
+static lzma_index *
+create_big(void)
+{
+ lzma_index *i = lzma_index_init(NULL);
+ expect(i != NULL);
+
+ lzma_vli total_size = 0;
+ lzma_vli uncompressed_size = 0;
+
+ // Add pseudo-random sizes (but always the same size values).
+ uint32_t n = 11;
+ for (size_t j = 0; j < BIG_COUNT; ++j) {
+ n = 7019 * n + 7607;
+ const uint32_t t = n * 3011;
+ expect(lzma_index_append(i, NULL, t, n) == LZMA_OK);
+ total_size += (t + 3) & ~LZMA_VLI_C(3);
+ uncompressed_size += n;
+ }
+
+ expect(lzma_index_block_count(i) == BIG_COUNT);
+ expect(lzma_index_total_size(i) == total_size);
+ expect(lzma_index_uncompressed_size(i) == uncompressed_size);
+ expect(lzma_index_total_size(i) + lzma_index_size(i)
+ + 2 * LZMA_STREAM_HEADER_SIZE
+ == lzma_index_stream_size(i));
+
+ return i;
+}
+
+
+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;
+ }
+}
+
+
+static void
+test_equal(void)
+{
+ lzma_index *a = create_empty();
+ lzma_index *b = create_small();
+ lzma_index *c = create_big();
+ expect(a && b && c);
+
+ expect(is_equal(a, a));
+ expect(is_equal(b, b));
+ expect(is_equal(c, c));
+
+ expect(!is_equal(a, b));
+ expect(!is_equal(a, c));
+ expect(!is_equal(b, c));
+
+ lzma_index_end(a, NULL);
+ lzma_index_end(b, NULL);
+ lzma_index_end(c, NULL);
+}
+
+
+static void
+test_overflow(void)
+{
+ // Integer overflow tests
+ lzma_index *i = create_empty();
+
+ expect(lzma_index_append(i, NULL, LZMA_VLI_MAX - 5, 1234)
+ == LZMA_DATA_ERROR);
+
+ // TODO
+
+ lzma_index_end(i, NULL);
+}
+
+
+static void
+test_copy(const lzma_index *i)
+{
+ lzma_index *d = lzma_index_dup(i, NULL);
+ expect(d != NULL);
+ expect(is_equal(i, d));
+ lzma_index_end(d, NULL);
+}
+
+
+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
+test_code(lzma_index *i)
+{
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+ 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);
+#else
+ (void)i;
+#endif
+}
+
+
+static void
+test_many(lzma_index *i)
+{
+ test_copy(i);
+ test_read(i);
+ test_code(i);
+}
+
+
+static void
+test_cat(void)
+{
+ lzma_index *a, *b, *c, *d, *e, *f;
+ 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);
+
+ // Test for the bug fix 3d5a99ca373a4e86faf671226ca6487febb9eeac.
+ // lzma_index_checks would previously only return the checks
+ // for the last stream that was concatenated to the index.
+ d = create_small();
+ e = create_small();
+ f = create_small();
+
+ lzma_stream_flags crc32_flags = {
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC32
+ };
+ expect(lzma_index_stream_flags(d, &crc32_flags) == LZMA_OK);
+
+ lzma_stream_flags crc64_flags = {
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_CRC64
+ };
+ expect(lzma_index_stream_flags(e, &crc64_flags) == LZMA_OK);
+
+ lzma_stream_flags sha256_flags = {
+ .backward_size = LZMA_BACKWARD_SIZE_MIN,
+ .check = LZMA_CHECK_SHA256
+ };
+ expect(lzma_index_stream_flags(f, &sha256_flags) == LZMA_OK);
+
+ expect(lzma_index_checks(d) == (1U << LZMA_CHECK_CRC32));
+ expect(lzma_index_checks(e) == (1U << LZMA_CHECK_CRC64));
+ expect(lzma_index_checks(f) == (1U << LZMA_CHECK_SHA256));
+
+ expect(lzma_index_cat(d, e, NULL) == LZMA_OK);
+ expect(lzma_index_checks(d) == ((1U << LZMA_CHECK_CRC32) |
+ (1U << LZMA_CHECK_CRC64)));
+
+ expect(lzma_index_cat(d, f, NULL) == LZMA_OK);
+ expect(lzma_index_checks(d) == ((1U << LZMA_CHECK_CRC32) |
+ (1U << LZMA_CHECK_CRC64) |
+ (1U << LZMA_CHECK_SHA256)));
+
+ lzma_index_end(d, NULL);
+
+}
+
+
+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_corrupt(void)
+{
+#if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS)
+ const size_t alloc_size = 128 * 1024;
+ uint8_t *buf = malloc(alloc_size);
+ expect(buf != NULL);
+ lzma_stream strm = LZMA_STREAM_INIT;
+
+ lzma_index *i = create_empty();
+ expect(lzma_index_append(i, NULL, 0, 1) == LZMA_PROG_ERROR);
+ lzma_index_end(i, NULL);
+
+ // Create a valid Index and corrupt it in different ways.
+ i = create_small();
+ expect(lzma_index_encoder(&strm, i) == LZMA_OK);
+ succeed(coder_loop(&strm, NULL, 0, buf, 20,
+ LZMA_STREAM_END, LZMA_RUN));
+ lzma_index_end(i, NULL);
+
+ // Wrong Index Indicator
+ buf[0] ^= 1;
+ expect(lzma_index_decoder(&strm, &i, MEMLIMIT) == LZMA_OK);
+ succeed(decoder_loop_ret(&strm, buf, 1, LZMA_DATA_ERROR));
+ buf[0] ^= 1;
+
+ // Wrong Number of Records and thus CRC32 fails.
+ --buf[1];
+ expect(lzma_index_decoder(&strm, &i, MEMLIMIT) == LZMA_OK);
+ succeed(decoder_loop_ret(&strm, buf, 10, LZMA_DATA_ERROR));
+ ++buf[1];
+
+ // Padding not NULs
+ buf[15] ^= 1;
+ expect(lzma_index_decoder(&strm, &i, MEMLIMIT) == LZMA_OK);
+ succeed(decoder_loop_ret(&strm, buf, 16, LZMA_DATA_ERROR));
+
+ lzma_end(&strm);
+ free(buf);
+#endif
+}
+
+
+// Allocator that succeeds for the first two allocation but fails the rest.
+static void *
+my_alloc(void *opaque, size_t a, size_t b)
+{
+ (void)opaque;
+
+ static unsigned count = 0;
+ if (++count > 2)
+ return NULL;
+
+ return malloc(a * b);
+}
+
+static const lzma_allocator my_allocator = { &my_alloc, NULL, NULL };
+
+
+int
+main(void)
+{
+ test_equal();
+
+ test_overflow();
+
+ lzma_index *i = create_empty();
+ test_many(i);
+ lzma_index_end(i, NULL);
+
+ i = create_small();
+ test_many(i);
+ lzma_index_end(i, NULL);
+
+ i = create_big();
+ test_many(i);
+ lzma_index_end(i, NULL);
+
+ test_cat();
+
+ test_locate();
+
+ test_corrupt();
+
+ // Test for the bug fix 21515d79d778b8730a434f151b07202d52a04611:
+ // liblzma: Fix lzma_index_dup() for empty Streams.
+ i = create_empty();
+ expect(lzma_index_stream_padding(i, 4) == LZMA_OK);
+ test_copy(i);
+ lzma_index_end(i, NULL);
+
+ // Test for the bug fix 3bf857edfef51374f6f3fffae3d817f57d3264a0:
+ // liblzma: Fix a memory leak in error path of lzma_index_dup().
+ // Use Valgrind to see that there are no leaks.
+ i = create_small();
+ expect(lzma_index_dup(i, &my_allocator) == NULL);
+ lzma_index_end(i, NULL);
+
+ return 0;
+}