blob: 6e86e846316caf946f32aff3c7c1d33b31f23b4e [file] [log] [blame]
Yann Collet32fb4072017-08-18 16:52:05 -07001/*
Yann Collet4ded9e52016-08-30 10:04:33 -07002 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
Yann Collet32fb4072017-08-18 16:52:05 -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 Collet3128e032017-09-08 00:09:23 -07008 * You may select, at your option, one of the above-listed licenses.
Yann Collet4ded9e52016-08-30 10:04:33 -07009 */
Yann Collet71eafdd2016-02-12 02:31:57 +010010
Yann Collet71eafdd2016-02-12 02:31:57 +010011
Yann Collet71eafdd2016-02-12 02:31:57 +010012
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010013/* **************************************
14* Compiler Warnings
15****************************************/
16#ifdef _MSC_VER
Yann Collet77c137b2017-09-14 15:12:57 -070017# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010018#endif
19
20
Yann Collet71eafdd2016-02-12 02:31:57 +010021/*-*************************************
22* Includes
23***************************************/
Przemyslaw Skibinski7a8a03c2016-12-21 15:08:44 +010024#include "platform.h" /* Large Files support */
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010025#include "util.h" /* UTIL_getFileSize, UTIL_getTotalFileSize */
Yann Collet71eafdd2016-02-12 02:31:57 +010026#include <stdlib.h> /* malloc, free */
27#include <string.h> /* memset */
28#include <stdio.h> /* fprintf, fopen, ftello64 */
inikep37337972016-05-10 14:22:55 +020029#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
Yann Colleta3d03a32016-07-06 16:27:17 +020030#include <errno.h> /* errno */
Yann Collet71eafdd2016-02-12 02:31:57 +010031
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010032#include "mem.h" /* read */
Yann Collet71eafdd2016-02-12 02:31:57 +010033#include "error_private.h"
inikep23a08892016-04-22 12:43:18 +020034#include "dibio.h"
Yann Collet71eafdd2016-02-12 02:31:57 +010035
36
37/*-*************************************
38* Constants
39***************************************/
40#define KB *(1 <<10)
41#define MB *(1 <<20)
42#define GB *(1U<<30)
43
Yann Collet1496c3d2016-12-18 11:58:23 +010044#define SAMPLESIZE_MAX (128 KB)
45#define MEMMULT 11 /* rough estimation : memory cost to analyze 1 byte of sample */
Nick Terrelldf8415c2016-12-31 21:08:24 -080046#define COVER_MEMMULT 9 /* rough estimation : memory cost to analyze 1 byte of sample */
Yann Collet77c137b2017-09-14 15:12:57 -070047static const size_t g_maxMemory = (sizeof(size_t) == 4) ? (2 GB - 64 MB) : ((size_t)(512 MB) << sizeof(size_t));
Yann Collet71eafdd2016-02-12 02:31:57 +010048
49#define NOISELENGTH 32
Yann Collet71eafdd2016-02-12 02:31:57 +010050
51
52/*-*************************************
53* Console display
54***************************************/
55#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
Yann Collet086b9592017-09-14 16:45:10 -070056#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
Yann Collet71eafdd2016-02-12 02:31:57 +010057
Yann Collet086b9592017-09-14 16:45:10 -070058#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
59 if ((DIB_clockSpan(g_time) > refreshRate) || (displayLevel>=4)) \
Yann Colletf6ca09b2016-05-09 04:44:45 +020060 { g_time = clock(); DISPLAY(__VA_ARGS__); \
Yann Collet086b9592017-09-14 16:45:10 -070061 if (displayLevel>=4) fflush(stderr); } }
Yann Colletbcb5f772016-07-06 15:41:03 +020062static const clock_t refreshRate = CLOCKS_PER_SEC * 2 / 10;
Yann Colletf6ca09b2016-05-09 04:44:45 +020063static clock_t g_time = 0;
64
Yann Colletbcb5f772016-07-06 15:41:03 +020065static clock_t DIB_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
Yann Colletf6ca09b2016-05-09 04:44:45 +020066
Yann Collet71eafdd2016-02-12 02:31:57 +010067
68/*-*************************************
69* Exceptions
70***************************************/
71#ifndef DEBUG
72# define DEBUG 0
73#endif
74#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
75#define EXM_THROW(error, ...) \
76{ \
77 DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
Yann Collet086b9592017-09-14 16:45:10 -070078 DISPLAY("Error %i : ", error); \
79 DISPLAY(__VA_ARGS__); \
80 DISPLAY("\n"); \
Yann Collet71eafdd2016-02-12 02:31:57 +010081 exit(error); \
82}
83
84
85/* ********************************************************
86* Helper functions
87**********************************************************/
88unsigned DiB_isError(size_t errorCode) { return ERR_isError(errorCode); }
89
90const char* DiB_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); }
91
Sean Purcell42bac7f2017-04-13 15:35:05 -070092#undef MIN
93#define MIN(a,b) ((a) < (b) ? (a) : (b))
Yann Colletbcb5f772016-07-06 15:41:03 +020094
Yann Collet71eafdd2016-02-12 02:31:57 +010095
96/* ********************************************************
97* File related operations
98**********************************************************/
Yann Collet290aaa72016-05-30 21:18:52 +020099/** DiB_loadFiles() :
Yann Collet77c137b2017-09-14 15:12:57 -0700100 * load files listed in fileNamesTable into buffer, even if buffer is too small.
101 * @return : nb of files effectively loaded into `buffer`
102 * *bufferSizePtr is modified, it provides the amount data loaded within buffer */
Yann Colletbcb5f772016-07-06 15:41:03 +0200103static unsigned DiB_loadFiles(void* buffer, size_t* bufferSizePtr,
Yann Collet086b9592017-09-14 16:45:10 -0700104 size_t* chunkSizes,
105 const char** fileNamesTable, unsigned nbFiles, size_t targetChunkSize,
106 unsigned displayLevel)
Yann Collet71eafdd2016-02-12 02:31:57 +0100107{
Yann Collet290aaa72016-05-30 21:18:52 +0200108 char* const buff = (char*)buffer;
Yann Collet71eafdd2016-02-12 02:31:57 +0100109 size_t pos = 0;
Yann Collet086b9592017-09-14 16:45:10 -0700110 unsigned nbLoadedChunks = 0, fileIndex;
Yann Collet71eafdd2016-02-12 02:31:57 +0100111
Yann Collet086b9592017-09-14 16:45:10 -0700112 for (fileIndex=0; fileIndex<nbFiles; fileIndex++) {
113 const char* const fileName = fileNamesTable[fileIndex];
Yann Colletbcb5f772016-07-06 15:41:03 +0200114 unsigned long long const fs64 = UTIL_getFileSize(fileName);
Yann Collet086b9592017-09-14 16:45:10 -0700115 unsigned long long remainingToLoad = fs64;
116 U32 const nbChunks = targetChunkSize ? (U32)((fs64 + (targetChunkSize-1)) / targetChunkSize) : 1;
117 U64 const chunkSize = targetChunkSize ? MIN(targetChunkSize, fs64) : fs64;
Yann Collet25a60482017-09-15 11:55:13 -0700118 size_t const maxChunkSize = (size_t)MIN(chunkSize, SAMPLESIZE_MAX);
Yann Collet086b9592017-09-14 16:45:10 -0700119 U32 cnb;
120 FILE* const f = fopen(fileName, "rb");
121 if (f==NULL) EXM_THROW(10, "zstd: dictBuilder: %s %s ", fileName, strerror(errno));
122 DISPLAYUPDATE(2, "Loading %s... \r", fileName);
123 for (cnb=0; cnb<nbChunks; cnb++) {
Yann Collet25a60482017-09-15 11:55:13 -0700124 size_t const toLoad = (size_t)MIN(maxChunkSize, remainingToLoad);
Yann Collet086b9592017-09-14 16:45:10 -0700125 if (toLoad > *bufferSizePtr-pos) break;
126 { size_t const readSize = fread(buff+pos, 1, toLoad, f);
127 if (readSize != toLoad) EXM_THROW(11, "Pb reading %s", fileName);
128 pos += readSize;
129 chunkSizes[nbLoadedChunks++] = toLoad;
130 remainingToLoad -= targetChunkSize;
131 if (toLoad < targetChunkSize) {
Yann Colleta9694232017-09-15 10:16:26 -0700132 fseek(f, (long)(targetChunkSize - toLoad), SEEK_CUR);
Yann Collet086b9592017-09-14 16:45:10 -0700133 } } }
134 fclose(f);
135 }
Nick Terrelldf8415c2016-12-31 21:08:24 -0800136 DISPLAYLEVEL(2, "\r%79s\r", "");
Yann Colletbcb5f772016-07-06 15:41:03 +0200137 *bufferSizePtr = pos;
Yann Collet086b9592017-09-14 16:45:10 -0700138 DISPLAYLEVEL(4, "loaded : %u KB \n", (U32)(pos >> 10))
139 return nbLoadedChunks;
Yann Collet71eafdd2016-02-12 02:31:57 +0100140}
141
Nick Terrelldf8415c2016-12-31 21:08:24 -0800142#define DiB_rotl32(x,r) ((x << r) | (x >> (32 - r)))
143static U32 DiB_rand(U32* src)
144{
145 static const U32 prime1 = 2654435761U;
146 static const U32 prime2 = 2246822519U;
147 U32 rand32 = *src;
148 rand32 *= prime1;
149 rand32 ^= prime2;
150 rand32 = DiB_rotl32(rand32, 13);
151 *src = rand32;
152 return rand32 >> 5;
153}
154
Yann Collet77c137b2017-09-14 15:12:57 -0700155/* DiB_shuffle() :
156 * shuffle a table of file names in a semi-random way
157 * It improves dictionary quality by reducing "locality" impact, so if sample set is very large,
158 * it will load random elements from it, instead of just the first ones. */
Nick Terrelldf8415c2016-12-31 21:08:24 -0800159static void DiB_shuffle(const char** fileNamesTable, unsigned nbFiles) {
Yann Collet77c137b2017-09-14 15:12:57 -0700160 U32 seed = 0xFD2FB528;
161 unsigned i;
162 for (i = nbFiles - 1; i > 0; --i) {
163 unsigned const j = DiB_rand(&seed) % (i + 1);
164 const char* const tmp = fileNamesTable[j];
165 fileNamesTable[j] = fileNamesTable[i];
166 fileNamesTable[i] = tmp;
167 }
Nick Terrelldf8415c2016-12-31 21:08:24 -0800168}
169
Yann Collet71eafdd2016-02-12 02:31:57 +0100170
171/*-********************************************************
172* Dictionary training functions
173**********************************************************/
174static size_t DiB_findMaxMem(unsigned long long requiredMem)
175{
Yann Collet290aaa72016-05-30 21:18:52 +0200176 size_t const step = 8 MB;
Yann Collet71eafdd2016-02-12 02:31:57 +0100177 void* testmem = NULL;
178
179 requiredMem = (((requiredMem >> 23) + 1) << 23);
Yann Colletbcb5f772016-07-06 15:41:03 +0200180 requiredMem += step;
Yann Collet77c137b2017-09-14 15:12:57 -0700181 if (requiredMem > g_maxMemory) requiredMem = g_maxMemory;
Yann Collet71eafdd2016-02-12 02:31:57 +0100182
183 while (!testmem) {
Yann Collet71eafdd2016-02-12 02:31:57 +0100184 testmem = malloc((size_t)requiredMem);
Yann Colletbcb5f772016-07-06 15:41:03 +0200185 requiredMem -= step;
Yann Collet71eafdd2016-02-12 02:31:57 +0100186 }
187
188 free(testmem);
Yann Colletbcb5f772016-07-06 15:41:03 +0200189 return (size_t)requiredMem;
Yann Collet71eafdd2016-02-12 02:31:57 +0100190}
191
192
193static void DiB_fillNoise(void* buffer, size_t length)
194{
Yann Colletbcb5f772016-07-06 15:41:03 +0200195 unsigned const prime1 = 2654435761U;
196 unsigned const prime2 = 2246822519U;
197 unsigned acc = prime1;
Yann Collet71eafdd2016-02-12 02:31:57 +0100198 size_t p=0;;
199
200 for (p=0; p<length; p++) {
Yann Colletbcb5f772016-07-06 15:41:03 +0200201 acc *= prime2;
Yann Collet71eafdd2016-02-12 02:31:57 +0100202 ((unsigned char*)buffer)[p] = (unsigned char)(acc >> 21);
203 }
204}
205
206
207static void DiB_saveDict(const char* dictFileName,
208 const void* buff, size_t buffSize)
209{
Yann Collet290aaa72016-05-30 21:18:52 +0200210 FILE* const f = fopen(dictFileName, "wb");
Yann Collet71eafdd2016-02-12 02:31:57 +0100211 if (f==NULL) EXM_THROW(3, "cannot open %s ", dictFileName);
212
Yann Colletf6ca09b2016-05-09 04:44:45 +0200213 { size_t const n = fwrite(buff, 1, buffSize, f);
214 if (n!=buffSize) EXM_THROW(4, "%s : write error", dictFileName) }
Yann Collet71eafdd2016-02-12 02:31:57 +0100215
Yann Colletf6ca09b2016-05-09 04:44:45 +0200216 { size_t const n = (size_t)fclose(f);
217 if (n!=0) EXM_THROW(5, "%s : flush error", dictFileName) }
Yann Collet71eafdd2016-02-12 02:31:57 +0100218}
219
220
Yann Collet086b9592017-09-14 16:45:10 -0700221typedef struct {
222 U64 totalSizeToLoad;
223 unsigned oneSampleTooLarge;
224 unsigned nbChunks;
225} fileStats;
226
227static fileStats DiB_fileStats(const char** fileNamesTable, unsigned nbFiles, size_t chunkSize, unsigned displayLevel)
Yann Collet1496c3d2016-12-18 11:58:23 +0100228{
Yann Collet086b9592017-09-14 16:45:10 -0700229 fileStats fs;
Yann Collet1496c3d2016-12-18 11:58:23 +0100230 unsigned n;
Yann Collet086b9592017-09-14 16:45:10 -0700231 memset(&fs, 0, sizeof(fs));
Yann Collet1496c3d2016-12-18 11:58:23 +0100232 for (n=0; n<nbFiles; n++) {
233 U64 const fileSize = UTIL_getFileSize(fileNamesTable[n]);
Yann Collet086b9592017-09-14 16:45:10 -0700234 U32 const nbChunks = (U32)(chunkSize ? (fileSize + (chunkSize-1)) / chunkSize : 1);
235 U64 const chunkToLoad = chunkSize ? MIN(chunkSize, fileSize) : fileSize;
Yann Collet25a60482017-09-15 11:55:13 -0700236 size_t const cappedChunkSize = (size_t)MIN(chunkToLoad, SAMPLESIZE_MAX);
Yann Collet086b9592017-09-14 16:45:10 -0700237 fs.totalSizeToLoad += cappedChunkSize * nbChunks;
238 fs.oneSampleTooLarge |= (chunkSize > 2*SAMPLESIZE_MAX);
239 fs.nbChunks += nbChunks;
Yann Collet1496c3d2016-12-18 11:58:23 +0100240 }
Yann Collet086b9592017-09-14 16:45:10 -0700241 DISPLAYLEVEL(4, "Preparing to load : %u KB \n", (U32)(fs.totalSizeToLoad >> 10));
242 return fs;
Yann Collet1496c3d2016-12-18 11:58:23 +0100243}
244
245
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700246/*! ZDICT_trainFromBuffer_unsafe_legacy() :
Yann Collet6f3acba2016-02-12 20:19:48 +0100247 Strictly Internal use only !!
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700248 Same as ZDICT_trainFromBuffer_legacy(), but does not control `samplesBuffer`.
Yann Collet6f3acba2016-02-12 20:19:48 +0100249 `samplesBuffer` must be followed by noisy guard band to avoid out-of-buffer reads.
250 @return : size of dictionary stored into `dictBuffer` (<= `dictBufferCapacity`)
251 or an error code.
252*/
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700253size_t ZDICT_trainFromBuffer_unsafe_legacy(void* dictBuffer, size_t dictBufferCapacity,
254 const void* samplesBuffer, const size_t* samplesSizes, unsigned nbSamples,
255 ZDICT_legacy_params_t parameters);
Yann Collet6f3acba2016-02-12 20:19:48 +0100256
257
Yann Collet71eafdd2016-02-12 02:31:57 +0100258int DiB_trainFromFiles(const char* dictFileName, unsigned maxDictSize,
Yann Collet086b9592017-09-14 16:45:10 -0700259 const char** fileNamesTable, unsigned nbFiles, size_t chunkSize,
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700260 ZDICT_legacy_params_t *params, ZDICT_cover_params_t *coverParams,
Nick Terrelldf8415c2016-12-31 21:08:24 -0800261 int optimizeCover)
Yann Collet71eafdd2016-02-12 02:31:57 +0100262{
Yann Collet086b9592017-09-14 16:45:10 -0700263 unsigned displayLevel = params ? params->zParams.notificationLevel :
264 coverParams ? coverParams->zParams.notificationLevel :
265 0; /* should never happen */
Yann Collet290aaa72016-05-30 21:18:52 +0200266 void* const dictBuffer = malloc(maxDictSize);
Yann Collet086b9592017-09-14 16:45:10 -0700267 fileStats const fs = DiB_fileStats(fileNamesTable, nbFiles, chunkSize, displayLevel);
268 size_t* const chunkSizes = (size_t*)malloc(fs.nbChunks * sizeof(size_t));
Nick Terrellc220d4c2017-01-09 16:49:04 -0800269 size_t const memMult = params ? MEMMULT : COVER_MEMMULT;
Yann Collet086b9592017-09-14 16:45:10 -0700270 size_t const maxMem = DiB_findMaxMem(fs.totalSizeToLoad * memMult) / memMult;
271 size_t loadedSize = (size_t) MIN ((unsigned long long)maxMem, fs.totalSizeToLoad);
272 void* const srcBuffer = malloc(loadedSize+NOISELENGTH);
Yann Collet71eafdd2016-02-12 02:31:57 +0100273 int result = 0;
274
Yann Collet290aaa72016-05-30 21:18:52 +0200275 /* Checks */
Yann Collet086b9592017-09-14 16:45:10 -0700276 if ((!chunkSizes) || (!srcBuffer) || (!dictBuffer))
Yann Collet77c137b2017-09-14 15:12:57 -0700277 EXM_THROW(12, "not enough memory for DiB_trainFiles"); /* should not happen */
Yann Collet086b9592017-09-14 16:45:10 -0700278 if (fs.oneSampleTooLarge) {
279 DISPLAYLEVEL(2, "! Warning : some sample(s) are very large \n");
280 DISPLAYLEVEL(2, "! Note that dictionary is only useful for small samples. \n");
281 DISPLAYLEVEL(2, "! As a consequence, only the first %u bytes of each sample are loaded \n", SAMPLESIZE_MAX);
Yann Collet1496c3d2016-12-18 11:58:23 +0100282 }
Yann Collet086b9592017-09-14 16:45:10 -0700283 if (fs.nbChunks < 5) {
Yann Collet49d105c2016-08-18 15:02:11 +0200284 DISPLAYLEVEL(2, "! Warning : nb of samples too low for proper processing ! \n");
285 DISPLAYLEVEL(2, "! Please provide _one file per sample_. \n");
Yann Collet086b9592017-09-14 16:45:10 -0700286 EXM_THROW(14, "nb of samples too low"); /* we now clearly forbid this case */
287 }
288 if (fs.totalSizeToLoad < (unsigned long long)(8 * maxDictSize)) {
289 DISPLAYLEVEL(2, "! Warning : data size of samples too small for target dictionary size \n");
290 DISPLAYLEVEL(2, "! Samples should be about 100x larger than target dictionary size \n");
Yann Colletdd25a272016-07-27 12:35:29 +0200291 }
Yann Collet290aaa72016-05-30 21:18:52 +0200292
Yann Collet71eafdd2016-02-12 02:31:57 +0100293 /* init */
Yann Collet086b9592017-09-14 16:45:10 -0700294 if (loadedSize < fs.totalSizeToLoad)
295 DISPLAYLEVEL(1, "Not enough memory; training on %u MB only...\n", (unsigned)(loadedSize >> 20));
Yann Collet71eafdd2016-02-12 02:31:57 +0100296
Yann Collet71eafdd2016-02-12 02:31:57 +0100297 /* Load input buffer */
Nick Terrelldf8415c2016-12-31 21:08:24 -0800298 DISPLAYLEVEL(3, "Shuffling input files\n");
299 DiB_shuffle(fileNamesTable, nbFiles);
Yann Collet086b9592017-09-14 16:45:10 -0700300 nbFiles = DiB_loadFiles(srcBuffer, &loadedSize, chunkSizes, fileNamesTable, nbFiles, chunkSize, displayLevel);
Yann Collet71eafdd2016-02-12 02:31:57 +0100301
Yann Collet77c137b2017-09-14 15:12:57 -0700302 { size_t dictSize;
Nick Terrelldf8415c2016-12-31 21:08:24 -0800303 if (params) {
Yann Collet086b9592017-09-14 16:45:10 -0700304 DiB_fillNoise((char*)srcBuffer + loadedSize, NOISELENGTH); /* guard band, for end of buffer condition */
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700305 dictSize = ZDICT_trainFromBuffer_unsafe_legacy(dictBuffer, maxDictSize,
Yann Collet086b9592017-09-14 16:45:10 -0700306 srcBuffer, chunkSizes, fs.nbChunks,
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700307 *params);
Nick Terrelldf8415c2016-12-31 21:08:24 -0800308 } else if (optimizeCover) {
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700309 dictSize = ZDICT_optimizeTrainFromBuffer_cover(dictBuffer, maxDictSize,
Yann Collet086b9592017-09-14 16:45:10 -0700310 srcBuffer, chunkSizes, fs.nbChunks,
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700311 coverParams);
Nick Terrelldf8415c2016-12-31 21:08:24 -0800312 if (!ZDICT_isError(dictSize)) {
Nick Terrell5b7fd7c2017-06-26 21:07:14 -0700313 DISPLAYLEVEL(2, "k=%u\nd=%u\nsteps=%u\n", coverParams->k, coverParams->d, coverParams->steps);
Nick Terrelldf8415c2016-12-31 21:08:24 -0800314 }
315 } else {
Yann Collet77c137b2017-09-14 15:12:57 -0700316 dictSize = ZDICT_trainFromBuffer_cover(dictBuffer, maxDictSize, srcBuffer,
Yann Collet086b9592017-09-14 16:45:10 -0700317 chunkSizes, fs.nbChunks, *coverParams);
Nick Terrelldf8415c2016-12-31 21:08:24 -0800318 }
Yann Collet290aaa72016-05-30 21:18:52 +0200319 if (ZDICT_isError(dictSize)) {
320 DISPLAYLEVEL(1, "dictionary training failed : %s \n", ZDICT_getErrorName(dictSize)); /* should not happen */
321 result = 1;
322 goto _cleanup;
323 }
324 /* save dict */
325 DISPLAYLEVEL(2, "Save dictionary of size %u into file %s \n", (U32)dictSize, dictFileName);
326 DiB_saveDict(dictFileName, dictBuffer, dictSize);
Yann Collet71eafdd2016-02-12 02:31:57 +0100327 }
328
Yann Collet71eafdd2016-02-12 02:31:57 +0100329 /* clean up */
330_cleanup:
331 free(srcBuffer);
Yann Collet086b9592017-09-14 16:45:10 -0700332 free(chunkSizes);
Yann Collet71eafdd2016-02-12 02:31:57 +0100333 free(dictBuffer);
Yann Collet71eafdd2016-02-12 02:31:57 +0100334 return result;
335}