lz4-ruby 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  LZ4 HC - High Compression Mode of LZ4
3
3
  Header File
4
- Copyright (C) 2011-2012, Yann Collet.
4
+ Copyright (C) 2011-2013, Yann Collet.
5
5
  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
6
 
7
7
  Redistribution and use in source and binary forms, with or without
@@ -39,19 +39,131 @@ extern "C" {
39
39
  #endif
40
40
 
41
41
 
42
- int LZ4_compressHC (const char* source, char* dest, int isize);
43
-
42
+ int LZ4_compressHC (const char* source, char* dest, int inputSize);
44
43
  /*
45
44
  LZ4_compressHC :
46
- return : the number of bytes in compressed buffer dest
47
- note : destination buffer must be already allocated.
48
- To avoid any problem, size it to handle worst cases situations (input data not compressible)
49
- Worst case size evaluation is provided by function LZ4_compressBound() (see "lz4.h")
45
+ return : the number of bytes in compressed buffer dest
46
+ or 0 if compression fails.
47
+ note : destination buffer must be already allocated.
48
+ To avoid any problem, size it to handle worst cases situations (input data not compressible)
49
+ Worst case size evaluation is provided by function LZ4_compressBound() (see "lz4.h")
50
+ */
51
+
52
+ int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
53
+ /*
54
+ LZ4_compress_limitedOutput() :
55
+ Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
56
+ If it cannot achieve it, compression will stop, and result of the function will be zero.
57
+ This function never writes outside of provided output buffer.
58
+
59
+ inputSize : Max supported value is 1 GB
60
+ maxOutputSize : is maximum allowed size into the destination buffer (which must be already allocated)
61
+ return : the number of output bytes written in buffer 'dest'
62
+ or 0 if compression fails.
50
63
  */
51
64
 
52
65
 
66
+ int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel);
67
+ int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
68
+ /*
69
+ Same functions as above, but with programmable 'compressionLevel'.
70
+ Recommended values are between 4 and 9, although any value between 0 and 16 will work.
71
+ 'compressionLevel'==0 means use default 'compressionLevel' value.
72
+ Values above 16 behave the same as 16.
73
+ Equivalent variants exist for all other compression functions below.
74
+ */
75
+
53
76
  /* Note :
54
- Decompression functions are provided within regular LZ4 source code (see "lz4.h") (BSD license)
77
+ Decompression functions are provided within LZ4 source code (see "lz4.h") (BSD license)
78
+ */
79
+
80
+
81
+ /**************************************
82
+ Using an external allocation
83
+ **************************************/
84
+ int LZ4_sizeofStateHC();
85
+ int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize);
86
+ int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
87
+
88
+ int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel);
89
+ int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
90
+
91
+ /*
92
+ These functions are provided should you prefer to allocate memory for compression tables with your own allocation methods.
93
+ To know how much memory must be allocated for the compression tables, use :
94
+ int LZ4_sizeofStateHC();
95
+
96
+ Note that tables must be aligned for pointer (32 or 64 bits), otherwise compression will fail (return code 0).
97
+
98
+ The allocated memory can be provided to the compressions functions using 'void* state' parameter.
99
+ LZ4_compress_withStateHC() and LZ4_compress_limitedOutput_withStateHC() are equivalent to previously described functions.
100
+ They just use the externally allocated memory area instead of allocating their own (on stack, or on heap).
101
+ */
102
+
103
+
104
+ /**************************************
105
+ Streaming Functions
106
+ **************************************/
107
+ void* LZ4_createHC (const char* inputBuffer);
108
+ int LZ4_compressHC_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize);
109
+ int LZ4_compressHC_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize);
110
+ char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
111
+ int LZ4_freeHC (void* LZ4HC_Data);
112
+
113
+ int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);
114
+ int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
115
+
116
+ /*
117
+ These functions allow the compression of dependent blocks, where each block benefits from prior 64 KB within preceding blocks.
118
+ In order to achieve this, it is necessary to start creating the LZ4HC Data Structure, thanks to the function :
119
+
120
+ void* LZ4_createHC (const char* inputBuffer);
121
+ The result of the function is the (void*) pointer on the LZ4HC Data Structure.
122
+ This pointer will be needed in all other functions.
123
+ If the pointer returned is NULL, then the allocation has failed, and compression must be aborted.
124
+ The only parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer.
125
+ The input buffer must be already allocated, and size at least 192KB.
126
+ 'inputBuffer' will also be the 'const char* source' of the first block.
127
+
128
+ All blocks are expected to lay next to each other within the input buffer, starting from 'inputBuffer'.
129
+ To compress each block, use either LZ4_compressHC_continue() or LZ4_compressHC_limitedOutput_continue().
130
+ Their behavior are identical to LZ4_compressHC() or LZ4_compressHC_limitedOutput(),
131
+ but require the LZ4HC Data Structure as their first argument, and check that each block starts right after the previous one.
132
+ If next block does not begin immediately after the previous one, the compression will fail (return 0).
133
+
134
+ When it's no longer possible to lay the next block after the previous one (not enough space left into input buffer), a call to :
135
+ char* LZ4_slideInputBufferHC(void* LZ4HC_Data);
136
+ must be performed. It will typically copy the latest 64KB of input at the beginning of input buffer.
137
+ Note that, for this function to work properly, minimum size of an input buffer must be 192KB.
138
+ ==> The memory position where the next input data block must start is provided as the result of the function.
139
+
140
+ Compression can then resume, using LZ4_compressHC_continue() or LZ4_compressHC_limitedOutput_continue(), as usual.
141
+
142
+ When compression is completed, a call to LZ4_freeHC() will release the memory used by the LZ4HC Data Structure.
143
+ */
144
+
145
+ int LZ4_sizeofStreamStateHC();
146
+ int LZ4_resetStreamStateHC(void* state, const char* inputBuffer);
147
+
148
+ /*
149
+ These functions achieve the same result as :
150
+ void* LZ4_createHC (const char* inputBuffer);
151
+
152
+ They are provided here to allow the user program to allocate memory using its own routines.
153
+
154
+ To know how much space must be allocated, use LZ4_sizeofStreamStateHC();
155
+ Note also that space must be aligned for pointers (32 or 64 bits).
156
+
157
+ Once space is allocated, you must initialize it using : LZ4_resetStreamStateHC(void* state, const char* inputBuffer);
158
+ void* state is a pointer to the space allocated.
159
+ It must be aligned for pointers (32 or 64 bits), and be large enough.
160
+ The parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer.
161
+ The input buffer must be already allocated, and size at least 192KB.
162
+ 'inputBuffer' will also be the 'const char* source' of the first block.
163
+
164
+ The same space can be re-used multiple times, just by initializing it each time with LZ4_resetStreamState().
165
+ return value of LZ4_resetStreamStateHC() must be 0 is OK.
166
+ Any other value means there was an error (typically, state is not aligned for pointers (32 or 64 bits)).
55
167
  */
