lz4-native-ruby 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CLAUDE.md +292 -0
  3. data/LICENSE +55 -21
  4. data/README.md +109 -15
  5. data/{vendor/lz4/lib → ext/lz4_native}/Makefile +29 -24
  6. data/{vendor/lz4/lib → ext/lz4_native}/README.md +1 -1
  7. data/ext/lz4_native/extconf.rb +33 -0
  8. data/{vendor/lz4/lib → ext/lz4_native}/liblz4.pc.in +1 -0
  9. data/{vendor/lz4/lib → ext/lz4_native}/lz4.c +26 -23
  10. data/{vendor/lz4/lib → ext/lz4_native}/lz4.h +11 -9
  11. data/ext/lz4_native/lz4_native.c +442 -0
  12. data/ext/lz4_native/lz4file.c +362 -0
  13. data/{vendor/lz4/lib → ext/lz4_native}/lz4file.h +32 -9
  14. data/{vendor/lz4/lib → ext/lz4_native}/lz4frame.c +50 -21
  15. data/{vendor/lz4/lib → ext/lz4_native}/lz4frame.h +48 -28
  16. data/{vendor/lz4/lib → ext/lz4_native}/lz4frame_static.h +1 -1
  17. data/{vendor/lz4/lib → ext/lz4_native}/lz4hc.c +123 -60
  18. data/{vendor/lz4/lib → ext/lz4_native}/lz4hc.h +1 -1
  19. data/lib/lz4_native/lz4_native.so +0 -0
  20. data/lib/lz4_native/version.rb +3 -0
  21. data/lib/lz4_native.rb +47 -0
  22. data/test/test_helper.rb +4 -0
  23. data/test/test_lz4_basic.rb +100 -0
  24. data/test/test_lz4frame.rb +129 -0
  25. data/test/test_lz4hc.rb +75 -0
  26. metadata +50 -43
  27. data/ext/lz4/extconf.rb +0 -12
  28. data/ext/lz4/lz4_ext.c +0 -230
  29. data/lib/lz4/lz4_ext.so +0 -0
  30. data/lib/lz4/version.rb +0 -3
  31. data/lib/lz4.rb +0 -60
  32. data/vendor/lz4/lib/lz4file.c +0 -341
  33. /data/{vendor/lz4/lib → ext/lz4_native}/LICENSE +0 -0
  34. /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/Makefile +0 -0
  35. /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/README.md +0 -0
  36. /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/fullbench-dll.sln +0 -0
  37. /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/fullbench-dll.vcxproj +0 -0
  38. /data/{vendor/lz4/lib → ext/lz4_native}/liblz4-dll.rc.in +0 -0
  39. /data/{vendor/lz4/lib → ext/lz4_native}/xxhash.c +0 -0
  40. /data/{vendor/lz4/lib → ext/lz4_native}/xxhash.h +0 -0
