1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file delta_encoder.c
6 /// \brief Delta filter encoder
8 // Author: Lasse Collin
10 ///////////////////////////////////////////////////////////////////////////////
12 #include "delta_encoder.h"
13 #include "delta_private.h"
16 /// Copies and encodes the data at the same time. This is used when Delta
17 /// is the first filter in the chain (and thus the last filter in the
18 /// encoder's filter stack).
20 copy_and_encode(lzma_delta_coder
*coder
,
21 const uint8_t *restrict in
, uint8_t *restrict out
, size_t size
)
23 const size_t distance
= coder
->distance
;
25 for (size_t i
= 0; i
< size
; ++i
) {
26 const uint8_t tmp
= coder
->history
[
27 (distance
+ coder
->pos
) & 0xFF];
28 coder
->history
[coder
->pos
-- & 0xFF] = in
[i
];
34 /// Encodes the data in place. This is used when we are the last filter
35 /// in the chain (and thus non-last filter in the encoder's filter stack).
37 encode_in_place(lzma_delta_coder
*coder
, uint8_t *buffer
, size_t size
)
39 const size_t distance
= coder
->distance
;
41 for (size_t i
= 0; i
< size
; ++i
) {
42 const uint8_t tmp
= coder
->history
[
43 (distance
+ coder
->pos
) & 0xFF];
44 coder
->history
[coder
->pos
-- & 0xFF] = buffer
[i
];
51 delta_encode(void *coder_ptr
, const lzma_allocator
*allocator
,
52 const uint8_t *restrict in
, size_t *restrict in_pos
,
53 size_t in_size
, uint8_t *restrict out
,
54 size_t *restrict out_pos
, size_t out_size
, lzma_action action
)
56 lzma_delta_coder
*coder
= coder_ptr
;
60 if (coder
->next
.code
== NULL
) {
61 const size_t in_avail
= in_size
- *in_pos
;
62 const size_t out_avail
= out_size
- *out_pos
;
63 const size_t size
= my_min(in_avail
, out_avail
);
65 // in and out might be NULL. In such cases size == 0.
66 // Null pointer + 0 is undefined behavior so skip
67 // the call in that case as it would do nothing anyway.
69 copy_and_encode(coder
, in
+ *in_pos
, out
+ *out_pos
,
75 ret
= action
!= LZMA_RUN
&& *in_pos
== in_size
76 ? LZMA_STREAM_END
: LZMA_OK
;
79 const size_t out_start
= *out_pos
;
81 ret
= coder
->next
.code(coder
->next
.coder
, allocator
,
82 in
, in_pos
, in_size
, out
, out_pos
, out_size
,
85 // Like above, avoid null pointer + 0.
86 const size_t size
= *out_pos
- out_start
;
88 encode_in_place(coder
, out
+ out_start
, size
);
96 delta_encoder_update(void *coder_ptr
, const lzma_allocator
*allocator
,
97 const lzma_filter
*filters_null
lzma_attribute((__unused__
)),
98 const lzma_filter
*reversed_filters
)
100 lzma_delta_coder
*coder
= coder_ptr
;
102 // Delta doesn't and will never support changing the options in
103 // the middle of encoding. If the app tries to change them, we
104 // simply ignore them.
105 return lzma_next_filter_update(
106 &coder
->next
, allocator
, reversed_filters
+ 1);
111 lzma_delta_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
112 const lzma_filter_info
*filters
)
114 next
->code
= &delta_encode
;
115 next
->update
= &delta_encoder_update
;
116 return lzma_delta_coder_init(next
, allocator
, filters
);
121 lzma_delta_props_encode(const void *options
, uint8_t *out
)
123 // The caller must have already validated the options, so it's
124 // LZMA_PROG_ERROR if they are invalid.
125 if (lzma_delta_coder_memusage(options
) == UINT64_MAX
)
126 return LZMA_PROG_ERROR
;
128 const lzma_options_delta
*opt
= options
;
129 out
[0] = opt
->dist
- LZMA_DELTA_DIST_MIN
;