From 5876ca27daa1429676b1160007d9688266907f00 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 29 Jan 2014 20:19:41 +0200 Subject: [PATCH] Docs: Add example program for threaded encoding. I didn't add -DLZMA_UNSTABLE to Makefile so one has to specify it manually as long as LZMA_UNSTABLE is needed. --- doc/examples/04_compress_easy_mt.c | 184 +++++++++++++++++++++++++++++ doc/examples/Makefile | 3 +- 2 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 doc/examples/04_compress_easy_mt.c diff --git a/doc/examples/04_compress_easy_mt.c b/doc/examples/04_compress_easy_mt.c new file mode 100644 index 00000000..121d3b11 --- /dev/null +++ b/doc/examples/04_compress_easy_mt.c @@ -0,0 +1,184 @@ +/////////////////////////////////////////////////////////////////////////////// +// +/// \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 +#include +#include +#include +#include +#include + + +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; +} diff --git a/doc/examples/Makefile b/doc/examples/Makefile index 644dc32e..0f3d1851 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -12,7 +12,8 @@ LDFLAGS = -llzma PROGS = \ 01_compress_easy \ 02_decompress \ - 03_compress_custom + 03_compress_custom \ + 04_compress_easy_mt all: $(PROGS)