blob: 17acec98dfa138c73c8ae46ee908af6822ea3359 [file] [log] [blame]
Yann Collet394bdd72017-08-29 09:24:11 -07001/*
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
Yann Collet4ded9e52016-08-30 10:04:33 -07003 * All rights reserved.
4 *
Yann Collet394bdd72017-08-29 09:24:11 -07005 * 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).
Yann Collet4ded9e52016-08-30 10:04:33 -07008 */
Yann Colletcadd7cd2016-07-15 18:52:37 +02009
Yann Colletcadd7cd2016-07-15 18:52:37 +020010
11#include <stdlib.h> // malloc, exit
12#include <stdio.h> // printf
13#include <string.h> // strerror
14#include <errno.h> // errno
15#include <sys/stat.h> // stat
16#include <zstd.h> // presumes zstd library is installed
17
18
Yann Collet373d4f92016-08-01 17:36:11 +020019static off_t fsize_orDie(const char *filename)
Yann Colletcadd7cd2016-07-15 18:52:37 +020020{
21 struct stat st;
22 if (stat(filename, &st) == 0) return st.st_size;
23 /* error */
24 perror(filename);
25 exit(1);
26}
27
Yann Collet373d4f92016-08-01 17:36:11 +020028static FILE* fopen_orDie(const char *filename, const char *instruction)
Yann Colletcadd7cd2016-07-15 18:52:37 +020029{
30 FILE* const inFile = fopen(filename, instruction);
31 if (inFile) return inFile;
32 /* error */
33 perror(filename);
34 exit(2);
35}
36
Yann Collet373d4f92016-08-01 17:36:11 +020037static void* malloc_orDie(size_t size)
Yann Colletcadd7cd2016-07-15 18:52:37 +020038{
39 void* const buff = malloc(size);
40 if (buff) return buff;
41 /* error */
Yann Collet373d4f92016-08-01 17:36:11 +020042 perror("malloc");
Yann Colletcadd7cd2016-07-15 18:52:37 +020043 exit(3);
44}
45
Yann Collet373d4f92016-08-01 17:36:11 +020046static void* loadFile_orDie(const char* fileName, size_t* size)
Yann Colletcadd7cd2016-07-15 18:52:37 +020047{
Yann Collet373d4f92016-08-01 17:36:11 +020048 off_t const buffSize = fsize_orDie(fileName);
49 FILE* const inFile = fopen_orDie(fileName, "rb");
50 void* const buffer = malloc_orDie(buffSize);
Yann Colletcadd7cd2016-07-15 18:52:37 +020051 size_t const readSize = fread(buffer, 1, buffSize, inFile);
52 if (readSize != (size_t)buffSize) {
53 fprintf(stderr, "fread: %s : %s \n", fileName, strerror(errno));
54 exit(4);
55 }
56 fclose(inFile);
57 *size = buffSize;
58 return buffer;
59}
60
Yann Collet373d4f92016-08-01 17:36:11 +020061static void saveFile_orDie(const char* fileName, const void* buff, size_t buffSize)
Yann Colletcadd7cd2016-07-15 18:52:37 +020062{
Yann Collet373d4f92016-08-01 17:36:11 +020063 FILE* const oFile = fopen_orDie(fileName, "wb");
Yann Colletcadd7cd2016-07-15 18:52:37 +020064 size_t const wSize = fwrite(buff, 1, buffSize, oFile);
65 if (wSize != (size_t)buffSize) {
66 fprintf(stderr, "fwrite: %s : %s \n", fileName, strerror(errno));
67 exit(5);
68 }
69 if (fclose(oFile)) {
70 perror(fileName);
71 exit(6);
72 }
73}
74
75/* createDict() :
76 `dictFileName` is supposed to have been created using `zstd --train` */
Yann Colleta2664642016-09-09 19:33:56 +020077static ZSTD_CDict* createCDict_orDie(const char* dictFileName, int cLevel)
Yann Colletcadd7cd2016-07-15 18:52:37 +020078{
79 size_t dictSize;
80 printf("loading dictionary %s \n", dictFileName);
Yann Collet373d4f92016-08-01 17:36:11 +020081 void* const dictBuffer = loadFile_orDie(dictFileName, &dictSize);
Yann Colleta2664642016-09-09 19:33:56 +020082 ZSTD_CDict* const cdict = ZSTD_createCDict(dictBuffer, dictSize, cLevel);
Yann Collet373d4f92016-08-01 17:36:11 +020083 if (!cdict) {
84 fprintf(stderr, "ZSTD_createCDict error \n");
85 exit(7);
86 }
Yann Colletcadd7cd2016-07-15 18:52:37 +020087 free(dictBuffer);
Yann Collet373d4f92016-08-01 17:36:11 +020088 return cdict;
Yann Colletcadd7cd2016-07-15 18:52:37 +020089}
90
91
92static void compress(const char* fname, const char* oname, const ZSTD_CDict* cdict)
93{
94 size_t fSize;
Yann Collet373d4f92016-08-01 17:36:11 +020095 void* const fBuff = loadFile_orDie(fname, &fSize);
Yann Colletcadd7cd2016-07-15 18:52:37 +020096 size_t const cBuffSize = ZSTD_compressBound(fSize);
Yann Collet373d4f92016-08-01 17:36:11 +020097 void* const cBuff = malloc_orDie(cBuffSize);
Yann Colletcadd7cd2016-07-15 18:52:37 +020098
99 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
Yann Colleta2664642016-09-09 19:33:56 +0200100 if (cctx==NULL) { fprintf(stderr, "ZSTD_createCCtx() error \n"); exit(10); }
Yann Colletcadd7cd2016-07-15 18:52:37 +0200101 size_t const cSize = ZSTD_compress_usingCDict(cctx, cBuff, cBuffSize, fBuff, fSize, cdict);
102 if (ZSTD_isError(cSize)) {
103 fprintf(stderr, "error compressing %s : %s \n", fname, ZSTD_getErrorName(cSize));
104 exit(7);
105 }
106
Yann Collet373d4f92016-08-01 17:36:11 +0200107 saveFile_orDie(oname, cBuff, cSize);
Yann Colletcadd7cd2016-07-15 18:52:37 +0200108
109 /* success */
110 printf("%25s : %6u -> %7u - %s \n", fname, (unsigned)fSize, (unsigned)cSize, oname);
111
Yann Colleta2664642016-09-09 19:33:56 +0200112 ZSTD_freeCCtx(cctx); /* never fails */
Yann Colletcadd7cd2016-07-15 18:52:37 +0200113 free(fBuff);
114 free(cBuff);
115}
116
117
Yann Collet373d4f92016-08-01 17:36:11 +0200118static char* createOutFilename_orDie(const char* filename)
Yann Colletcadd7cd2016-07-15 18:52:37 +0200119{
120 size_t const inL = strlen(filename);
121 size_t const outL = inL + 5;
Yann Collet373d4f92016-08-01 17:36:11 +0200122 void* outSpace = malloc_orDie(outL);
Yann Colletcadd7cd2016-07-15 18:52:37 +0200123 memset(outSpace, 0, outL);
124 strcat(outSpace, filename);
125 strcat(outSpace, ".zst");
126 return (char*)outSpace;
127}
128
129int main(int argc, const char** argv)
130{
131 const char* const exeName = argv[0];
Yann Colleta2664642016-09-09 19:33:56 +0200132 int const cLevel = 3;
Yann Colletcadd7cd2016-07-15 18:52:37 +0200133
134 if (argc<3) {
135 fprintf(stderr, "wrong arguments\n");
136 fprintf(stderr, "usage:\n");
137 fprintf(stderr, "%s [FILES] dictionary\n", exeName);
138 return 1;
139 }
140
141 /* load dictionary only once */
142 const char* const dictName = argv[argc-1];
Yann Colleta2664642016-09-09 19:33:56 +0200143 ZSTD_CDict* const dictPtr = createCDict_orDie(dictName, cLevel);
Yann Colletcadd7cd2016-07-15 18:52:37 +0200144
145 int u;
146 for (u=1; u<argc-1; u++) {
147 const char* inFilename = argv[u];
Yann Collet373d4f92016-08-01 17:36:11 +0200148 char* const outFilename = createOutFilename_orDie(inFilename);
Yann Colletcadd7cd2016-07-15 18:52:37 +0200149 compress(inFilename, outFilename, dictPtr);
150 free(outFilename);
151 }
152
Yann Collet0b2d6822016-08-01 17:39:06 +0200153 ZSTD_freeCDict(dictPtr);
Yann Colletcadd7cd2016-07-15 18:52:37 +0200154 printf("All %u files compressed. \n", argc-2);
Yann Collet07639052016-08-03 01:57:57 +0200155 return 0;
Yann Colletcadd7cd2016-07-15 18:52:37 +0200156}