diff --git a/ext/zstdruby/streaming_decompress.c b/ext/zstdruby/streaming_decompress.c index b310ac3..0336967 100644 --- a/ext/zstdruby/streaming_decompress.c +++ b/ext/zstdruby/streaming_decompress.c @@ -114,7 +114,7 @@ rb_streaming_decompress_decompress(VALUE obj, VALUE src) } static VALUE -rb_streaming_decompress_decompress2(VALUE obj, VALUE src) +rb_streaming_decompress_decompress_with_pos(VALUE obj, VALUE src) { StringValue(src); const char* input_data = RSTRING_PTR(src); @@ -131,7 +131,7 @@ rb_streaming_decompress_decompress2(VALUE obj, VALUE src) rb_raise(rb_eRuntimeError, "decompress error error code: %s", ZSTD_getErrorName(ret)); } rb_str_cat(result, output.dst, output.pos); - return rb_ary_new_from_args(3, UINT2NUM(ret), result, ULONG2NUM(input.pos)); + return rb_ary_new_from_args(2, result, ULONG2NUM(input.pos)); } extern VALUE rb_mZstd, cStreamingDecompress; @@ -142,5 +142,5 @@ zstd_ruby_streaming_decompress_init(void) rb_define_alloc_func(cStreamingDecompress, rb_streaming_decompress_allocate); rb_define_method(cStreamingDecompress, "initialize", rb_streaming_decompress_initialize, -1); rb_define_method(cStreamingDecompress, "decompress", rb_streaming_decompress_decompress, 1); - rb_define_method(cStreamingDecompress, "decompress2", rb_streaming_decompress_decompress2, 1); + rb_define_method(cStreamingDecompress, "decompress_with_pos", rb_streaming_decompress_decompress_with_pos, 1); } diff --git a/spec/zstd-ruby-streaming-decompress_spec.rb b/spec/zstd-ruby-streaming-decompress_spec.rb index 6eb0534..de25b47 100644 --- a/spec/zstd-ruby-streaming-decompress_spec.rb +++ b/spec/zstd-ruby-streaming-decompress_spec.rb @@ -17,6 +17,71 @@ end end + describe 'decompress_with_pos' do + it 'should return decompressed data and consumed input position' do + str = "hello world test data" + cstr = Zstd.compress(str) + stream = Zstd::StreamingDecompress.new + + # Test with partial input + result_array = stream.decompress_with_pos(cstr[0, 10]) + expect(result_array).to be_an(Array) + expect(result_array.length).to eq(2) + + decompressed_data = result_array[0] + consumed_bytes = result_array[1] + + expect(decompressed_data).to be_a(String) + expect(consumed_bytes).to be_a(Integer) + expect(consumed_bytes).to be > 0 + expect(consumed_bytes).to be <= 10 + end + + it 'should work with complete compressed data' do + str = "foo bar buzz" + cstr = Zstd.compress(str) + stream = Zstd::StreamingDecompress.new + + result_array = stream.decompress_with_pos(cstr) + decompressed_data = result_array[0] + consumed_bytes = result_array[1] + + expect(decompressed_data).to eq(str) + expect(consumed_bytes).to eq(cstr.length) + end + + it 'should work with multiple calls' do + str = "test data for multiple calls" + cstr = Zstd.compress(str) + stream = Zstd::StreamingDecompress.new + + result = '' + total_consumed = 0 + chunk_size = 5 + + while total_consumed < cstr.length + remaining_data = cstr[total_consumed..-1] + chunk = remaining_data[0, chunk_size] + + result_array = stream.decompress_with_pos(chunk) + decompressed_chunk = result_array[0] + consumed_bytes = result_array[1] + + result << decompressed_chunk + total_consumed += consumed_bytes + + expect(consumed_bytes).to be > 0 + expect(consumed_bytes).to be <= chunk.length + + # If we consumed less than the chunk size, we might be done or need more data + break if consumed_bytes < chunk.length && total_consumed == cstr.length + end + + expect(result).to eq(str) + expect(total_consumed).to eq(cstr.length) + end + end + describe 'streaming decompress + GC.compact' do it 'shoud work' do # str = SecureRandom.hex(150) @@ -109,4 +174,3 @@ end end end -