@@ -0,0 +1,362 @@
1
+ /*
2
+ * LZ4 file library
3
+ * Copyright (c) Yann Collet and LZ4 contributors. All rights reserved.
4
+ *
5
+ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are
9
+ * met:
10
+ *
11
+ * - Redistributions of source code must retain the above copyright
12
+ * notice, this list of conditions and the following disclaimer.
13
+ * - Redistributions in binary form must reproduce the above
14
+ * copyright notice, this list of conditions and the following disclaimer
15
+ * in the documentation and/or other materials provided with the
16
+ * distribution.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
+ * You can contact the author at :
31
+ * - LZ4 homepage : http://www.lz4.org
32
+ * - LZ4 source repository : https://github.com/lz4/lz4
33
+ */
34
+ #include <stdlib.h> /* malloc, free */
35
+ #include <string.h>
36
+ #include <assert.h>
37
+ #include "lz4.h"
38
+ #include "lz4file.h"
39
+
40
+ /* ===== Error Handling ===== */
41
+ static LZ4F_errorCode_t returnErrorCode(LZ4F_errorCodes code)
42
+ {
43
+ return (LZ4F_errorCode_t)-(ptrdiff_t)code;
44
+ }
45
+
46
+ #undef RETURN_ERROR
47
+ #define RETURN_ERROR(e) return returnErrorCode(LZ4F_ERROR_ ## e)
48
+
49
+ /* ===== Read API Implementation ===== */
50
+
51
+ struct LZ4_readFile_s {
52
+ LZ4F_dctx* dctxPtr;
53
+ FILE* fp;
54
+ LZ4_byte* srcBuf;
55
+ size_t srcBufNext;
56
+ size_t srcBufSize;
57
+ size_t srcBufMaxSize;
58
+ };
59
+
60
+ static void freeReadFileResources(LZ4_readFile_t* lz4fRead)
61
+ {
62
+ if (lz4fRead==NULL) return;
63
+ LZ4F_freeDecompressionContext(lz4fRead->dctxPtr);
64
+ free(lz4fRead->srcBuf);
65
+ free(lz4fRead);
66
+ }
67
+
68
+ static void freeAndNullReadFile(LZ4_readFile_t** statePtr)
69
+ {
70
+ assert(statePtr != NULL);
71
+ freeReadFileResources(*statePtr);
72
+ *statePtr = NULL;
73
+ }
74
+
75
+ static LZ4F_errorCode_t readAndParseHeader(LZ4_readFile_t* readFile, FILE* fp)
76
+ {
77
+ char headerBuf[LZ4F_HEADER_SIZE_MAX];
78
+ LZ4F_frameInfo_t frameInfo;
79
+ size_t consumedSize;
80
+
81
+ /* Read the header from file */
82
+ const size_t bytesRead = fread(headerBuf, 1, sizeof(headerBuf), fp);
83
+ if (bytesRead < LZ4F_HEADER_SIZE_MIN + LZ4F_ENDMARK_SIZE) {
84
+ RETURN_ERROR(io_read);
85
+ }
86
+
87
+ /* Parse frame information */
88
+ consumedSize = bytesRead;
89
+ { const LZ4F_errorCode_t result = LZ4F_getFrameInfo(readFile->dctxPtr, &frameInfo, headerBuf, &consumedSize);
90
+ if (LZ4F_isError(result)) {
91
+ return result;
92
+ } }
93
+
94
+ /* Determine buffer size based on block size */
95
+ { const size_t blockSize = LZ4F_getBlockSize(frameInfo.blockSizeID);
96
+ if (blockSize == 0) {
97
+ RETURN_ERROR(maxBlockSize_invalid);
98
+ }
99
+ readFile->srcBufMaxSize = blockSize;
100
+ }
101
+
102
+ /* Allocate source buffer */
103
+ assert(readFile->srcBuf == NULL); /* Should be NULL from calloc */
104
+ readFile->srcBuf = (LZ4_byte*)malloc(readFile->srcBufMaxSize);
105
+ if (readFile->srcBuf == NULL) {
106
+ RETURN_ERROR(allocation_failed);
107
+ }
108
+
109
+ /* Store remaining header data in buffer */
110
+ readFile->srcBufSize = bytesRead - consumedSize;
111
+ if (readFile->srcBufSize > 0) {
112
+ memcpy(readFile->srcBuf, headerBuf + consumedSize, readFile->srcBufSize);
113
+ }
114
+ readFile->srcBufNext = 0;
115
+
116
+ return LZ4F_OK_NoError;
117
+ }
118
+
119
+ LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp)
120
+ {
121
+ LZ4_readFile_t* readFile;
122
+
123
+ /* Validate parameters */
124
+ if (fp == NULL || lz4fRead == NULL) {
125
+ RETURN_ERROR(parameter_null);
126
+ }
127
+
128
+ /* Allocate read file structure */
129
+ readFile = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t));
130
+ if (readFile == NULL) {
131
+ RETURN_ERROR(allocation_failed);
132
+ }
133
+
134
+ readFile->fp = fp;
135
+
136
+ /* Initialize decompression context */
137
+ { LZ4F_errorCode_t const result = LZ4F_createDecompressionContext(&readFile->dctxPtr, LZ4F_VERSION);
138
+ if (LZ4F_isError(result)) {
139
+ freeAndNullReadFile(&readFile);
140
+ return result;
141
+ } }
142
+
143
+ /* Read and parse the header */
144
+ { LZ4F_errorCode_t const result = readAndParseHeader(readFile, fp);
145
+ if (LZ4F_isError(result)) {
146
+ freeAndNullReadFile(&readFile);
147
+ return result;
148
+ } }
149
+
150
+ *lz4fRead = readFile;
151
+ return LZ4F_OK_NoError;
152
+ }
153
+
154
+ size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size)
155
+ {
156
+ LZ4_byte* outPtr = (LZ4_byte*)buf;
157
+ size_t totalBytesRead = 0;
158
+
159
+ if (lz4fRead == NULL || buf == NULL)
160
+ RETURN_ERROR(parameter_null);
161
+
162
+ while (totalBytesRead < size) {
163
+ size_t srcBytes = lz4fRead->srcBufSize - lz4fRead->srcBufNext;
164
+ size_t dstBytes = size - totalBytesRead;
165
+
166
+ if (srcBytes == 0) {
167
+ size_t const bytesRead = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp);
168
+ if (bytesRead == 0) {
169
+ if (ferror(lz4fRead->fp)) {
170
+ RETURN_ERROR(io_read);
171
+ }
172
+ break; /* end of input reached */
173
+ }
174
+ /* success: ret > 0*/
175
+ lz4fRead->srcBufSize = bytesRead;
176
+ srcBytes = lz4fRead->srcBufSize;
177
+ lz4fRead->srcBufNext = 0;
178
+ }
179
+
180
+ { size_t const decStatus = LZ4F_decompress(
181
+ lz4fRead->dctxPtr,
182
+ outPtr, &dstBytes,
183
+ lz4fRead->srcBuf + lz4fRead->srcBufNext,
184
+ &srcBytes,
185
+ NULL);
186
+ if (LZ4F_isError(decStatus)) {
187
+ return decStatus;
188
+ } }
189
+
190
+ lz4fRead->srcBufNext += srcBytes;
191
+ totalBytesRead += dstBytes;
192
+ outPtr += dstBytes;
193
+ }
194
+
195
+ return totalBytesRead;
196
+ }
197
+
198
+ LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead)
199
+ {
200
+ if (lz4fRead == NULL)
201
+ RETURN_ERROR(parameter_null);
202
+ freeReadFileResources(lz4fRead);
203
+ return LZ4F_OK_NoError;
204
+ }
205
+
206
+ /* ===== write API ===== */
207
+
208
+ struct LZ4_writeFile_s {
209
+ LZ4F_cctx* cctxPtr;
210
+ FILE* fp;
211
+ LZ4_byte* dstBuf;
212
+ size_t maxWriteSize;
213
+ size_t dstBufMaxSize;
214
+ LZ4F_errorCode_t errCode;
215
+ };
216
+
217
+ static void freeWriteFileResources(LZ4_writeFile_t* state)
218
+ {
219
+ if (state == NULL) return;
220
+ LZ4F_freeCompressionContext(state->cctxPtr);
221
+ free(state->dstBuf);
222
+ free(state);
223
+ }
224
+
225
+ static void freeAndNullWriteFile(LZ4_writeFile_t** statePtr)
226
+ {
227
+ assert(statePtr != NULL);
228
+ freeWriteFileResources(*statePtr);
229
+ *statePtr = NULL;
230
+ }
231
+
232
+ static LZ4F_errorCode_t writeHeader(LZ4_writeFile_t* writeFile,
233
+ FILE* fp,
234
+ const LZ4F_preferences_t* prefsPtr)
235
+ {
236
+ LZ4_byte headerBuf[LZ4F_HEADER_SIZE_MAX];
237
+
238
+ /* Generate header */
239
+ LZ4F_errorCode_t const headerSize = LZ4F_compressBegin(writeFile->cctxPtr,
240
+ headerBuf, LZ4F_HEADER_SIZE_MAX, prefsPtr);
241
+ if (LZ4F_isError(headerSize)) {
242
+ return headerSize;
243
+ }
244
+
245
+ /* Write header to file */
246
+ if (headerSize != fwrite(headerBuf, 1, headerSize, fp)) {
247
+ RETURN_ERROR(io_write);
248
+ }
249
+
250
+ return LZ4F_OK_NoError;
251
+ }
252
+
253
+ LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr)
254
+ {
255
+ LZ4_writeFile_t* writeFile;
256
+ size_t blockSize;
257
+
258
+ if (fp == NULL || lz4fWrite == NULL)
259
+ RETURN_ERROR(parameter_null);
260
+
261
+ /* Validate block size */
262
+ { LZ4F_blockSizeID_t const blockSizeID = prefsPtr ? prefsPtr->frameInfo.blockSizeID : LZ4F_default;
263
+ blockSize = LZ4F_getBlockSize(blockSizeID);
264
+ if (blockSize == 0) {
265
+ RETURN_ERROR(maxBlockSize_invalid);
266
+ } }
267
+
268
+ /* Allocate write file structure */
269
+ writeFile = (LZ4_writeFile_t*)calloc(1, sizeof(LZ4_writeFile_t));
270
+ if (writeFile == NULL) {
271
+ RETURN_ERROR(allocation_failed);
272
+ }
273
+ writeFile->fp = fp;
274
+ writeFile->errCode = LZ4F_OK_NoError;
275
+ writeFile->maxWriteSize = blockSize;
276
+
277
+ /* Calculate and allocate destination buffer */
278
+ writeFile->dstBufMaxSize = LZ4F_compressBound(0, prefsPtr);
279
+ writeFile->dstBuf = (LZ4_byte*)malloc(writeFile->dstBufMaxSize);
280
+ if (writeFile->dstBuf == NULL) {
281
+ freeAndNullWriteFile(&writeFile);
282
+ RETURN_ERROR(allocation_failed);
283
+ }
284
+
285
+ /* Initialize compression context */
286
+ { LZ4F_errorCode_t const status = LZ4F_createCompressionContext(&writeFile->cctxPtr, LZ4F_VERSION);
287
+ if (LZ4F_isError(status)) {
288
+ freeAndNullWriteFile(lz4fWrite);
289
+ return status;
290
+ } }
291
+
292
+ /* Write header to file */
293
+ { LZ4F_errorCode_t const writeStatus = writeHeader(writeFile, fp, prefsPtr);
294
+ if (LZ4F_isError(writeStatus)) {
295
+ freeAndNullWriteFile(&writeFile);
296
+ return writeStatus;
297
+ } }
298
+
299
+ *lz4fWrite = writeFile;
300
+ return LZ4F_OK_NoError;
301
+ }
302
+
303
+ size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, const void* buf, size_t size)
304
+ {
305
+ const LZ4_byte* p = (const LZ4_byte*)buf;
306
+ size_t remainingBytes = size;
307
+
308
+ /* Validate parameters */
309
+ if (lz4fWrite == NULL || buf == NULL)
310
+ RETURN_ERROR(parameter_null);
311
+
312
+ while (remainingBytes) {
313
+ size_t const chunkSize = (remainingBytes > lz4fWrite->maxWriteSize) ? lz4fWrite->maxWriteSize : remainingBytes;
314
+
315
+ /* Compress and write chunk */
316
+ size_t cSize = LZ4F_compressUpdate(lz4fWrite->cctxPtr,
317
+ lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
318
+ p, chunkSize,
319
+ NULL);
320
+ if (LZ4F_isError(cSize)) {
321
+ lz4fWrite->errCode = cSize;
322
+ return cSize;
323
+ }
324
+
325
+ if (cSize != fwrite(lz4fWrite->dstBuf, 1, cSize, lz4fWrite->fp)) {
326
+ lz4fWrite->errCode = returnErrorCode(LZ4F_ERROR_io_write);
327
+ RETURN_ERROR(io_write);
328
+ }
329
+
330
+ /* Update positions */
331
+ p += chunkSize;
332
+ remainingBytes -= chunkSize;
333
+ }
334
+
335
+ return size;
336
+ }
337
+
338
+ LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite)
339
+ {
340
+ LZ4F_errorCode_t ret = LZ4F_OK_NoError;
341
+
342
+ if (lz4fWrite == NULL) {
343
+ RETURN_ERROR(parameter_null);
344
+ }
345
+
346
+ if (lz4fWrite->errCode == LZ4F_OK_NoError) {
347
+ ret = LZ4F_compressEnd(lz4fWrite->cctxPtr,
348
+ lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
349
+ NULL);
350
+ if (LZ4F_isError(ret)) {
351
+ goto cleanup;
352
+ }
353
+
354
+ if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
355
+ ret = returnErrorCode(LZ4F_ERROR_io_write);
356
+ }
357
+ }
358
+
359
+ cleanup:
360
+ freeWriteFileResources(lz4fWrite);
361
+ return ret;
362
+ }
@@ -1,7 +1,8 @@
1
1
  /*
2
2
  LZ4 file library
3
3
  Header File
4
- Copyright (C) 2022, Xiaomi Inc.
4
+ Copyright (c) Yann Collet and LZ4 contributors. All rights reserved.
5
+
5
6
  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7
 
7
8
  Redistribution and use in source and binary forms, with or without
@@ -44,10 +45,21 @@ extern "C" {
44
45
  typedef struct LZ4_readFile_s LZ4_readFile_t;
45
46
  typedef struct LZ4_writeFile_s LZ4_writeFile_t;
46
47
 
47
- /*! LZ4F_readOpen() :
48
- * Set read lz4file handle.
49
- * `lz4f` will set a lz4file handle.
50
- * `fp` must be the return value of the lz4 file opened by fopen.
48
+ /** LZ4 File Decompression **/
49
+
50
+ /**
51
+ * Opens an LZ4 file for reading.
52
+ * Note that the FILE* handle @p fp must be opened in binary mode.
53
+ *
54
+ * @param lz4fRead Pointer to receive the read file handle.
55
+ * It is an OUT parameter, so its initial value is ignored and will be overwritten.
56
+ * Its value on exit is only valid if the function returns LZ4F_OK_NoError.
57
+ * @param fp FILE* positioned at start of LZ4 file (binary mode).
58
+ *
59
+ * @return LZ4F_OK_NoError on success, or error code on failure.
60
+ * Can be tested with LZ4F_isError().
61
+ *
62
+ * @note Must be closed with LZ4F_readClose() when done.
51
63
  */
