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