multi_compress 0.2.4 → 0.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/CHANGELOG.md +25 -2
- data/GET_STARTED.md +863 -0
- data/README.md +15 -19
- data/ext/multi_compress/extconf.rb +2 -0
- data/ext/multi_compress/multi_compress.c +683 -245
- data/lib/multi_compress/version.rb +1 -1
- data/lib/multi_compress.rb +104 -21
- metadata +2 -1
data/lib/multi_compress.rb
CHANGED
|
@@ -21,6 +21,9 @@ module MultiCompress
|
|
|
21
21
|
DEFAULT = :default
|
|
22
22
|
BEST = :best
|
|
23
23
|
|
|
24
|
+
DEFAULT_MAX_OUTPUT_SIZE = 512 * 1024 * 1024
|
|
25
|
+
DEFAULT_STREAMING_MAX_OUTPUT_SIZE = 2 * 1024 * 1024 * 1024
|
|
26
|
+
|
|
24
27
|
EXTENSION_MAP = {
|
|
25
28
|
".zst" => :zstd,
|
|
26
29
|
".zstd" => :zstd,
|
|
@@ -30,24 +33,95 @@ module MultiCompress
|
|
|
30
33
|
|
|
31
34
|
private_constant :EXTENSION_MAP
|
|
32
35
|
|
|
36
|
+
class Config
|
|
37
|
+
attr_reader :max_output_size, :streaming_max_output_size
|
|
38
|
+
|
|
39
|
+
def initialize
|
|
40
|
+
reset!
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def max_output_size=(value)
|
|
44
|
+
@max_output_size = normalize_limit(value, :max_output_size, DEFAULT_MAX_OUTPUT_SIZE)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def streaming_max_output_size=(value)
|
|
48
|
+
@streaming_max_output_size = normalize_limit(
|
|
49
|
+
value,
|
|
50
|
+
:streaming_max_output_size,
|
|
51
|
+
DEFAULT_STREAMING_MAX_OUTPUT_SIZE
|
|
52
|
+
)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def reset!
|
|
56
|
+
@max_output_size = DEFAULT_MAX_OUTPUT_SIZE
|
|
57
|
+
@streaming_max_output_size = DEFAULT_STREAMING_MAX_OUTPUT_SIZE
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def dup
|
|
62
|
+
copy = self.class.new
|
|
63
|
+
copy.max_output_size = max_output_size
|
|
64
|
+
copy.streaming_max_output_size = streaming_max_output_size
|
|
65
|
+
copy
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def normalize_limit(value, name, default)
|
|
71
|
+
return default if value.nil?
|
|
72
|
+
raise TypeError, "#{name} must be an Integer" unless value.respond_to?(:to_int)
|
|
73
|
+
|
|
74
|
+
limit = value.to_int
|
|
75
|
+
raise ArgumentError, "#{name} must be greater than 0" if limit <= 0
|
|
76
|
+
|
|
77
|
+
limit
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class << self
|
|
82
|
+
def config
|
|
83
|
+
@config ||= Config.new
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def configure
|
|
87
|
+
return config unless block_given?
|
|
88
|
+
|
|
89
|
+
yield(config)
|
|
90
|
+
config
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
unless private_method_defined?(:_c_decompress)
|
|
94
|
+
alias_method :_c_decompress, :decompress
|
|
95
|
+
private :_c_decompress
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
33
99
|
def self.zstd(data, level: nil)
|
|
34
100
|
compress(data, algo: :zstd, **level_opts(level))
|
|
35
101
|
end
|
|
36
102
|
|
|
37
|
-
def self.lz4(data, level: nil)
|
|
38
|
-
|
|
103
|
+
def self.lz4(data, level: nil, format: nil)
|
|
104
|
+
opts = level_opts(level)
|
|
105
|
+
opts[:format] = format if format
|
|
106
|
+
compress(data, algo: :lz4, **opts)
|
|
39
107
|
end
|
|
40
108
|
|
|
41
109
|
def self.brotli(data, level: nil)
|
|
42
110
|
compress(data, algo: :brotli, **level_opts(level))
|
|
43
111
|
end
|
|
44
112
|
|
|
113
|
+
def self.decompress(data, **opts)
|
|
114
|
+
_c_decompress(data, **resolved_one_shot_options(opts))
|
|
115
|
+
end
|
|
116
|
+
|
|
45
117
|
def self.zstd_decompress(data)
|
|
46
118
|
decompress(data, algo: :zstd)
|
|
47
119
|
end
|
|
48
120
|
|
|
49
|
-
def self.lz4_decompress(data)
|
|
50
|
-
|
|
121
|
+
def self.lz4_decompress(data, format: nil)
|
|
122
|
+
opts = { algo: :lz4 }
|
|
123
|
+
opts[:format] = format if format
|
|
124
|
+
decompress(data, **opts)
|
|
51
125
|
end
|
|
52
126
|
|
|
53
127
|
def self.brotli_decompress(data)
|
|
@@ -62,11 +136,24 @@ module MultiCompress
|
|
|
62
136
|
level ? { level: level } : {}
|
|
63
137
|
end
|
|
64
138
|
|
|
65
|
-
|
|
139
|
+
def self.resolved_one_shot_options(opts)
|
|
140
|
+
resolved = opts.dup
|
|
141
|
+
resolved[:max_output_size] = config.max_output_size unless resolved.key?(:max_output_size)
|
|
142
|
+
resolved
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private_class_method :level_opts, :resolved_one_shot_options
|
|
146
|
+
|
|
147
|
+
module InflaterDefaults
|
|
148
|
+
def initialize(*args, **opts)
|
|
149
|
+
resolved = opts.dup
|
|
150
|
+
resolved[:max_output_size] = MultiCompress.config.streaming_max_output_size unless resolved.key?(:max_output_size)
|
|
151
|
+
super(*args, **resolved)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
Inflater.prepend(InflaterDefaults)
|
|
66
156
|
|
|
67
|
-
# Streaming compressed writer.
|
|
68
|
-
#
|
|
69
|
-
# Supports block form via +Writer.open+ or manual lifecycle management.
|
|
70
157
|
class Writer
|
|
71
158
|
CHUNK_BUFFER_SIZE = 8192
|
|
72
159
|
|
|
@@ -125,7 +212,7 @@ module MultiCompress
|
|
|
125
212
|
end
|
|
126
213
|
|
|
127
214
|
def puts(*args)
|
|
128
|
-
args.each do |arg|
|
|
215
|
+
args.flatten.each do |arg|
|
|
129
216
|
str = arg.to_s
|
|
130
217
|
write(str)
|
|
131
218
|
write("\n") unless str.end_with?("\n")
|
|
@@ -159,15 +246,12 @@ module MultiCompress
|
|
|
159
246
|
private_class_method :resolve_io
|
|
160
247
|
end
|
|
161
248
|
|
|
162
|
-
# Streaming compressed reader.
|
|
163
|
-
#
|
|
164
|
-
# Supports block form via +Reader.open+ or manual lifecycle management.
|
|
165
249
|
class Reader
|
|
166
250
|
CHUNK_SIZE = 8192
|
|
167
251
|
|
|
168
|
-
def self.open(path_or_io, algo: nil, dictionary: nil,
|
|
252
|
+
def self.open(path_or_io, algo: nil, dictionary: nil, **opts, &block)
|
|
169
253
|
io, algo, owned = resolve_io(path_or_io, algo, mode: "rb")
|
|
170
|
-
reader = new(io, algo: algo, dictionary: dictionary,
|
|
254
|
+
reader = new(io, algo: algo, dictionary: dictionary, **opts)
|
|
171
255
|
reader.instance_variable_set(:@owned_io, owned)
|
|
172
256
|
|
|
173
257
|
return reader unless block
|
|
@@ -179,9 +263,9 @@ module MultiCompress
|
|
|
179
263
|
end
|
|
180
264
|
end
|
|
181
265
|
|
|
182
|
-
def initialize(io, algo: nil, dictionary: nil,
|
|
266
|
+
def initialize(io, algo: nil, dictionary: nil, **opts)
|
|
183
267
|
@io = io
|
|
184
|
-
@inflater = Inflater.new(algo: algo, dictionary: dictionary,
|
|
268
|
+
@inflater = Inflater.new(algo: algo, dictionary: dictionary, **opts)
|
|
185
269
|
@closed = false
|
|
186
270
|
@owned_io = false
|
|
187
271
|
@buffer = +""
|
|
@@ -237,7 +321,6 @@ module MultiCompress
|
|
|
237
321
|
|
|
238
322
|
while (chunk = read(size))
|
|
239
323
|
yield chunk
|
|
240
|
-
break if chunk.bytesize < size
|
|
241
324
|
end
|
|
242
325
|
end
|
|
243
326
|
|
|
@@ -272,7 +355,7 @@ module MultiCompress
|
|
|
272
355
|
end
|
|
273
356
|
|
|
274
357
|
def read_exactly(length)
|
|
275
|
-
return
|
|
358
|
+
return nil if @eof && @buffer.empty?
|
|
276
359
|
|
|
277
360
|
fill_buffer_until { @buffer.bytesize >= length }
|
|
278
361
|
|
|
@@ -298,9 +381,9 @@ module MultiCompress
|
|
|
298
381
|
end
|
|
299
382
|
|
|
300
383
|
def extract_line(separator)
|
|
301
|
-
idx
|
|
302
|
-
result = @buffer[0
|
|
303
|
-
@buffer = @buffer[(idx +
|
|
384
|
+
idx = @buffer.index(separator)
|
|
385
|
+
result = @buffer[0, idx + separator.bytesize]
|
|
386
|
+
@buffer = @buffer[(idx + separator.bytesize)..] || +""
|
|
304
387
|
result
|
|
305
388
|
end
|
|
306
389
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: multi_compress
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Roman Haydarov
|
|
@@ -78,6 +78,7 @@ extensions:
|
|
|
78
78
|
extra_rdoc_files: []
|
|
79
79
|
files:
|
|
80
80
|
- CHANGELOG.md
|
|
81
|
+
- GET_STARTED.md
|
|
81
82
|
- LICENSE.txt
|
|
82
83
|
- README.md
|
|
83
84
|
- ext/multi_compress/extconf.rb
|