🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
10 KiB

  1. // example5.c - Demonstrates how to use miniz.c's low-level tdefl_compress() and tinfl_inflate() API's for simple file to file compression/decompression.
  2. // The low-level API's are the fastest, make no use of dynamic memory allocation, and are the most flexible functions exposed by miniz.c.
  3. // Public domain, April 11 2012, Rich Geldreich, richgel99@gmail.com. See "unlicense" statement at the end of tinfl.c.
  4. // For simplicity, this example is limited to files smaller than 4GB, but this is not a limitation of miniz.c.
  5. // Purposely disable a whole bunch of stuff this low-level example doesn't use.
  6. #define MINIZ_NO_STDIO
  7. #define MINIZ_NO_ARCHIVE_APIS
  8. #define MINIZ_NO_TIME
  9. #define MINIZ_NO_ZLIB_APIS
  10. #define MINIZ_NO_MALLOC
  11. #include "miniz.h"
  12. // Now include stdio.h because this test uses fopen(), etc. (but we still don't want miniz.c's stdio stuff, for testing).
  13. #include <stdio.h>
  14. #include <limits.h>
  15. typedef unsigned char uint8;
  16. typedef unsigned short uint16;
  17. typedef unsigned int uint;
  18. #define my_max(a,b) (((a) > (b)) ? (a) : (b))
  19. #define my_min(a,b) (((a) < (b)) ? (a) : (b))
  20. // IN_BUF_SIZE is the size of the file read buffer.
  21. // IN_BUF_SIZE must be >= 1
  22. #define IN_BUF_SIZE (1024*512)
  23. static uint8 s_inbuf[IN_BUF_SIZE];
  24. // COMP_OUT_BUF_SIZE is the size of the output buffer used during compression.
  25. // COMP_OUT_BUF_SIZE must be >= 1 and <= OUT_BUF_SIZE
  26. #define COMP_OUT_BUF_SIZE (1024*512)
  27. // OUT_BUF_SIZE is the size of the output buffer used during decompression.
  28. // OUT_BUF_SIZE must be a power of 2 >= TINFL_LZ_DICT_SIZE (because the low-level decompressor not only writes, but reads from the output buffer as it decompresses)
  29. //#define OUT_BUF_SIZE (TINFL_LZ_DICT_SIZE)
  30. #define OUT_BUF_SIZE (1024*512)
  31. static uint8 s_outbuf[OUT_BUF_SIZE];
  32. // tdefl_compressor contains all the state needed by the low-level compressor so it's a pretty big struct (~300k).
  33. // This example makes it a global vs. putting it on the stack, of course in real-world usage you'll probably malloc() or new it.
  34. tdefl_compressor g_deflator;
  35. int main(int argc, char *argv[])
  36. {
  37. const char *pMode;
  38. FILE *pInfile, *pOutfile;
  39. uint infile_size;
  40. int level = 9;
  41. int p = 1;
  42. const char *pSrc_filename;
  43. const char *pDst_filename;
  44. const void *next_in = s_inbuf;
  45. size_t avail_in = 0;
  46. void *next_out = s_outbuf;
  47. size_t avail_out = OUT_BUF_SIZE;
  48. size_t total_in = 0, total_out = 0;
  49. long file_loc;
  50. assert(COMP_OUT_BUF_SIZE <= OUT_BUF_SIZE);
  51. printf("miniz.c example5 (demonstrates tinfl/tdefl)\n");
  52. if (argc < 4)
  53. {
  54. printf("File to file compression/decompression using the low-level tinfl/tdefl API's.\n");
  55. printf("Usage: example5 [options] [mode:c or d] infile outfile\n");
  56. printf("\nModes:\n");
  57. printf("c - Compresses file infile to a zlib stream in file outfile\n");
  58. printf("d - Decompress zlib stream in file infile to file outfile\n");
  59. printf("\nOptions:\n");
  60. printf("-l[0-10] - Compression level, higher values are slower, 0 is none.\n");
  61. return EXIT_FAILURE;
  62. }
  63. while ((p < argc) && (argv[p][0] == '-'))
  64. {
  65. switch (argv[p][1])
  66. {
  67. case 'l':
  68. {
  69. level = atoi(&argv[1][2]);
  70. if ((level < 0) || (level > 10))
  71. {
  72. printf("Invalid level!\n");
  73. return EXIT_FAILURE;
  74. }
  75. break;
  76. }
  77. default:
  78. {
  79. printf("Invalid option: %s\n", argv[p]);
  80. return EXIT_FAILURE;
  81. }
  82. }
  83. p++;
  84. }
  85. if ((argc - p) < 3)
  86. {
  87. printf("Must specify mode, input filename, and output filename after options!\n");
  88. return EXIT_FAILURE;
  89. }
  90. else if ((argc - p) > 3)
  91. {
  92. printf("Too many filenames!\n");
  93. return EXIT_FAILURE;
  94. }
  95. pMode = argv[p++];
  96. if (!strchr("cCdD", pMode[0]))
  97. {
  98. printf("Invalid mode!\n");
  99. return EXIT_FAILURE;
  100. }
  101. pSrc_filename = argv[p++];
  102. pDst_filename = argv[p++];
  103. printf("Mode: %c, Level: %u\nInput File: \"%s\"\nOutput File: \"%s\"\n", pMode[0], level, pSrc_filename, pDst_filename);
  104. // Open input file.
  105. pInfile = fopen(pSrc_filename, "rb");
  106. if (!pInfile)
  107. {
  108. printf("Failed opening input file!\n");
  109. return EXIT_FAILURE;
  110. }
  111. // Determine input file's size.
  112. fseek(pInfile, 0, SEEK_END);
  113. file_loc = ftell(pInfile);
  114. fseek(pInfile, 0, SEEK_SET);
  115. if ((file_loc < 0) || (file_loc > INT_MAX))
  116. {
  117. // This is not a limitation of miniz or tinfl, but this example.
  118. printf("File is too large to be processed by this example.\n");
  119. return EXIT_FAILURE;
  120. }
  121. infile_size = (uint)file_loc;
  122. // Open output file.
  123. pOutfile = fopen(pDst_filename, "wb");
  124. if (!pOutfile)
  125. {
  126. printf("Failed opening output file!\n");
  127. return EXIT_FAILURE;
  128. }
  129. printf("Input file size: %u\n", infile_size);
  130. if ((pMode[0] == 'c') || (pMode[0] == 'C'))
  131. {
  132. // The number of dictionary probes to use at each compression level (0-10). 0=implies fastest/minimal possible probing.
  133. static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
  134. tdefl_status status;
  135. uint infile_remaining = infile_size;
  136. // create tdefl() compatible flags (we have to compose the low-level flags ourselves, or use tdefl_create_comp_flags_from_zip_params() but that means MINIZ_NO_ZLIB_APIS can't be defined).
  137. mz_uint comp_flags = TDEFL_WRITE_ZLIB_HEADER | s_tdefl_num_probes[MZ_MIN(10, level)] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
  138. if (!level)
  139. comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
  140. // Initialize the low-level compressor.
  141. status = tdefl_init(&g_deflator, NULL, NULL, comp_flags);
  142. if (status != TDEFL_STATUS_OKAY)
  143. {
  144. printf("tdefl_init() failed!\n");
  145. return EXIT_FAILURE;
  146. }
  147. avail_out = COMP_OUT_BUF_SIZE;
  148. // Compression.
  149. for ( ; ; )
  150. {
  151. size_t in_bytes, out_bytes;
  152. if (!avail_in)
  153. {
  154. // Input buffer is empty, so read more bytes from input file.
  155. uint n = my_min(IN_BUF_SIZE, infile_remaining);
  156. if (fread(s_inbuf, 1, n, pInfile) != n)
  157. {
  158. printf("Failed reading from input file!\n");
  159. return EXIT_FAILURE;
  160. }
  161. next_in = s_inbuf;
  162. avail_in = n;
  163. infile_remaining -= n;
  164. //printf("Input bytes remaining: %u\n", infile_remaining);
  165. }
  166. in_bytes = avail_in;
  167. out_bytes = avail_out;
  168. // Compress as much of the input as possible (or all of it) to the output buffer.
  169. status = tdefl_compress(&g_deflator, next_in, &in_bytes, next_out, &out_bytes, infile_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
  170. next_in = (const char *)next_in + in_bytes;
  171. avail_in -= in_bytes;
  172. total_in += in_bytes;
  173. next_out = (char *)next_out + out_bytes;
  174. avail_out -= out_bytes;
  175. total_out += out_bytes;
  176. if ((status != TDEFL_STATUS_OKAY) || (!avail_out))
  177. {
  178. // Output buffer is full, or compression is done or failed, so write buffer to output file.
  179. uint n = COMP_OUT_BUF_SIZE - (uint)avail_out;
  180. if (fwrite(s_outbuf, 1, n, pOutfile) != n)
  181. {
  182. printf("Failed writing to output file!\n");
  183. return EXIT_FAILURE;
  184. }
  185. next_out = s_outbuf;
  186. avail_out = COMP_OUT_BUF_SIZE;
  187. }
  188. if (status == TDEFL_STATUS_DONE)
  189. {
  190. // Compression completed successfully.
  191. break;
  192. }
  193. else if (status != TDEFL_STATUS_OKAY)
  194. {
  195. // Compression somehow failed.
  196. printf("tdefl_compress() failed with status %i!\n", status);
  197. return EXIT_FAILURE;
  198. }
  199. }
  200. }
  201. else if ((pMode[0] == 'd') || (pMode[0] == 'D'))
  202. {
  203. // Decompression.
  204. uint infile_remaining = infile_size;
  205. tinfl_decompressor inflator;
  206. tinfl_init(&inflator);
  207. for ( ; ; )
  208. {
  209. size_t in_bytes, out_bytes;
  210. tinfl_status status;
  211. if (!avail_in)
  212. {
  213. // Input buffer is empty, so read more bytes from input file.
  214. uint n = my_min(IN_BUF_SIZE, infile_remaining);
  215. if (fread(s_inbuf, 1, n, pInfile) != n)
  216. {
  217. printf("Failed reading from input file!\n");
  218. return EXIT_FAILURE;
  219. }
  220. next_in = s_inbuf;
  221. avail_in = n;
  222. infile_remaining -= n;
  223. }
  224. in_bytes = avail_in;
  225. out_bytes = avail_out;
  226. status = tinfl_decompress(&inflator, (const mz_uint8 *)next_in, &in_bytes, s_outbuf, (mz_uint8 *)next_out, &out_bytes, (infile_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0) | TINFL_FLAG_PARSE_ZLIB_HEADER);
  227. avail_in -= in_bytes;
  228. next_in = (const mz_uint8 *)next_in + in_bytes;
  229. total_in += in_bytes;
  230. avail_out -= out_bytes;
  231. next_out = (mz_uint8 *)next_out + out_bytes;
  232. total_out += out_bytes;
  233. if ((status <= TINFL_STATUS_DONE) || (!avail_out))
  234. {
  235. // Output buffer is full, or decompression is done, so write buffer to output file.
  236. uint n = OUT_BUF_SIZE - (uint)avail_out;
  237. if (fwrite(s_outbuf, 1, n, pOutfile) != n)
  238. {
  239. printf("Failed writing to output file!\n");
  240. return EXIT_FAILURE;
  241. }
  242. next_out = s_outbuf;
  243. avail_out = OUT_BUF_SIZE;
  244. }
  245. // If status is <= TINFL_STATUS_DONE then either decompression is done or something went wrong.
  246. if (status <= TINFL_STATUS_DONE)
  247. {
  248. if (status == TINFL_STATUS_DONE)
  249. {
  250. // Decompression completed successfully.
  251. break;
  252. }
  253. else
  254. {
  255. // Decompression failed.
  256. printf("tinfl_decompress() failed with status %i!\n", status);
  257. return EXIT_FAILURE;
  258. }
  259. }
  260. }
  261. }
  262. else
  263. {
  264. printf("Invalid mode!\n");
  265. return EXIT_FAILURE;
  266. }
  267. fclose(pInfile);
  268. if (EOF == fclose(pOutfile))
  269. {
  270. printf("Failed writing to output file!\n");
  271. return EXIT_FAILURE;
  272. }
  273. printf("Total input bytes: %u\n", (mz_uint32)total_in);
  274. printf("Total output bytes: %u\n", (mz_uint32)total_out);
  275. printf("Success.\n");
  276. return EXIT_SUCCESS;
  277. }