52
64
  LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp);
53
65
 
@@ -65,10 +77,21 @@ LZ4FLIB_STATIC_API size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t
65
77
  */
66
78
  LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead);
67
79
 
68
- /*! LZ4F_writeOpen() :
69
- * Set write lz4file handle.
70
- * `lz4f` will set a lz4file handle.
71
- * `fp` must be the return value of the lz4 file opened by fopen.
80
+ /** LZ4 File Decompression **/
81
+
82
+ /**
83
+ * Opens an LZ4 file for writing.
84
+ * Note that the FILE* handle @p fp must be opened in write binary mode.
85
+ *
86
+ * @param lz4fWrite Pointer to receive the write file handle.
87
+ * It is an OUT parameter, so its initial value is ignored and will be overwritten.
88
+ * Its value on exit is only valid if the function returns LZ4F_OK_NoError.
89
+ * @param fp FILE* positioned at start of LZ4 file (binary mode).
90
+ *
91
+ * @return LZ4F_OK_NoError on success, or error code on failure.
92
+ * Can be tested with LZ4F_isError().
93
+ *
94
+ * @note Must be closed with LZ4F_writeClose() when done.
72
95
  */
73
96
  LZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr);
74
97
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * LZ4 auto-framing library
3
- * Copyright (C) 2011-2016, Yann Collet.
3
+ * Copyright (c) Yann Collet. All rights reserved.
4
4
  *