56
168
 
57
169
 
@@ -3,6 +3,7 @@
3
3
  #include "lz4hc.h"
4
4
 
5
5
  typedef int (*CompressFunc)(const char *source, char *dest, int isize);
6
+ typedef int (*CompressLimitedOutputFunc)(const char* source, char* dest, int inputSize, int maxOutputSize);
6
7
 
7
8
  static VALUE lz4internal;
8
9
  static VALUE lz4_error;
@@ -43,6 +44,80 @@ static VALUE compress_internal(CompressFunc compressor, VALUE header, VALUE inpu
43
44
  return result;
44
45
  }
45
46
 
47
+ static VALUE compress_raw_internal(
48
+ CompressLimitedOutputFunc compressor,
49
+ VALUE _input,
50
+ VALUE _input_size,
51
+ VALUE _output_buffer,
52
+ VALUE _max_output_size) {
53
+
54
+ const char *src_p;
55
+ int src_size;
56
+
57
+ int needs_resize;
58
+ char *buf_p;
59
+
60
+ int max_output_size;
61
+
62
+ int comp_size;
63
+
64
+
65
+ Check_Type(_input, T_STRING);
66
+ src_p = RSTRING_PTR(_input);
67
+ src_size = NUM2INT(_input_size);
68
+
69
+ if (NIL_P(_output_buffer)) {
70
+ needs_resize = 1;
71
+ _output_buffer = rb_str_new(NULL, _max_output_size);
72
+
73
+ } else {
74
+ needs_resize = 0;
75
+ }
76
+
77
+ buf_p = RSTRING_PTR(_output_buffer);
78
+
79
+ max_output_size = NUM2INT(_max_output_size);
80
+
81
+ comp_size = compressor(src_p, buf_p, src_size, max_output_size);
82
+
83
+ if (comp_size > 0 && needs_resize) {
84
+ rb_str_resize(_output_buffer, comp_size);
85
+ }
86
+
87
+ return rb_ary_new3(2, _output_buffer, INT2NUM(comp_size));
88
+ }
89
+
90
+ static VALUE lz4internal_compress_raw(
91
+ VALUE self,
92
+ VALUE _input,
93
+ VALUE _input_size,
94
+ VALUE _output_buffer,
95
+ VALUE _max_output_size)
96
+ {
97
+ return compress_raw_internal(
98
+ LZ4_compress_limitedOutput,
99
+ _input,
100
+ _input_size,
101
+ _output_buffer,
102
+ _max_output_size);
103
+ }
104
+
105
+ static VALUE lz4internal_compressHC_raw(
106
+ VALUE self,
107
+ VALUE _input,
108
+ VALUE _input_size,
109
+ VALUE _output_buffer,
110
+ VALUE _max_output_size)
111
+ {
112
+ return compress_raw_internal(
113
+ LZ4_compressHC_limitedOutput,
114
+ _input,
115
+ _input_size,
116
+ _output_buffer,
117
+ _max_output_size);
118
+ }
119
+
120
+
46
121
  static VALUE lz4internal_compress(VALUE self, VALUE header, VALUE input, VALUE in_size) {
47
122
  return compress_internal(LZ4_compress, header, input, in_size);
48
123
  }
