1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file microlzma_encoder.c
4 /// \brief Encode into MicroLZMA format
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 "lzma_encoder.h"
20 /// LZMA properties byte (lc/lp/pb)
22 } lzma_microlzma_coder
;
26 microlzma_encode(void *coder_ptr
, const lzma_allocator
*allocator
,
27 const uint8_t *restrict in
, size_t *restrict in_pos
,
28 size_t in_size
, uint8_t *restrict out
,
29 size_t *restrict out_pos
, size_t out_size
, lzma_action action
)
31 lzma_microlzma_coder
*coder
= coder_ptr
;
33 // Remember *out_pos so that we can overwrite the first byte with
34 // the LZMA properties byte.
35 const size_t out_start
= *out_pos
;
37 // Remember *in_pos so that we can set it based on how many
38 // uncompressed bytes were actually encoded.
39 const size_t in_start
= *in_pos
;
41 // Set the output size limit based on the available output space.
42 // We know that the encoder supports set_out_limit() so
43 // LZMA_OPTIONS_ERROR isn't possible. LZMA_BUF_ERROR is possible
44 // but lzma_code() has an assertion to not allow it to be returned
45 // from here and I don't want to change that for now, so
46 // LZMA_BUF_ERROR becomes LZMA_PROG_ERROR.
48 if (coder
->lzma
.set_out_limit(coder
->lzma
.coder
,
49 &uncomp_size
, out_size
- *out_pos
) != LZMA_OK
)
50 return LZMA_PROG_ERROR
;
52 // set_out_limit fails if this isn't true.
53 assert(out_size
- *out_pos
>= 6);
55 // Encode as much as possible.
56 const lzma_ret ret
= coder
->lzma
.code(coder
->lzma
.coder
, allocator
,
57 in
, in_pos
, in_size
, out
, out_pos
, out_size
, action
);
59 if (ret
!= LZMA_STREAM_END
) {
62 return LZMA_PROG_ERROR
;
68 // The first output byte is bitwise-negation of the properties byte.
69 // We know that there is space for this byte because set_out_limit
70 // and the actual encoding succeeded.
71 out
[out_start
] = (uint8_t)(~coder
->props
);
73 // The LZMA encoder likely read more input than it was able to encode.
74 // Set *in_pos based on uncomp_size.
75 assert(uncomp_size
<= in_size
- in_start
);
76 *in_pos
= in_start
+ (size_t)(uncomp_size
);
83 microlzma_encoder_end(void *coder_ptr
, const lzma_allocator
*allocator
)
85 lzma_microlzma_coder
*coder
= coder_ptr
;
86 lzma_next_end(&coder
->lzma
, allocator
);
87 lzma_free(coder
, allocator
);
93 microlzma_encoder_init(lzma_next_coder
*next
, const lzma_allocator
*allocator
,
94 const lzma_options_lzma
*options
)
96 lzma_next_coder_init(µlzma_encoder_init
, next
, allocator
);
98 lzma_microlzma_coder
*coder
= next
->coder
;
101 coder
= lzma_alloc(sizeof(lzma_microlzma_coder
), allocator
);
103 return LZMA_MEM_ERROR
;
106 next
->code
= µlzma_encode
;
107 next
->end
= µlzma_encoder_end
;
109 coder
->lzma
= LZMA_NEXT_CODER_INIT
;
112 // Encode the properties byte. Bitwise-negation of it will be the
113 // first output byte.
114 if (lzma_lzma_lclppb_encode(options
, &coder
->props
))
115 return LZMA_OPTIONS_ERROR
;
117 // Initialize the LZMA encoder.
118 const lzma_filter_info filters
[2] = {
120 .id
= LZMA_FILTER_LZMA1
,
121 .init
= &lzma_lzma_encoder_init
,
122 .options
= (void *)(options
),
128 return lzma_next_filter_init(&coder
->lzma
, allocator
, filters
);
132 extern LZMA_API(lzma_ret
)
133 lzma_microlzma_encoder(lzma_stream
*strm
, const lzma_options_lzma
*options
)
135 lzma_next_strm_init(microlzma_encoder_init
, strm
, options
);
137 strm
->internal
->supported_actions
[LZMA_FINISH
] = true;