xref: /freebsd/sys/contrib/zstd/doc/educational_decoder/harness.c (revision 9cbefe25d46756f342c7dd3d174d2d1103808f21)
10c16b537SWarner Losh /*
20c16b537SWarner Losh  * Copyright (c) 2017-present, Facebook, Inc.
30c16b537SWarner Losh  * All rights reserved.
40c16b537SWarner Losh  *
50c16b537SWarner Losh  * This source code is licensed under both the BSD-style license (found in the
60c16b537SWarner Losh  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
70c16b537SWarner Losh  * in the COPYING file in the root directory of this source tree).
80c16b537SWarner Losh  */
90c16b537SWarner Losh 
100c16b537SWarner Losh #include <stdio.h>
110c16b537SWarner Losh #include <stdlib.h>
120c16b537SWarner Losh 
130c16b537SWarner Losh #include "zstd_decompress.h"
140c16b537SWarner Losh 
150c16b537SWarner Losh typedef unsigned char u8;
160c16b537SWarner Losh 
170c16b537SWarner Losh // If the data doesn't have decompressed size with it, fallback on assuming the
180c16b537SWarner Losh // compression ratio is at most 16
190c16b537SWarner Losh #define MAX_COMPRESSION_RATIO (16)
200c16b537SWarner Losh 
210c16b537SWarner Losh // Protect against allocating too much memory for output
220c16b537SWarner Losh #define MAX_OUTPUT_SIZE ((size_t)1024 * 1024 * 1024)
230c16b537SWarner Losh 
24*9cbefe25SConrad Meyer static size_t read_file(const char *path, u8 **ptr)
25*9cbefe25SConrad Meyer {
26*9cbefe25SConrad Meyer     FILE* const f = fopen(path, "rb");
270c16b537SWarner Losh     if (!f) {
280c16b537SWarner Losh         fprintf(stderr, "failed to open file %s \n", path);
290c16b537SWarner Losh         exit(1);
300c16b537SWarner Losh     }
310c16b537SWarner Losh 
320c16b537SWarner Losh     fseek(f, 0L, SEEK_END);
33*9cbefe25SConrad Meyer     size_t const size = (size_t)ftell(f);
340c16b537SWarner Losh     rewind(f);
350c16b537SWarner Losh 
360c16b537SWarner Losh     *ptr = malloc(size);
370c16b537SWarner Losh     if (!ptr) {
380c16b537SWarner Losh         fprintf(stderr, "failed to allocate memory to hold %s \n", path);
390c16b537SWarner Losh         exit(1);
400c16b537SWarner Losh     }
410c16b537SWarner Losh 
42*9cbefe25SConrad Meyer     size_t const read = fread(*ptr, 1, size, f);
43*9cbefe25SConrad Meyer     if (read != size) {  /* must read everything in one pass */
440c16b537SWarner Losh         fprintf(stderr, "error while reading file %s \n", path);
450c16b537SWarner Losh         exit(1);
460c16b537SWarner Losh     }
470c16b537SWarner Losh 
480c16b537SWarner Losh     fclose(f);
490c16b537SWarner Losh 
50*9cbefe25SConrad Meyer     return read;
510c16b537SWarner Losh }
520c16b537SWarner Losh 
53*9cbefe25SConrad Meyer static void write_file(const char *path, const u8 *ptr, size_t size)
54*9cbefe25SConrad Meyer {
55*9cbefe25SConrad Meyer     FILE* const f = fopen(path, "wb");
56*9cbefe25SConrad Meyer     if (!f) {
57*9cbefe25SConrad Meyer         fprintf(stderr, "failed to open file %s \n", path);
58*9cbefe25SConrad Meyer         exit(1);
59*9cbefe25SConrad Meyer     }
600c16b537SWarner Losh 
610c16b537SWarner Losh     size_t written = 0;
620c16b537SWarner Losh     while (written < size) {
63*9cbefe25SConrad Meyer         written += fwrite(ptr+written, 1, size, f);
640c16b537SWarner Losh         if (ferror(f)) {
650c16b537SWarner Losh             fprintf(stderr, "error while writing file %s\n", path);
660c16b537SWarner Losh             exit(1);
67*9cbefe25SConrad Meyer     }   }
680c16b537SWarner Losh 
690c16b537SWarner Losh     fclose(f);
700c16b537SWarner Losh }
710c16b537SWarner Losh 
72*9cbefe25SConrad Meyer int main(int argc, char **argv)
73*9cbefe25SConrad Meyer {
740c16b537SWarner Losh     if (argc < 3) {
750c16b537SWarner Losh         fprintf(stderr, "usage: %s <file.zst> <out_path> [dictionary] \n",
760c16b537SWarner Losh                 argv[0]);
770c16b537SWarner Losh 
780c16b537SWarner Losh         return 1;
790c16b537SWarner Losh     }
800c16b537SWarner Losh 
81*9cbefe25SConrad Meyer     u8* input;
82*9cbefe25SConrad Meyer     size_t const input_size = read_file(argv[1], &input);
83*9cbefe25SConrad Meyer 
84*9cbefe25SConrad Meyer     u8* dict = NULL;
850c16b537SWarner Losh     size_t dict_size = 0;
860c16b537SWarner Losh     if (argc >= 4) {
870c16b537SWarner Losh         dict_size = read_file(argv[3], &dict);
880c16b537SWarner Losh     }
890c16b537SWarner Losh 
90*9cbefe25SConrad Meyer     size_t out_capacity = ZSTD_get_decompressed_size(input, input_size);
91*9cbefe25SConrad Meyer     if (out_capacity == (size_t)-1) {
92*9cbefe25SConrad Meyer         out_capacity = MAX_COMPRESSION_RATIO * input_size;
930c16b537SWarner Losh         fprintf(stderr, "WARNING: Compressed data does not contain "
940c16b537SWarner Losh                         "decompressed size, going to assume the compression "
950c16b537SWarner Losh                         "ratio is at most %d (decompressed size of at most "
96*9cbefe25SConrad Meyer                         "%u) \n",
97*9cbefe25SConrad Meyer                 MAX_COMPRESSION_RATIO, (unsigned)out_capacity);
980c16b537SWarner Losh     }
99*9cbefe25SConrad Meyer     if (out_capacity > MAX_OUTPUT_SIZE) {
1000c16b537SWarner Losh         fprintf(stderr,
1010c16b537SWarner Losh                 "Required output size too large for this implementation \n");
1020c16b537SWarner Losh         return 1;
1030c16b537SWarner Losh     }
104*9cbefe25SConrad Meyer 
105*9cbefe25SConrad Meyer     u8* const output = malloc(out_capacity);
1060c16b537SWarner Losh     if (!output) {
1070c16b537SWarner Losh         fprintf(stderr, "failed to allocate memory \n");
1080c16b537SWarner Losh         return 1;
1090c16b537SWarner Losh     }
1100c16b537SWarner Losh 
1110c16b537SWarner Losh     dictionary_t* const parsed_dict = create_dictionary();
1120c16b537SWarner Losh     if (dict) {
1130c16b537SWarner Losh         parse_dictionary(parsed_dict, dict, dict_size);
1140c16b537SWarner Losh     }
115*9cbefe25SConrad Meyer     size_t const decompressed_size =
116*9cbefe25SConrad Meyer         ZSTD_decompress_with_dict(output, out_capacity,
117*9cbefe25SConrad Meyer                                   input, input_size,
118*9cbefe25SConrad Meyer                                   parsed_dict);
1190c16b537SWarner Losh 
1200c16b537SWarner Losh     free_dictionary(parsed_dict);
1210c16b537SWarner Losh 
122*9cbefe25SConrad Meyer     write_file(argv[2], output, decompressed_size);
1230c16b537SWarner Losh 
1240c16b537SWarner Losh     free(input);
1250c16b537SWarner Losh     free(output);
1260c16b537SWarner Losh     free(dict);
127*9cbefe25SConrad Meyer     return 0;
1280c16b537SWarner Losh }
129