1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file block_encoder.c
6 /// \brief Encodes .xz Blocks
8 // Author: Lasse Collin
10 ///////////////////////////////////////////////////////////////////////////////
12 #include "block_encoder.h"
13 #include "filter_encoder.h"
18 /// The filters in the chain; initialized with lzma_raw_decoder_init().
21 /// Encoding options; we also write Unpadded Size, Compressed Size,
22 /// and Uncompressed Size back to this structure when the encoding
23 /// has been finished.
32 /// Compressed Size calculated while encoding
33 lzma_vli compressed_size
;
35 /// Uncompressed Size calculated while encoding
36 lzma_vli uncompressed_size
;
38 /// Position in the Check field
41 /// Check of the uncompressed data
42 lzma_check_state check
;
47 block_encode(void *coder_ptr
, const lzma_allocator
*allocator
,
48 const uint8_t *restrict in
, size_t *restrict in_pos
,
49 size_t in_size
, uint8_t *restrict out
,
50 size_t *restrict out_pos
, size_t out_size
, lzma_action action
)
52 lzma_block_coder
*coder
= coder_ptr
;
54 // Check that our amount of input stays in proper limits.
55 if (LZMA_VLI_MAX
- coder
->uncompressed_size
< in_size
- *in_pos
)
56 return LZMA_DATA_ERROR
;
58 switch (coder
->sequence
) {
60 const size_t in_start
= *in_pos
;
61 const size_t out_start
= *out_pos
;
63 const lzma_ret ret
= coder
->next
.code(coder
->next
.coder
,
64 allocator
, in
, in_pos
, in_size
,
65 out
, out_pos
, out_size
, action
);
67 const size_t in_used
= *in_pos
- in_start
;
68 const size_t out_used
= *out_pos
- out_start
;
70 if (COMPRESSED_SIZE_MAX
- coder
->compressed_size
< out_used
)
71 return LZMA_DATA_ERROR
;
73 coder
->compressed_size
+= out_used
;
75 // No need to check for overflow because we have already
76 // checked it at the beginning of this function.
77 coder
->uncompressed_size
+= in_used
;
79 // Call lzma_check_update() only if input was consumed. This
80 // avoids null pointer + 0 (undefined behavior) when in == 0.
82 lzma_check_update(&coder
->check
, coder
->block
->check
,
83 in
+ in_start
, in_used
);
85 if (ret
!= LZMA_STREAM_END
|| action
== LZMA_SYNC_FLUSH
)
88 assert(*in_pos
== in_size
);
89 assert(action
== LZMA_FINISH
);
91 // Copy the values into coder->block. The caller
92 // may use this information to construct Index.
93 coder
->block
->compressed_size
= coder
->compressed_size
;
94 coder
->block
->uncompressed_size
= coder
->uncompressed_size
;
96 coder
->sequence
= SEQ_PADDING
;
102 // Pad Compressed Data to a multiple of four bytes. We can
103 // use coder->compressed_size for this since we don't need
104 // it for anything else anymore.
105 while (coder
->compressed_size
& 3) {
106 if (*out_pos
>= out_size
)
109 out
[*out_pos
] = 0x00;
111 ++coder
->compressed_size
;
114 if (coder
->block
->check
== LZMA_CHECK_NONE
)
115 return LZMA_STREAM_END
;
117 lzma_check_finish(&coder
->check
, coder
->block
->check
);
119 coder
->sequence
= SEQ_CHECK
;
124 const size_t check_size
= lzma_check_size(coder
->block
->check
);
125 lzma_bufcpy(coder
->check
.buffer
.u8
, &coder
->pos
, check_size
,
126 out
, out_pos
, out_size
);
127 if (coder
->pos
< check_size
)
130 memcpy(coder
->block
->raw_check
, coder
->check
.buffer
.u8
,
132 return LZMA_STREAM_END
;
136 return LZMA_PROG_ERROR
;
141 block_encoder_end(void *coder_ptr
, const lzma_allocator
*allocator
)
143 lzma_block_coder
*coder
= coder_ptr
;
144 lzma_next_end(&coder
->next
, allocator
);
145 lzma_free(coder
, allocator
);
151 block_encoder_update(void *coder_ptr
, const lzma_allocator
*allocator
,
152 const lzma_filter
*filters
lzma_attribute((__unused__
)),
153 const lzma_filter
*reversed_filters
)
155 lzma_block_coder
*coder
= coder_ptr
;
157 if (coder
->sequence
!= SEQ_CODE
)
158 return LZMA_PROG_ERROR
;
160 return lzma_next_filter_update(
161 &coder
->next
, allocator
, reversed_filters
);
166 lzma_block_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
169 lzma_next_coder_init(&lzma_block_encoder_init
, next
, allocator
);
172 return LZMA_PROG_ERROR
;
174 // The contents of the structure may depend on the version so
175 // check the version first.
176 if (block
->version
> 1)
177 return LZMA_OPTIONS_ERROR
;
179 // If the Check ID is not supported, we cannot calculate the check and
180 // thus not create a proper Block.
181 if ((unsigned int)(block
->check
) > LZMA_CHECK_ID_MAX
)
182 return LZMA_PROG_ERROR
;
184 if (!lzma_check_is_supported(block
->check
))
185 return LZMA_UNSUPPORTED_CHECK
;
187 // Allocate and initialize *next->coder if needed.
188 lzma_block_coder
*coder
= next
->coder
;
190 coder
= lzma_alloc(sizeof(lzma_block_coder
), allocator
);
192 return LZMA_MEM_ERROR
;
195 next
->code
= &block_encode
;
196 next
->end
= &block_encoder_end
;
197 next
->update
= &block_encoder_update
;
198 coder
->next
= LZMA_NEXT_CODER_INIT
;
201 // Basic initializations
202 coder
->sequence
= SEQ_CODE
;
203 coder
->block
= block
;
204 coder
->compressed_size
= 0;
205 coder
->uncompressed_size
= 0;
208 // Initialize the check
209 lzma_check_init(&coder
->check
, block
->check
);
211 // Initialize the requested filters.
212 return lzma_raw_encoder_init(&coder
->next
, allocator
, block
->filters
);
216 extern LZMA_API(lzma_ret
)
217 lzma_block_encoder(lzma_stream
*strm
, lzma_block
*block
)
219 lzma_next_strm_init(lzma_block_encoder_init
, strm
, block
);
221 strm
->internal
->supported_actions
[LZMA_RUN
] = true;
222 strm
->internal
->supported_actions
[LZMA_SYNC_FLUSH
] = true;
223 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;