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