5
5
  * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
6
  *
@@ -155,7 +155,7 @@ static void LZ4F_free(void* p, LZ4F_CustomMem cmem)
155
155
  static int g_debuglog_enable = 1;
156
156
  # define DEBUGLOG(l, ...) { \
157
157
  if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \
158
- fprintf(stderr, __FILE__ " (%i): ", __LINE__ ); \
158
+ fprintf(stderr, __FILE__ " %i: ", __LINE__ ); \
159
159
  fprintf(stderr, __VA_ARGS__); \
160
160
  fprintf(stderr, " \n"); \
161
161
  } }
@@ -539,9 +539,16 @@ LZ4F_CDict*
539
539
  LZ4F_createCDict_advanced(LZ4F_CustomMem cmem, const void* dictBuffer, size_t dictSize)
540
540
  {
541
541
  const char* dictStart = (const char*)dictBuffer;
542
- LZ4F_CDict* const cdict = (LZ4F_CDict*)LZ4F_malloc(sizeof(*cdict), cmem);
542
+ LZ4F_CDict* cdict = NULL;
543
+
543
544
  DEBUGLOG(4, "LZ4F_createCDict_advanced");
544
- if (!cdict) return NULL;
545
+
546
+ if (!dictStart)
547
+ return NULL;
548
+ cdict = (LZ4F_CDict*)LZ4F_malloc(sizeof(*cdict), cmem);
549
+ if (!cdict)
550
+ return NULL;
551
+
545
552
  cdict->cmem = cmem;
546
553
  if (dictSize > 64 KB) {
547
554
  dictStart += dictSize - 64 KB;
@@ -684,6 +691,13 @@ static int ctxTypeID_to_size(int ctxTypeID) {
684
691
  }
685
692
  }
686
693
 
694
+ size_t LZ4F_cctx_size(const LZ4F_cctx* cctx) {
695
+ if (cctx == NULL) {
696
+ return 0;
697
+ }
698
+ return sizeof(*cctx) + cctx->maxBufferSize + ctxTypeID_to_size(cctx->lz4CtxAlloc);
699
+ }
700
+
687
701
  /* LZ4F_compressBegin_internal()
688
702
  * Note: only accepts @cdict _or_ @dictBuffer as non NULL.
689
703
  */
@@ -700,6 +714,7 @@ size_t LZ4F_compressBegin_internal(LZ4F_cctx* cctx,
700
714
  RETURN_ERROR_IF(dstCapacity < maxFHSize, dstMaxSize_tooSmall);
701
715
  if (preferencesPtr == NULL) preferencesPtr = &prefNull;
702
716
  cctx->prefs = *preferencesPtr;
717
+ DEBUGLOG(5, "LZ4F_compressBegin_internal: Independent_blocks=%u", cctx->prefs.frameInfo.blockMode);
703
718
 
704
719
  /* cctx Management */
705
720
  { U16 const ctxTypeID = (cctx->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;
@@ -887,10 +902,11 @@ static size_t LZ4F_makeBlock(void* dst,
887
902
  LZ4F_blockChecksum_t crcFlag)
888
903
  {
889
904
  BYTE* const cSizePtr = (BYTE*)dst;
905
+ int dstCapacity = (srcSize > 1) ? (int)srcSize - 1 : 1;
890
906
  U32 cSize;
891
907
  assert(compress != NULL);
892
908
  cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize),
893
- (int)(srcSize), (int)(srcSize-1),
909
+ (int)srcSize, dstCapacity,
894
910
  level, cdict);
895
911
 
896
912
  if (cSize == 0 || cSize >= srcSize) {
@@ -961,12 +977,13 @@ static compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int lev
961
977
  return LZ4F_compressBlockHC_continue;
962
978
  }
963
979
 
964
- /* Save history (up to 64KB) into @tmpBuff */
965
- static int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr)
980
+ /* Save or shorten history (up to 64KB) into @tmpBuff */
981
+ static void LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr)
966
982
  {
967
- if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)
968
- return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
969
- return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
983
+ int const dictSize = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ?
984
+ LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB) :
985
+ LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);
986
+ cctxPtr->tmpIn = cctxPtr->tmpBuff + dictSize;
970
987
  }
