1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file delta_encoder.c
4 /// \brief Delta filter encoder
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
13 #include "delta_encoder.h"
14 #include "delta_private.h"
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).
21 copy_and_encode(lzma_delta_coder
*coder
,
22 const uint8_t *restrict in
, uint8_t *restrict out
, size_t size
)
24 const size_t distance
= coder
->distance
;
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
];
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).
38 encode_in_place(lzma_delta_coder
*coder
, uint8_t *buffer
, size_t size
)
40 const size_t distance
= coder
->distance
;
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
];
52 delta_encode(void *coder_ptr
, 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
)
57 lzma_delta_coder
*coder
= coder_ptr
;
61 if (coder
->next
.code
== NULL
) {
62 const size_t in_avail
= in_size
- *in_pos
;
63 const size_t out_avail
= out_size
- *out_pos
;
64 const size_t size
= my_min(in_avail
, out_avail
);
66 // in and out might be NULL. In such cases size == 0.
67 // Null pointer + 0 is undefined behavior so skip
68 // the call in that case as it would do nothing anyway.
70 copy_and_encode(coder
, in
+ *in_pos
, out
+ *out_pos
,
76 ret
= action
!= LZMA_RUN
&& *in_pos
== in_size
77 ? LZMA_STREAM_END
: LZMA_OK
;
80 const size_t out_start
= *out_pos
;
82 ret
= coder
->next
.code(coder
->next
.coder
, allocator
,
83 in
, in_pos
, in_size
, out
, out_pos
, out_size
,
86 // Like above, avoid null pointer + 0.
87 const size_t size
= *out_pos
- out_start
;
89 encode_in_place(coder
, out
+ out_start
, size
);
97 delta_encoder_update(void *coder_ptr
, const lzma_allocator
*allocator
,
98 const lzma_filter
*filters_null
lzma_attribute((__unused__
)),
99 const lzma_filter
*reversed_filters
)
101 lzma_delta_coder
*coder
= coder_ptr
;
103 // Delta doesn't and will never support changing the options in
104 // the middle of encoding. If the app tries to change them, we
105 // simply ignore them.
106 return lzma_next_filter_update(
107 &coder
->next
, allocator
, reversed_filters
+ 1);
112 lzma_delta_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
113 const lzma_filter_info
*filters
)
115 next
->code
= &delta_encode
;
116 next
->update
= &delta_encoder_update
;
117 return lzma_delta_coder_init(next
, allocator
, filters
);
122 lzma_delta_props_encode(const void *options
, uint8_t *out
)
124 // The caller must have already validated the options, so it's
125 // LZMA_PROG_ERROR if they are invalid.
126 if (lzma_delta_coder_memusage(options
) == UINT64_MAX
)
127 return LZMA_PROG_ERROR
;
129 const lzma_options_delta
*opt
= options
;
130 out
[0] = opt
->dist
- LZMA_DELTA_DIST_MIN
;