1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
5 /// \file 03_compress_custom.c
6 /// \brief Compress in multi-call mode using x86 BCJ and LZMA2
8 /// Usage: ./03_compress_custom < INFILE > OUTFILE
10 /// Example: ./03_compress_custom < foo > foo.xz
12 // Author: Lasse Collin
14 ///////////////////////////////////////////////////////////////////////////////
25 init_encoder(lzma_stream
*strm
)
27 // Use the default preset (6) for LZMA2.
29 // The lzma_options_lzma structure and the lzma_lzma_preset() function
30 // are declared in lzma/lzma12.h (src/liblzma/api/lzma/lzma12.h in the
31 // source package or e.g. /usr/include/lzma/lzma12.h depending on
32 // the install prefix).
33 lzma_options_lzma opt_lzma2
;
34 if (lzma_lzma_preset(&opt_lzma2
, LZMA_PRESET_DEFAULT
)) {
35 // It should never fail because the default preset
36 // (and presets 0-9 optionally with LZMA_PRESET_EXTREME)
37 // are supported by all stable liblzma versions.
39 // (The encoder initialization later in this function may
40 // still fail due to unsupported preset *if* the features
41 // required by the preset have been disabled at build time,
42 // but no-one does such things except on embedded systems.)
43 fprintf(stderr
, "Unsupported preset, possibly a bug\n");
47 // Now we could customize the LZMA2 options if we wanted. For example,
48 // we could set the the dictionary size (opt_lzma2.dict_size) to
49 // something else than the default (8 MiB) of the default preset.
50 // See lzma/lzma12.h for details of all LZMA2 options.
52 // The x86 BCJ filter will try to modify the x86 instruction stream so
53 // that LZMA2 can compress it better. The x86 BCJ filter doesn't need
54 // any options so it will be set to NULL below.
56 // Construct the filter chain. The uncompressed data goes first to
57 // the first filter in the array, in this case the x86 BCJ filter.
58 // The array is always terminated by setting .id = LZMA_VLI_UNKNOWN.
60 // See lzma/filter.h for more information about the lzma_filter
62 lzma_filter filters
[] = {
63 { .id
= LZMA_FILTER_X86
, .options
= NULL
},
64 { .id
= LZMA_FILTER_LZMA2
, .options
= &opt_lzma2
},
65 { .id
= LZMA_VLI_UNKNOWN
, .options
= NULL
},
68 // Initialize the encoder using the custom filter chain.
69 lzma_ret ret
= lzma_stream_encoder(strm
, filters
, LZMA_CHECK_CRC64
);
77 msg
= "Memory allocation failed";
80 case LZMA_OPTIONS_ERROR
:
81 // We are no longer using a plain preset so this error
82 // message has been edited accordingly compared to
83 // 01_compress_easy.c.
84 msg
= "Specified filter chain is not supported";
87 case LZMA_UNSUPPORTED_CHECK
:
88 msg
= "Specified integrity check is not supported";
92 msg
= "Unknown error, possibly a bug";
96 fprintf(stderr
, "Error initializing the encoder: %s (error code %u)\n",
102 // This function is identical to the one in 01_compress_easy.c.
104 compress(lzma_stream
*strm
, FILE *infile
, FILE *outfile
)
106 lzma_action action
= LZMA_RUN
;
108 uint8_t inbuf
[BUFSIZ
];
109 uint8_t outbuf
[BUFSIZ
];
111 strm
->next_in
= NULL
;
113 strm
->next_out
= outbuf
;
114 strm
->avail_out
= sizeof(outbuf
);
117 if (strm
->avail_in
== 0 && !feof(infile
)) {
118 strm
->next_in
= inbuf
;
119 strm
->avail_in
= fread(inbuf
, 1, sizeof(inbuf
),
122 if (ferror(infile
)) {
123 fprintf(stderr
, "Read error: %s\n",
129 action
= LZMA_FINISH
;
132 lzma_ret ret
= lzma_code(strm
, action
);
134 if (strm
->avail_out
== 0 || ret
== LZMA_STREAM_END
) {
135 size_t write_size
= sizeof(outbuf
) - strm
->avail_out
;
137 if (fwrite(outbuf
, 1, write_size
, outfile
)
139 fprintf(stderr
, "Write error: %s\n",
144 strm
->next_out
= outbuf
;
145 strm
->avail_out
= sizeof(outbuf
);
148 if (ret
!= LZMA_OK
) {
149 if (ret
== LZMA_STREAM_END
)
155 msg
= "Memory allocation failed";
158 case LZMA_DATA_ERROR
:
159 msg
= "File size limits exceeded";
163 msg
= "Unknown error, possibly a bug";
167 fprintf(stderr
, "Encoder error: %s (error code %u)\n",
178 lzma_stream strm
= LZMA_STREAM_INIT
;
180 bool success
= init_encoder(&strm
);
182 success
= compress(&strm
, stdin
, stdout
);
186 if (fclose(stdout
)) {
187 fprintf(stderr
, "Write error: %s\n", strerror(errno
));
191 return success
? EXIT_SUCCESS
: EXIT_FAILURE
;