971
988
 
972
989
  typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus;
@@ -974,7 +991,7 @@ typedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus;
974
991
  static const LZ4F_compressOptions_t k_cOptionsNull = { 0, { 0, 0, 0 } };
975
992
 
976
993
 
977
- /*! LZ4F_compressUpdateImpl() :
994
+ /*! LZ4F_compressUpdateImpl() :
978
995
  * LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
979
996
  * When successful, the function always entirely consumes @srcBuffer.
980
997
  * src data is either buffered or compressed into @dstBuffer.
@@ -994,7 +1011,7 @@ static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr,
994
1011
  {
995
1012
  size_t const blockSize = cctxPtr->maxBlockSize;
996
1013
  const BYTE* srcPtr = (const BYTE*)srcBuffer;
997
- const BYTE* const srcEnd = srcPtr + srcSize;
1014
+ const BYTE* const srcEnd = srcSize ? (assert(srcPtr!=NULL), srcPtr + srcSize) : srcPtr;
998
1015
  BYTE* const dstStart = (BYTE*)dstBuffer;
999
1016
  BYTE* dstPtr = dstStart;
1000
1017
  LZ4F_lastBlockStatus lastBlockCompressed = notDone;
@@ -1072,9 +1089,7 @@ static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr,
1072
1089
  if (compressOptionsPtr->stableSrc) {
1073
1090
  cctxPtr->tmpIn = cctxPtr->tmpBuff; /* src is stable : dictionary remains in src across invocations */
