multiple_streaming_compression.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Copyright (c) Yann Collet, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under both the BSD-style license (found in the
  6. * LICENSE file in the root directory of this source tree) and the GPLv2 (found
  7. * in the COPYING file in the root directory of this source tree).
  8. * You may select, at your option, one of the above-listed licenses.
  9. */
  10. /* The objective of this example is to show of to compress multiple successive files
  11. * while preserving memory management.
  12. * All structures and buffers will be created only once,
  13. * and shared across all compression operations */
  14. #include <stdio.h> // printf
  15. #include <stdlib.h> // free
  16. #include <string.h> // memset, strcat
  17. #include <zstd.h> // presumes zstd library is installed
  18. #include "common.h" // Helper functions, CHECK(), and CHECK_ZSTD()
  19. typedef struct {
  20. void* buffIn;
  21. void* buffOut;
  22. size_t buffInSize;
  23. size_t buffOutSize;
  24. ZSTD_CCtx* cctx;
  25. } resources;
  26. static resources createResources_orDie(int cLevel)
  27. {
  28. resources ress;
  29. ress.buffInSize = ZSTD_CStreamInSize(); /* can always read one full block */
  30. ress.buffOutSize= ZSTD_CStreamOutSize(); /* can always flush a full block */
  31. ress.buffIn = malloc_orDie(ress.buffInSize);
  32. ress.buffOut= malloc_orDie(ress.buffOutSize);
  33. ress.cctx = ZSTD_createCCtx();
  34. CHECK(ress.cctx != NULL, "ZSTD_createCCtx() failed!");
  35. /* Set any compression parameters you want here.
  36. * They will persist for every compression operation.
  37. * Here we set the compression level, and enable the checksum.
  38. */
  39. CHECK_ZSTD( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_compressionLevel, cLevel) );
  40. CHECK_ZSTD( ZSTD_CCtx_setParameter(ress.cctx, ZSTD_c_checksumFlag, 1) );
  41. return ress;
  42. }
  43. static void freeResources(resources ress)
  44. {
  45. ZSTD_freeCCtx(ress.cctx);
  46. free(ress.buffIn);
  47. free(ress.buffOut);
  48. }
  49. static void compressFile_orDie(resources ress, const char* fname, const char* outName)
  50. {
  51. // Open the input and output files.
  52. FILE* const fin = fopen_orDie(fname, "rb");
  53. FILE* const fout = fopen_orDie(outName, "wb");
  54. /* Reset the context to a clean state to start a new compression operation.
  55. * The parameters are sticky, so we keep the compression level and extra
  56. * parameters that we set in createResources_orDie().
  57. */
  58. CHECK_ZSTD( ZSTD_CCtx_reset(ress.cctx, ZSTD_reset_session_only) );
  59. size_t const toRead = ress.buffInSize;
  60. size_t read;
  61. while ( (read = fread_orDie(ress.buffIn, toRead, fin)) ) {
  62. /* This loop is the same as streaming_compression.c.
  63. * See that file for detailed comments.
  64. */
  65. int const lastChunk = (read < toRead);
  66. ZSTD_EndDirective const mode = lastChunk ? ZSTD_e_end : ZSTD_e_continue;
  67. ZSTD_inBuffer input = { ress.buffIn, read, 0 };
  68. int finished;
  69. do {
  70. ZSTD_outBuffer output = { ress.buffOut, ress.buffOutSize, 0 };
  71. size_t const remaining = ZSTD_compressStream2(ress.cctx, &output, &input, mode);
  72. CHECK_ZSTD(remaining);
  73. fwrite_orDie(ress.buffOut, output.pos, fout);
  74. finished = lastChunk ? (remaining == 0) : (input.pos == input.size);
  75. } while (!finished);
  76. CHECK(input.pos == input.size,
  77. "Impossible: zstd only returns 0 when the input is completely consumed!");
  78. }
  79. fclose_orDie(fout);
  80. fclose_orDie(fin);
  81. }
  82. int main(int argc, const char** argv)
  83. {
  84. const char* const exeName = argv[0];
  85. if (argc<2) {
  86. printf("wrong arguments\n");
  87. printf("usage:\n");
  88. printf("%s FILE(s)\n", exeName);
  89. return 1;
  90. }
  91. int const cLevel = 7;
  92. resources const ress = createResources_orDie(cLevel);
  93. void* ofnBuffer = NULL;
  94. size_t ofnbSize = 0;
  95. int argNb;
  96. for (argNb = 1; argNb < argc; argNb++) {
  97. const char* const ifn = argv[argNb];
  98. size_t const ifnSize = strlen(ifn);
  99. size_t const ofnSize = ifnSize + 5;
  100. if (ofnbSize <= ofnSize) {
  101. ofnbSize = ofnSize + 16;
  102. free(ofnBuffer);
  103. ofnBuffer = malloc_orDie(ofnbSize);
  104. }
  105. memset(ofnBuffer, 0, ofnSize);
  106. strcat(ofnBuffer, ifn);
  107. strcat(ofnBuffer, ".zst");
  108. compressFile_orDie(ress, ifn, ofnBuffer);
  109. }
  110. freeResources(ress);
  111. free(ofnBuffer);
  112. printf("compressed %i files \n", argc-1);
  113. return 0;
  114. }