| /////////////////////////////////////////////////////////////////////////////// | |
| // | |
| /// \file 04_compress_easy_mt.c | |
| /// \brief Compress in multi-call mode using LZMA2 in multi-threaded mode | |
| /// | |
| /// Usage: ./04_compress_easy_mt < INFILE > OUTFILE | |
| /// | |
| /// Example: ./04_compress_easy_mt < foo > foo.xz | |
| // | |
| // Author: Lasse Collin | |
| // | |
| // This file has been put into the public domain. | |
| // You can do whatever you want with this file. | |
| // | |
| /////////////////////////////////////////////////////////////////////////////// | |
| #include <stdbool.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <lzma.h> | |
| static bool | |
| init_encoder(lzma_stream *strm) | |
| { | |
| // The threaded encoder takes the options as pointer to | |
| // a lzma_mt structure. | |
| lzma_mt mt = { | |
| // No flags are needed. | |
| .flags = 0, | |
| // Set the number of threads to use. | |
| // FIXME: Add how to autodetect a reasonable number. | |
| .threads = 4, | |
| // Let liblzma determine a sane block size. | |
| .block_size = 0, | |
| // Use no timeout for lzma_code() calls by setting timeout | |
| // to zero. That is, sometimes lzma_code() might block for | |
| // a long time (from several seconds to even minutes). | |
| // If this is not OK, for example due to progress indicator | |
| // needing updates, specify a timeout in milliseconds here. | |
| // See the documentation of lzma_mt in lzma/container.h for | |
| // information how to choose a reasonable timeout. | |
| .timeout = 0, | |
| // Use the default preset (6) for LZMA2. | |
| // To use a preset, filters must be set to NULL. | |
| .preset = LZMA_PRESET_DEFAULT, | |
| .filters = NULL, | |
| // Use CRC64 for integrity checking. See also | |
| // 01_compress_easy.c about choosing the integrity check. | |
| .check = LZMA_CHECK_CRC64, | |
| }; | |
| // Initialize the threaded encoder. | |
| lzma_ret ret = lzma_stream_encoder_mt(strm, &mt); | |
| if (ret == LZMA_OK) | |
| return true; | |
| const char *msg; | |
| switch (ret) { | |
| case LZMA_MEM_ERROR: | |
| msg = "Memory allocation failed"; | |
| break; | |
| case LZMA_OPTIONS_ERROR: | |
| // We are no longer using a plain preset so this error | |
| // message has been edited accordingly compared to | |
| // 01_compress_easy.c. | |
| msg = "Specified filter chain is not supported"; | |
| break; | |
| case LZMA_UNSUPPORTED_CHECK: | |
| msg = "Specified integrity check is not supported"; | |
| break; | |
| default: | |
| msg = "Unknown error, possibly a bug"; | |
| break; | |
| } | |
| fprintf(stderr, "Error initializing the encoder: %s (error code %u)\n", | |
| msg, ret); | |
| return false; | |
| } | |
| // This function is identical to the one in 01_compress_easy.c. | |
| static bool | |
| compress(lzma_stream *strm, FILE *infile, FILE *outfile) | |
| { | |
| lzma_action action = LZMA_RUN; | |
| uint8_t inbuf[BUFSIZ]; | |
| uint8_t outbuf[BUFSIZ]; | |
| strm->next_in = NULL; | |
| strm->avail_in = 0; | |
| strm->next_out = outbuf; | |
| strm->avail_out = sizeof(outbuf); | |
| while (true) { | |
| if (strm->avail_in == 0 && !feof(infile)) { | |
| strm->next_in = inbuf; | |
| strm->avail_in = fread(inbuf, 1, sizeof(inbuf), | |
| infile); | |
| if (ferror(infile)) { | |
| fprintf(stderr, "Read error: %s\n", | |
| strerror(errno)); | |
| return false; | |
| } | |
| if (feof(infile)) | |
| action = LZMA_FINISH; | |
| } | |
| lzma_ret ret = lzma_code(strm, action); | |
| if (strm->avail_out == 0 || ret == LZMA_STREAM_END) { | |
| size_t write_size = sizeof(outbuf) - strm->avail_out; | |
| if (fwrite(outbuf, 1, write_size, outfile) | |
| != write_size) { | |
| fprintf(stderr, "Write error: %s\n", | |
| strerror(errno)); | |
| return false; | |
| } | |
| strm->next_out = outbuf; | |
| strm->avail_out = sizeof(outbuf); | |
| } | |
| if (ret != LZMA_OK) { | |
| if (ret == LZMA_STREAM_END) | |
| return true; | |
| const char *msg; | |
| switch (ret) { | |
| case LZMA_MEM_ERROR: | |
| msg = "Memory allocation failed"; | |
| break; | |
| case LZMA_DATA_ERROR: | |
| msg = "File size limits exceeded"; | |
| break; | |
| default: | |
| msg = "Unknown error, possibly a bug"; | |
| break; | |
| } | |
| fprintf(stderr, "Encoder error: %s (error code %u)\n", | |
| msg, ret); | |
| return false; | |
| } | |
| } | |
| } | |
| extern int | |
| main(void) | |
| { | |
| lzma_stream strm = LZMA_STREAM_INIT; | |
| bool success = init_encoder(&strm); | |
| if (success) | |
| success = compress(&strm, stdin, stdout); | |
| lzma_end(&strm); | |
| if (fclose(stdout)) { | |
| fprintf(stderr, "Write error: %s\n", strerror(errno)); | |
| success = false; | |
| } | |
| return success ? EXIT_SUCCESS : EXIT_FAILURE; | |
| } |