1/*
2 * Copyright (c) Yann Collet, Facebook, Inc.
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#include <stdio.h>     // printf
11#include <stdlib.h>    // free
12#include <string.h>    // memset, strcat
13#include <zstd.h>      // presumes zstd library is installed
14#include "common.h"    // Helper functions, CHECK(), and CHECK_ZSTD()
15
16/* createDict() :
17   `dictFileName` is supposed to have been created using `zstd --train` */
18static ZSTD_CDict* createCDict_orDie(const char* dictFileName, int cLevel)
19{
20    size_t dictSize;
21    printf("loading dictionary %s \n", dictFileName);
22    void* const dictBuffer = mallocAndLoadFile_orDie(dictFileName, &dictSize);
23    ZSTD_CDict* const cdict = ZSTD_createCDict(dictBuffer, dictSize, cLevel);
24    CHECK(cdict != NULL, "ZSTD_createCDict() failed!");
25    free(dictBuffer);
26    return cdict;
27}
28
29
30static void compress(const char* fname, const char* oname, const ZSTD_CDict* cdict)
31{
32    size_t fSize;
33    void* const fBuff = mallocAndLoadFile_orDie(fname, &fSize);
34    size_t const cBuffSize = ZSTD_compressBound(fSize);
35    void* const cBuff = malloc_orDie(cBuffSize);
36
37    /* Compress using the dictionary.
38     * This function writes the dictionary id, and content size into the header.
39     * But, it doesn't use a checksum. You can control these options using the
40     * advanced API: ZSTD_CCtx_setParameter(), ZSTD_CCtx_refCDict(),
41     * and ZSTD_compress2().
42     */
43    ZSTD_CCtx* const cctx = ZSTD_createCCtx();
44    CHECK(cctx != NULL, "ZSTD_createCCtx() failed!");
45    size_t const cSize = ZSTD_compress_usingCDict(cctx, cBuff, cBuffSize, fBuff, fSize, cdict);
46    CHECK_ZSTD(cSize);
47
48    saveFile_orDie(oname, cBuff, cSize);
49
50    /* success */
51    printf("%25s : %6u -> %7u - %s \n", fname, (unsigned)fSize, (unsigned)cSize, oname);
52
53    ZSTD_freeCCtx(cctx);   /* never fails */
54    free(fBuff);
55    free(cBuff);
56}
57
58
59static char* createOutFilename_orDie(const char* filename)
60{
61    size_t const inL = strlen(filename);
62    size_t const outL = inL + 5;
63    void* outSpace = malloc_orDie(outL);
64    memset(outSpace, 0, outL);
65    strcat(outSpace, filename);
66    strcat(outSpace, ".zst");
67    return (char*)outSpace;
68}
69
70int main(int argc, const char** argv)
71{
72    const char* const exeName = argv[0];
73    int const cLevel = 3;
74
75    if (argc<3) {
76        fprintf(stderr, "wrong arguments\n");
77        fprintf(stderr, "usage:\n");
78        fprintf(stderr, "%s [FILES] dictionary\n", exeName);
79        return 1;
80    }
81
82    /* load dictionary only once */
83    const char* const dictName = argv[argc-1];
84    ZSTD_CDict* const dictPtr = createCDict_orDie(dictName, cLevel);
85
86    int u;
87    for (u=1; u<argc-1; u++) {
88        const char* inFilename = argv[u];
89        char* const outFilename = createOutFilename_orDie(inFilename);
90        compress(inFilename, outFilename, dictPtr);
91        free(outFilename);
92    }
93
94    ZSTD_freeCDict(dictPtr);
95    printf("All %u files compressed. \n", argc-2);
96    return 0;
97}
98