delta_encoder.c revision 213700
1178825Sdfr///////////////////////////////////////////////////////////////////////////////
2233294Sstas//
3233294Sstas/// \file       delta_encoder.c
4233294Sstas/// \brief      Delta filter encoder
5178825Sdfr//
6233294Sstas//  Author:     Lasse Collin
7233294Sstas//
8233294Sstas//  This file has been put into the public domain.
9178825Sdfr//  You can do whatever you want with this file.
10233294Sstas//
11233294Sstas///////////////////////////////////////////////////////////////////////////////
12178825Sdfr
13233294Sstas#include "delta_encoder.h"
14233294Sstas#include "delta_private.h"
15233294Sstas
16178825Sdfr
17233294Sstas/// Copies and encodes the data at the same time. This is used when Delta
18233294Sstas/// is the first filter in the chain (and thus the last filter in the
19233294Sstas/// encoder's filter stack).
20178825Sdfrstatic void
21233294Sstascopy_and_encode(lzma_coder *coder,
22233294Sstas		const uint8_t *restrict in, uint8_t *restrict out, size_t size)
23233294Sstas{
24233294Sstas	const size_t distance = coder->distance;
25233294Sstas
26233294Sstas	for (size_t i = 0; i < size; ++i) {
27233294Sstas		const uint8_t tmp = coder->history[
28233294Sstas				(distance + coder->pos) & 0xFF];
29233294Sstas		coder->history[coder->pos-- & 0xFF] = in[i];
30233294Sstas		out[i] = in[i] - tmp;
31233294Sstas	}
32178825Sdfr}
33178825Sdfr
34233294Sstas
35233294Sstas/// Encodes the data in place. This is used when we are the last filter
36178825Sdfr/// in the chain (and thus non-last filter in the encoder's filter stack).
37178825Sdfrstatic void
38178825Sdfrencode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size)
39178825Sdfr{
40178825Sdfr	const size_t distance = coder->distance;
41178825Sdfr
42178825Sdfr	for (size_t i = 0; i < size; ++i) {
43233294Sstas		const uint8_t tmp = coder->history[
44233294Sstas				(distance + coder->pos) & 0xFF];
45233294Sstas		coder->history[coder->pos-- & 0xFF] = buffer[i];
46233294Sstas		buffer[i] -= tmp;
47178825Sdfr	}
48233294Sstas}
49233294Sstas
50233294Sstas
51233294Sstasstatic lzma_ret
52178825Sdfrdelta_encode(lzma_coder *coder, lzma_allocator *allocator,
53178825Sdfr		const uint8_t *restrict in, size_t *restrict in_pos,
54178825Sdfr		size_t in_size, uint8_t *restrict out,
55178825Sdfr		size_t *restrict out_pos, size_t out_size, lzma_action action)
56178825Sdfr{
57178825Sdfr	lzma_ret ret;
58178825Sdfr
59178825Sdfr	if (coder->next.code == NULL) {
60178825Sdfr		const size_t in_avail = in_size - *in_pos;
61178825Sdfr		const size_t out_avail = out_size - *out_pos;
62178825Sdfr		const size_t size = my_min(in_avail, out_avail);
63178825Sdfr
64178825Sdfr		copy_and_encode(coder, in + *in_pos, out + *out_pos, size);
65178825Sdfr
66178825Sdfr		*in_pos += size;
67178825Sdfr		*out_pos += size;
68178825Sdfr
69178825Sdfr		ret = action != LZMA_RUN && *in_pos == in_size
70178825Sdfr				? LZMA_STREAM_END : LZMA_OK;
71178825Sdfr
72178825Sdfr	} else {
73178825Sdfr		const size_t out_start = *out_pos;
74178825Sdfr
75178825Sdfr		ret = coder->next.code(coder->next.coder, allocator,
76178825Sdfr				in, in_pos, in_size, out, out_pos, out_size,
77178825Sdfr				action);
78178825Sdfr
79178825Sdfr		encode_in_place(coder, out + out_start, *out_pos - out_start);
80178825Sdfr	}
81178825Sdfr
82178825Sdfr	return ret;
83178825Sdfr}
84178825Sdfr
85178825Sdfr
86178825Sdfrstatic lzma_ret
87178825Sdfrdelta_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
88178825Sdfr		const lzma_filter *filters_null lzma_attribute((unused)),
89178825Sdfr		const lzma_filter *reversed_filters)
90178825Sdfr{
91178825Sdfr	// Delta doesn't and will never support changing the options in
92178825Sdfr	// the middle of encoding. If the app tries to change them, we
93178825Sdfr	// simply ignore them.
94178825Sdfr	return lzma_next_filter_update(
95178825Sdfr			&coder->next, allocator, reversed_filters + 1);
96178825Sdfr}
97178825Sdfr
98178825Sdfr
99178825Sdfrextern lzma_ret
100178825Sdfrlzma_delta_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
101178825Sdfr		const lzma_filter_info *filters)
102178825Sdfr{
103178825Sdfr	next->code = &delta_encode;
104178825Sdfr	next->update = &delta_encoder_update;
105178825Sdfr	return lzma_delta_coder_init(next, allocator, filters);
106178825Sdfr}
107178825Sdfr
108178825Sdfr
109178825Sdfrextern lzma_ret
110178825Sdfrlzma_delta_props_encode(const void *options, uint8_t *out)
111178825Sdfr{
112178825Sdfr	// The caller must have already validated the options, so it's
113178825Sdfr	// LZMA_PROG_ERROR if they are invalid.
114178825Sdfr	if (lzma_delta_coder_memusage(options) == UINT64_MAX)
115178825Sdfr		return LZMA_PROG_ERROR;
116178825Sdfr
117178825Sdfr	const lzma_options_delta *opt = options;
118178825Sdfr	out[0] = opt->dist - LZMA_DELTA_DIST_MIN;
119178825Sdfr
120178825Sdfr	return LZMA_OK;
121178825Sdfr}
122178825Sdfr