ruby-zstds 1.2.0 → 1.3.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/AUTHORS +2 -0
- data/README.md +34 -12
- data/ext/extconf.rb +14 -1
- data/ext/zstds_ext/dictionary.c +233 -45
- data/ext/zstds_ext/dictionary.h +22 -0
- data/ext/zstds_ext/error.c +3 -0
- data/ext/zstds_ext/error.h +1 -0
- data/ext/zstds_ext/gvl.h +2 -2
- data/ext/zstds_ext/macro.h +7 -1
- data/ext/zstds_ext/option.h +14 -0
- data/lib/zstds/dictionary.rb +76 -6
- data/lib/zstds/error.rb +9 -4
- data/lib/zstds/file.rb +17 -27
- data/lib/zstds/option.rb +60 -0
- data/lib/zstds/stream/raw/compressor.rb +12 -76
- data/lib/zstds/stream/raw/decompressor.rb +7 -51
- data/lib/zstds/stream/reader.rb +6 -176
- data/lib/zstds/stream/writer.rb +6 -140
- data/lib/zstds/string.rb +18 -9
- data/lib/zstds/validation.rb +5 -49
- data/lib/zstds/version.rb +1 -1
- metadata +44 -19
- data/lib/zstds/stream/abstract.rb +0 -152
- data/lib/zstds/stream/delegates.rb +0 -36
- data/lib/zstds/stream/raw/abstract.rb +0 -59
- data/lib/zstds/stream/reader_helpers.rb +0 -194
- data/lib/zstds/stream/stat.rb +0 -78
- data/lib/zstds/stream/writer_helpers.rb +0 -91
data/lib/zstds/dictionary.rb
CHANGED
@@ -7,15 +7,36 @@ require_relative "error"
|
|
7
7
|
require_relative "validation"
|
8
8
|
|
9
9
|
module ZSTDS
|
10
|
+
# ZSTDS::Dictionary class.
|
10
11
|
class Dictionary
|
12
|
+
# Current train defaults.
|
11
13
|
TRAIN_DEFAULTS = {
|
12
14
|
:gvl => false,
|
13
15
|
:capacity => 0
|
14
16
|
}
|
15
17
|
.freeze
|
16
18
|
|
19
|
+
# Current finalize defaults.
|
20
|
+
FINALIZE_DEFAULTS = {
|
21
|
+
:gvl => false,
|
22
|
+
:max_size => 0,
|
23
|
+
:dictionary_options => {}
|
24
|
+
}
|
25
|
+
.freeze
|
26
|
+
|
27
|
+
# Current finalize dictionary defaults.
|
28
|
+
FINALIZE_DICTIONARY_DEFAULTS = {
|
29
|
+
:compression_level => 0,
|
30
|
+
:notification_level => 0,
|
31
|
+
:dictionary_id => 0
|
32
|
+
}
|
33
|
+
.freeze
|
34
|
+
|
35
|
+
# Reads current +buffer+ binary data.
|
17
36
|
attr_reader :buffer
|
18
37
|
|
38
|
+
# Initializes compressor.
|
39
|
+
# Uses +buffer+ binary data.
|
19
40
|
def initialize(buffer)
|
20
41
|
Validation.validate_string buffer
|
21
42
|
raise ValidateError, "dictionary buffer should not be empty" if buffer.empty?
|
@@ -23,13 +44,14 @@ module ZSTDS
|
|
23
44
|
@buffer = buffer
|
24
45
|
end
|
25
46
|
|
47
|
+
# Trains dictionary.
|
48
|
+
# Uses +samples+ list of binary datas.
|
49
|
+
# Uses +options+ options hash.
|
50
|
+
# Option +gvl+ is global interpreter lock enabled.
|
51
|
+
# Option +capacity+ capacity of dictionary buffer.
|
52
|
+
# Returns dictionary based on new buffer.
|
26
53
|
def self.train(samples, options = {})
|
27
|
-
|
28
|
-
|
29
|
-
samples.each do |sample|
|
30
|
-
Validation.validate_string sample
|
31
|
-
raise ValidateError, "dictionary sample should not be empty" if sample.empty?
|
32
|
-
end
|
54
|
+
validate_samples samples
|
33
55
|
|
34
56
|
Validation.validate_hash options
|
35
57
|
|
@@ -42,10 +64,58 @@ module ZSTDS
|
|
42
64
|
new buffer
|
43
65
|
end
|
44
66
|
|
67
|
+
# Finalizes dictionary.
|
68
|
+
# Uses +content+ binary data.
|
69
|
+
# Uses +samples+ list of binary datas.
|
70
|
+
# Uses +options+ options hash.
|
71
|
+
# Option +gvl+ is global interpreter lock enabled.
|
72
|
+
# Option +max_size+ max size of dictionary buffer.
|
73
|
+
# Option +dictionary_options+ standard dictionary options hash.
|
74
|
+
# Returns dictionary based on new buffer.
|
75
|
+
def self.finalize(content, samples, options = {})
|
76
|
+
Validation.validate_string content
|
77
|
+
raise ValidateError, "content should not be empty" if content.empty?
|
78
|
+
|
79
|
+
validate_samples samples
|
80
|
+
|
81
|
+
Validation.validate_hash options
|
82
|
+
|
83
|
+
options = FINALIZE_DEFAULTS.merge options
|
84
|
+
|
85
|
+
Validation.validate_bool options[:gvl]
|
86
|
+
Validation.validate_not_negative_integer options[:max_size]
|
87
|
+
Validation.validate_hash options[:dictionary_options]
|
88
|
+
|
89
|
+
dictionary_options = FINALIZE_DICTIONARY_DEFAULTS.merge options[:dictionary_options]
|
90
|
+
|
91
|
+
compression_level = dictionary_options[:compression_level]
|
92
|
+
Validation.validate_integer compression_level
|
93
|
+
raise ValidateError, "invalid compression level" if
|
94
|
+
compression_level < Option::MIN_COMPRESSION_LEVEL || compression_level > Option::MAX_COMPRESSION_LEVEL
|
95
|
+
|
96
|
+
Validation.validate_not_negative_integer dictionary_options[:notification_level]
|
97
|
+
Validation.validate_not_negative_integer dictionary_options[:dictionary_id]
|
98
|
+
|
99
|
+
buffer = finalize_buffer content, samples, options
|
100
|
+
new buffer
|
101
|
+
end
|
102
|
+
|
103
|
+
# Raises error when +samples+ are not list of not empty strings.
|
104
|
+
def self.validate_samples(samples)
|
105
|
+
Validation.validate_array samples
|
106
|
+
|
107
|
+
samples.each do |sample|
|
108
|
+
Validation.validate_string sample
|
109
|
+
raise ValidateError, "dictionary sample should not be empty" if sample.empty?
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns current dictionary id.
|
45
114
|
def id
|
46
115
|
self.class.get_buffer_id @buffer
|
47
116
|
end
|
48
117
|
|
118
|
+
# Returns current dictionary header size.
|
49
119
|
def header_size
|
50
120
|
self.class.get_header_size @buffer
|
51
121
|
end
|
data/lib/zstds/error.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
# Ruby bindings for zstd library.
|
2
2
|
# Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
require "adsp"
|
5
|
+
|
4
6
|
module ZSTDS
|
5
7
|
class BaseError < ::StandardError; end
|
6
8
|
|
7
9
|
class AllocateError < BaseError; end
|
8
|
-
class ValidateError < BaseError; end
|
9
10
|
|
10
|
-
class UsedAfterCloseError < BaseError; end
|
11
11
|
class NotEnoughSourceBufferError < BaseError; end
|
12
12
|
class NotEnoughDestinationBufferError < BaseError; end
|
13
|
-
class NotEnoughDestinationError < BaseError; end
|
14
13
|
class DecompressorCorruptedSourceError < BaseError; end
|
15
14
|
class CorruptedDictionaryError < BaseError; end
|
16
15
|
|
@@ -18,5 +17,11 @@ module ZSTDS
|
|
18
17
|
class ReadIOError < BaseError; end
|
19
18
|
class WriteIOError < BaseError; end
|
20
19
|
|
21
|
-
|
20
|
+
ValidateError = ADSP::ValidateError
|
21
|
+
|
22
|
+
NotEnoughDestinationError = ADSP::NotEnoughDestinationError
|
23
|
+
UsedAfterCloseError = ADSP::UsedAfterCloseError
|
24
|
+
|
25
|
+
NotImplementedError = ADSP::NotImplementedError
|
26
|
+
UnexpectedError = ADSP::UnexpectedError
|
22
27
|
end
|
data/lib/zstds/file.rb
CHANGED
@@ -1,50 +1,40 @@
|
|
1
1
|
# Ruby bindings for zstd library.
|
2
2
|
# Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
require "adsp/file"
|
4
5
|
require "zstds_ext"
|
5
6
|
|
6
|
-
require_relative "error"
|
7
7
|
require_relative "option"
|
8
8
|
require_relative "validation"
|
9
9
|
|
10
10
|
module ZSTDS
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
# ZSTDS::File class.
|
12
|
+
class File < ADSP::File
|
13
|
+
# Current option class.
|
14
|
+
Option = ZSTDS::Option
|
15
|
+
|
16
|
+
# Compresses data from +source+ file path to +destination+ file path.
|
17
|
+
# Option: +:source_buffer_length+ source buffer length.
|
18
|
+
# Option: +:destination_buffer_length+ destination buffer length.
|
19
|
+
# Option: +:pledged_size+ source bytesize.
|
14
20
|
def self.compress(source, destination, options = {})
|
15
21
|
Validation.validate_string source
|
16
|
-
Validation.validate_string destination
|
17
22
|
|
18
23
|
options = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
|
19
24
|
|
20
25
|
options[:pledged_size] = ::File.size source
|
21
26
|
|
22
|
-
|
23
|
-
ZSTDS._native_compress_io source_io, destination_io, options
|
24
|
-
end
|
25
|
-
|
26
|
-
nil
|
27
|
+
super source, destination, options
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
options = Option.get_decompressor_options options, BUFFER_LENGTH_NAMES
|
34
|
-
|
35
|
-
open_files source, destination do |source_io, destination_io|
|
36
|
-
ZSTDS._native_decompress_io source_io, destination_io, options
|
37
|
-
end
|
38
|
-
|
39
|
-
nil
|
30
|
+
# Bypass native compress.
|
31
|
+
def self.native_compress_io(*args)
|
32
|
+
ZSTDS._native_compress_io(*args)
|
40
33
|
end
|
41
34
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
yield source_io, destination_io
|
46
|
-
end
|
47
|
-
end
|
35
|
+
# Bypass native decompress.
|
36
|
+
def self.native_decompress_io(*args)
|
37
|
+
ZSTDS._native_decompress_io(*args)
|
48
38
|
end
|
49
39
|
end
|
50
40
|
end
|
data/lib/zstds/option.rb
CHANGED
@@ -8,41 +8,95 @@ require_relative "error"
|
|
8
8
|
require_relative "validation"
|
9
9
|
|
10
10
|
module ZSTDS
|
11
|
+
# ZSTDS::Option module.
|
11
12
|
module Option
|
13
|
+
# Current default buffer length.
|
12
14
|
DEFAULT_BUFFER_LENGTH = 0
|
13
15
|
|
16
|
+
# Current compressor defaults.
|
14
17
|
COMPRESSOR_DEFAULTS = {
|
18
|
+
# Enables global VM lock where possible.
|
15
19
|
:gvl => false,
|
20
|
+
# Compression level.
|
16
21
|
:compression_level => nil,
|
22
|
+
# Maximum back-reference distance (power of 2).
|
17
23
|
:window_log => nil,
|
24
|
+
# Size of the initial probe table (power of 2).
|
18
25
|
:hash_log => nil,
|
26
|
+
# Size of the multi-probe search table (power of 2).
|
19
27
|
:chain_log => nil,
|
28
|
+
# Number of search attempts (power of 2).
|
20
29
|
:search_log => nil,
|
30
|
+
# Minimum size of searched matches.
|
21
31
|
:min_match => nil,
|
32
|
+
# Distance between match sampling (for :fast strategy),
|
33
|
+
# length of match considered "good enough" for (for other strategies).
|
22
34
|
:target_length => nil,
|
35
|
+
# Choses strategy.
|
23
36
|
:strategy => nil,
|
37
|
+
# Enables long distance matching.
|
24
38
|
:enable_long_distance_matching => nil,
|
39
|
+
# Size of the table for long distance matching (power of 2).
|
25
40
|
:ldm_hash_log => nil,
|
41
|
+
# Minimum match size for long distance matcher.
|
26
42
|
:ldm_min_match => nil,
|
43
|
+
# Log size of each bucket in the LDM hash table for collision resolution.
|
27
44
|
:ldm_bucket_size_log => nil,
|
45
|
+
# Frequency of inserting/looking up entries into the LDM hash table.
|
28
46
|
:ldm_hash_rate_log => nil,
|
47
|
+
# Enables writing of content size into frame header (if known).
|
29
48
|
:content_size_flag => nil,
|
49
|
+
# Enables writing of 32-bits checksum of content at end of frame.
|
30
50
|
:checksum_flag => nil,
|
51
|
+
# Enables writing of dictionary id into frame header.
|
31
52
|
:dict_id_flag => nil,
|
53
|
+
# Number of threads spawned in parallel.
|
32
54
|
:nb_workers => nil,
|
55
|
+
# Size of job (nb_workers >= 1).
|
33
56
|
:job_size => nil,
|
57
|
+
# Overlap size, as a fraction of window size.
|
34
58
|
:overlap_log => nil,
|
59
|
+
# Chose dictionary.
|
35
60
|
:dictionary => nil
|
36
61
|
}
|
37
62
|
.freeze
|
38
63
|
|
64
|
+
# Current decompressor defaults.
|
39
65
|
DECOMPRESSOR_DEFAULTS = {
|
66
|
+
# Enables global VM lock where possible.
|
40
67
|
:gvl => false,
|
68
|
+
# Size limit (power of 2).
|
41
69
|
:window_log_max => nil,
|
70
|
+
# Chose dictionary.
|
42
71
|
:dictionary => nil
|
43
72
|
}
|
44
73
|
.freeze
|
45
74
|
|
75
|
+
# Processes compressor +options+ and +buffer_length_names+.
|
76
|
+
# Option: +:source_buffer_length+ source buffer length.
|
77
|
+
# Option: +:destination_buffer_length+ destination buffer length.
|
78
|
+
# Option: +:gvl+ enables global VM lock where possible.
|
79
|
+
# Option: +:compression_level+ compression level.
|
80
|
+
# Option: +:window_log+ maximum back-reference distance (power of 2).
|
81
|
+
# Option: +:hash_log+ size of the initial probe table (power of 2).
|
82
|
+
# Option: +:chain_log+ size of the multi-probe search table (power of 2).
|
83
|
+
# Option: +:search_log+ number of search attempts (power of 2).
|
84
|
+
# Option: +:min_match+ minimum size of searched matches.
|
85
|
+
# Option: +:target_length+ distance between match sampling (for :fast strategy),
|
86
|
+
# length of match considered "good enough" for (for other strategies).
|
87
|
+
# Option: +:strategy+ choses strategy.
|
88
|
+
# Option: +:ldm_hash_log+ size of the table for long distance matching (power of 2).
|
89
|
+
# Option: +:ldm_min_match+ minimum match size for long distance matcher.
|
90
|
+
# Option: +:ldm_bucket_size_log+ log size of each bucket in the LDM hash table for collision resolution.
|
91
|
+
# Option: +:ldm_hash_rate_log+ frequency of inserting/looking up entries into the LDM hash table.
|
92
|
+
# Option: +:content_size_flag+ enables writing of content size into frame header (if known).
|
93
|
+
# Option: +:checksum_flag+ enables writing of 32-bits checksum of content at end of frame.
|
94
|
+
# Option: +:dict_id_flag+ enables writing of dictionary id into frame header.
|
95
|
+
# Option: +:nb_workers+ number of threads spawned in parallel.
|
96
|
+
# Option: +:job_size+ size of job (nb_workers >= 1).
|
97
|
+
# Option: +:overlap_log+ overlap size, as a fraction of window size.
|
98
|
+
# Option: +:dictionary+ chose dictionary.
|
99
|
+
# Returns processed compressor options.
|
46
100
|
def self.get_compressor_options(options, buffer_length_names)
|
47
101
|
Validation.validate_hash options
|
48
102
|
|
@@ -179,6 +233,12 @@ module ZSTDS
|
|
179
233
|
options
|
180
234
|
end
|
181
235
|
|
236
|
+
# Processes decompressor +options+ and +buffer_length_names+.
|
237
|
+
# Option: +:source_buffer_length+ source buffer length.
|
238
|
+
# Option: +:destination_buffer_length+ destination buffer length.
|
239
|
+
# Option: +:gvl+ enables global VM lock where possible.
|
240
|
+
# Option: +:window_log_max+ size limit (power of 2).
|
241
|
+
# Returns processed decompressor options.
|
182
242
|
def self.get_decompressor_options(options, buffer_length_names)
|
183
243
|
Validation.validate_hash options
|
184
244
|
|
@@ -1,97 +1,33 @@
|
|
1
1
|
# Ruby bindings for zstd library.
|
2
2
|
# Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
require "adsp/stream/raw/compressor"
|
4
5
|
require "zstds_ext"
|
5
6
|
|
6
|
-
require_relative "abstract"
|
7
|
-
require_relative "../../error"
|
8
7
|
require_relative "../../option"
|
9
8
|
require_relative "../../validation"
|
10
9
|
|
11
10
|
module ZSTDS
|
12
11
|
module Stream
|
13
12
|
module Raw
|
14
|
-
|
15
|
-
|
13
|
+
# ZSTDS::Stream::Raw::Compressor class.
|
14
|
+
class Compressor < ADSP::Stream::Raw::Compressor
|
15
|
+
# Current native compressor class.
|
16
|
+
NativeCompressor = Stream::NativeCompressor
|
16
17
|
|
18
|
+
# Current option class.
|
19
|
+
Option = ZSTDS::Option
|
20
|
+
|
21
|
+
# Initializes compressor.
|
22
|
+
# Option: +:destination_buffer_length+ destination buffer length.
|
23
|
+
# Option: +:pledged_size+ source bytesize.
|
17
24
|
def initialize(options = {})
|
18
25
|
options = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
|
19
26
|
|
20
27
|
pledged_size = options[:pledged_size]
|
21
28
|
Validation.validate_not_negative_integer pledged_size unless pledged_size.nil?
|
22
29
|
|
23
|
-
|
24
|
-
|
25
|
-
super native_stream
|
26
|
-
end
|
27
|
-
|
28
|
-
def write(source, &writer)
|
29
|
-
do_not_use_after_close
|
30
|
-
|
31
|
-
Validation.validate_string source
|
32
|
-
Validation.validate_proc writer
|
33
|
-
|
34
|
-
total_bytes_written = 0
|
35
|
-
|
36
|
-
loop do
|
37
|
-
bytes_written, need_more_destination = @native_stream.write source
|
38
|
-
total_bytes_written += bytes_written
|
39
|
-
|
40
|
-
if need_more_destination
|
41
|
-
source = source.byteslice bytes_written, source.bytesize - bytes_written
|
42
|
-
more_destination(&writer)
|
43
|
-
next
|
44
|
-
end
|
45
|
-
|
46
|
-
unless bytes_written == source.bytesize
|
47
|
-
# :nocov:
|
48
|
-
# Compressor write should eat all provided "source" without remainder.
|
49
|
-
raise UnexpectedError, "unexpected error"
|
50
|
-
# :nocov:
|
51
|
-
end
|
52
|
-
|
53
|
-
break
|
54
|
-
end
|
55
|
-
|
56
|
-
total_bytes_written
|
57
|
-
end
|
58
|
-
|
59
|
-
def flush(&writer)
|
60
|
-
do_not_use_after_close
|
61
|
-
|
62
|
-
Validation.validate_proc writer
|
63
|
-
|
64
|
-
loop do
|
65
|
-
need_more_destination = @native_stream.flush
|
66
|
-
|
67
|
-
if need_more_destination
|
68
|
-
more_destination(&writer)
|
69
|
-
next
|
70
|
-
end
|
71
|
-
|
72
|
-
break
|
73
|
-
end
|
74
|
-
|
75
|
-
super
|
76
|
-
end
|
77
|
-
|
78
|
-
def close(&writer)
|
79
|
-
return nil if closed?
|
80
|
-
|
81
|
-
Validation.validate_proc writer
|
82
|
-
|
83
|
-
loop do
|
84
|
-
need_more_destination = @native_stream.finish
|
85
|
-
|
86
|
-
if need_more_destination
|
87
|
-
more_destination(&writer)
|
88
|
-
next
|
89
|
-
end
|
90
|
-
|
91
|
-
break
|
92
|
-
end
|
93
|
-
|
94
|
-
super
|
30
|
+
super options
|
95
31
|
end
|
96
32
|
end
|
97
33
|
end
|
@@ -1,65 +1,21 @@
|
|
1
1
|
# Ruby bindings for zstd library.
|
2
2
|
# Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
require "adsp/stream/raw/decompressor"
|
4
5
|
require "zstds_ext"
|
5
6
|
|
6
|
-
require_relative "abstract"
|
7
7
|
require_relative "../../option"
|
8
|
-
require_relative "../../validation"
|
9
8
|
|
10
9
|
module ZSTDS
|
11
10
|
module Stream
|
12
11
|
module Raw
|
13
|
-
|
14
|
-
|
12
|
+
# ZSTDS::Stream::Raw::Decompressor class.
|
13
|
+
class Decompressor < ADSP::Stream::Raw::Decompressor
|
14
|
+
# Current native decompressor class.
|
15
|
+
NativeDecompressor = Stream::NativeDecompressor
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
native_stream = NativeDecompressor.new options
|
19
|
-
|
20
|
-
super native_stream
|
21
|
-
end
|
22
|
-
|
23
|
-
def read(source, &writer)
|
24
|
-
do_not_use_after_close
|
25
|
-
|
26
|
-
Validation.validate_string source
|
27
|
-
Validation.validate_proc writer
|
28
|
-
|
29
|
-
total_bytes_read = 0
|
30
|
-
|
31
|
-
loop do
|
32
|
-
bytes_read, need_more_destination = @native_stream.read source
|
33
|
-
total_bytes_read += bytes_read
|
34
|
-
|
35
|
-
if need_more_destination
|
36
|
-
source = source.byteslice bytes_read, source.bytesize - bytes_read
|
37
|
-
more_destination(&writer)
|
38
|
-
next
|
39
|
-
end
|
40
|
-
|
41
|
-
break
|
42
|
-
end
|
43
|
-
|
44
|
-
# Please remember that "total_bytes_read" can not be equal to "source.bytesize".
|
45
|
-
total_bytes_read
|
46
|
-
end
|
47
|
-
|
48
|
-
def flush(&writer)
|
49
|
-
do_not_use_after_close
|
50
|
-
|
51
|
-
Validation.validate_proc writer
|
52
|
-
|
53
|
-
super
|
54
|
-
end
|
55
|
-
|
56
|
-
def close(&writer)
|
57
|
-
return nil if closed?
|
58
|
-
|
59
|
-
Validation.validate_proc writer
|
60
|
-
|
61
|
-
super
|
62
|
-
end
|
17
|
+
# Current option class.
|
18
|
+
Option = ZSTDS::Option
|
63
19
|
end
|
64
20
|
end
|
65
21
|
end
|
data/lib/zstds/stream/reader.rb
CHANGED
@@ -1,186 +1,16 @@
|
|
1
1
|
# Ruby bindings for zstd library.
|
2
2
|
# Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
-
|
4
|
+
require "adsp/stream/reader"
|
5
|
+
|
5
6
|
require_relative "raw/decompressor"
|
6
|
-
require_relative "reader_helpers"
|
7
|
-
require_relative "../validation"
|
8
7
|
|
9
8
|
module ZSTDS
|
10
9
|
module Stream
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
def initialize(source_io, options = {}, *args)
|
17
|
-
@options = options
|
18
|
-
|
19
|
-
super source_io, *args
|
20
|
-
|
21
|
-
initialize_source_buffer_length
|
22
|
-
reset_io_remainder
|
23
|
-
reset_need_to_flush
|
24
|
-
|
25
|
-
@lineno = 0
|
26
|
-
end
|
27
|
-
|
28
|
-
protected def create_raw_stream
|
29
|
-
Raw::Decompressor.new @options
|
30
|
-
end
|
31
|
-
|
32
|
-
protected def initialize_source_buffer_length
|
33
|
-
source_buffer_length = @options[:source_buffer_length]
|
34
|
-
Validation.validate_not_negative_integer source_buffer_length unless source_buffer_length.nil?
|
35
|
-
|
36
|
-
if source_buffer_length.nil? || source_buffer_length.zero?
|
37
|
-
source_buffer_length = Buffer::DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR
|
38
|
-
end
|
39
|
-
|
40
|
-
@source_buffer_length = source_buffer_length
|
41
|
-
end
|
42
|
-
|
43
|
-
protected def reset_io_remainder
|
44
|
-
@io_remainder = ::String.new :encoding => ::Encoding::BINARY
|
45
|
-
end
|
46
|
-
|
47
|
-
protected def reset_need_to_flush
|
48
|
-
@need_to_flush = false
|
49
|
-
end
|
50
|
-
|
51
|
-
# -- synchronous --
|
52
|
-
|
53
|
-
def read(bytes_to_read = nil, out_buffer = nil)
|
54
|
-
Validation.validate_not_negative_integer bytes_to_read unless bytes_to_read.nil?
|
55
|
-
Validation.validate_string out_buffer unless out_buffer.nil?
|
56
|
-
|
57
|
-
unless bytes_to_read.nil?
|
58
|
-
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read.zero?
|
59
|
-
return nil if eof?
|
60
|
-
|
61
|
-
append_io_data @io.read(@source_buffer_length) while @buffer.bytesize < bytes_to_read && !@io.eof?
|
62
|
-
flush_io_data if @buffer.bytesize < bytes_to_read
|
63
|
-
|
64
|
-
return read_bytes_from_buffer bytes_to_read, out_buffer
|
65
|
-
end
|
66
|
-
|
67
|
-
append_io_data @io.read(@source_buffer_length) until @io.eof?
|
68
|
-
flush_io_data
|
69
|
-
|
70
|
-
read_buffer out_buffer
|
71
|
-
end
|
72
|
-
|
73
|
-
def rewind
|
74
|
-
raw_wrapper :close
|
75
|
-
|
76
|
-
reset_io_remainder
|
77
|
-
reset_need_to_flush
|
78
|
-
|
79
|
-
super
|
80
|
-
end
|
81
|
-
|
82
|
-
def close
|
83
|
-
raw_wrapper :close
|
84
|
-
|
85
|
-
super
|
86
|
-
end
|
87
|
-
|
88
|
-
def eof?
|
89
|
-
empty? && @io.eof?
|
90
|
-
end
|
91
|
-
|
92
|
-
# -- asynchronous --
|
93
|
-
|
94
|
-
def readpartial(bytes_to_read, out_buffer = nil)
|
95
|
-
read_more_nonblock(bytes_to_read, out_buffer) { @io.readpartial @source_buffer_length }
|
96
|
-
end
|
97
|
-
|
98
|
-
def read_nonblock(bytes_to_read, out_buffer = nil, *options)
|
99
|
-
read_more_nonblock(bytes_to_read, out_buffer) { @io.read_nonblock(@source_buffer_length, *options) }
|
100
|
-
end
|
101
|
-
|
102
|
-
protected def read_more_nonblock(bytes_to_read, out_buffer, &_block)
|
103
|
-
Validation.validate_not_negative_integer bytes_to_read
|
104
|
-
Validation.validate_string out_buffer unless out_buffer.nil?
|
105
|
-
|
106
|
-
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read.zero?
|
107
|
-
|
108
|
-
io_provided_eof_error = false
|
109
|
-
|
110
|
-
if @buffer.bytesize < bytes_to_read
|
111
|
-
begin
|
112
|
-
append_io_data yield
|
113
|
-
rescue ::EOFError
|
114
|
-
io_provided_eof_error = true
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
flush_io_data if @buffer.bytesize < bytes_to_read
|
119
|
-
raise ::EOFError if empty? && io_provided_eof_error
|
120
|
-
|
121
|
-
read_bytes_from_buffer bytes_to_read, out_buffer
|
122
|
-
end
|
123
|
-
|
124
|
-
# -- common --
|
125
|
-
|
126
|
-
protected def append_io_data(io_data)
|
127
|
-
io_portion = @io_remainder + io_data
|
128
|
-
bytes_read = raw_wrapper :read, io_portion
|
129
|
-
@io_remainder = io_portion.byteslice bytes_read, io_portion.bytesize - bytes_read
|
130
|
-
|
131
|
-
# Even empty io data may require flush.
|
132
|
-
@need_to_flush = true
|
133
|
-
end
|
134
|
-
|
135
|
-
protected def flush_io_data
|
136
|
-
raw_wrapper :flush
|
137
|
-
|
138
|
-
@need_to_flush = false
|
139
|
-
end
|
140
|
-
|
141
|
-
protected def empty?
|
142
|
-
!@need_to_flush && @buffer.bytesize.zero?
|
143
|
-
end
|
144
|
-
|
145
|
-
protected def read_bytes_from_buffer(bytes_to_read, out_buffer)
|
146
|
-
bytes_read = [@buffer.bytesize, bytes_to_read].min
|
147
|
-
|
148
|
-
# Result uses buffer binary encoding.
|
149
|
-
result = @buffer.byteslice 0, bytes_read
|
150
|
-
@buffer = @buffer.byteslice bytes_read, @buffer.bytesize - bytes_read
|
151
|
-
@pos += bytes_read
|
152
|
-
|
153
|
-
result = out_buffer.replace result unless out_buffer.nil?
|
154
|
-
result
|
155
|
-
end
|
156
|
-
|
157
|
-
protected def read_buffer(out_buffer)
|
158
|
-
result = @buffer
|
159
|
-
reset_buffer
|
160
|
-
@pos += result.bytesize
|
161
|
-
|
162
|
-
result.force_encoding @external_encoding unless @external_encoding.nil?
|
163
|
-
result = transcode_to_internal result
|
164
|
-
|
165
|
-
result = out_buffer.replace result unless out_buffer.nil?
|
166
|
-
result
|
167
|
-
end
|
168
|
-
|
169
|
-
protected def transcode_to_internal(data)
|
170
|
-
data = data.encode @internal_encoding, **@transcode_options unless @internal_encoding.nil?
|
171
|
-
data
|
172
|
-
end
|
173
|
-
|
174
|
-
# We should be able to return data back to buffer.
|
175
|
-
# We won't use any transcode options because transcoded data should be backward compatible.
|
176
|
-
protected def transcode_to_external(data)
|
177
|
-
data = data.encode @external_encoding unless @external_encoding.nil?
|
178
|
-
data
|
179
|
-
end
|
180
|
-
|
181
|
-
protected def raw_wrapper(method_name, *args)
|
182
|
-
@raw_stream.send(method_name, *args) { |portion| @buffer << portion }
|
183
|
-
end
|
10
|
+
# ZSTDS::Stream::Reader class.
|
11
|
+
class Reader < ADSP::Stream::Reader
|
12
|
+
# Current raw stream class.
|
13
|
+
RawDecompressor = Raw::Decompressor
|
184
14
|
end
|
185
15
|
end
|
186
16
|
end
|