1 ///////////////////////////////////////////////////////////////////////////////
3 /// \file 03_compress_custom.c
4 /// \brief Compress in multi-call mode using x86 BCJ and LZMA2
6 /// Usage: ./03_compress_custom < INFILE > OUTFILE
8 /// Example: ./03_compress_custom < foo > foo.xz
10 // Author: Lasse Collin
12 // This file has been put into the public domain.
13 // You can do whatever you want with this file.
15 ///////////////////////////////////////////////////////////////////////////////
26 init_encoder(lzma_stream
*strm
)
28 // Use the default preset (6) for LZMA2.
30 // The lzma_options_lzma structure and the lzma_lzma_preset() function
31 // are declared in lzma/lzma12.h (src/liblzma/api/lzma/lzma12.h in the
32 // source package or e.g. /usr/include/lzma/lzma12.h depending on
33 // the install prefix).
34 lzma_options_lzma opt_lzma2
;
35 if (lzma_lzma_preset(&opt_lzma2
, LZMA_PRESET_DEFAULT
)) {
36 // It should never fail because the default preset
37 // (and presets 0-9 optionally with LZMA_PRESET_EXTREME)
38 // are supported by all stable liblzma versions.
40 // (The encoder initialization later in this function may
41 // still fail due to unsupported preset *if* the features
42 // required by the preset have been disabled at build time,
43 // but no-one does such things except on embedded systems.)
44 fprintf(stderr
, "Unsupported preset, possibly a bug\n");
48 // Now we could customize the LZMA2 options if we wanted. For example,
49 // we could set the the dictionary size (opt_lzma2.dict_size) to
50 // something else than the default (8 MiB) of the default preset.
51 // See lzma/lzma12.h for details of all LZMA2 options.
53 // The x86 BCJ filter will try to modify the x86 instruction stream so
54 // that LZMA2 can compress it better. The x86 BCJ filter doesn't need
55 // any options so it will be set to NULL below.
57 // Construct the filter chain. The uncompressed data goes first to
58 // the first filter in the array, in this case the x86 BCJ filter.
59 // The array is always terminated by setting .id = LZMA_VLI_UNKNOWN.
61 // See lzma/filter.h for more information about the lzma_filter
63 lzma_filter filters
[] = {
64 { .id
= LZMA_FILTER_X86
, .options
= NULL
},
65 { .id
= LZMA_FILTER_LZMA2
, .options
= &opt_lzma2
},
66 { .id
= LZMA_VLI_UNKNOWN
, .options
= NULL
},
69 // Initialize the encoder using the custom filter chain.
70 lzma_ret ret
= lzma_stream_encoder(strm
, filters
, LZMA_CHECK_CRC64
);
78 msg
= "Memory allocation failed";
81 case LZMA_OPTIONS_ERROR
:
82 // We are no longer using a plain preset so this error
83 // message has been edited accordingly compared to
84 // 01_compress_easy.c.
85 msg
= "Specified filter chain is not supported";
88 case LZMA_UNSUPPORTED_CHECK
:
89 msg
= "Specified integrity check is not supported";
93 msg
= "Unknown error, possibly a bug";
97 fprintf(stderr
, "Error initializing the encoder: %s (error code %u)\n",
103 // This function is identical to the one in 01_compress_easy.c.
105 compress(lzma_stream
*strm
, FILE *infile
, FILE *outfile
)
107 lzma_action action
= LZMA_RUN
;
109 uint8_t inbuf
[BUFSIZ
];
110 uint8_t outbuf
[BUFSIZ
];
112 strm
->next_in
= NULL
;
114 strm
->next_out
= outbuf
;
115 strm
->avail_out
= sizeof(outbuf
);
118 if (strm
->avail_in
== 0 && !feof(infile
)) {
119 strm
->next_in
= inbuf
;
120 strm
->avail_in
= fread(inbuf
, 1, sizeof(inbuf
),
123 if (ferror(infile
)) {
124 fprintf(stderr
, "Read error: %s\n",
130 action
= LZMA_FINISH
;
133 lzma_ret ret
= lzma_code(strm
, action
);
135 if (strm
->avail_out
== 0 || ret
== LZMA_STREAM_END
) {
136 size_t write_size
= sizeof(outbuf
) - strm
->avail_out
;
138 if (fwrite(outbuf
, 1, write_size
, outfile
)
140 fprintf(stderr
, "Write error: %s\n",
145 strm
->next_out
= outbuf
;
146 strm
->avail_out
= sizeof(outbuf
);
149 if (ret
!= LZMA_OK
) {
150 if (ret
== LZMA_STREAM_END
)
156 msg
= "Memory allocation failed";
159 case LZMA_DATA_ERROR
:
160 msg
= "File size limits exceeded";
164 msg
= "Unknown error, possibly a bug";
168 fprintf(stderr
, "Encoder error: %s (error code %u)\n",
179 lzma_stream strm
= LZMA_STREAM_INIT
;
181 bool success
= init_encoder(&strm
);
183 success
= compress(&strm
, stdin
, stdout
);
187 if (fclose(stdout
)) {
188 fprintf(stderr
, "Write error: %s\n", strerror(errno
));
192 return success
? EXIT_SUCCESS
: EXIT_FAILURE
;