예제 #1
0
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;
}
예제 #2
0
static lzma_index *
create_empty(void)
{
    lzma_index *i = lzma_index_init(NULL);
    expect(i != NULL);
    return i;
}
예제 #3
0
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;
}
예제 #4
0
static lzma_ret
stream_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
		const lzma_filter *filters, lzma_check check)
{
	lzma_next_coder_init(&stream_encoder_init, next, allocator);

	if (filters == NULL)
		return LZMA_PROG_ERROR;

	if (next->coder == NULL) {
		next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
		if (next->coder == NULL)
			return LZMA_MEM_ERROR;

		next->code = &stream_encode;
		next->end = &stream_encoder_end;
		next->update = &stream_encoder_update;

		next->coder->filters[0].id = LZMA_VLI_UNKNOWN;
		next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
		next->coder->index_encoder = LZMA_NEXT_CODER_INIT;
		next->coder->index = NULL;
	}

	// Basic initializations
	next->coder->sequence = SEQ_STREAM_HEADER;
	next->coder->block_options.version = 0;
	next->coder->block_options.check = check;

	// Initialize the Index
	lzma_index_end(next->coder->index, allocator);
	next->coder->index = lzma_index_init(allocator);
	if (next->coder->index == NULL)
		return LZMA_MEM_ERROR;

	// Encode the Stream Header
	lzma_stream_flags stream_flags = {
		.version = 0,
		.check = check,
	};
	return_if_error(lzma_stream_header_encode(
			&stream_flags, next->coder->buffer));

	next->coder->buffer_pos = 0;
	next->coder->buffer_size = LZMA_STREAM_HEADER_SIZE;

	// Initialize the Block encoder. This way we detect unsupported
	// filter chains when initializing the Stream encoder instead of
	// giving an error after Stream Header has already written out.
	return stream_encoder_update(
			next->coder, allocator, filters, NULL);
}


extern LZMA_API(lzma_ret)
lzma_stream_encoder(lzma_stream *strm,
		const lzma_filter *filters, lzma_check check)
{
	lzma_next_strm_init(stream_encoder_init, strm, filters, check);

	strm->internal->supported_actions[LZMA_RUN] = true;
	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
	strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
	strm->internal->supported_actions[LZMA_FINISH] = true;

	return LZMA_OK;
}
예제 #5
0
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);
}
예제 #6
0
lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check,
		lzma_allocator *allocator, const uint8_t *in, size_t in_size,
		uint8_t *out, size_t *out_pos_ptr, size_t out_size)
{
	// Sanity checks
	if (filters == NULL || (unsigned int)(check) > LZMA_CHECK_ID_MAX
			|| (in == NULL && in_size != 0) || out == NULL
			|| out_pos_ptr == NULL || *out_pos_ptr > out_size)
		return LZMA_PROG_ERROR;

	if (!lzma_check_is_supported(check))
		return LZMA_UNSUPPORTED_CHECK;

	// Note for the paranoids: Index encoder prevents the Stream from
	// getting too big and still being accepted with LZMA_OK, and Block
	// encoder catches if the input is too big. So we don't need to
	// separately check if the buffers are too big.

	// Use a local copy. We update *out_pos_ptr only if everything
	// succeeds.
	size_t out_pos = *out_pos_ptr;

	// Check that there's enough space for both Stream Header and
	// Stream Footer.
	if (out_size - out_pos <= 2 * LZMA_STREAM_HEADER_SIZE)
		return LZMA_BUF_ERROR;

	// Reserve space for Stream Footer so we don't need to check for
	// available space again before encoding Stream Footer.
	out_size -= LZMA_STREAM_HEADER_SIZE;

	// Encode the Stream Header.
	lzma_stream_flags stream_flags = {
		.version = 0,
		.check = check,
	};

	if (lzma_stream_header_encode(&stream_flags, out + out_pos)
			!= LZMA_OK)
		return LZMA_PROG_ERROR;

	out_pos += LZMA_STREAM_HEADER_SIZE;

	// Encode a Block but only if there is at least one byte of input.
	lzma_block block = {
		.version = 0,
		.check = check,
		.filters = filters,
	};

	if (in_size > 0)
		return_if_error(lzma_block_buffer_encode(&block, allocator,
				in, in_size, out, &out_pos, out_size));

	// Index
	{
		// Create an Index. It will have one Record if there was
		// at least one byte of input to encode. Otherwise the
		// Index will be empty.
		lzma_index *i = lzma_index_init(allocator);
		if (i == NULL)
			return LZMA_MEM_ERROR;

		lzma_ret ret = LZMA_OK;

		if (in_size > 0)
			ret = lzma_index_append(i, allocator,
					lzma_block_unpadded_size(&block),
					block.uncompressed_size);

		// If adding the Record was successful, encode the Index
		// and get its size which will be stored into Stream Footer.
		if (ret == LZMA_OK) {
			ret = lzma_index_buffer_encode(
					i, out, &out_pos, out_size);

			stream_flags.backward_size = lzma_index_size(i);
		}

		lzma_index_end(i, allocator);

		if (ret != LZMA_OK)
			return ret;
	}

	// Stream Footer. We have already reserved space for this.
	if (lzma_stream_footer_encode(&stream_flags, out + out_pos)
			!= LZMA_OK)
		return LZMA_PROG_ERROR;

	out_pos += LZMA_STREAM_HEADER_SIZE;

	// Everything went fine, make the new output position available
	// to the application.
	*out_pos_ptr = out_pos;
	return LZMA_OK;
}