xref: /netbsd-src/external/bsd/zstd/dist/doc/educational_decoder/harness.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /*
2*3117ece4Schristos  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
6*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
8*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
9*3117ece4Schristos  */
10*3117ece4Schristos 
11*3117ece4Schristos #include <stdio.h>
12*3117ece4Schristos #include <stdlib.h>
13*3117ece4Schristos 
14*3117ece4Schristos #include "zstd_decompress.h"
15*3117ece4Schristos 
16*3117ece4Schristos typedef unsigned char u8;
17*3117ece4Schristos 
18*3117ece4Schristos // If the data doesn't have decompressed size with it, fallback on assuming the
19*3117ece4Schristos // compression ratio is at most 16
20*3117ece4Schristos #define MAX_COMPRESSION_RATIO (16)
21*3117ece4Schristos 
22*3117ece4Schristos // Protect against allocating too much memory for output
23*3117ece4Schristos #define MAX_OUTPUT_SIZE ((size_t)1024 * 1024 * 1024)
24*3117ece4Schristos 
25*3117ece4Schristos // Error message then exit
26*3117ece4Schristos #define ERR_OUT(...) { fprintf(stderr, __VA_ARGS__); exit(1); }
27*3117ece4Schristos 
28*3117ece4Schristos 
29*3117ece4Schristos typedef struct {
30*3117ece4Schristos     u8* address;
31*3117ece4Schristos     size_t size;
32*3117ece4Schristos } buffer_s;
33*3117ece4Schristos 
34*3117ece4Schristos static void freeBuffer(buffer_s b) { free(b.address); }
35*3117ece4Schristos 
36*3117ece4Schristos static buffer_s read_file(const char *path)
37*3117ece4Schristos {
38*3117ece4Schristos     FILE* const f = fopen(path, "rb");
39*3117ece4Schristos     if (!f) ERR_OUT("failed to open file %s \n", path);
40*3117ece4Schristos 
41*3117ece4Schristos     fseek(f, 0L, SEEK_END);
42*3117ece4Schristos     size_t const size = (size_t)ftell(f);
43*3117ece4Schristos     rewind(f);
44*3117ece4Schristos 
45*3117ece4Schristos     void* const ptr = malloc(size);
46*3117ece4Schristos     if (!ptr) ERR_OUT("failed to allocate memory to hold %s \n", path);
47*3117ece4Schristos 
48*3117ece4Schristos     size_t const read = fread(ptr, 1, size, f);
49*3117ece4Schristos     if (read != size) ERR_OUT("error while reading file %s \n", path);
50*3117ece4Schristos 
51*3117ece4Schristos     fclose(f);
52*3117ece4Schristos     buffer_s const b = { ptr, size };
53*3117ece4Schristos     return b;
54*3117ece4Schristos }
55*3117ece4Schristos 
56*3117ece4Schristos static void write_file(const char* path, const u8* ptr, size_t size)
57*3117ece4Schristos {
58*3117ece4Schristos     FILE* const f = fopen(path, "wb");
59*3117ece4Schristos     if (!f) ERR_OUT("failed to open file %s \n", path);
60*3117ece4Schristos 
61*3117ece4Schristos     size_t written = 0;
62*3117ece4Schristos     while (written < size) {
63*3117ece4Schristos         written += fwrite(ptr+written, 1, size, f);
64*3117ece4Schristos         if (ferror(f)) ERR_OUT("error while writing file %s\n", path);
65*3117ece4Schristos     }
66*3117ece4Schristos 
67*3117ece4Schristos     fclose(f);
68*3117ece4Schristos }
69*3117ece4Schristos 
70*3117ece4Schristos int main(int argc, char **argv)
71*3117ece4Schristos {
72*3117ece4Schristos     if (argc < 3)
73*3117ece4Schristos         ERR_OUT("usage: %s <file.zst> <out_path> [dictionary] \n", argv[0]);
74*3117ece4Schristos 
75*3117ece4Schristos     buffer_s const input = read_file(argv[1]);
76*3117ece4Schristos 
77*3117ece4Schristos     buffer_s dict = { NULL, 0 };
78*3117ece4Schristos     if (argc >= 4) {
79*3117ece4Schristos         dict = read_file(argv[3]);
80*3117ece4Schristos     }
81*3117ece4Schristos 
82*3117ece4Schristos     size_t out_capacity = ZSTD_get_decompressed_size(input.address, input.size);
83*3117ece4Schristos     if (out_capacity == (size_t)-1) {
84*3117ece4Schristos         out_capacity = MAX_COMPRESSION_RATIO * input.size;
85*3117ece4Schristos         fprintf(stderr, "WARNING: Compressed data does not contain "
86*3117ece4Schristos                         "decompressed size, going to assume the compression "
87*3117ece4Schristos                         "ratio is at most %d (decompressed size of at most "
88*3117ece4Schristos                         "%u) \n",
89*3117ece4Schristos                 MAX_COMPRESSION_RATIO, (unsigned)out_capacity);
90*3117ece4Schristos     }
91*3117ece4Schristos     if (out_capacity > MAX_OUTPUT_SIZE)
92*3117ece4Schristos         ERR_OUT("Required output size too large for this implementation \n");
93*3117ece4Schristos 
94*3117ece4Schristos     u8* const output = malloc(out_capacity);
95*3117ece4Schristos     if (!output) ERR_OUT("failed to allocate memory \n");
96*3117ece4Schristos 
97*3117ece4Schristos     dictionary_t* const parsed_dict = create_dictionary();
98*3117ece4Schristos     if (dict.size) {
99*3117ece4Schristos #if defined (ZDEC_NO_DICTIONARY)
100*3117ece4Schristos         printf("dict.size = %zu \n", dict.size);
101*3117ece4Schristos         ERR_OUT("no dictionary support \n");
102*3117ece4Schristos #else
103*3117ece4Schristos         parse_dictionary(parsed_dict, dict.address, dict.size);
104*3117ece4Schristos #endif
105*3117ece4Schristos     }
106*3117ece4Schristos     size_t const decompressed_size =
107*3117ece4Schristos         ZSTD_decompress_with_dict(output, out_capacity,
108*3117ece4Schristos                                   input.address, input.size,
109*3117ece4Schristos                                   parsed_dict);
110*3117ece4Schristos 
111*3117ece4Schristos     free_dictionary(parsed_dict);
112*3117ece4Schristos 
113*3117ece4Schristos     write_file(argv[2], output, decompressed_size);
114*3117ece4Schristos 
115*3117ece4Schristos     freeBuffer(input);
116*3117ece4Schristos     freeBuffer(dict);
117*3117ece4Schristos     free(output);
118*3117ece4Schristos     return 0;
119*3117ece4Schristos }
120