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