]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 | ||
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 | ||
9f95a23c | 87 | static void decompressFile_orDie(const char* fname, off_t startOffset, off_t endOffset) |
11fdf7f2 TL |
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 | ||
103 | if (ZSTD_isError(result)) { | |
104 | fprintf(stderr, "ZSTD_seekable_decompress() error : %s \n", | |
105 | ZSTD_getErrorName(result)); | |
106 | exit(12); | |
107 | } | |
108 | fwrite_orDie(buffOut, result, fout); | |
109 | startOffset += result; | |
110 | } | |
111 | ||
112 | ZSTD_seekable_free(seekable); | |
113 | fclose_orDie(fin); | |
114 | fclose_orDie(fout); | |
115 | free(buffOut); | |
116 | } | |
117 | ||
118 | ||
119 | int main(int argc, const char** argv) | |
120 | { | |
121 | const char* const exeName = argv[0]; | |
122 | ||
123 | if (argc!=4) { | |
124 | fprintf(stderr, "wrong arguments\n"); | |
125 | fprintf(stderr, "usage:\n"); | |
126 | fprintf(stderr, "%s FILE START END\n", exeName); | |
127 | return 1; | |
128 | } | |
129 | ||
130 | { | |
131 | const char* const inFilename = argv[1]; | |
9f95a23c TL |
132 | off_t const startOffset = atoll(argv[2]); |
133 | off_t const endOffset = atoll(argv[3]); | |
11fdf7f2 TL |
134 | decompressFile_orDie(inFilename, startOffset, endOffset); |
135 | } | |
136 | ||
137 | return 0; | |
138 | } |