mirror of
				https://git.tukaani.org/xz.git
				synced 2025-11-03 23:12:57 +00:00 
			
		
		
		
	Using return_if_error on lzma_lzma_lclppb_encode was improper because return_if_error is expecting an lzma_ret value, but lzma_lzma_lclppb_encode returns a boolean. This could result in lzma_microlzma_encoder, which would be misleading for applications.
		
			
				
	
	
		
			142 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
///////////////////////////////////////////////////////////////////////////////
 | 
						|
//
 | 
						|
/// \file       microlzma_encoder.c
 | 
						|
/// \brief      Encode into MicroLZMA format
 | 
						|
//
 | 
						|
//  Author:     Lasse Collin
 | 
						|
//
 | 
						|
//  This file has been put into the public domain.
 | 
						|
//  You can do whatever you want with this file.
 | 
						|
//
 | 
						|
///////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
#include "lzma_encoder.h"
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
	/// LZMA1 encoder
 | 
						|
	lzma_next_coder lzma;
 | 
						|
 | 
						|
	/// LZMA properties byte (lc/lp/pb)
 | 
						|
	uint8_t props;
 | 
						|
} lzma_microlzma_coder;
 | 
						|
 | 
						|
 | 
						|
static lzma_ret
 | 
						|
microlzma_encode(void *coder_ptr, const lzma_allocator *allocator,
 | 
						|
		const uint8_t *restrict in, size_t *restrict in_pos,
 | 
						|
		size_t in_size, uint8_t *restrict out,
 | 
						|
		size_t *restrict out_pos, size_t out_size, lzma_action action)
 | 
						|
{
 | 
						|
	lzma_microlzma_coder *coder = coder_ptr;
 | 
						|
 | 
						|
	// Remember *out_pos so that we can overwrite the first byte with
 | 
						|
	// the LZMA properties byte.
 | 
						|
	const size_t out_start = *out_pos;
 | 
						|
 | 
						|
	// Remember *in_pos so that we can set it based on how many
 | 
						|
	// uncompressed bytes were actually encoded.
 | 
						|
	const size_t in_start = *in_pos;
 | 
						|
 | 
						|
	// Set the output size limit based on the available output space.
 | 
						|
	// We know that the encoder supports set_out_limit() so
 | 
						|
	// LZMA_OPTIONS_ERROR isn't possible. LZMA_BUF_ERROR is possible
 | 
						|
	// but lzma_code() has an assertion to not allow it to be returned
 | 
						|
	// from here and I don't want to change that for now, so
 | 
						|
	// LZMA_BUF_ERROR becomes LZMA_PROG_ERROR.
 | 
						|
	uint64_t uncomp_size;
 | 
						|
	if (coder->lzma.set_out_limit(coder->lzma.coder,
 | 
						|
			&uncomp_size, out_size - *out_pos) != LZMA_OK)
 | 
						|
		return LZMA_PROG_ERROR;
 | 
						|
 | 
						|
	// set_out_limit fails if this isn't true.
 | 
						|
	assert(out_size - *out_pos >= 6);
 | 
						|
 | 
						|
	// Encode as much as possible.
 | 
						|
	const lzma_ret ret = coder->lzma.code(coder->lzma.coder, allocator,
 | 
						|
			in, in_pos, in_size, out, out_pos, out_size, action);
 | 
						|
 | 
						|
	if (ret != LZMA_STREAM_END) {
 | 
						|
		if (ret == LZMA_OK) {
 | 
						|
			assert(0);
 | 
						|
			return LZMA_PROG_ERROR;
 | 
						|
		}
 | 
						|
 | 
						|
		return ret;
 | 
						|
	}
 | 
						|
 | 
						|
	// The first output byte is bitwise-negation of the properties byte.
 | 
						|
	// We know that there is space for this byte because set_out_limit
 | 
						|
	// and the actual encoding succeeded.
 | 
						|
	out[out_start] = (uint8_t)(~coder->props);
 | 
						|
 | 
						|
	// The LZMA encoder likely read more input than it was able to encode.
 | 
						|
	// Set *in_pos based on uncomp_size.
 | 
						|
	assert(uncomp_size <= in_size - in_start);
 | 
						|
	*in_pos = in_start + (size_t)(uncomp_size);
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
microlzma_encoder_end(void *coder_ptr, const lzma_allocator *allocator)
 | 
						|
{
 | 
						|
	lzma_microlzma_coder *coder = coder_ptr;
 | 
						|
	lzma_next_end(&coder->lzma, allocator);
 | 
						|
	lzma_free(coder, allocator);
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static lzma_ret
 | 
						|
microlzma_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
 | 
						|
		const lzma_options_lzma *options)
 | 
						|
{
 | 
						|
	lzma_next_coder_init(µlzma_encoder_init, next, allocator);
 | 
						|
 | 
						|
	lzma_microlzma_coder *coder = next->coder;
 | 
						|
 | 
						|
	if (coder == NULL) {
 | 
						|
		coder = lzma_alloc(sizeof(lzma_microlzma_coder), allocator);
 | 
						|
		if (coder == NULL)
 | 
						|
			return LZMA_MEM_ERROR;
 | 
						|
 | 
						|
		next->coder = coder;
 | 
						|
		next->code = µlzma_encode;
 | 
						|
		next->end = µlzma_encoder_end;
 | 
						|
 | 
						|
		coder->lzma = LZMA_NEXT_CODER_INIT;
 | 
						|
	}
 | 
						|
 | 
						|
	// Encode the properties byte. Bitwise-negation of it will be the
 | 
						|
	// first output byte.
 | 
						|
	if (lzma_lzma_lclppb_encode(options, &coder->props))
 | 
						|
		return LZMA_OPTIONS_ERROR;
 | 
						|
 | 
						|
	// Initialize the LZMA encoder.
 | 
						|
	const lzma_filter_info filters[2] = {
 | 
						|
		{
 | 
						|
			.id = LZMA_FILTER_LZMA1,
 | 
						|
			.init = &lzma_lzma_encoder_init,
 | 
						|
			.options = (void *)(options),
 | 
						|
		}, {
 | 
						|
			.init = NULL,
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	return lzma_next_filter_init(&coder->lzma, allocator, filters);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
extern LZMA_API(lzma_ret)
 | 
						|
lzma_microlzma_encoder(lzma_stream *strm, const lzma_options_lzma *options)
 | 
						|
{
 | 
						|
	lzma_next_strm_init(microlzma_encoder_init, strm, options);
 | 
						|
 | 
						|
	strm->internal->supported_actions[LZMA_FINISH] = true;
 | 
						|
 | 
						|
	return LZMA_OK;
 | 
						|
 | 
						|
}
 |