1074
1091
  } else {
1075
- int const realDictSize = LZ4F_localSaveDict(cctxPtr);
1076
- assert(0 <= realDictSize && realDictSize <= 64 KB);
1077
- cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
1092
+ LZ4F_localSaveDict(cctxPtr);
1078
1093
  }
1079
1094
  }
1080
1095
 
@@ -1084,8 +1099,7 @@ static size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr,
1084
1099
  {
1085
1100
  /* only preserve 64KB within internal buffer. Ensures there is enough room for next block.
1086
1101
  * note: this situation necessarily implies lastBlockCompressed==fromTmpBuffer */
1087
- int const realDictSize = LZ4F_localSaveDict(cctxPtr);
1088
- cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
1102
+ LZ4F_localSaveDict(cctxPtr);
1089
1103
  assert((cctxPtr->tmpIn + blockSize) <= (cctxPtr->tmpBuff + cctxPtr->maxBufferSize));
1090
1104
  }
1091
1105
 
@@ -1150,7 +1164,7 @@ size_t LZ4F_uncompressedUpdate(LZ4F_cctx* cctxPtr,
1150
1164
 
1151
1165
  /*! LZ4F_flush() :
1152
1166
  * When compressed data must be sent immediately, without waiting for a block to be filled,
1153
- * invoke LZ4_flush(), which will immediately compress any remaining data stored within LZ4F_cctx.
1167
+ * invoke LZ4F_flush(), which will immediately compress any remaining data stored within LZ4F_cctx.
1154
1168
  * The result of the function is the number of bytes written into dstBuffer.
1155
1169
  * It can be zero, this means there was no data left within LZ4F_cctx.
1156
1170
  * The function outputs an error code if it fails (can be tested using LZ4F_isError())
@@ -1164,6 +1178,8 @@ size_t LZ4F_flush(LZ4F_cctx* cctxPtr,
1164
1178
  BYTE* dstPtr = dstStart;
1165
1179
  compressFunc_t compress;
1166
1180
 
1181
+ DEBUGLOG(5, "LZ4F_flush: %zu buffered bytes (saved dict size = %i) (dstCapacity=%u)",
1182
+ cctxPtr->tmpInSize, (int)(cctxPtr->tmpIn - cctxPtr->tmpBuff), (unsigned)dstCapacity);
1167
1183
  if (cctxPtr->tmpInSize == 0) return 0; /* nothing to flush */
1168
1184
  RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized);
