Drop main() prototype. Syncs with NetBSD-8
[minix.git] / external / public-domain / xz / dist / doc / examples / 03_compress_custom.c
blob40c85e365e7c2c7cd8f909f3d325ca2a088c6c09
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file 03_compress_custom.c
4 /// \brief Compress in multi-call mode using x86 BCJ and LZMA2
5 ///
6 /// Usage: ./03_compress_custom < INFILE > OUTFILE
7 ///
8 /// Example: ./03_compress_custom < foo > foo.xz
9 //
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 ///////////////////////////////////////////////////////////////////////////////
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <lzma.h>
25 static bool
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");
45 return false;
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
62 // structure.
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);
72 if (ret == LZMA_OK)
73 return true;
75 const char *msg;
76 switch (ret) {
77 case LZMA_MEM_ERROR:
78 msg = "Memory allocation failed";
79 break;
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";
86 break;
88 case LZMA_UNSUPPORTED_CHECK:
89 msg = "Specified integrity check is not supported";
90 break;
92 default:
93 msg = "Unknown error, possibly a bug";
94 break;
97 fprintf(stderr, "Error initializing the encoder: %s (error code %u)\n",
98 msg, ret);
99 return false;
103 // This function is identical to the one in 01_compress_easy.c.
104 static bool
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;
113 strm->avail_in = 0;
114 strm->next_out = outbuf;
115 strm->avail_out = sizeof(outbuf);
117 while (true) {
118 if (strm->avail_in == 0 && !feof(infile)) {
119 strm->next_in = inbuf;
120 strm->avail_in = fread(inbuf, 1, sizeof(inbuf),
121 infile);
123 if (ferror(infile)) {
124 fprintf(stderr, "Read error: %s\n",
125 strerror(errno));
126 return false;
129 if (feof(infile))
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)
139 != write_size) {
140 fprintf(stderr, "Write error: %s\n",
141 strerror(errno));
142 return false;
145 strm->next_out = outbuf;
146 strm->avail_out = sizeof(outbuf);
149 if (ret != LZMA_OK) {
150 if (ret == LZMA_STREAM_END)
151 return true;
153 const char *msg;
154 switch (ret) {
155 case LZMA_MEM_ERROR:
156 msg = "Memory allocation failed";
157 break;
159 case LZMA_DATA_ERROR:
160 msg = "File size limits exceeded";
161 break;
163 default:
164 msg = "Unknown error, possibly a bug";
165 break;
168 fprintf(stderr, "Encoder error: %s (error code %u)\n",
169 msg, ret);
170 return false;
176 extern int
177 main(void)
179 lzma_stream strm = LZMA_STREAM_INIT;
181 bool success = init_encoder(&strm);
182 if (success)
183 success = compress(&strm, stdin, stdout);
185 lzma_end(&strm);
187 if (fclose(stdout)) {
188 fprintf(stderr, "Write error: %s\n", strerror(errno));
189 success = false;
192 return success ? EXIT_SUCCESS : EXIT_FAILURE;