| 1 | /* |
| 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * This source code is licensed under both the BSD-style license (found in the |
| 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found |
| 7 | * in the COPYING file in the root directory of this source tree). |
| 8 | * You may select, at your option, one of the above-listed licenses. |
| 9 | */ |
| 10 | |
| 11 | #include <stdio.h> // printf |
| 12 | #include <stdlib.h> // free |
| 13 | #include <string.h> // memcpy, strlen |
| 14 | #include <zstd.h> // presumes zstd library is installed |
| 15 | #include "common.h" // Helper functions, CHECK(), and CHECK_ZSTD() |
| 16 | |
| 17 | typedef struct { |
| 18 | void* fBuffer; |
| 19 | void* cBuffer; |
| 20 | size_t fBufferSize; |
| 21 | size_t cBufferSize; |
| 22 | ZSTD_CCtx* cctx; |
| 23 | } resources; |
| 24 | |
| 25 | /* |
| 26 | * allocate memory for buffers big enough to compress all files |
| 27 | * as well as memory for output file name (ofn) |
| 28 | */ |
| 29 | static resources createResources_orDie(int argc, const char** argv, char **ofn, size_t* ofnBufferLen) |
| 30 | { |
| 31 | size_t maxFilenameLength=0; |
| 32 | size_t maxFileSize = 0; |
| 33 | |
| 34 | int argNb; |
| 35 | for (argNb = 1; argNb < argc; argNb++) { |
| 36 | const char* const filename = argv[argNb]; |
| 37 | size_t const filenameLength = strlen(filename); |
| 38 | size_t const fileSize = fsize_orDie(filename); |
| 39 | |
| 40 | if (filenameLength > maxFilenameLength) maxFilenameLength = filenameLength; |
| 41 | if (fileSize > maxFileSize) maxFileSize = fileSize; |
| 42 | } |
| 43 | |
| 44 | resources ress; |
| 45 | ress.fBufferSize = maxFileSize; |
| 46 | ress.cBufferSize = ZSTD_compressBound(maxFileSize); |
| 47 | |
| 48 | *ofnBufferLen = maxFilenameLength + 5; |
| 49 | *ofn = (char*)malloc_orDie(*ofnBufferLen); |
| 50 | ress.fBuffer = malloc_orDie(ress.fBufferSize); |
| 51 | ress.cBuffer = malloc_orDie(ress.cBufferSize); |
| 52 | ress.cctx = ZSTD_createCCtx(); |
| 53 | CHECK(ress.cctx != NULL, "ZSTD_createCCtx() failed!"); |
| 54 | return ress; |
| 55 | } |
| 56 | |
| 57 | static void freeResources(resources ress, char *outFilename) |
| 58 | { |
| 59 | free(ress.fBuffer); |
| 60 | free(ress.cBuffer); |
| 61 | ZSTD_freeCCtx(ress.cctx); /* never fails */ |
| 62 | free(outFilename); |
| 63 | } |
| 64 | |
| 65 | /* compress with pre-allocated context (ZSTD_CCtx) and input/output buffers*/ |
| 66 | static void compressFile_orDie(resources ress, const char* fname, const char* oname) |
| 67 | { |
| 68 | size_t fSize = loadFile_orDie(fname, ress.fBuffer, ress.fBufferSize); |
| 69 | |
| 70 | /* Compress using the context. |
| 71 | * If you need more control over parameters, use the advanced API: |
| 72 | * ZSTD_CCtx_setParameter(), and ZSTD_compress2(). |
| 73 | */ |
| 74 | size_t const cSize = ZSTD_compressCCtx(ress.cctx, ress.cBuffer, ress.cBufferSize, ress.fBuffer, fSize, 1); |
| 75 | CHECK_ZSTD(cSize); |
| 76 | |
| 77 | saveFile_orDie(oname, ress.cBuffer, cSize); |
| 78 | |
| 79 | /* success */ |
| 80 | printf("%25s : %6u -> %7u - %s \n", fname, (unsigned)fSize, (unsigned)cSize, oname); |
| 81 | } |
| 82 | |
| 83 | int main(int argc, const char** argv) |
| 84 | { |
| 85 | const char* const exeName = argv[0]; |
| 86 | |
| 87 | if (argc<2) { |
| 88 | printf("wrong arguments\n"); |
| 89 | printf("usage:\n"); |
| 90 | printf("%s FILE(s)\n", exeName); |
| 91 | return 1; |
| 92 | } |
| 93 | |
| 94 | /* memory allocation for outFilename and resources */ |
| 95 | char* outFilename; |
| 96 | size_t outFilenameBufferLen; |
| 97 | resources const ress = createResources_orDie(argc, argv, &outFilename, &outFilenameBufferLen); |
| 98 | |
| 99 | /* compress files with shared context, input and output buffers */ |
| 100 | int argNb; |
| 101 | for (argNb = 1; argNb < argc; argNb++) { |
| 102 | const char* const inFilename = argv[argNb]; |
| 103 | size_t const inFilenameLen = strlen(inFilename); |
| 104 | CHECK(inFilenameLen + 5 <= outFilenameBufferLen, "File name too long!"); |
| 105 | memcpy(outFilename, inFilename, inFilenameLen); |
| 106 | memcpy(outFilename+inFilenameLen, ".zst", 5); |
| 107 | compressFile_orDie(ress, inFilename, outFilename); |
| 108 | } |
| 109 | |
| 110 | /* free memory */ |
| 111 | freeResources(ress,outFilename); |
| 112 | |
| 113 | printf("compressed %i files \n", argc-1); |
| 114 | |
| 115 | return 0; |
| 116 | } |