seekable_decompression.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. * Copyright (c) 2017-present, 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. */
  9. #include <stdlib.h> // malloc, exit
  10. #include <stdio.h> // fprintf, perror, feof
  11. #include <string.h> // strerror
  12. #include <errno.h> // errno
  13. #define ZSTD_STATIC_LINKING_ONLY
  14. #include <zstd.h> // presumes zstd library is installed
  15. #include <zstd_errors.h>
  16. #include "zstd_seekable.h"
  17. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  18. static void* malloc_orDie(size_t size)
  19. {
  20. void* const buff = malloc(size);
  21. if (buff) return buff;
  22. /* error */
  23. perror("malloc");
  24. exit(1);
  25. }
  26. static void* realloc_orDie(void* ptr, size_t size)
  27. {
  28. ptr = realloc(ptr, size);
  29. if (ptr) return ptr;
  30. /* error */
  31. perror("realloc");
  32. exit(1);
  33. }
  34. static FILE* fopen_orDie(const char *filename, const char *instruction)
  35. {
  36. FILE* const inFile = fopen(filename, instruction);
  37. if (inFile) return inFile;
  38. /* error */
  39. perror(filename);
  40. exit(3);
  41. }
  42. static size_t fread_orDie(void* buffer, size_t sizeToRead, FILE* file)
  43. {
  44. size_t const readSize = fread(buffer, 1, sizeToRead, file);
  45. if (readSize == sizeToRead) return readSize; /* good */
  46. if (feof(file)) return readSize; /* good, reached end of file */
  47. /* error */
  48. perror("fread");
  49. exit(4);
  50. }
  51. static size_t fwrite_orDie(const void* buffer, size_t sizeToWrite, FILE* file)
  52. {
  53. size_t const writtenSize = fwrite(buffer, 1, sizeToWrite, file);
  54. if (writtenSize == sizeToWrite) return sizeToWrite; /* good */
  55. /* error */
  56. perror("fwrite");
  57. exit(5);
  58. }
  59. static size_t fclose_orDie(FILE* file)
  60. {
  61. if (!fclose(file)) return 0;
  62. /* error */
  63. perror("fclose");
  64. exit(6);
  65. }
  66. static void fseek_orDie(FILE* file, long int offset, int origin) {
  67. if (!fseek(file, offset, origin)) {
  68. if (!fflush(file)) return;
  69. }
  70. /* error */
  71. perror("fseek");
  72. exit(7);
  73. }
  74. static void decompressFile_orDie(const char* fname, off_t startOffset, off_t endOffset)
  75. {
  76. FILE* const fin = fopen_orDie(fname, "rb");
  77. FILE* const fout = stdout;
  78. size_t const buffOutSize = ZSTD_DStreamOutSize(); /* Guarantee to successfully flush at least one complete compressed block in all circumstances. */
  79. void* const buffOut = malloc_orDie(buffOutSize);
  80. ZSTD_seekable* const seekable = ZSTD_seekable_create();
  81. if (seekable==NULL) { fprintf(stderr, "ZSTD_seekable_create() error \n"); exit(10); }
  82. size_t const initResult = ZSTD_seekable_initFile(seekable, fin);
  83. if (ZSTD_isError(initResult)) { fprintf(stderr, "ZSTD_seekable_init() error : %s \n", ZSTD_getErrorName(initResult)); exit(11); }
  84. while (startOffset < endOffset) {
  85. size_t const result = ZSTD_seekable_decompress(seekable, buffOut, MIN(endOffset - startOffset, buffOutSize), startOffset);
  86. if (!result) {
  87. break;
  88. }
  89. if (ZSTD_isError(result)) {
  90. fprintf(stderr, "ZSTD_seekable_decompress() error : %s \n",
  91. ZSTD_getErrorName(result));
  92. exit(12);
  93. }
  94. fwrite_orDie(buffOut, result, fout);
  95. startOffset += result;
  96. }
  97. ZSTD_seekable_free(seekable);
  98. fclose_orDie(fin);
  99. fclose_orDie(fout);
  100. free(buffOut);
  101. }
  102. int main(int argc, const char** argv)
  103. {
  104. const char* const exeName = argv[0];
  105. if (argc!=4) {
  106. fprintf(stderr, "wrong arguments\n");
  107. fprintf(stderr, "usage:\n");
  108. fprintf(stderr, "%s FILE START END\n", exeName);
  109. return 1;
  110. }
  111. {
  112. const char* const inFilename = argv[1];
  113. off_t const startOffset = atoll(argv[2]);
  114. off_t const endOffset = atoll(argv[3]);
  115. decompressFile_orDie(inFilename, startOffset, endOffset);
  116. }
  117. return 0;
  118. }