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