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.
- checksums.yaml +4 -4
- data/CLAUDE.md +292 -0
- data/LICENSE +55 -21
- data/README.md +109 -15
- data/{vendor/lz4/lib → ext/lz4_native}/Makefile +29 -24
- data/{vendor/lz4/lib → ext/lz4_native}/README.md +1 -1
- data/ext/lz4_native/extconf.rb +33 -0
- data/{vendor/lz4/lib → ext/lz4_native}/liblz4.pc.in +1 -0
- data/{vendor/lz4/lib → ext/lz4_native}/lz4.c +26 -23
- data/{vendor/lz4/lib → ext/lz4_native}/lz4.h +11 -9
- data/ext/lz4_native/lz4_native.c +442 -0
- data/ext/lz4_native/lz4file.c +362 -0
- data/{vendor/lz4/lib → ext/lz4_native}/lz4file.h +32 -9
- data/{vendor/lz4/lib → ext/lz4_native}/lz4frame.c +50 -21
- data/{vendor/lz4/lib → ext/lz4_native}/lz4frame.h +48 -28
- data/{vendor/lz4/lib → ext/lz4_native}/lz4frame_static.h +1 -1
- data/{vendor/lz4/lib → ext/lz4_native}/lz4hc.c +123 -60
- data/{vendor/lz4/lib → ext/lz4_native}/lz4hc.h +1 -1
- data/lib/lz4_native/lz4_native.so +0 -0
- data/lib/lz4_native/version.rb +3 -0
- data/lib/lz4_native.rb +47 -0
- data/test/test_helper.rb +4 -0
- data/test/test_lz4_basic.rb +100 -0
- data/test/test_lz4frame.rb +129 -0
- data/test/test_lz4hc.rb +75 -0
- metadata +50 -43
- data/ext/lz4/extconf.rb +0 -12
- data/ext/lz4/lz4_ext.c +0 -230
- data/lib/lz4/lz4_ext.so +0 -0
- data/lib/lz4/version.rb +0 -3
- data/lib/lz4.rb +0 -60
- data/vendor/lz4/lib/lz4file.c +0 -341
- /data/{vendor/lz4/lib → ext/lz4_native}/LICENSE +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/Makefile +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/README.md +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/fullbench-dll.sln +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/fullbench-dll.vcxproj +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/liblz4-dll.rc.in +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/xxhash.c +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/xxhash.h +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
LZ4 - Fast LZ compression algorithm
|
|
3
|
-
Copyright (
|
|
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
|
|
|
@@ -77,7 +77,8 @@
|
|
|
77
77
|
#ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */
|
|
78
78
|
# if defined(__GNUC__) && \
|
|
79
79
|
( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \
|
|
80
|
-
|| defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
|
|
80
|
+
|| defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
|
|
81
|
+
|| (defined(__riscv) && defined(__riscv_zicclsm)) )
|
|
81
82
|
# define LZ4_FORCE_MEMORY_ACCESS 2
|
|
82
83
|
# elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__) || defined(_MSC_VER)
|
|
83
84
|
# define LZ4_FORCE_MEMORY_ACCESS 1
|
|
@@ -301,12 +302,12 @@ static int LZ4_isAligned(const void* ptr, size_t alignment)
|
|
|
301
302
|
#include <limits.h>
|
|
302
303
|
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
|
303
304
|
# include <stdint.h>
|
|
304
|
-
typedef
|
|
305
|
-
typedef uint16_t
|
|
306
|
-
typedef uint32_t
|
|
307
|
-
typedef int32_t
|
|
308
|
-
typedef uint64_t
|
|
309
|
-
typedef uintptr_t
|
|
305
|
+
typedef unsigned char BYTE; /*uint8_t not necessarily blessed to alias arbitrary type*/
|
|
306
|
+
typedef uint16_t U16;
|
|
307
|
+
typedef uint32_t U32;
|
|
308
|
+
typedef int32_t S32;
|
|
309
|
+
typedef uint64_t U64;
|
|
310
|
+
typedef uintptr_t uptrval;
|
|
310
311
|
#else
|
|
311
312
|
# if UINT_MAX != 4294967295UL
|
|
312
313
|
# error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4"
|
|
@@ -478,13 +479,15 @@ static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
|
|
|
478
479
|
#ifndef LZ4_FAST_DEC_LOOP
|
|
479
480
|
# if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64
|
|
480
481
|
# define LZ4_FAST_DEC_LOOP 1
|
|
481
|
-
# elif defined(__aarch64__)
|
|
482
|
-
#
|
|
483
|
-
|
|
484
|
-
/* On non-Apple aarch64, we disable this optimization for clang because
|
|
482
|
+
# elif defined(__aarch64__)
|
|
483
|
+
# if defined(__clang__) && defined(__ANDROID__)
|
|
484
|
+
/* On Android aarch64, we disable this optimization for clang because
|
|
485
485
|
* on certain mobile chipsets, performance is reduced with clang. For
|
|
486
486
|
* more information refer to https://github.com/lz4/lz4/pull/707 */
|
|
487
|
-
#
|
|
487
|
+
# define LZ4_FAST_DEC_LOOP 0
|
|
488
|
+
# else
|
|
489
|
+
# define LZ4_FAST_DEC_LOOP 1
|
|
490
|
+
# endif
|
|
488
491
|
# else
|
|
489
492
|
# define LZ4_FAST_DEC_LOOP 0
|
|
490
493
|
# endif
|
|
@@ -896,7 +899,7 @@ LZ4_prepareTable(LZ4_stream_t_internal* const cctx,
|
|
|
896
899
|
|| tableType == byPtr
|
|
897
900
|
|| inputSize >= 4 KB)
|
|
898
901
|
{
|
|
899
|
-
DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx);
|
|
902
|
+
DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", (void*)cctx);
|
|
900
903
|
MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);
|
|
901
904
|
cctx->currentOffset = 0;
|
|
902
905
|
cctx->tableType = (U32)clearedTable;
|
|
@@ -1532,7 +1535,7 @@ LZ4_stream_t* LZ4_createStream(void)
|
|
|
1532
1535
|
{
|
|
1533
1536
|
LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));
|
|
1534
1537
|
LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal));
|
|
1535
|
-
DEBUGLOG(4, "LZ4_createStream %p", lz4s);
|
|
1538
|
+
DEBUGLOG(4, "LZ4_createStream %p", (void*)lz4s);
|
|
1536
1539
|
if (lz4s == NULL) return NULL;
|
|
1537
1540
|
LZ4_initStream(lz4s, sizeof(*lz4s));
|
|
1538
1541
|
return lz4s;
|
|
@@ -1563,7 +1566,7 @@ LZ4_stream_t* LZ4_initStream (void* buffer, size_t size)
|
|
|
1563
1566
|
* prefer initStream() which is more general */
|
|
1564
1567
|
void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
|
|
1565
1568
|
{
|
|
1566
|
-
DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream);
|
|
1569
|
+
DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", (void*)LZ4_stream);
|
|
1567
1570
|
MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal));
|
|
1568
1571
|
}
|
|
1569
1572
|
|
|
@@ -1575,7 +1578,7 @@ void LZ4_resetStream_fast(LZ4_stream_t* ctx) {
|
|
|
1575
1578
|
int LZ4_freeStream (LZ4_stream_t* LZ4_stream)
|
|
1576
1579
|
{
|
|
1577
1580
|
if (!LZ4_stream) return 0; /* support free on NULL */
|
|
1578
|
-
DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream);
|
|
1581
|
+
DEBUGLOG(5, "LZ4_freeStream %p", (void*)LZ4_stream);
|
|
1579
1582
|
FREEMEM(LZ4_stream);
|
|
1580
1583
|
return (0);
|
|
1581
1584
|
}
|
|
@@ -1594,7 +1597,7 @@ int LZ4_loadDict_internal(LZ4_stream_t* LZ4_dict,
|
|
|
1594
1597
|
const BYTE* const dictEnd = p + dictSize;
|
|
1595
1598
|
U32 idx32;
|
|
1596
1599
|
|
|
1597
|
-
DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict);
|
|
1600
|
+
DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, (void*)dictionary, (void*)LZ4_dict);
|
|
1598
1601
|
|
|
1599
1602
|
/* It's necessary to reset the context,
|
|
1600
1603
|
* and not just continue it with prepareTable()
|
|
@@ -1661,7 +1664,7 @@ void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dict
|
|
|
1661
1664
|
&(dictionaryStream->internal_donotuse);
|
|
1662
1665
|
|
|
1663
1666
|
DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)",
|
|
1664
|
-
workingStream, dictionaryStream,
|
|
1667
|
+
(void*)workingStream, (void*)dictionaryStream,
|
|
1665
1668
|
dictCtx != NULL ? dictCtx->dictSize : 0);
|
|
1666
1669
|
|
|
1667
1670
|
if (dictCtx != NULL) {
|
|
@@ -1725,7 +1728,7 @@ int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,
|
|
|
1725
1728
|
&& (inputSize > 0) /* tolerance : don't lose history, in case next invocation would use prefix mode */
|
|
1726
1729
|
&& (streamPtr->dictCtx == NULL) /* usingDictCtx */
|
|
1727
1730
|
) {
|
|
1728
|
-
DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary);
|
|
1731
|
+
DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, (void*)streamPtr->dictionary);
|
|
1729
1732
|
/* remove dictionary existence from history, to employ faster prefix mode */
|
|
1730
1733
|
streamPtr->dictSize = 0;
|
|
1731
1734
|
streamPtr->dictionary = (const BYTE*)source;
|
|
@@ -1815,7 +1818,7 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)
|
|
|
1815
1818
|
{
|
|
1816
1819
|
LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;
|
|
1817
1820
|
|
|
1818
|
-
DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, safeBuffer);
|
|
1821
|
+
DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, (void*)safeBuffer);
|
|
1819
1822
|
|
|
1820
1823
|
if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */
|
|
1821
1824
|
if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; }
|
|
@@ -2311,8 +2314,8 @@ LZ4_decompress_generic(
|
|
|
2311
2314
|
*/
|
|
2312
2315
|
if ((ip+length != iend) || (cpy > oend)) {
|
|
2313
2316
|
DEBUGLOG(5, "should have been last run of literals")
|
|
2314
|
-
DEBUGLOG(5, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend);
|
|
2315
|
-
DEBUGLOG(5, "or cpy(%p) > (oend-MFLIMIT)(%p)", cpy, oend-MFLIMIT);
|
|
2317
|
+
DEBUGLOG(5, "ip(%p) + length(%i) = %p != iend (%p)", (void*)ip, (int)length, (void*)(ip+length), (void*)iend);
|
|
2318
|
+
DEBUGLOG(5, "or cpy(%p) > (oend-MFLIMIT)(%p)", (void*)cpy, (void*)(oend-MFLIMIT));
|
|
2316
2319
|
DEBUGLOG(5, "after writing %u bytes / %i bytes available", (unsigned)(op-(BYTE*)dst), outputSize);
|
|
2317
2320
|
goto _output_error;
|
|
2318
2321
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* LZ4 - Fast LZ compression algorithm
|
|
3
3
|
* Header File
|
|
4
|
-
* Copyright (
|
|
4
|
+
* Copyright (c) Yann Collet. All rights reserved.
|
|
5
5
|
|
|
6
6
|
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
|
7
7
|
|
|
@@ -258,10 +258,12 @@ LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* d
|
|
|
258
258
|
* @return : Nb bytes written into 'dst' (necessarily <= dstCapacity)
|
|
259
259
|
* or 0 if compression fails.
|
|
260
260
|
*
|
|
261
|
-
* Note :
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
261
|
+
* Note : 'targetDstSize' must be >= 1, because it's the smallest valid lz4 payload.
|
|
262
|
+
*
|
|
263
|
+
* Note 2:from v1.8.2 to v1.9.1, this function had a bug (fixed in v1.9.2+):
|
|
264
|
+
* the produced compressed content could, in rare circumstances,
|
|
265
|
+
* require to be decompressed into a destination buffer
|
|
266
|
+
* larger by at least 1 byte than decompressesSize.
|
|
265
267
|
* If an application uses `LZ4_compress_destSize()`,
|
|
266
268
|
* it's highly recommended to update liblz4 to v1.9.2 or better.
|
|
267
269
|
* If this can't be done or ensured,
|
|
@@ -698,10 +700,10 @@ int LZ4_compress_destSize_extState(void* state, const char* src, char* dst, int*
|
|
|
698
700
|
|
|
699
701
|
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
|
700
702
|
# include <stdint.h>
|
|
701
|
-
typedef
|
|
702
|
-
typedef
|
|
703
|
-
typedef uint16_t
|
|
704
|
-
typedef uint32_t
|
|
703
|
+
typedef int8_t LZ4_i8;
|
|
704
|
+
typedef unsigned char LZ4_byte;
|
|
705
|
+
typedef uint16_t LZ4_u16;
|
|
706
|
+
typedef uint32_t LZ4_u32;
|
|
705
707
|
#else
|
|
706
708
|
typedef signed char LZ4_i8;
|
|
707
709
|
typedef unsigned char LZ4_byte;
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* LZ4 Native Ruby Extension
|
|
3
|
+
* Provides complete bindings for lz4.h, lz4hc.h, and lz4frame.h
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "ruby.h"
|
|
7
|
+
#include "lz4.h"
|
|
8
|
+
#include "lz4hc.h"
|
|
9
|
+
#include "lz4frame.h"
|
|
10
|
+
#include <string.h>
|
|
11
|
+
|
|
12
|
+
/* Module and class definitions */
|
|
13
|
+
static VALUE mLZ4Native;
|
|
14
|
+
static VALUE mLZ4;
|
|
15
|
+
static VALUE mLZ4HC;
|
|
16
|
+
static VALUE mLZ4Frame;
|
|
17
|
+
static VALUE eLZ4Error;
|
|
18
|
+
static VALUE eLZ4CompressionError;
|
|
19
|
+
static VALUE eLZ4DecompressionError;
|
|
20
|
+
static VALUE eLZ4FrameError;
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* ============================================================================
|
|
24
|
+
* LZ4 Basic Functions (lz4.h)
|
|
25
|
+
* ============================================================================
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* call-seq:
|
|
30
|
+
* LZ4.compress_default(source) -> compressed_string
|
|
31
|
+
*
|
|
32
|
+
* Compresses source data using default LZ4 compression.
|
|
33
|
+
* Returns compressed data as a binary string.
|
|
34
|
+
*/
|
|
35
|
+
static VALUE
|
|
36
|
+
lz4_compress_default_wrapper(VALUE self, VALUE source)
|
|
37
|
+
{
|
|
38
|
+
Check_Type(source, T_STRING);
|
|
39
|
+
|
|
40
|
+
const char* src = RSTRING_PTR(source);
|
|
41
|
+
int src_size = (int)RSTRING_LEN(source);
|
|
42
|
+
|
|
43
|
+
if (src_size > LZ4_MAX_INPUT_SIZE) {
|
|
44
|
+
rb_raise(eLZ4CompressionError, "Input size exceeds LZ4_MAX_INPUT_SIZE");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
int max_dst_size = LZ4_compressBound(src_size);
|
|
48
|
+
if (max_dst_size == 0) {
|
|
49
|
+
rb_raise(eLZ4CompressionError, "Invalid input size");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
VALUE result = rb_str_buf_new(max_dst_size);
|
|
53
|
+
char* dst = RSTRING_PTR(result);
|
|
54
|
+
|
|
55
|
+
int compressed_size = LZ4_compress_default(src, dst, src_size, max_dst_size);
|
|
56
|
+
|
|
57
|
+
if (compressed_size <= 0) {
|
|
58
|
+
rb_raise(eLZ4CompressionError, "Compression failed");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
rb_str_set_len(result, compressed_size);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
* call-seq:
|
|
67
|
+
* LZ4.decompress_safe(source, max_size) -> decompressed_string
|
|
68
|
+
*
|
|
69
|
+
* Decompresses LZ4 compressed data safely.
|
|
70
|
+
* max_size must be >= actual decompressed size.
|
|
71
|
+
*/
|
|
72
|
+
static VALUE
|
|
73
|
+
lz4_decompress_safe_wrapper(VALUE self, VALUE source, VALUE max_size)
|
|
74
|
+
{
|
|
75
|
+
Check_Type(source, T_STRING);
|
|
76
|
+
Check_Type(max_size, T_FIXNUM);
|
|
77
|
+
|
|
78
|
+
const char* src = RSTRING_PTR(source);
|
|
79
|
+
int src_size = (int)RSTRING_LEN(source);
|
|
80
|
+
int dst_capacity = NUM2INT(max_size);
|
|
81
|
+
|
|
82
|
+
if (dst_capacity <= 0) {
|
|
83
|
+
rb_raise(eLZ4DecompressionError, "Invalid max_size");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
VALUE result = rb_str_buf_new(dst_capacity);
|
|
87
|
+
char* dst = RSTRING_PTR(result);
|
|
88
|
+
|
|
89
|
+
int decompressed_size = LZ4_decompress_safe(src, dst, src_size, dst_capacity);
|
|
90
|
+
|
|
91
|
+
if (decompressed_size < 0) {
|
|
92
|
+
rb_raise(eLZ4DecompressionError, "Decompression failed - possibly corrupt data");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
rb_str_set_len(result, decompressed_size);
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/*
|
|
100
|
+
* call-seq:
|
|
101
|
+
* LZ4.compress_bound(input_size) -> max_compressed_size
|
|
102
|
+
*
|
|
103
|
+
* Returns maximum compressed size for given input size.
|
|
104
|
+
*/
|
|
105
|
+
static VALUE
|
|
106
|
+
lz4_compress_bound_wrapper(VALUE self, VALUE input_size)
|
|
107
|
+
{
|
|
108
|
+
Check_Type(input_size, T_FIXNUM);
|
|
109
|
+
int size = NUM2INT(input_size);
|
|
110
|
+
int bound = LZ4_compressBound(size);
|
|
111
|
+
return INT2NUM(bound);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* call-seq:
|
|
116
|
+
* LZ4.compress_fast(source, acceleration) -> compressed_string
|
|
117
|
+
*
|
|
118
|
+
* Compresses with acceleration factor (higher = faster, less compression).
|
|
119
|
+
*/
|
|
120
|
+
static VALUE
|
|
121
|
+
lz4_compress_fast_wrapper(VALUE self, VALUE source, VALUE acceleration)
|
|
122
|
+
{
|
|
123
|
+
Check_Type(source, T_STRING);
|
|
124
|
+
Check_Type(acceleration, T_FIXNUM);
|
|
125
|
+
|
|
126
|
+
const char* src = RSTRING_PTR(source);
|
|
127
|
+
int src_size = (int)RSTRING_LEN(source);
|
|
128
|
+
int accel = NUM2INT(acceleration);
|
|
129
|
+
|
|
130
|
+
int max_dst_size = LZ4_compressBound(src_size);
|
|
131
|
+
VALUE result = rb_str_buf_new(max_dst_size);
|
|
132
|
+
char* dst = RSTRING_PTR(result);
|
|
133
|
+
|
|
134
|
+
int compressed_size = LZ4_compress_fast(src, dst, src_size, max_dst_size, accel);
|
|
135
|
+
|
|
136
|
+
if (compressed_size <= 0) {
|
|
137
|
+
rb_raise(eLZ4CompressionError, "Compression failed");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
rb_str_set_len(result, compressed_size);
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/*
|
|
145
|
+
* call-seq:
|
|
146
|
+
* LZ4.version_number -> integer
|
|
147
|
+
*
|
|
148
|
+
* Returns the LZ4 library version number.
|
|
149
|
+
*/
|
|
150
|
+
static VALUE
|
|
151
|
+
lz4_version_number_wrapper(VALUE self)
|
|
152
|
+
{
|
|
153
|
+
return INT2NUM(LZ4_versionNumber());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/*
|
|
157
|
+
* call-seq:
|
|
158
|
+
* LZ4.version_string -> string
|
|
159
|
+
*
|
|
160
|
+
* Returns the LZ4 library version string.
|
|
161
|
+
*/
|
|
162
|
+
static VALUE
|
|
163
|
+
lz4_version_string_wrapper(VALUE self)
|
|
164
|
+
{
|
|
165
|
+
return rb_str_new_cstr(LZ4_versionString());
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/*
|
|
169
|
+
* ============================================================================
|
|
170
|
+
* LZ4 HC Functions (lz4hc.h)
|
|
171
|
+
* ============================================================================
|
|
172
|
+
*/
|
|
173
|
+
|
|
174
|
+
/*
|
|
175
|
+
* call-seq:
|
|
176
|
+
* LZ4HC.compress(source, compression_level = 9) -> compressed_string
|
|
177
|
+
*
|
|
178
|
+
* Compresses using high-compression mode.
|
|
179
|
+
* compression_level: 1-12 (default 9), higher = better compression, slower.
|
|
180
|
+
*/
|
|
181
|
+
static VALUE
|
|
182
|
+
lz4hc_compress_wrapper(int argc, VALUE *argv, VALUE self)
|
|
183
|
+
{
|
|
184
|
+
VALUE source, level;
|
|
185
|
+
rb_scan_args(argc, argv, "11", &source, &level);
|
|
186
|
+
|
|
187
|
+
Check_Type(source, T_STRING);
|
|
188
|
+
int compression_level = NIL_P(level) ? LZ4HC_CLEVEL_DEFAULT : NUM2INT(level);
|
|
189
|
+
|
|
190
|
+
if (compression_level < LZ4HC_CLEVEL_MIN) {
|
|
191
|
+
compression_level = LZ4HC_CLEVEL_MIN;
|
|
192
|
+
} else if (compression_level > LZ4HC_CLEVEL_MAX) {
|
|
193
|
+
compression_level = LZ4HC_CLEVEL_MAX;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const char* src = RSTRING_PTR(source);
|
|
197
|
+
int src_size = (int)RSTRING_LEN(source);
|
|
198
|
+
|
|
199
|
+
int max_dst_size = LZ4_compressBound(src_size);
|
|
200
|
+
VALUE result = rb_str_buf_new(max_dst_size);
|
|
201
|
+
char* dst = RSTRING_PTR(result);
|
|
202
|
+
|
|
203
|
+
int compressed_size = LZ4_compress_HC(src, dst, src_size, max_dst_size, compression_level);
|
|
204
|
+
|
|
205
|
+
if (compressed_size <= 0) {
|
|
206
|
+
rb_raise(eLZ4CompressionError, "HC compression failed");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
rb_str_set_len(result, compressed_size);
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/*
|
|
214
|
+
* call-seq:
|
|
215
|
+
* LZ4HC.sizeof_state -> integer
|
|
216
|
+
*
|
|
217
|
+
* Returns the size needed for HC compression state.
|
|
218
|
+
*/
|
|
219
|
+
static VALUE
|
|
220
|
+
lz4hc_sizeof_state_wrapper(VALUE self)
|
|
221
|
+
{
|
|
222
|
+
return INT2NUM(LZ4_sizeofStateHC());
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/*
|
|
226
|
+
* ============================================================================
|
|
227
|
+
* LZ4 Frame Functions (lz4frame.h)
|
|
228
|
+
* ============================================================================
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
/*
|
|
232
|
+
* call-seq:
|
|
233
|
+
* LZ4Frame.compress_frame(source, options = {}) -> compressed_frame
|
|
234
|
+
*
|
|
235
|
+
* Compresses data into a complete LZ4 frame (self-contained format).
|
|
236
|
+
* Options hash can include:
|
|
237
|
+
* - block_size: :max64KB, :max256KB, :max1MB, :max4MB (default :max64KB)
|
|
238
|
+
* - block_mode: :linked, :independent (default :linked)
|
|
239
|
+
* - checksum: true/false (default false)
|
|
240
|
+
* - compression_level: 0-12 (default 0 = fast mode)
|
|
241
|
+
*/
|
|
242
|
+
static VALUE
|
|
243
|
+
lz4frame_compress_frame_wrapper(int argc, VALUE *argv, VALUE self)
|
|
244
|
+
{
|
|
245
|
+
VALUE source, options;
|
|
246
|
+
rb_scan_args(argc, argv, "11", &source, &options);
|
|
247
|
+
|
|
248
|
+
Check_Type(source, T_STRING);
|
|
249
|
+
|
|
250
|
+
const char* src = RSTRING_PTR(source);
|
|
251
|
+
size_t src_size = RSTRING_LEN(source);
|
|
252
|
+
|
|
253
|
+
/* Set up preferences */
|
|
254
|
+
LZ4F_preferences_t prefs;
|
|
255
|
+
memset(&prefs, 0, sizeof(prefs));
|
|
256
|
+
prefs.frameInfo.blockSizeID = LZ4F_max64KB;
|
|
257
|
+
prefs.frameInfo.blockMode = LZ4F_blockLinked;
|
|
258
|
+
prefs.frameInfo.contentChecksumFlag = LZ4F_noContentChecksum;
|
|
259
|
+
prefs.compressionLevel = 0;
|
|
260
|
+
|
|
261
|
+
/* Parse options if provided */
|
|
262
|
+
if (!NIL_P(options)) {
|
|
263
|
+
Check_Type(options, T_HASH);
|
|
264
|
+
|
|
265
|
+
VALUE block_size = rb_hash_aref(options, ID2SYM(rb_intern("block_size")));
|
|
266
|
+
if (!NIL_P(block_size)) {
|
|
267
|
+
ID bs_id = SYM2ID(block_size);
|
|
268
|
+
if (bs_id == rb_intern("max64KB")) prefs.frameInfo.blockSizeID = LZ4F_max64KB;
|
|
269
|
+
else if (bs_id == rb_intern("max256KB")) prefs.frameInfo.blockSizeID = LZ4F_max256KB;
|
|
270
|
+
else if (bs_id == rb_intern("max1MB")) prefs.frameInfo.blockSizeID = LZ4F_max1MB;
|
|
271
|
+
else if (bs_id == rb_intern("max4MB")) prefs.frameInfo.blockSizeID = LZ4F_max4MB;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
VALUE block_mode = rb_hash_aref(options, ID2SYM(rb_intern("block_mode")));
|
|
275
|
+
if (!NIL_P(block_mode)) {
|
|
276
|
+
ID bm_id = SYM2ID(block_mode);
|
|
277
|
+
if (bm_id == rb_intern("linked")) prefs.frameInfo.blockMode = LZ4F_blockLinked;
|
|
278
|
+
else if (bm_id == rb_intern("independent")) prefs.frameInfo.blockMode = LZ4F_blockIndependent;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
VALUE checksum = rb_hash_aref(options, ID2SYM(rb_intern("checksum")));
|
|
282
|
+
if (RTEST(checksum)) {
|
|
283
|
+
prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
VALUE comp_level = rb_hash_aref(options, ID2SYM(rb_intern("compression_level")));
|
|
287
|
+
if (!NIL_P(comp_level)) {
|
|
288
|
+
prefs.compressionLevel = NUM2INT(comp_level);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
size_t dst_capacity = LZ4F_compressFrameBound(src_size, &prefs);
|
|
293
|
+
VALUE result = rb_str_buf_new(dst_capacity);
|
|
294
|
+
char* dst = RSTRING_PTR(result);
|
|
295
|
+
|
|
296
|
+
size_t compressed_size = LZ4F_compressFrame(dst, dst_capacity, src, src_size, &prefs);
|
|
297
|
+
|
|
298
|
+
if (LZ4F_isError(compressed_size)) {
|
|
299
|
+
rb_raise(eLZ4FrameError, "Frame compression failed: %s",
|
|
300
|
+
LZ4F_getErrorName(compressed_size));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
rb_str_set_len(result, compressed_size);
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/*
|
|
308
|
+
* call-seq:
|
|
309
|
+
* LZ4Frame.decompress_frame(source) -> decompressed_string
|
|
310
|
+
*
|
|
311
|
+
* Decompresses a complete LZ4 frame.
|
|
312
|
+
*/
|
|
313
|
+
static VALUE
|
|
314
|
+
lz4frame_decompress_frame_wrapper(VALUE self, VALUE source)
|
|
315
|
+
{
|
|
316
|
+
Check_Type(source, T_STRING);
|
|
317
|
+
|
|
318
|
+
const char* src = RSTRING_PTR(source);
|
|
319
|
+
size_t src_size = RSTRING_LEN(source);
|
|
320
|
+
|
|
321
|
+
/* Create decompression context */
|
|
322
|
+
LZ4F_dctx* dctx;
|
|
323
|
+
LZ4F_errorCode_t err = LZ4F_createDecompressionContext(&dctx, LZ4F_VERSION);
|
|
324
|
+
if (LZ4F_isError(err)) {
|
|
325
|
+
rb_raise(eLZ4FrameError, "Failed to create decompression context: %s",
|
|
326
|
+
LZ4F_getErrorName(err));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Allocate output buffer - start with 4x input size, may need to grow */
|
|
330
|
+
size_t dst_capacity = src_size * 4;
|
|
331
|
+
if (dst_capacity < 1024) dst_capacity = 1024;
|
|
332
|
+
|
|
333
|
+
VALUE result = rb_str_buf_new(dst_capacity);
|
|
334
|
+
char* dst = RSTRING_PTR(result);
|
|
335
|
+
size_t total_decompressed = 0;
|
|
336
|
+
|
|
337
|
+
size_t src_pos = 0;
|
|
338
|
+
|
|
339
|
+
while (src_pos < src_size) {
|
|
340
|
+
size_t src_remaining = src_size - src_pos;
|
|
341
|
+
size_t dst_remaining = dst_capacity - total_decompressed;
|
|
342
|
+
|
|
343
|
+
/* Ensure we have space, grow if needed */
|
|
344
|
+
if (dst_remaining < 64 * 1024) {
|
|
345
|
+
dst_capacity *= 2;
|
|
346
|
+
rb_str_resize(result, dst_capacity);
|
|
347
|
+
dst = RSTRING_PTR(result);
|
|
348
|
+
dst_remaining = dst_capacity - total_decompressed;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
size_t ret = LZ4F_decompress(dctx,
|
|
352
|
+
dst + total_decompressed, &dst_remaining,
|
|
353
|
+
src + src_pos, &src_remaining,
|
|
354
|
+
NULL);
|
|
355
|
+
|
|
356
|
+
if (LZ4F_isError(ret)) {
|
|
357
|
+
LZ4F_freeDecompressionContext(dctx);
|
|
358
|
+
rb_raise(eLZ4FrameError, "Frame decompression failed: %s",
|
|
359
|
+
LZ4F_getErrorName(ret));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
src_pos += src_remaining;
|
|
363
|
+
total_decompressed += dst_remaining;
|
|
364
|
+
|
|
365
|
+
/* ret == 0 means frame is complete */
|
|
366
|
+
if (ret == 0) {
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
LZ4F_freeDecompressionContext(dctx);
|
|
372
|
+
|
|
373
|
+
rb_str_set_len(result, total_decompressed);
|
|
374
|
+
return result;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/*
|
|
378
|
+
* call-seq:
|
|
379
|
+
* LZ4Frame.version -> integer
|
|
380
|
+
*
|
|
381
|
+
* Returns the LZ4F API version number.
|
|
382
|
+
*/
|
|
383
|
+
static VALUE
|
|
384
|
+
lz4frame_version_wrapper(VALUE self)
|
|
385
|
+
{
|
|
386
|
+
return INT2NUM(LZ4F_getVersion());
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/*
|
|
390
|
+
* call-seq:
|
|
391
|
+
* LZ4Frame.compression_level_max -> integer
|
|
392
|
+
*
|
|
393
|
+
* Returns the maximum compression level supported.
|
|
394
|
+
*/
|
|
395
|
+
static VALUE
|
|
396
|
+
lz4frame_compression_level_max_wrapper(VALUE self)
|
|
397
|
+
{
|
|
398
|
+
return INT2NUM(LZ4F_compressionLevel_max());
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/*
|
|
402
|
+
* Extension initialization
|
|
403
|
+
*/
|
|
404
|
+
void
|
|
405
|
+
Init_lz4_native(void)
|
|
406
|
+
{
|
|
407
|
+
/* Main module */
|
|
408
|
+
mLZ4Native = rb_define_module("LZ4Native");
|
|
409
|
+
|
|
410
|
+
/* LZ4 basic module */
|
|
411
|
+
mLZ4 = rb_define_module_under(mLZ4Native, "LZ4");
|
|
412
|
+
rb_define_singleton_method(mLZ4, "compress_default", lz4_compress_default_wrapper, 1);
|
|
413
|
+
rb_define_singleton_method(mLZ4, "decompress_safe", lz4_decompress_safe_wrapper, 2);
|
|
414
|
+
rb_define_singleton_method(mLZ4, "compress_bound", lz4_compress_bound_wrapper, 1);
|
|
415
|
+
rb_define_singleton_method(mLZ4, "compress_fast", lz4_compress_fast_wrapper, 2);
|
|
416
|
+
rb_define_singleton_method(mLZ4, "version_number", lz4_version_number_wrapper, 0);
|
|
417
|
+
rb_define_singleton_method(mLZ4, "version_string", lz4_version_string_wrapper, 0);
|
|
418
|
+
|
|
419
|
+
/* LZ4HC module */
|
|
420
|
+
mLZ4HC = rb_define_module_under(mLZ4Native, "LZ4HC");
|
|
421
|
+
rb_define_singleton_method(mLZ4HC, "compress", lz4hc_compress_wrapper, -1);
|
|
422
|
+
rb_define_singleton_method(mLZ4HC, "sizeof_state", lz4hc_sizeof_state_wrapper, 0);
|
|
423
|
+
|
|
424
|
+
/* LZ4Frame module */
|
|
425
|
+
mLZ4Frame = rb_define_module_under(mLZ4Native, "LZ4Frame");
|
|
426
|
+
rb_define_singleton_method(mLZ4Frame, "compress_frame", lz4frame_compress_frame_wrapper, -1);
|
|
427
|
+
rb_define_singleton_method(mLZ4Frame, "decompress_frame", lz4frame_decompress_frame_wrapper, 1);
|
|
428
|
+
rb_define_singleton_method(mLZ4Frame, "version", lz4frame_version_wrapper, 0);
|
|
429
|
+
rb_define_singleton_method(mLZ4Frame, "compression_level_max", lz4frame_compression_level_max_wrapper, 0);
|
|
430
|
+
|
|
431
|
+
/* Exception classes */
|
|
432
|
+
eLZ4Error = rb_define_class_under(mLZ4Native, "Error", rb_eStandardError);
|
|
433
|
+
eLZ4CompressionError = rb_define_class_under(mLZ4Native, "CompressionError", eLZ4Error);
|
|
434
|
+
eLZ4DecompressionError = rb_define_class_under(mLZ4Native, "DecompressionError", eLZ4Error);
|
|
435
|
+
eLZ4FrameError = rb_define_class_under(mLZ4Native, "FrameError", eLZ4Error);
|
|
436
|
+
|
|
437
|
+
/* Constants */
|
|
438
|
+
rb_define_const(mLZ4, "MAX_INPUT_SIZE", INT2NUM(LZ4_MAX_INPUT_SIZE));
|
|
439
|
+
rb_define_const(mLZ4HC, "CLEVEL_MIN", INT2NUM(LZ4HC_CLEVEL_MIN));
|
|
440
|
+
rb_define_const(mLZ4HC, "CLEVEL_DEFAULT", INT2NUM(LZ4HC_CLEVEL_DEFAULT));
|
|
441
|
+
rb_define_const(mLZ4HC, "CLEVEL_MAX", INT2NUM(LZ4HC_CLEVEL_MAX));
|
|
442
|
+
}
|