648db22b |
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 | } |