OLD | NEW |
(Empty) | |
| 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 |
| 11 // |
| 12 // This file has been put into the public domain. |
| 13 // You can do whatever you want with this file. |
| 14 // |
| 15 /////////////////////////////////////////////////////////////////////////////// |
| 16 |
| 17 #include <stdbool.h> |
| 18 #include <stdlib.h> |
| 19 #include <stdio.h> |
| 20 #include <string.h> |
| 21 #include <errno.h> |
| 22 #include <lzma.h> |
| 23 |
| 24 |
| 25 static bool |
| 26 init_encoder(lzma_stream *strm) |
| 27 { |
| 28 // Use the default preset (6) for LZMA2. |
| 29 // |
| 30 // The lzma_options_lzma structure and the lzma_lzma_preset() function |
| 31 // are declared in lzma/lzma.h (src/liblzma/api/lzma/lzma.h in the |
| 32 // source package or e.g. /usr/include/lzma/lzma.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. |
| 39 // |
| 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; |
| 46 } |
| 47 |
| 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/lzma.h for details of all LZMA2 options. |
| 52 // |
| 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. |
| 56 // |
| 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. |
| 60 // |
| 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 }, |
| 67 }; |
| 68 |
| 69 // Initialize the encoder using the custom filter chain. |
| 70 lzma_ret ret = lzma_stream_encoder(strm, filters, LZMA_CHECK_CRC64); |
| 71 |
| 72 if (ret == LZMA_OK) |
| 73 return true; |
| 74 |
| 75 const char *msg; |
| 76 switch (ret) { |
| 77 case LZMA_MEM_ERROR: |
| 78 msg = "Memory allocation failed"; |
| 79 break; |
| 80 |
| 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; |
| 87 |
| 88 case LZMA_UNSUPPORTED_CHECK: |
| 89 msg = "Specified integrity check is not supported"; |
| 90 break; |
| 91 |
| 92 default: |
| 93 msg = "Unknown error, possibly a bug"; |
| 94 break; |
| 95 } |
| 96 |
| 97 fprintf(stderr, "Error initializing the encoder: %s (error code %u)\n", |
| 98 msg, ret); |
| 99 return false; |
| 100 } |
| 101 |
| 102 |
| 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) |
| 106 { |
| 107 lzma_action action = LZMA_RUN; |
| 108 |
| 109 uint8_t inbuf[BUFSIZ]; |
| 110 uint8_t outbuf[BUFSIZ]; |
| 111 |
| 112 strm->next_in = NULL; |
| 113 strm->avail_in = 0; |
| 114 strm->next_out = outbuf; |
| 115 strm->avail_out = sizeof(outbuf); |
| 116 |
| 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); |
| 122 |
| 123 if (ferror(infile)) { |
| 124 fprintf(stderr, "Read error: %s\n", |
| 125 strerror(errno)); |
| 126 return false; |
| 127 } |
| 128 |
| 129 if (feof(infile)) |
| 130 action = LZMA_FINISH; |
| 131 } |
| 132 |
| 133 lzma_ret ret = lzma_code(strm, action); |
| 134 |
| 135 if (strm->avail_out == 0 || ret == LZMA_STREAM_END) { |
| 136 size_t write_size = sizeof(outbuf) - strm->avail_out; |
| 137 |
| 138 if (fwrite(outbuf, 1, write_size, outfile) |
| 139 != write_size) { |
| 140 fprintf(stderr, "Write error: %s\n", |
| 141 strerror(errno)); |
| 142 return false; |
| 143 } |
| 144 |
| 145 strm->next_out = outbuf; |
| 146 strm->avail_out = sizeof(outbuf); |
| 147 } |
| 148 |
| 149 if (ret != LZMA_OK) { |
| 150 if (ret == LZMA_STREAM_END) |
| 151 return true; |
| 152 |
| 153 const char *msg; |
| 154 switch (ret) { |
| 155 case LZMA_MEM_ERROR: |
| 156 msg = "Memory allocation failed"; |
| 157 break; |
| 158 |
| 159 case LZMA_DATA_ERROR: |
| 160 msg = "File size limits exceeded"; |
| 161 break; |
| 162 |
| 163 default: |
| 164 msg = "Unknown error, possibly a bug"; |
| 165 break; |
| 166 } |
| 167 |
| 168 fprintf(stderr, "Encoder error: %s (error code %u)\n", |
| 169 msg, ret); |
| 170 return false; |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 |
| 176 extern int |
| 177 main(void) |
| 178 { |
| 179 lzma_stream strm = LZMA_STREAM_INIT; |
| 180 |
| 181 bool success = init_encoder(&strm); |
| 182 if (success) |
| 183 success = compress(&strm, stdin, stdout); |
| 184 |
| 185 lzma_end(&strm); |
| 186 |
| 187 if (fclose(stdout)) { |
| 188 fprintf(stderr, "Write error: %s\n", strerror(errno)); |
| 189 success = false; |
| 190 } |
| 191 |
| 192 return success ? EXIT_SUCCESS : EXIT_FAILURE; |
| 193 } |
OLD | NEW |