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