1 |
/////////////////////////////////////////////////////////////////////////////// |
2 |
// |
3 |
/// \file delta_encoder.c |
4 |
/// \brief Delta filter encoder |
5 |
// |
6 |
// Author: Lasse Collin |
7 |
// |
8 |
// This file has been put into the public domain. |
9 |
// You can do whatever you want with this file. |
10 |
// |
11 |
/////////////////////////////////////////////////////////////////////////////// |
12 |
|
13 |
#include "delta_encoder.h" |
14 |
#include "delta_private.h" |
15 |
|
16 |
|
17 |
/// Copies and encodes the data at the same time. This is used when Delta |
18 |
/// is the first filter in the chain (and thus the last filter in the |
19 |
/// encoder's filter stack). |
20 |
static void |
21 |
copy_and_encode(lzma_coder *coder, |
22 |
const uint8_t *restrict in, uint8_t *restrict out, size_t size) |
23 |
{ |
24 |
const size_t distance = coder->distance; |
25 |
|
26 |
for (size_t i = 0; i < size; ++i) { |
27 |
const uint8_t tmp = coder->history[ |
28 |
(distance + coder->pos) & 0xFF]; |
29 |
coder->history[coder->pos-- & 0xFF] = in[i]; |
30 |
out[i] = in[i] - tmp; |
31 |
} |
32 |
} |
33 |
|
34 |
|
35 |
/// Encodes the data in place. This is used when we are the last filter |
36 |
/// in the chain (and thus non-last filter in the encoder's filter stack). |
37 |
static void |
38 |
encode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size) |
39 |
{ |
40 |
const size_t distance = coder->distance; |
41 |
|
42 |
for (size_t i = 0; i < size; ++i) { |
43 |
const uint8_t tmp = coder->history[ |
44 |
(distance + coder->pos) & 0xFF]; |
45 |
coder->history[coder->pos-- & 0xFF] = buffer[i]; |
46 |
buffer[i] -= tmp; |
47 |
} |
48 |
} |
49 |
|
50 |
|
51 |
static lzma_ret |
52 |
delta_encode(lzma_coder *coder, const lzma_allocator *allocator, |
53 |
const uint8_t *restrict in, size_t *restrict in_pos, |
54 |
size_t in_size, uint8_t *restrict out, |
55 |
size_t *restrict out_pos, size_t out_size, lzma_action action) |
56 |
{ |
57 |
lzma_ret ret; |
58 |
|
59 |
if (coder->next.code == NULL) { |
60 |
const size_t in_avail = in_size - *in_pos; |
61 |
const size_t out_avail = out_size - *out_pos; |
62 |
const size_t size = my_min(in_avail, out_avail); |
63 |
|
64 |
copy_and_encode(coder, in + *in_pos, out + *out_pos, size); |
65 |
|
66 |
*in_pos += size; |
67 |
*out_pos += size; |
68 |
|
69 |
ret = action != LZMA_RUN && *in_pos == in_size |
70 |
? LZMA_STREAM_END : LZMA_OK; |
71 |
|
72 |
} else { |
73 |
const size_t out_start = *out_pos; |
74 |
|
75 |
ret = coder->next.code(coder->next.coder, allocator, |
76 |
in, in_pos, in_size, out, out_pos, out_size, |
77 |
action); |
78 |
|
79 |
encode_in_place(coder, out + out_start, *out_pos - out_start); |
80 |
} |
81 |
|
82 |
return ret; |
83 |
} |
84 |
|
85 |
|
86 |
static lzma_ret |
87 |
delta_encoder_update(lzma_coder *coder, const lzma_allocator *allocator, |
88 |
const lzma_filter *filters_null lzma_attribute((__unused__)), |
89 |
const lzma_filter *reversed_filters) |
90 |
{ |
91 |
// Delta doesn't and will never support changing the options in |
92 |
// the middle of encoding. If the app tries to change them, we |
93 |
// simply ignore them. |
94 |
return lzma_next_filter_update( |
95 |
&coder->next, allocator, reversed_filters + 1); |
96 |
} |
97 |
|
98 |
|
99 |
extern lzma_ret |
100 |
lzma_delta_encoder_init(lzma_next_coder *next, const lzma_allocator *allocator, |
101 |
const lzma_filter_info *filters) |
102 |
{ |
103 |
next->code = &delta_encode; |
104 |
next->update = &delta_encoder_update; |
105 |
return lzma_delta_coder_init(next, allocator, filters); |
106 |
} |
107 |
|
108 |
|
109 |
extern lzma_ret |
110 |
lzma_delta_props_encode(const void *options, uint8_t *out) |
111 |
{ |
112 |
// The caller must have already validated the options, so it's |
113 |
// LZMA_PROG_ERROR if they are invalid. |
114 |
if (lzma_delta_coder_memusage(options) == UINT64_MAX) |
115 |
return LZMA_PROG_ERROR; |
116 |
|
117 |
const lzma_options_delta *opt = options; |
118 |
out[0] = opt->dist - LZMA_DELTA_DIST_MIN; |
119 |
|
120 |
return LZMA_OK; |
121 |
} |