@@ -81,6 +156,202 @@ static VALUE lz4internal_uncompress(VALUE self, VALUE input, VALUE in_size, VALU
81
156
  return result;
82
157
  }
83
158
 
159
+ static VALUE lz4internal_decompress_raw(
160
+ VALUE self,
161
+ VALUE _input,
162
+ VALUE _input_size,
163
+ VALUE _output_buffer,
164
+ VALUE _max_output_size) {
165
+
166
+ const char *src_p;
167
+ int src_size;
168
+
169
+ int max_output_size;
170
+
171
+ int needs_resize;
172
+ char *buf_p;
173
+
174
+ int decomp_size;
175
+
176
+ Check_Type(_input, T_STRING);
177
+ src_p = RSTRING_PTR(_input);
178
+ src_size = NUM2INT(_input_size);
179
+
180
+ max_output_size = NUM2INT(_max_output_size);
181
+
182
+ if (NIL_P(_output_buffer)) {
183
+ needs_resize = 1;
184
+ _output_buffer = rb_str_new(NULL, max_output_size);
185
+
186
+ } else {
187
+ needs_resize = 0;
188
+ }
189
+
190
+ buf_p = RSTRING_PTR(_output_buffer);
191
+ decomp_size = LZ4_decompress_safe(src_p, buf_p, src_size, max_output_size);
192
+
193
+ if (decomp_size > 0 && needs_resize) {
194
+ rb_str_resize(_output_buffer, decomp_size);
195
+ }
196
+
197
+ return rb_ary_new3(2, _output_buffer, INT2NUM(decomp_size));
198
+ }
199
+
200
+ #if 0
201
+
202
+ static inline void lz4internal_raw_compress_scanargs(int argc, VALUE *argv, VALUE *src, VALUE *dest, size_t *srcsize, size_t *maxsize) {
203
+ switch (argc) {
204
+ case 1:
205
+ *src = argv[0];
206
+ Check_Type(*src, RUBY_T_STRING);
207
+ *srcsize = RSTRING_LEN(*src);
208
+ *dest = rb_str_buf_new(0);
209
+ *maxsize = LZ4_compressBound(*srcsize);
210
+ break;
211
+ case 2:
212
+ *src = argv[0];
213
+ Check_Type(*src, RUBY_T_STRING);
214
+ *srcsize = RSTRING_LEN(*src);
215
+ if (TYPE(argv[1]) == T_STRING) {
216
+ *dest = argv[1];
217
+ *maxsize = LZ4_compressBound(*srcsize);
218
+ } else {
219
+ *dest = rb_str_buf_new(0);
220
+ *maxsize = NUM2SIZET(argv[1]);
221
+ }
222
+ break;
223
+ case 3:
224
+ *src = argv[0];
225
+ Check_Type(*src, RUBY_T_STRING);
226
+ *srcsize = RSTRING_LEN(*src);
227
+ *dest = argv[1];
228
+ Check_Type(*dest, RUBY_T_STRING);
229
+ *maxsize = NUM2SIZET(argv[2]);
230
+ break;
231
+ default:
232
+ //rb_error_arity(argc, 1, 3);
233
+ rb_scan_args(argc, argv, "12", NULL, NULL, NULL);
234
+ // the following code is used to eliminate compiler warnings.
235
+ *src = *dest = 0;
236
+ *srcsize = *maxsize = 0;
237
+ }
238
+ }
239
+
240
+ static inline VALUE lz4internal_raw_compress_common(int argc, VALUE *argv, VALUE lz4, CompressLimitedOutputFunc compressor) {
241
+ VALUE src, dest;
242
+ size_t srcsize;
243
+ size_t maxsize;
244
+
245
+ lz4internal_raw_compress_scanargs(argc, argv, &src, &dest, &srcsize, &maxsize);
246
+
247
+ if (srcsize > LZ4_MAX_INPUT_SIZE) {
248
+ rb_raise(lz4_error,
249
+ "input size is too big for lz4 compress (max %u bytes)",
250
+ LZ4_MAX_INPUT_SIZE);
251
+ }
252
+ rb_str_modify(dest);
253
+ rb_str_resize(dest, maxsize);
254
+ rb_str_set_len(dest, 0);
255
+
256
+ int size = compressor(RSTRING_PTR(src), RSTRING_PTR(dest), srcsize, maxsize);
257
+ if (size < 0) {
258
+ rb_raise(lz4_error, "failed LZ4 raw compress");
259
+ }
260
+
261
+ rb_str_resize(dest, size);
262
+ rb_str_set_len(dest, size);
263
+
264
+ return dest;
265
+ }
266
+
267
+ /*
268
+ * call-seq:
269
+ * (compressed string data) raw_compress(src)
270
+ * (compressed string data) raw_compress(src, max_dest_size)
271
+ * (dest with compressed string data) raw_compress(src, dest)
272
+ * (dest with compressed string data) raw_compress(src, dest, max_dest_size)
273
+ */
274
+ static VALUE lz4internal_raw_compress(int argc, VALUE *argv, VALUE lz4i) {
275
+ return lz4internal_raw_compress_common(argc, argv, lz4i, LZ4_compress_limitedOutput);
276
+ }
277
+
278
+ /*
279
+ * call-seq:
280
+ * (compressed string data) raw_compressHC(src)
281
+ * (compressed string data) raw_compressHC(src, max_dest_size)
282
+ * (dest with compressed string data) raw_compressHC(src, dest)
283
+ * (dest with compressed string data) raw_compressHC(src, dest, max_dest_size)
284
+ */
285
+ static VALUE lz4internal_raw_compressHC(int argc, VALUE *argv, VALUE lz4i) {
286
+ return lz4internal_raw_compress_common(argc, argv, lz4i, LZ4_compressHC_limitedOutput);
287
+ }
288
+
289
+ enum {
290
+ LZ4RUBY_UNCOMPRESS_MAXSIZE = 1 << 24, // tentative value
291
+ };
292
+
293
+ static inline void lz4internal_raw_uncompress_scanargs(int argc, VALUE *argv, VALUE *src, VALUE *dest, size_t *maxsize) {
294
+ switch (argc) {
295
+ case 1:
296
+ *src = argv[0];
297
+ Check_Type(*src, RUBY_T_STRING);
298
+ *dest = rb_str_buf_new(0);
299
+ *maxsize = LZ4RUBY_UNCOMPRESS_MAXSIZE;
300
+ break;
301
+ case 2:
302
+ *src = argv[0];
303
+ Check_Type(*src, RUBY_T_STRING);
304
+ *dest = argv[1];
305
+ if (TYPE(*dest) == T_STRING) {
306
+ *maxsize = LZ4RUBY_UNCOMPRESS_MAXSIZE;
307
+ } else {
308
+ *maxsize = NUM2SIZET(*dest);
309
+ *dest = rb_str_buf_new(0);
310
+ }
311
+ break;
312
+ case 3:
313
+ *src = argv[0];
314
+ Check_Type(*src, RUBY_T_STRING);
315
+ *dest = argv[1];
316
+ Check_Type(*dest, RUBY_T_STRING);
317
+ *maxsize = NUM2SIZET(argv[2]);
318
+ break;
319
+ default:
320
+ //rb_error_arity(argc, 2, 3);
321
+ rb_scan_args(argc, argv, "21", NULL, NULL, NULL);
322
+ // the following code is used to eliminate compiler warnings.
323
+ *src = *dest = 0;
324
+ *maxsize = 0;
325
+ }
326
+ }
327
+
328
+ /*
329
+ * call-seq:
330
+ * (uncompressed string data) raw_uncompress(src, max_dest_size = 1 << 24)
331
+ * (dest for uncompressed string data) raw_uncompress(src, dest, max_dest_size = 1 << 24)
332
+ */
333
+ static VALUE lz4internal_raw_uncompress(int argc, VALUE *argv, VALUE lz4i) {
334
+ VALUE src, dest;
335
+ size_t maxsize;
336
+ lz4internal_raw_uncompress_scanargs(argc, argv, &src, &dest, &maxsize);
337
+
338
+ rb_str_modify(dest);
339
+ rb_str_resize(dest, maxsize);
340
+ rb_str_set_len(dest, 0);
341
+
342
+ int size = LZ4_decompress_safe(RSTRING_PTR(src), RSTRING_PTR(dest), RSTRING_LEN(src), maxsize);
343
+ if (size < 0) {
344
+ rb_raise(lz4_error, "failed LZ4 raw uncompress at %d", -size);
345
+ }
346
+
347
+ rb_str_resize(dest, size);
348
+ rb_str_set_len(dest, size);
349
+
350
+ return dest;
351
+ }
352
+
353
+ #endif
354
+
84
355
  void Init_lz4ruby(void) {
85
356
  lz4internal = rb_define_module("LZ4Internal");
86
357
 
@@ -88,5 +359,13 @@ void Init_lz4ruby(void) {
88
359
  rb_define_module_function(lz4internal, "compressHC", lz4internal_compressHC, 3);
89
360
  rb_define_module_function(lz4internal, "uncompress", lz4internal_uncompress, 4);
90
361
 
362
+ //rb_define_module_function(lz4internal, "raw_compress", lz4internal_raw_compress, -1);
363
+ //rb_define_module_function(lz4internal, "raw_compressHC", lz4internal_raw_compressHC, -1);
364
+ //rb_define_module_function(lz4internal, "raw_uncompress", lz4internal_raw_uncompress, -1);
365
+
366
+ rb_define_module_function(lz4internal, "compress_raw", lz4internal_compress_raw, 4);
367
+ rb_define_module_function(lz4internal, "compressHC_raw", lz4internal_compressHC_raw, 4);
368
+ rb_define_module_function(lz4internal, "decompress_raw", lz4internal_decompress_raw, 4);
369
+
91
370
  lz4_error = rb_define_class_under(lz4internal, "Error", rb_eStandardError);
92
371
  }
@@ -17,28 +17,35 @@ class LZ4
17
17
  return _compress(input, in_size, true)
18
18
  end
19
19
 
20
- def self._compress(input, in_size, high_compression)
20
+ def self.decompress(input, in_size = nil)
21
21
  in_size = input.length if in_size == nil
22
- header = encode_varbyte(in_size)
22
+ out_size, varbyte_len = decode_varbyte(input)
23
23
 
24
- if high_compression
25
- return LZ4Internal.compressHC(header, input, in_size)
26
- else
27
- return LZ4Internal.compress(header, input, in_size)
24
+ if out_size < 0 || varbyte_len < 0
25
+ raise "Compressed data is maybe corrupted"
28
26
  end
27
+
28
+ return LZ4Internal::uncompress(input, in_size, varbyte_len, out_size)
29
29
  end
30
30
 
31
+ # @deprecated Use {#decompress} and will be removed.
31
32
  def self.uncompress(input, in_size = nil)
33
+ return decompress(input, in_size)
34
+ end
35
+
36
+ private
37
+ def self._compress(input, in_size, high_compression)
32
38
  in_size = input.length if in_size == nil
33
- out_size, varbyte_len = decode_varbyte(input)
39
+ header = encode_varbyte(in_size)
34
40
 
35
- if out_size < 0 || varbyte_len < 0
36
- raise "Compressed data is maybe corrupted"
41
+ if high_compression
42
+ return LZ4Internal.compressHC(header, input, in_size)
43
+ else
44
+ return LZ4Internal.compress(header, input, in_size)
37
45
  end
38
-
39
- return LZ4Internal::uncompress(input, in_size, varbyte_len, out_size)
40
46
  end
41
47
 
48
+ private
42
49
  def self.encode_varbyte(val)
43
50
  varbytes = []
44
51
 
@@ -57,6 +64,7 @@ class LZ4
57
64
  return varbytes.pack("C*")
58
65
  end
59
66
 
67
+ private
60
68
  def self.decode_varbyte(text)
61
69
  len = [text.length, 5].min
62
70
  bytes = text[0, len].unpack("C*")
@@ -71,4 +79,111 @@ class LZ4
71
79
 
72
80
  return -1, -1
73
81
  end
82
+
83
+ # Handles LZ4 native data stream (without any additional headers).
84
+ class Raw
85
+ # Compresses `source` string.
86
+ #
87
+ # @param [String] source string to be compressed
88
+ # @param [Hash] options
89
+ # @option options [Fixnum] :input_size length of source to compress (must be less than or equal to `source.length`)
90
+ # @option options [String] :dest output buffer which will receive compressed string
91
+ # @option options [Fixnum] :max_output_size acceptable maximum output size
92
+ # @return [String, Fixnum] compressed string and its length.
93
+ def self.compress(source, options = {})
94
+ return _compress(source, false, options)
95
+ end
96
+
97
+ # Compresses `source` string using High Compress Mode.
98
+ #
99
+ # @param [String] source string to be compressed
100
+ # @param [Hash] options
101
+ # @option options [Fixnum] :input_size length of source to compress (must be less than or equal to `source.length`)
102
+ # @option options [String] :dest output buffer which will receive compressed string
103
+ # @option options [Fixnum] :max_output_size acceptable maximum output size
104
+ # @return [String, Fixnum] compressed string and its length.
105
+ def self.compressHC(source, options = {})
106
+ return _compress(source, true, options)
107
+ end
108
+
109
+ private
110
+ def self._compress(source, high_compression, options = {})
111
+ input_size = options[:input_size]
112
+ if input_size == nil
113
+ input_size = source.length
114
+
115
+ else
116
+ if source.length < input_size
117
+ raise ArgumentError, "`:input_size` (#{input_size}) must be less than or equal `source.length` (#{source.length})"
118
+ end
119
+ end
120
+
121
+ dest = options[:dest]
122
+
123
+ max_output_size = options[:max_output_size]
124
+ if max_output_size == nil
125
+ if dest != nil
126
+ max_output_size = dest.length
127
+ else
128
+ max_output_size = input_size + (input_size / 255) + 16 if dest == nil
129
+ end
130
+
131
+ else
132
+ if dest != nil && dest.length < max_output_size
133
+ raise ArgumentError, "`:dest` buffer size (#{dest.length}) must be greater than or equal `:max_output_size` (#{max_output_size})"
134
+ end
135
+ end
136
+
137
+ result = nil
138
+ if high_compression
139
+ result = LZ4Internal.compressHC_raw(source, input_size, dest, max_output_size)
140
+ else
141
+ result = LZ4Internal.compress_raw(source, input_size, dest, max_output_size)
142
+ end
143
+
144
+ if result[1] <= 0
145
+ raise LZ4Error, "compression failed"
146
+ end
147
+
148
+ return result[0], result[1]
149
+ end
150
+
151
+ # Decompresses `source` compressed string.
152
+ #
153
+ # @param [String] source
154
+ # @param [Fixnum] max_output_size
155
+ # @param [Hash] options
156
+ # @option options [Fixnum] :input_size length of source to decompress (must be less than or equal to `source.length`)
157
+ # @option options [String] :dest output buffer which will receive decompressed string
158
+ # @return [String, Fixnum] decompressed string and its length.
159
+ def self.decompress(source, max_output_size, options = {})
160
+ input_size = options[:input_size]
161
+ if input_size == nil
162
+ input_size = source.length
163
+
164
+ else
165
+ if source.length < input_size
166
+ raise ArgumentError, "`:input_size` (#{input_size}) must be less than or equal `source.length` (#{source.length})"
167
+ end
168
+ end
169
+
170
+ dest = options[:dest]
171
+
172
+ if dest != nil && dest.length < max_output_size
173
+ raise ArgumentError, "`:dest` buffer size (#{dest.length}) must be greater than or equal `max_output_size` (#{max_output_size})"
174
+ end
175
+
176
+ result = LZ4Internal.decompress_raw(source, input_size, dest, max_output_size)
177
+
178
+ if result[1] <= 0
179
+ return "", 0 if source == "\x00"
180
+ raise LZ4Error, "decompression failed"
181
+ end
182
+
183
+ return result[0], result[1]
184
+ end
185
+ end
186
+ end
187
+
188
+ class LZ4Error < StandardError
74
189
  end