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 lzma_check_update(&coder
->check
, coder
->block
->check
,
81 in
+ in_start
, in_used
);
83 if (ret
!= LZMA_STREAM_END
|| action
== LZMA_SYNC_FLUSH
)
86 assert(*in_pos
== in_size
);
87 assert(action
== LZMA_FINISH
);
89 // Copy the values into coder->block. The caller
90 // may use this information to construct Index.
91 coder
->block
->compressed_size
= coder
->compressed_size
;
92 coder
->block
->uncompressed_size
= coder
->uncompressed_size
;
94 coder
->sequence
= SEQ_PADDING
;
100 // Pad Compressed Data to a multiple of four bytes. We can
101 // use coder->compressed_size for this since we don't need
102 // it for anything else anymore.
103 while (coder
->compressed_size
& 3) {
104 if (*out_pos
>= out_size
)
107 out
[*out_pos
] = 0x00;
109 ++coder
->compressed_size
;
112 if (coder
->block
->check
== LZMA_CHECK_NONE
)
113 return LZMA_STREAM_END
;
115 lzma_check_finish(&coder
->check
, coder
->block
->check
);
117 coder
->sequence
= SEQ_CHECK
;
122 const size_t check_size
= lzma_check_size(coder
->block
->check
);
123 lzma_bufcpy(coder
->check
.buffer
.u8
, &coder
->pos
, check_size
,
124 out
, out_pos
, out_size
);
125 if (coder
->pos
< check_size
)
128 memcpy(coder
->block
->raw_check
, coder
->check
.buffer
.u8
,
130 return LZMA_STREAM_END
;
134 return LZMA_PROG_ERROR
;
139 block_encoder_end(void *coder_ptr
, const lzma_allocator
*allocator
)
141 lzma_block_coder
*coder
= coder_ptr
;
142 lzma_next_end(&coder
->next
, allocator
);
143 lzma_free(coder
, allocator
);
149 block_encoder_update(void *coder_ptr
, const lzma_allocator
*allocator
,
150 const lzma_filter
*filters
lzma_attribute((__unused__
)),
151 const lzma_filter
*reversed_filters
)
153 lzma_block_coder
*coder
= coder_ptr
;
155 if (coder
->sequence
!= SEQ_CODE
)
156 return LZMA_PROG_ERROR
;
158 return lzma_next_filter_update(
159 &coder
->next
, allocator
, reversed_filters
);
164 lzma_block_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
167 lzma_next_coder_init(&lzma_block_encoder_init
, next
, allocator
);
170 return LZMA_PROG_ERROR
;
172 // The contents of the structure may depend on the version so
173 // check the version first.
174 if (block
->version
> 1)
175 return LZMA_OPTIONS_ERROR
;
177 // If the Check ID is not supported, we cannot calculate the check and
178 // thus not create a proper Block.
179 if ((unsigned int)(block
->check
) > LZMA_CHECK_ID_MAX
)
180 return LZMA_PROG_ERROR
;
182 if (!lzma_check_is_supported(block
->check
))
183 return LZMA_UNSUPPORTED_CHECK
;
185 // Allocate and initialize *next->coder if needed.
186 lzma_block_coder
*coder
= next
->coder
;
188 coder
= lzma_alloc(sizeof(lzma_block_coder
), allocator
);
190 return LZMA_MEM_ERROR
;
193 next
->code
= &block_encode
;
194 next
->end
= &block_encoder_end
;
195 next
->update
= &block_encoder_update
;
196 coder
->next
= LZMA_NEXT_CODER_INIT
;
199 // Basic initializations
200 coder
->sequence
= SEQ_CODE
;
201 coder
->block
= block
;
202 coder
->compressed_size
= 0;
203 coder
->uncompressed_size
= 0;
206 // Initialize the check
207 lzma_check_init(&coder
->check
, block
->check
);
209 // Initialize the requested filters.
210 return lzma_raw_encoder_init(&coder
->next
, allocator
, block
->filters
);
214 extern LZMA_API(lzma_ret
)
215 lzma_block_encoder(lzma_stream
*strm
, lzma_block
*block
)
217 lzma_next_strm_init(lzma_block_encoder_init
, strm
, block
);
219 strm
->internal
->supported_actions
[LZMA_RUN
] = true;
220 strm
->internal
->supported_actions
[LZMA_SYNC_FLUSH
] = true;
221 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;