Translations: Update the Chinese (traditional) translation.
[xz/debian.git] / doc / examples / 04_compress_easy_mt.c
blobefe56975cd5ea74a186d56ea1d31b44e94cf64f8
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file 04_compress_easy_mt.c
4 /// \brief Compress in multi-call mode using LZMA2 in multi-threaded mode
5 ///
6 /// Usage: ./04_compress_easy_mt < INFILE > OUTFILE
7 ///
8 /// Example: ./04_compress_easy_mt < 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 // The threaded encoder takes the options as pointer to
29 // a lzma_mt structure.
30 lzma_mt mt = {
31 // No flags are needed.
32 .flags = 0,
34 // Let liblzma determine a sane block size.
35 .block_size = 0,
37 // Use no timeout for lzma_code() calls by setting timeout
38 // to zero. That is, sometimes lzma_code() might block for
39 // a long time (from several seconds to even minutes).
40 // If this is not OK, for example due to progress indicator
41 // needing updates, specify a timeout in milliseconds here.
42 // See the documentation of lzma_mt in lzma/container.h for
43 // information how to choose a reasonable timeout.
44 .timeout = 0,
46 // Use the default preset (6) for LZMA2.
47 // To use a preset, filters must be set to NULL.
48 .preset = LZMA_PRESET_DEFAULT,
49 .filters = NULL,
51 // Use CRC64 for integrity checking. See also
52 // 01_compress_easy.c about choosing the integrity check.
53 .check = LZMA_CHECK_CRC64,
56 // Detect how many threads the CPU supports.
57 mt.threads = lzma_cputhreads();
59 // If the number of CPU cores/threads cannot be detected,
60 // use one thread. Note that this isn't the same as the normal
61 // single-threaded mode as this will still split the data into
62 // blocks and use more RAM than the normal single-threaded mode.
63 // You may want to consider using lzma_easy_encoder() or
64 // lzma_stream_encoder() instead of lzma_stream_encoder_mt() if
65 // lzma_cputhreads() returns 0 or 1.
66 if (mt.threads == 0)
67 mt.threads = 1;
69 // If the number of CPU cores/threads exceeds threads_max,
70 // limit the number of threads to keep memory usage lower.
71 // The number 8 is arbitrarily chosen and may be too low or
72 // high depending on the compression preset and the computer
73 // being used.
75 // FIXME: A better way could be to check the amount of RAM
76 // (or available RAM) and use lzma_stream_encoder_mt_memusage()
77 // to determine if the number of threads should be reduced.
78 const uint32_t threads_max = 8;
79 if (mt.threads > threads_max)
80 mt.threads = threads_max;
82 // Initialize the threaded encoder.
83 lzma_ret ret = lzma_stream_encoder_mt(strm, &mt);
85 if (ret == LZMA_OK)
86 return true;
88 const char *msg;
89 switch (ret) {
90 case LZMA_MEM_ERROR:
91 msg = "Memory allocation failed";
92 break;
94 case LZMA_OPTIONS_ERROR:
95 // We are no longer using a plain preset so this error
96 // message has been edited accordingly compared to
97 // 01_compress_easy.c.
98 msg = "Specified filter chain is not supported";
99 break;
101 case LZMA_UNSUPPORTED_CHECK:
102 msg = "Specified integrity check is not supported";
103 break;
105 default:
106 msg = "Unknown error, possibly a bug";
107 break;
110 fprintf(stderr, "Error initializing the encoder: %s (error code %u)\n",
111 msg, ret);
112 return false;
116 // This function is identical to the one in 01_compress_easy.c.
117 static bool
118 compress(lzma_stream *strm, FILE *infile, FILE *outfile)
120 lzma_action action = LZMA_RUN;
122 uint8_t inbuf[BUFSIZ];
123 uint8_t outbuf[BUFSIZ];
125 strm->next_in = NULL;
126 strm->avail_in = 0;
127 strm->next_out = outbuf;
128 strm->avail_out = sizeof(outbuf);
130 while (true) {
131 if (strm->avail_in == 0 && !feof(infile)) {
132 strm->next_in = inbuf;
133 strm->avail_in = fread(inbuf, 1, sizeof(inbuf),
134 infile);
136 if (ferror(infile)) {
137 fprintf(stderr, "Read error: %s\n",
138 strerror(errno));
139 return false;
142 if (feof(infile))
143 action = LZMA_FINISH;
146 lzma_ret ret = lzma_code(strm, action);
148 if (strm->avail_out == 0 || ret == LZMA_STREAM_END) {
149 size_t write_size = sizeof(outbuf) - strm->avail_out;
151 if (fwrite(outbuf, 1, write_size, outfile)
152 != write_size) {
153 fprintf(stderr, "Write error: %s\n",
154 strerror(errno));
155 return false;
158 strm->next_out = outbuf;
159 strm->avail_out = sizeof(outbuf);
162 if (ret != LZMA_OK) {
163 if (ret == LZMA_STREAM_END)
164 return true;
166 const char *msg;
167 switch (ret) {
168 case LZMA_MEM_ERROR:
169 msg = "Memory allocation failed";
170 break;
172 case LZMA_DATA_ERROR:
173 msg = "File size limits exceeded";
174 break;
176 default:
177 msg = "Unknown error, possibly a bug";
178 break;
181 fprintf(stderr, "Encoder error: %s (error code %u)\n",
182 msg, ret);
183 return false;
189 extern int
190 main(void)
192 lzma_stream strm = LZMA_STREAM_INIT;
194 bool success = init_encoder(&strm);
195 if (success)
196 success = compress(&strm, stdin, stdout);
198 lzma_end(&strm);
200 if (fclose(stdout)) {
201 fprintf(stderr, "Write error: %s\n", strerror(errno));
202 success = false;
205 return success ? EXIT_SUCCESS : EXIT_FAILURE;