delta_encoder.c revision 292588
133965Sjdp///////////////////////////////////////////////////////////////////////////////
260484Sobrien//
338889Sjdp/// \file       delta_encoder.c
433965Sjdp/// \brief      Delta filter encoder
533965Sjdp//
633965Sjdp//  Author:     Lasse Collin
733965Sjdp//
833965Sjdp//  This file has been put into the public domain.
933965Sjdp//  You can do whatever you want with this file.
1033965Sjdp//
1133965Sjdp///////////////////////////////////////////////////////////////////////////////
1233965Sjdp
1333965Sjdp#include "delta_encoder.h"
1433965Sjdp#include "delta_private.h"
1533965Sjdp
1633965Sjdp
1733965Sjdp/// Copies and encodes the data at the same time. This is used when Delta
1833965Sjdp/// is the first filter in the chain (and thus the last filter in the
1933965Sjdp/// encoder's filter stack).
2033965Sjdpstatic void
2133965Sjdpcopy_and_encode(lzma_coder *coder,
2233965Sjdp		const uint8_t *restrict in, uint8_t *restrict out, size_t size)
2333965Sjdp{
2433965Sjdp	const size_t distance = coder->distance;
2533965Sjdp
2633965Sjdp	for (size_t i = 0; i < size; ++i) {
2733965Sjdp		const uint8_t tmp = coder->history[
2833965Sjdp				(distance + coder->pos) & 0xFF];
2933965Sjdp		coder->history[coder->pos-- & 0xFF] = in[i];
3033965Sjdp		out[i] = in[i] - tmp;
3133965Sjdp	}
3233965Sjdp}
3333965Sjdp
3433965Sjdp
3533965Sjdp/// Encodes the data in place. This is used when we are the last filter
3633965Sjdp/// in the chain (and thus non-last filter in the encoder's filter stack).
3733965Sjdpstatic void
3833965Sjdpencode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size)
3933965Sjdp{
4033965Sjdp	const size_t distance = coder->distance;
4133965Sjdp
4233965Sjdp	for (size_t i = 0; i < size; ++i) {
4333965Sjdp		const uint8_t tmp = coder->history[
4433965Sjdp				(distance + coder->pos) & 0xFF];
4533965Sjdp		coder->history[coder->pos-- & 0xFF] = buffer[i];
4633965Sjdp		buffer[i] -= tmp;
4733965Sjdp	}
4833965Sjdp}
4933965Sjdp
5033965Sjdp
5133965Sjdpstatic lzma_ret
5233965Sjdpdelta_encode(lzma_coder *coder, const lzma_allocator *allocator,
5333965Sjdp		const uint8_t *restrict in, size_t *restrict in_pos,
5433965Sjdp		size_t in_size, uint8_t *restrict out,
5533965Sjdp		size_t *restrict out_pos, size_t out_size, lzma_action action)
5633965Sjdp{
5733965Sjdp	lzma_ret ret;
5833965Sjdp
5933965Sjdp	if (coder->next.code == NULL) {
6033965Sjdp		const size_t in_avail = in_size - *in_pos;
6133965Sjdp		const size_t out_avail = out_size - *out_pos;
6233965Sjdp		const size_t size = my_min(in_avail, out_avail);
6377298Sobrien
6433965Sjdp		copy_and_encode(coder, in + *in_pos, out + *out_pos, size);
6533965Sjdp
6638889Sjdp		*in_pos += size;
6733965Sjdp		*out_pos += size;
6833965Sjdp
6933965Sjdp		ret = action != LZMA_RUN && *in_pos == in_size
7033965Sjdp				? LZMA_STREAM_END : LZMA_OK;
7133965Sjdp
7233965Sjdp	} else {
7333965Sjdp		const size_t out_start = *out_pos;
7433965Sjdp
7533965Sjdp		ret = coder->next.code(coder->next.coder, allocator,
7633965Sjdp				in, in_pos, in_size, out, out_pos, out_size,
7733965Sjdp				action);
7833965Sjdp
7933965Sjdp		encode_in_place(coder, out + out_start, *out_pos - out_start);
8033965Sjdp	}
8133965Sjdp
8233965Sjdp	return ret;
8333965Sjdp}
8433965Sjdp
8533965Sjdp
8633965Sjdpstatic lzma_ret
8733965Sjdpdelta_encoder_update(lzma_coder *coder, const lzma_allocator *allocator,
8833965Sjdp		const lzma_filter *filters_null lzma_attribute((__unused__)),
8933965Sjdp		const lzma_filter *reversed_filters)
9033965Sjdp{
9133965Sjdp	// Delta doesn't and will never support changing the options in
9233965Sjdp	// the middle of encoding. If the app tries to change them, we
9333965Sjdp	// simply ignore them.
9433965Sjdp	return lzma_next_filter_update(
9533965Sjdp			&coder->next, allocator, reversed_filters + 1);
9633965Sjdp}
9733965Sjdp
9833965Sjdp
9933965Sjdpextern lzma_ret
10033965Sjdplzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator,
10133965Sjdp		const lzma_filter_info *filters)
10233965Sjdp{
10333965Sjdp	next->code = &delta_encode;
10433965Sjdp	next->update = &delta_encoder_update;
10533965Sjdp	return lzma_delta_coder_init(next, allocator, filters);
10633965Sjdp}
10733965Sjdp
10833965Sjdp
10933965Sjdpextern lzma_ret
11033965Sjdplzma_delta_props_encode(const void *options, uint8_t *out)
11133965Sjdp{
11233965Sjdp	// The caller must have already validated the options, so it's
11333965Sjdp	// LZMA_PROG_ERROR if they are invalid.
11433965Sjdp	if (lzma_delta_coder_memusage(options) == UINT64_MAX)
11533965Sjdp		return LZMA_PROG_ERROR;
11633965Sjdp
11733965Sjdp	const lzma_options_delta *opt = options;
11833965Sjdp	out[0] = opt->dist - LZMA_DELTA_DIST_MIN;
11933965Sjdp
12033965Sjdp	return LZMA_OK;
12133965Sjdp}
12233965Sjdp