ci: add po4a
[xz/debian.git] / doc / examples / 03_compress_custom.c
blob57797b876728bf4c544183a72360c345ad935c37
1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file 03_compress_custom.c
6 /// \brief Compress in multi-call mode using x86 BCJ and LZMA2
7 ///
8 /// Usage: ./03_compress_custom < INFILE > OUTFILE
9 ///
10 /// Example: ./03_compress_custom < foo > foo.xz
12 // Author: Lasse Collin
14 ///////////////////////////////////////////////////////////////////////////////
16 #include <stdbool.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <lzma.h>
24 static bool
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");
44 return false;
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
61 // structure.
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);
71 if (ret == LZMA_OK)
72 return true;
74 const char *msg;
75 switch (ret) {
76 case LZMA_MEM_ERROR:
77 msg = "Memory allocation failed";
78 break;
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";
85 break;
87 case LZMA_UNSUPPORTED_CHECK:
88 msg = "Specified integrity check is not supported";
89 break;
91 default:
92 msg = "Unknown error, possibly a bug";
93 break;
96 fprintf(stderr, "Error initializing the encoder: %s (error code %u)\n",
97 msg, ret);
98 return false;
102 // This function is identical to the one in 01_compress_easy.c.
103 static bool
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;
112 strm->avail_in = 0;
113 strm->next_out = outbuf;
114 strm->avail_out = sizeof(outbuf);
116 while (true) {
117 if (strm->avail_in == 0 && !feof(infile)) {
118 strm->next_in = inbuf;
119 strm->avail_in = fread(inbuf, 1, sizeof(inbuf),
120 infile);
122 if (ferror(infile)) {
123 fprintf(stderr, "Read error: %s\n",
124 strerror(errno));
125 return false;
128 if (feof(infile))
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)
138 != write_size) {
139 fprintf(stderr, "Write error: %s\n",
140 strerror(errno));
141 return false;
144 strm->next_out = outbuf;
145 strm->avail_out = sizeof(outbuf);
148 if (ret != LZMA_OK) {
149 if (ret == LZMA_STREAM_END)
150 return true;
152 const char *msg;
153 switch (ret) {
154 case LZMA_MEM_ERROR:
155 msg = "Memory allocation failed";
156 break;
158 case LZMA_DATA_ERROR:
159 msg = "File size limits exceeded";
160 break;
162 default:
163 msg = "Unknown error, possibly a bug";
164 break;
167 fprintf(stderr, "Encoder error: %s (error code %u)\n",
168 msg, ret);
169 return false;
175 extern int
176 main(void)
178 lzma_stream strm = LZMA_STREAM_INIT;
180 bool success = init_encoder(&strm);
181 if (success)
182 success = compress(&strm, stdin, stdout);
184 lzma_end(&strm);
186 if (fclose(stdout)) {
187 fprintf(stderr, "Write error: %s\n", strerror(errno));
188 success = false;
191 return success ? EXIT_SUCCESS : EXIT_FAILURE;