Esempio n. 1
0
lzma_block_unpadded_size(const lzma_block *block)
{
	// Validate the values that we are interested in i.e. all but
	// Uncompressed Size and the filters.
	//
	// NOTE: This function is used for validation too, so it is
	// essential that these checks are always done even if
	// Compressed Size is unknown.
	if (block == NULL || block->version != 0
			|| block->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
			|| block->header_size > LZMA_BLOCK_HEADER_SIZE_MAX
			|| (block->header_size & 3)
			|| !lzma_vli_is_valid(block->compressed_size)
			|| block->compressed_size == 0
			|| (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
		return 0;

	// If Compressed Size is unknown, return that we cannot know
	// size of the Block either.
	if (block->compressed_size == LZMA_VLI_UNKNOWN)
		return LZMA_VLI_UNKNOWN;

	// Calculate Unpadded Size and validate it.
	const lzma_vli unpadded_size = block->compressed_size
				+ block->header_size
				+ lzma_check_size(block->check);

	assert(unpadded_size >= UNPADDED_SIZE_MIN);
	if (unpadded_size > UNPADDED_SIZE_MAX)
		return 0;

	return unpadded_size;
}
Esempio n. 2
0
/// \brief      Parse the Check field and put it into check_value[]
///
/// \return     False on success, true on error.
static bool
parse_check_value(file_pair *pair, const lzma_index_iter *iter)
{
	// Don't read anything from the file if there is no integrity Check.
	if (iter->stream.flags->check == LZMA_CHECK_NONE) {
		snprintf(check_value, sizeof(check_value), "---");
		return false;
	}

	// Locate and read the Check field.
	const uint32_t size = lzma_check_size(iter->stream.flags->check);
	const off_t offset = iter->block.compressed_file_offset
			+ iter->block.total_size - size;
	io_buf buf;
	if (io_pread(pair, &buf, size, offset))
		return true;

	// CRC32 and CRC64 are in little endian. Guess that all the future
	// 32-bit and 64-bit Check values are little endian too. It shouldn't
	// be a too big problem if this guess is wrong.
	if (size == 4)
		snprintf(check_value, sizeof(check_value),
				"%08" PRIx32, conv32le(buf.u32[0]));
	else if (size == 8)
		snprintf(check_value, sizeof(check_value),
				"%016" PRIx64, conv64le(buf.u64[0]));
	else
		for (size_t i = 0; i < size; ++i)
			snprintf(check_value + i * 2, 3, "%02x", buf.u8[i]);

	return false;
}
Esempio n. 3
0
lzma_block_compressed_size(lzma_block *block, lzma_vli unpadded_size)
{
	// Validate everything but Uncompressed Size and filters.
	if (lzma_block_unpadded_size(block) == 0)
		return LZMA_PROG_ERROR;

	const uint32_t container_size = block->header_size
			+ lzma_check_size(block->check);

	// Validate that Compressed Size will be greater than zero.
	if (unpadded_size <= container_size)
		return LZMA_DATA_ERROR;

	// Calculate what Compressed Size is supposed to be.
	// If Compressed Size was present in Block Header,
	// compare that the new value matches it.
	const lzma_vli compressed_size = unpadded_size - container_size;
	if (block->compressed_size != LZMA_VLI_UNKNOWN
			&& block->compressed_size != compressed_size)
		return LZMA_DATA_ERROR;

	block->compressed_size = compressed_size;

	return LZMA_OK;
}
Esempio n. 4
0
Handle<Value> lzmaCheckSize(const Arguments& args) {
	HandleScope scope;
	Local<Integer> arg = Local<Integer>::Cast(args[0]);
	
	return scope.Close(Integer::NewFromUnsigned(lzma_check_size((lzma_check) arg->Value())));
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
/// \brief      Parse the Block Header
///
/// The result is stored into *bhi. The caller takes care of initializing it.
///
/// \return     False on success, true on error.
static bool
parse_block_header(file_pair *pair, const lzma_index_iter *iter,
		block_header_info *bhi, xz_file_info *xfi)
{
#if IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
#	error IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
#endif

	// Get the whole Block Header with one read, but don't read past
	// the end of the Block (or even its Check field).
	const uint32_t size = my_min(iter->block.total_size
				- lzma_check_size(iter->stream.flags->check),
			LZMA_BLOCK_HEADER_SIZE_MAX);
	io_buf buf;
	if (io_pread(pair, &buf, size, iter->block.compressed_file_offset))
		return true;

	// Zero would mean Index Indicator and thus not a valid Block.
	if (buf.u8[0] == 0)
		goto data_error;

	// Initialize the block structure and decode Block Header Size.
	lzma_filter filters[LZMA_FILTERS_MAX + 1];
	lzma_block block;
	block.version = 0;
	block.check = iter->stream.flags->check;
	block.filters = filters;

	block.header_size = lzma_block_header_size_decode(buf.u8[0]);
	if (block.header_size > size)
		goto data_error;

	// Decode the Block Header.
	switch (lzma_block_header_decode(&block, NULL, buf.u8)) {
	case LZMA_OK:
		break;

	case LZMA_OPTIONS_ERROR:
		message_error("%s: %s", pair->src_name,
				message_strm(LZMA_OPTIONS_ERROR));
		return true;

	case LZMA_DATA_ERROR:
		goto data_error;

	default:
		message_bug();
	}

	// Check the Block Flags. These must be done before calling
	// lzma_block_compressed_size(), because it overwrites
	// block.compressed_size.
	bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
			? 'c' : '-';
	bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
			? 'u' : '-';
	bhi->flags[2] = '\0';

	// Collect information if all Blocks have both Compressed Size
	// and Uncompressed Size fields. They can be useful e.g. for
	// multi-threaded decompression so it can be useful to know it.
	xfi->all_have_sizes &= block.compressed_size != LZMA_VLI_UNKNOWN
			&& block.uncompressed_size != LZMA_VLI_UNKNOWN;

	// Validate or set block.compressed_size.
	switch (lzma_block_compressed_size(&block,
			iter->block.unpadded_size)) {
	case LZMA_OK:
		// Validate also block.uncompressed_size if it is present.
		// If it isn't present, there's no need to set it since
		// we aren't going to actually decompress the Block; if
		// we were decompressing, then we should set it so that
		// the Block decoder could validate the Uncompressed Size
		// that was stored in the Index.
		if (block.uncompressed_size == LZMA_VLI_UNKNOWN
				|| block.uncompressed_size
					== iter->block.uncompressed_size)
			break;

		// If the above fails, the file is corrupt so
		// LZMA_DATA_ERROR is a good error code.

	// Fall through

	case LZMA_DATA_ERROR:
		// Free the memory allocated by lzma_block_header_decode().
		for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
			free(filters[i].options);

		goto data_error;

	default:
		message_bug();
	}

	// Copy the known sizes.
	bhi->header_size = block.header_size;
	bhi->compressed_size = block.compressed_size;

	// Calculate the decoder memory usage and update the maximum
	// memory usage of this Block.
	bhi->memusage = lzma_raw_decoder_memusage(filters);
	if (xfi->memusage_max < bhi->memusage)
		xfi->memusage_max = bhi->memusage;

	// Determine the minimum XZ Utils version that supports this Block.
	//
	// Currently the only thing that 5.0.0 doesn't support is empty
	// LZMA2 Block. This decoder bug was fixed in 5.0.2.
	{
		size_t i = 0;
		while (filters[i + 1].id != LZMA_VLI_UNKNOWN)
			++i;

		if (filters[i].id == LZMA_FILTER_LZMA2
				&& iter->block.uncompressed_size == 0
				&& xfi->min_version < 50000022U)
			xfi->min_version = 50000022U;
	}

	// Convert the filter chain to human readable form.
	message_filters_to_str(bhi->filter_chain, filters, false);

	// Free the memory allocated by lzma_block_header_decode().
	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
		free(filters[i].options);

	return false;

data_error:
	// Show the error message.
	message_error("%s: %s", pair->src_name,
			message_strm(LZMA_DATA_ERROR));
	return true;
}
Esempio n. 7
0
lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator,
		const uint8_t *in, size_t in_size,
		uint8_t *out, size_t *out_pos, size_t out_size)
{
	size_t check_size;
	lzma_ret ret;
	size_t i;

	// Validate the arguments.
	if (block == NULL || (in == NULL && in_size != 0) || out == NULL
			|| out_pos == NULL || *out_pos > out_size)
		return LZMA_PROG_ERROR;

	// The contents of the structure may depend on the version so
	// check the version before validating the contents of *block.
	if (block->version != 0)
		return LZMA_OPTIONS_ERROR;

	if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX
			|| block->filters == NULL)
		return LZMA_PROG_ERROR;

	if (!lzma_check_is_supported(block->check))
		return LZMA_UNSUPPORTED_CHECK;

	// Size of a Block has to be a multiple of four, so limit the size
	// here already. This way we don't need to check it again when adding
	// Block Padding.
	out_size -= (out_size - *out_pos) & 3;

	// Get the size of the Check field.
	check_size = lzma_check_size(block->check);
	assert(check_size != UINT32_MAX);

	// Reserve space for the Check field.
	if (out_size - *out_pos <= check_size)
		return LZMA_BUF_ERROR;

	out_size -= check_size;

	// Do the actual compression.
	ret = block_encode_normal(block, allocator,
			in, in_size, out, out_pos, out_size);
	if (ret != LZMA_OK) {
		// If the error was something else than output buffer
		// becoming full, return the error now.
		if (ret != LZMA_BUF_ERROR)
			return ret;

		// The data was uncompressible (at least with the options
		// given to us) or the output buffer was too small. Use the
		// uncompressed chunks of LZMA2 to wrap the data into a valid
		// Block. If we haven't been given enough output space, even
		// this may fail.
		return_if_error(block_encode_uncompressed(block, in, in_size,
				out, out_pos, out_size));
	}

	assert(*out_pos <= out_size);

	// Block Padding. No buffer overflow here, because we already adjusted
	// out_size so that (out_size - out_start) is a multiple of four.
	// Thus, if the buffer is full, the loop body can never run.
	for (i = (size_t)(block->compressed_size); i & 3; ++i) {
		assert(*out_pos < out_size);
		out[(*out_pos)++] = 0x00;
	}

	// If there's no Check field, we are done now.
	if (check_size > 0) {
		// Calculate the integrity check. We reserved space for
		// the Check field earlier so we don't need to check for
		// available output space here.
		lzma_check_state check;
		lzma_check_init(&check, block->check);
		lzma_check_update(&check, block->check, in, in_size);
		lzma_check_finish(&check, block->check);

		memcpy(block->raw_check, check.buffer.u8, check_size);
		memcpy(out + *out_pos, check.buffer.u8, check_size);
		*out_pos += check_size;
	}

	return LZMA_OK;
}
Esempio n. 8
0
/// \brief      Parse the Block Header
///
/// The result is stored into *bhi. The caller takes care of initializing it.
///
/// \return     False on success, true on error.
static bool
parse_block_header(file_pair *pair, const lzma_index_iter *iter,
		block_header_info *bhi, xz_file_info *xfi)
{
#if IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
#	error IO_BUFFER_SIZE < LZMA_BLOCK_HEADER_SIZE_MAX
#endif

	// Get the whole Block Header with one read, but don't read past
	// the end of the Block (or even its Check field).
	const uint32_t size = my_min(iter->block.total_size
				- lzma_check_size(iter->stream.flags->check),
			LZMA_BLOCK_HEADER_SIZE_MAX);
	io_buf buf;
	if (io_pread(pair, &buf, size, iter->block.compressed_file_offset))
		return true;

	// Zero would mean Index Indicator and thus not a valid Block.
	if (buf.u8[0] == 0)
		goto data_error;

	lzma_block block;
	lzma_filter filters[LZMA_FILTERS_MAX + 1];

	// Initialize the pointers so that they can be passed to free().
	for (size_t i = 0; i < ARRAY_SIZE(filters); ++i)
		filters[i].options = NULL;

	// Initialize the block structure and decode Block Header Size.
	block.version = 0;
	block.check = iter->stream.flags->check;
	block.filters = filters;

	block.header_size = lzma_block_header_size_decode(buf.u8[0]);
	if (block.header_size > size)
		goto data_error;

	// Decode the Block Header.
	switch (lzma_block_header_decode(&block, NULL, buf.u8)) {
	case LZMA_OK:
		break;

	case LZMA_OPTIONS_ERROR:
		message_error("%s: %s", pair->src_name,
				message_strm(LZMA_OPTIONS_ERROR));
		return true;

	case LZMA_DATA_ERROR:
		goto data_error;

	default:
		message_bug();
	}

	// Check the Block Flags. These must be done before calling
	// lzma_block_compressed_size(), because it overwrites
	// block.compressed_size.
	bhi->flags[0] = block.compressed_size != LZMA_VLI_UNKNOWN
			? 'c' : '-';
	bhi->flags[1] = block.uncompressed_size != LZMA_VLI_UNKNOWN
			? 'u' : '-';
	bhi->flags[2] = '\0';

	// Collect information if all Blocks have both Compressed Size
	// and Uncompressed Size fields. They can be useful e.g. for
	// multi-threaded decompression so it can be useful to know it.
	xfi->all_have_sizes &= block.compressed_size != LZMA_VLI_UNKNOWN
			&& block.uncompressed_size != LZMA_VLI_UNKNOWN;

	// Validate or set block.compressed_size.
	switch (lzma_block_compressed_size(&block,
			iter->block.unpadded_size)) {
	case LZMA_OK:
		break;

	case LZMA_DATA_ERROR:
		goto data_error;

	default:
		message_bug();
	}

	// Copy the known sizes.
	bhi->header_size = block.header_size;
	bhi->compressed_size = block.compressed_size;

	// Calculate the decoder memory usage and update the maximum
	// memory usage of this Block.
	bhi->memusage = lzma_raw_decoder_memusage(filters);
	if (xfi->memusage_max < bhi->memusage)
		xfi->memusage_max = bhi->memusage;

	// Convert the filter chain to human readable form.
	message_filters_to_str(bhi->filter_chain, filters, false);

	// Free the memory allocated by lzma_block_header_decode().
	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
		free(filters[i].options);

	return false;

data_error:
	// Show the error message.
	message_error("%s: %s", pair->src_name,
			message_strm(LZMA_DATA_ERROR));

	// Free the memory allocated by lzma_block_header_decode().
	// This is truly needed only if we get here after a succcessful
	// call to lzma_block_header_decode() but it doesn't hurt to
	// always do it.
	for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i)
		free(filters[i].options);

	return true;
}