xref: /freebsd/contrib/xz/src/liblzma/common/block_encoder.c (revision 3b35e7ee8de9b0260149a2b77e87a2b9c7a36244)
1*3b35e7eeSXin LI // SPDX-License-Identifier: 0BSD
2*3b35e7eeSXin LI 
381ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
481ad8388SMartin Matuska //
581ad8388SMartin Matuska /// \file       block_encoder.c
681ad8388SMartin Matuska /// \brief      Encodes .xz Blocks
781ad8388SMartin Matuska //
881ad8388SMartin Matuska //  Author:     Lasse Collin
981ad8388SMartin Matuska //
1081ad8388SMartin Matuska ///////////////////////////////////////////////////////////////////////////////
1181ad8388SMartin Matuska 
1281ad8388SMartin Matuska #include "block_encoder.h"
1381ad8388SMartin Matuska #include "filter_encoder.h"
1481ad8388SMartin Matuska #include "check.h"
1581ad8388SMartin Matuska 
1681ad8388SMartin Matuska 
171456f0f9SXin LI typedef struct {
1881ad8388SMartin Matuska 	/// The filters in the chain; initialized with lzma_raw_decoder_init().
1981ad8388SMartin Matuska 	lzma_next_coder next;
2081ad8388SMartin Matuska 
2181ad8388SMartin Matuska 	/// Encoding options; we also write Unpadded Size, Compressed Size,
2281ad8388SMartin Matuska 	/// and Uncompressed Size back to this structure when the encoding
2381ad8388SMartin Matuska 	/// has been finished.
2481ad8388SMartin Matuska 	lzma_block *block;
2581ad8388SMartin Matuska 
2681ad8388SMartin Matuska 	enum {
2781ad8388SMartin Matuska 		SEQ_CODE,
2881ad8388SMartin Matuska 		SEQ_PADDING,
2981ad8388SMartin Matuska 		SEQ_CHECK,
3081ad8388SMartin Matuska 	} sequence;
3181ad8388SMartin Matuska 
3281ad8388SMartin Matuska 	/// Compressed Size calculated while encoding
3381ad8388SMartin Matuska 	lzma_vli compressed_size;
3481ad8388SMartin Matuska 
3581ad8388SMartin Matuska 	/// Uncompressed Size calculated while encoding
3681ad8388SMartin Matuska 	lzma_vli uncompressed_size;
3781ad8388SMartin Matuska 
3881ad8388SMartin Matuska 	/// Position in the Check field
3981ad8388SMartin Matuska 	size_t pos;
4081ad8388SMartin Matuska 
4181ad8388SMartin Matuska 	/// Check of the uncompressed data
4281ad8388SMartin Matuska 	lzma_check_state check;
431456f0f9SXin LI } lzma_block_coder;
4481ad8388SMartin Matuska 
4581ad8388SMartin Matuska 
4681ad8388SMartin Matuska static lzma_ret
471456f0f9SXin LI block_encode(void *coder_ptr, const lzma_allocator *allocator,
4881ad8388SMartin Matuska 		const uint8_t *restrict in, size_t *restrict in_pos,
4981ad8388SMartin Matuska 		size_t in_size, uint8_t *restrict out,
5081ad8388SMartin Matuska 		size_t *restrict out_pos, size_t out_size, lzma_action action)
5181ad8388SMartin Matuska {
521456f0f9SXin LI 	lzma_block_coder *coder = coder_ptr;
531456f0f9SXin LI 
5481ad8388SMartin Matuska 	// Check that our amount of input stays in proper limits.
5581ad8388SMartin Matuska 	if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos)
5681ad8388SMartin Matuska 		return LZMA_DATA_ERROR;
5781ad8388SMartin Matuska 
5881ad8388SMartin Matuska 	switch (coder->sequence) {
5981ad8388SMartin Matuska 	case SEQ_CODE: {
6081ad8388SMartin Matuska 		const size_t in_start = *in_pos;
6181ad8388SMartin Matuska 		const size_t out_start = *out_pos;
6281ad8388SMartin Matuska 
6381ad8388SMartin Matuska 		const lzma_ret ret = coder->next.code(coder->next.coder,
6481ad8388SMartin Matuska 				allocator, in, in_pos, in_size,
6581ad8388SMartin Matuska 				out, out_pos, out_size, action);
6681ad8388SMartin Matuska 
6781ad8388SMartin Matuska 		const size_t in_used = *in_pos - in_start;
6881ad8388SMartin Matuska 		const size_t out_used = *out_pos - out_start;
6981ad8388SMartin Matuska 
7081ad8388SMartin Matuska 		if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used)
7181ad8388SMartin Matuska 			return LZMA_DATA_ERROR;
7281ad8388SMartin Matuska 
7381ad8388SMartin Matuska 		coder->compressed_size += out_used;
7481ad8388SMartin Matuska 
7581ad8388SMartin Matuska 		// No need to check for overflow because we have already
7681ad8388SMartin Matuska 		// checked it at the beginning of this function.
7781ad8388SMartin Matuska 		coder->uncompressed_size += in_used;
7881ad8388SMartin Matuska 
79c917796cSXin LI 		// Call lzma_check_update() only if input was consumed. This
80c917796cSXin LI 		// avoids null pointer + 0 (undefined behavior) when in == 0.
81c917796cSXin LI 		if (in_used > 0)
8281ad8388SMartin Matuska 			lzma_check_update(&coder->check, coder->block->check,
8381ad8388SMartin Matuska 					in + in_start, in_used);
8481ad8388SMartin Matuska 
8581ad8388SMartin Matuska 		if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
8681ad8388SMartin Matuska 			return ret;
8781ad8388SMartin Matuska 
8881ad8388SMartin Matuska 		assert(*in_pos == in_size);
8981ad8388SMartin Matuska 		assert(action == LZMA_FINISH);
9081ad8388SMartin Matuska 
9181ad8388SMartin Matuska 		// Copy the values into coder->block. The caller
9281ad8388SMartin Matuska 		// may use this information to construct Index.
9381ad8388SMartin Matuska 		coder->block->compressed_size = coder->compressed_size;
9481ad8388SMartin Matuska 		coder->block->uncompressed_size = coder->uncompressed_size;
9581ad8388SMartin Matuska 
9681ad8388SMartin Matuska 		coder->sequence = SEQ_PADDING;
9781ad8388SMartin Matuska 	}
9881ad8388SMartin Matuska 
9981ad8388SMartin Matuska 	// Fall through
10081ad8388SMartin Matuska 
10181ad8388SMartin Matuska 	case SEQ_PADDING:
10281ad8388SMartin Matuska 		// Pad Compressed Data to a multiple of four bytes. We can
10381ad8388SMartin Matuska 		// use coder->compressed_size for this since we don't need
10481ad8388SMartin Matuska 		// it for anything else anymore.
10581ad8388SMartin Matuska 		while (coder->compressed_size & 3) {
10681ad8388SMartin Matuska 			if (*out_pos >= out_size)
10781ad8388SMartin Matuska 				return LZMA_OK;
10881ad8388SMartin Matuska 
10981ad8388SMartin Matuska 			out[*out_pos] = 0x00;
11081ad8388SMartin Matuska 			++*out_pos;
11181ad8388SMartin Matuska 			++coder->compressed_size;
11281ad8388SMartin Matuska 		}
11381ad8388SMartin Matuska 
11481ad8388SMartin Matuska 		if (coder->block->check == LZMA_CHECK_NONE)
11581ad8388SMartin Matuska 			return LZMA_STREAM_END;
11681ad8388SMartin Matuska 
11781ad8388SMartin Matuska 		lzma_check_finish(&coder->check, coder->block->check);
11881ad8388SMartin Matuska 
11981ad8388SMartin Matuska 		coder->sequence = SEQ_CHECK;
12081ad8388SMartin Matuska 
12181ad8388SMartin Matuska 	// Fall through
12281ad8388SMartin Matuska 
12381ad8388SMartin Matuska 	case SEQ_CHECK: {
12481ad8388SMartin Matuska 		const size_t check_size = lzma_check_size(coder->block->check);
12581ad8388SMartin Matuska 		lzma_bufcpy(coder->check.buffer.u8, &coder->pos, check_size,
12681ad8388SMartin Matuska 				out, out_pos, out_size);
12781ad8388SMartin Matuska 		if (coder->pos < check_size)
12881ad8388SMartin Matuska 			return LZMA_OK;
12981ad8388SMartin Matuska 
13081ad8388SMartin Matuska 		memcpy(coder->block->raw_check, coder->check.buffer.u8,
13181ad8388SMartin Matuska 				check_size);
13281ad8388SMartin Matuska 		return LZMA_STREAM_END;
13381ad8388SMartin Matuska 	}
13481ad8388SMartin Matuska 	}
13581ad8388SMartin Matuska 
13681ad8388SMartin Matuska 	return LZMA_PROG_ERROR;
13781ad8388SMartin Matuska }
13881ad8388SMartin Matuska 
13981ad8388SMartin Matuska 
14081ad8388SMartin Matuska static void
1411456f0f9SXin LI block_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
14281ad8388SMartin Matuska {
1431456f0f9SXin LI 	lzma_block_coder *coder = coder_ptr;
14481ad8388SMartin Matuska 	lzma_next_end(&coder->next, allocator);
14581ad8388SMartin Matuska 	lzma_free(coder, allocator);
14681ad8388SMartin Matuska 	return;
14781ad8388SMartin Matuska }
14881ad8388SMartin Matuska 
14981ad8388SMartin Matuska 
15081ad8388SMartin Matuska static lzma_ret
1511456f0f9SXin LI block_encoder_update(void *coder_ptr, const lzma_allocator *allocator,
152e24134bcSMartin Matuska 		const lzma_filter *filters lzma_attribute((__unused__)),
15381ad8388SMartin Matuska 		const lzma_filter *reversed_filters)
15481ad8388SMartin Matuska {
1551456f0f9SXin LI 	lzma_block_coder *coder = coder_ptr;
1561456f0f9SXin LI 
15781ad8388SMartin Matuska 	if (coder->sequence != SEQ_CODE)
15881ad8388SMartin Matuska 		return LZMA_PROG_ERROR;
15981ad8388SMartin Matuska 
16081ad8388SMartin Matuska 	return lzma_next_filter_update(
16181ad8388SMartin Matuska 			&coder->next, allocator, reversed_filters);
16281ad8388SMartin Matuska }
16381ad8388SMartin Matuska 
16481ad8388SMartin Matuska 
16581ad8388SMartin Matuska extern lzma_ret
16653200025SRui Paulo lzma_block_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
16781ad8388SMartin Matuska 		lzma_block *block)
16881ad8388SMartin Matuska {
16981ad8388SMartin Matuska 	lzma_next_coder_init(&lzma_block_encoder_init, next, allocator);
17081ad8388SMartin Matuska 
171e24134bcSMartin Matuska 	if (block == NULL)
172e24134bcSMartin Matuska 		return LZMA_PROG_ERROR;
173e24134bcSMartin Matuska 
174e24134bcSMartin Matuska 	// The contents of the structure may depend on the version so
175e24134bcSMartin Matuska 	// check the version first.
17653200025SRui Paulo 	if (block->version > 1)
17781ad8388SMartin Matuska 		return LZMA_OPTIONS_ERROR;
17881ad8388SMartin Matuska 
17981ad8388SMartin Matuska 	// If the Check ID is not supported, we cannot calculate the check and
18081ad8388SMartin Matuska 	// thus not create a proper Block.
18181ad8388SMartin Matuska 	if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
18281ad8388SMartin Matuska 		return LZMA_PROG_ERROR;
18381ad8388SMartin Matuska 
18481ad8388SMartin Matuska 	if (!lzma_check_is_supported(block->check))
18581ad8388SMartin Matuska 		return LZMA_UNSUPPORTED_CHECK;
18681ad8388SMartin Matuska 
18781ad8388SMartin Matuska 	// Allocate and initialize *next->coder if needed.
1881456f0f9SXin LI 	lzma_block_coder *coder = next->coder;
1891456f0f9SXin LI 	if (coder == NULL) {
1901456f0f9SXin LI 		coder = lzma_alloc(sizeof(lzma_block_coder), allocator);
1911456f0f9SXin LI 		if (coder == NULL)
19281ad8388SMartin Matuska 			return LZMA_MEM_ERROR;
19381ad8388SMartin Matuska 
1941456f0f9SXin LI 		next->coder = coder;
19581ad8388SMartin Matuska 		next->code = &block_encode;
19681ad8388SMartin Matuska 		next->end = &block_encoder_end;
19781ad8388SMartin Matuska 		next->update = &block_encoder_update;
1981456f0f9SXin LI 		coder->next = LZMA_NEXT_CODER_INIT;
19981ad8388SMartin Matuska 	}
20081ad8388SMartin Matuska 
20181ad8388SMartin Matuska 	// Basic initializations
2021456f0f9SXin LI 	coder->sequence = SEQ_CODE;
2031456f0f9SXin LI 	coder->block = block;
2041456f0f9SXin LI 	coder->compressed_size = 0;
2051456f0f9SXin LI 	coder->uncompressed_size = 0;
2061456f0f9SXin LI 	coder->pos = 0;
20781ad8388SMartin Matuska 
20881ad8388SMartin Matuska 	// Initialize the check
2091456f0f9SXin LI 	lzma_check_init(&coder->check, block->check);
21081ad8388SMartin Matuska 
21181ad8388SMartin Matuska 	// Initialize the requested filters.
2121456f0f9SXin LI 	return lzma_raw_encoder_init(&coder->next, allocator, block->filters);
21381ad8388SMartin Matuska }
21481ad8388SMartin Matuska 
21581ad8388SMartin Matuska 
21681ad8388SMartin Matuska extern LZMA_API(lzma_ret)
21781ad8388SMartin Matuska lzma_block_encoder(lzma_stream *strm, lzma_block *block)
21881ad8388SMartin Matuska {
21981ad8388SMartin Matuska 	lzma_next_strm_init(lzma_block_encoder_init, strm, block);
22081ad8388SMartin Matuska 
22181ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_RUN] = true;
2220ca90ed4SXin LI 	strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
22381ad8388SMartin Matuska 	strm->internal->supported_actions[LZMA_FINISH] = true;
22481ad8388SMartin Matuska 
22581ad8388SMartin Matuska 	return LZMA_OK;
22681ad8388SMartin Matuska }
227