1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file block_encoder.c
4 /// \brief Encodes .xz Blocks
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 "block_encoder.h"
14 #include "filter_encoder.h"
19 /// The filters in the chain; initialized with lzma_raw_decoder_init().
22 /// Encoding options; we also write Unpadded Size, Compressed Size,
23 /// and Uncompressed Size back to this structure when the encoding
24 /// has been finished.
33 /// Compressed Size calculated while encoding
34 lzma_vli compressed_size
;
36 /// Uncompressed Size calculated while encoding
37 lzma_vli uncompressed_size
;
39 /// Position in the Check field
42 /// Check of the uncompressed data
43 lzma_check_state check
;
48 block_encode(void *coder_ptr
, const lzma_allocator
*allocator
,
49 const uint8_t *restrict in
, size_t *restrict in_pos
,
50 size_t in_size
, uint8_t *restrict out
,
51 size_t *restrict out_pos
, size_t out_size
, lzma_action action
)
53 lzma_block_coder
*coder
= coder_ptr
;
55 // Check that our amount of input stays in proper limits.
56 if (LZMA_VLI_MAX
- coder
->uncompressed_size
< in_size
- *in_pos
)
57 return LZMA_DATA_ERROR
;
59 switch (coder
->sequence
) {
61 const size_t in_start
= *in_pos
;
62 const size_t out_start
= *out_pos
;
64 const lzma_ret ret
= coder
->next
.code(coder
->next
.coder
,
65 allocator
, in
, in_pos
, in_size
,
66 out
, out_pos
, out_size
, action
);
68 const size_t in_used
= *in_pos
- in_start
;
69 const size_t out_used
= *out_pos
- out_start
;
71 if (COMPRESSED_SIZE_MAX
- coder
->compressed_size
< out_used
)
72 return LZMA_DATA_ERROR
;
74 coder
->compressed_size
+= out_used
;
76 // No need to check for overflow because we have already
77 // checked it at the beginning of this function.
78 coder
->uncompressed_size
+= in_used
;
80 // Call lzma_check_update() only if input was consumed. This
81 // avoids null pointer + 0 (undefined behavior) when in == 0.
83 lzma_check_update(&coder
->check
, coder
->block
->check
,
84 in
+ in_start
, in_used
);
86 if (ret
!= LZMA_STREAM_END
|| action
== LZMA_SYNC_FLUSH
)
89 assert(*in_pos
== in_size
);
90 assert(action
== LZMA_FINISH
);
92 // Copy the values into coder->block. The caller
93 // may use this information to construct Index.
94 coder
->block
->compressed_size
= coder
->compressed_size
;
95 coder
->block
->uncompressed_size
= coder
->uncompressed_size
;
97 coder
->sequence
= SEQ_PADDING
;
103 // Pad Compressed Data to a multiple of four bytes. We can
104 // use coder->compressed_size for this since we don't need
105 // it for anything else anymore.
106 while (coder
->compressed_size
& 3) {
107 if (*out_pos
>= out_size
)
110 out
[*out_pos
] = 0x00;
112 ++coder
->compressed_size
;
115 if (coder
->block
->check
== LZMA_CHECK_NONE
)
116 return LZMA_STREAM_END
;
118 lzma_check_finish(&coder
->check
, coder
->block
->check
);
120 coder
->sequence
= SEQ_CHECK
;
125 const size_t check_size
= lzma_check_size(coder
->block
->check
);
126 lzma_bufcpy(coder
->check
.buffer
.u8
, &coder
->pos
, check_size
,
127 out
, out_pos
, out_size
);
128 if (coder
->pos
< check_size
)
131 memcpy(coder
->block
->raw_check
, coder
->check
.buffer
.u8
,
133 return LZMA_STREAM_END
;
137 return LZMA_PROG_ERROR
;
142 block_encoder_end(void *coder_ptr
, const lzma_allocator
*allocator
)
144 lzma_block_coder
*coder
= coder_ptr
;
145 lzma_next_end(&coder
->next
, allocator
);
146 lzma_free(coder
, allocator
);
152 block_encoder_update(void *coder_ptr
, const lzma_allocator
*allocator
,
153 const lzma_filter
*filters
lzma_attribute((__unused__
)),
154 const lzma_filter
*reversed_filters
)
156 lzma_block_coder
*coder
= coder_ptr
;
158 if (coder
->sequence
!= SEQ_CODE
)
159 return LZMA_PROG_ERROR
;
161 return lzma_next_filter_update(
162 &coder
->next
, allocator
, reversed_filters
);
167 lzma_block_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
170 lzma_next_coder_init(&lzma_block_encoder_init
, next
, allocator
);
173 return LZMA_PROG_ERROR
;
175 // The contents of the structure may depend on the version so
176 // check the version first.
177 if (block
->version
> 1)
178 return LZMA_OPTIONS_ERROR
;
180 // If the Check ID is not supported, we cannot calculate the check and
181 // thus not create a proper Block.
182 if ((unsigned int)(block
->check
) > LZMA_CHECK_ID_MAX
)
183 return LZMA_PROG_ERROR
;
185 if (!lzma_check_is_supported(block
->check
))
186 return LZMA_UNSUPPORTED_CHECK
;
188 // Allocate and initialize *next->coder if needed.
189 lzma_block_coder
*coder
= next
->coder
;
191 coder
= lzma_alloc(sizeof(lzma_block_coder
), allocator
);
193 return LZMA_MEM_ERROR
;
196 next
->code
= &block_encode
;
197 next
->end
= &block_encoder_end
;
198 next
->update
= &block_encoder_update
;
199 coder
->next
= LZMA_NEXT_CODER_INIT
;
202 // Basic initializations
203 coder
->sequence
= SEQ_CODE
;
204 coder
->block
= block
;
205 coder
->compressed_size
= 0;
206 coder
->uncompressed_size
= 0;
209 // Initialize the check
210 lzma_check_init(&coder
->check
, block
->check
);
212 // Initialize the requested filters.
213 return lzma_raw_encoder_init(&coder
->next
, allocator
, block
->filters
);
217 extern LZMA_API(lzma_ret
)
218 lzma_block_encoder(lzma_stream
*strm
, lzma_block
*block
)
220 lzma_next_strm_init(lzma_block_encoder_init
, strm
, block
);
222 strm
->internal
->supported_actions
[LZMA_RUN
] = true;
223 strm
->internal
->supported_actions
[LZMA_SYNC_FLUSH
] = true;
224 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;