1169
1185
  RETURN_ERROR_IF(dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize), dstMaxSize_tooSmall);
@@ -1185,9 +1201,9 @@ size_t LZ4F_flush(LZ4F_cctx* cctxPtr,
1185
1201
  cctxPtr->tmpInSize = 0;
1186
1202
 
1187
1203
  /* keep tmpIn within limits */
1188
- if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) { /* necessarily LZ4F_blockLinked */
1189
- int const realDictSize = LZ4F_localSaveDict(cctxPtr);
1190
- cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;
1204
+ if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) {
1205
+ assert(cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked);
1206
+ LZ4F_localSaveDict(cctxPtr);
1191
1207
  }
1192
1208
 
1193
1209
  return (size_t)(dstPtr - dstStart);
@@ -1322,6 +1338,15 @@ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx)
1322
1338
  return result;
1323
1339
  }
1324
1340
 
1341
+ size_t LZ4F_dctx_size(const LZ4F_dctx* dctx) {
1342
+ if (dctx == NULL) {
1343
+ return 0;
1344
+ }
1345
+ return sizeof(*dctx)
1346
+ + (dctx->tmpIn != NULL ? dctx->maxBlockSize + BFSize : 0)
1347
+ + (dctx->tmpOutBuffer != NULL ? dctx->maxBufferSize : 0);
1348
+ }
1349
+
1325
1350
 
1326
1351
  /*==--- Streaming Decompression operations ---==*/
1327
1352
  void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)
@@ -1486,6 +1511,10 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,
1486
1511
  LZ4F_frameInfo_t* frameInfoPtr,
1487
1512
  const void* srcBuffer, size_t* srcSizePtr)
1488
1513
  {
1514
+ assert(dctx != NULL);
1515
+ RETURN_ERROR_IF(frameInfoPtr == NULL, parameter_null);
1516
+ RETURN_ERROR_IF(srcSizePtr == NULL, parameter_null);
1517
+
1489
1518
  LZ4F_STATIC_ASSERT(dstage_getFrameHeader < dstage_storeFrameHeader);
1490
1519
  if (dctx->dStage > dstage_storeFrameHeader) {
1491
1520
  /* frameInfo already decoded */