ruby-brs 1.0.1 → 1.1.4
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/README.md +73 -71
- data/ext/brs_ext/buffer.c +17 -5
- data/ext/brs_ext/buffer.h +12 -0
- data/ext/brs_ext/common.h +3 -0
- data/ext/brs_ext/error.c +2 -3
- data/ext/brs_ext/error.h +1 -1
- data/ext/brs_ext/io.c +93 -77
- data/ext/brs_ext/main.c +0 -1
- data/ext/brs_ext/option.c +23 -19
- data/ext/brs_ext/option.h +9 -10
- data/ext/brs_ext/stream/compressor.c +22 -23
- data/ext/brs_ext/stream/compressor.h +3 -3
- data/ext/brs_ext/stream/decompressor.c +18 -20
- data/ext/brs_ext/stream/decompressor.h +3 -3
- data/ext/brs_ext/string.c +30 -45
- data/ext/extconf.rb +45 -30
- data/lib/brs.rb +1 -0
- data/lib/brs/file.rb +6 -0
- data/lib/brs/option.rb +14 -7
- data/lib/brs/stream/abstract.rb +9 -12
- data/lib/brs/stream/raw/abstract.rb +6 -2
- data/lib/brs/stream/raw/compressor.rb +10 -8
- data/lib/brs/stream/raw/decompressor.rb +1 -5
- data/lib/brs/stream/reader.rb +71 -52
- data/lib/brs/stream/reader_helpers.rb +2 -0
- data/lib/brs/stream/writer.rb +10 -5
- data/lib/brs/stream/writer_helpers.rb +8 -10
- data/lib/brs/string.rb +2 -0
- data/lib/brs/validation.rb +15 -2
- data/lib/brs/version.rb +1 -1
- metadata +63 -21
data/ext/extconf.rb
CHANGED
@@ -3,46 +3,52 @@
|
|
3
3
|
|
4
4
|
require "mkmf"
|
5
5
|
|
6
|
-
def require_header(name)
|
6
|
+
def require_header(name, types = [])
|
7
7
|
abort "Can't find #{name} header" unless find_header name
|
8
|
+
|
9
|
+
types.each do |type|
|
10
|
+
abort "Can't find #{type} type in #{name} header" unless find_type type, nil, name
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
|
-
require_header "brotli/
|
11
|
-
require_header "brotli/
|
14
|
+
require_header "brotli/types.h", %w[BROTLI_BOOL]
|
15
|
+
require_header "brotli/encode.h", ["BrotliEncoderState *", "BrotliEncoderMode"]
|
16
|
+
require_header "brotli/decode.h", ["BrotliDecoderState *", "BrotliDecoderResult", "BrotliDecoderErrorCode"]
|
12
17
|
|
13
18
|
def require_library(name, functions)
|
14
19
|
functions.each do |function|
|
15
|
-
abort "Can't find #{
|
20
|
+
abort "Can't find #{function} function in #{name} library" unless find_library name, function
|
16
21
|
end
|
17
22
|
end
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
require_library(
|
25
|
+
"brotlienc",
|
26
|
+
%w[
|
27
|
+
BrotliEncoderCreateInstance
|
28
|
+
BrotliEncoderSetParameter
|
29
|
+
BrotliEncoderCompressStream
|
30
|
+
BrotliEncoderHasMoreOutput
|
31
|
+
BrotliEncoderIsFinished
|
32
|
+
BrotliEncoderDestroyInstance
|
33
|
+
]
|
34
|
+
)
|
28
35
|
|
29
|
-
require_library
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
]
|
38
|
-
|
39
|
-
|
40
|
-
require_library "brotlidec", decoder_functions
|
36
|
+
require_library(
|
37
|
+
"brotlidec",
|
38
|
+
%w[
|
39
|
+
BrotliDecoderCreateInstance
|
40
|
+
BrotliDecoderSetParameter
|
41
|
+
BrotliDecoderDecompressStream
|
42
|
+
BrotliDecoderGetErrorCode
|
43
|
+
BrotliDecoderDestroyInstance
|
44
|
+
]
|
45
|
+
)
|
41
46
|
|
42
47
|
extension_name = "brs_ext".freeze
|
43
48
|
dir_config extension_name
|
44
49
|
|
45
|
-
|
50
|
+
# rubocop:disable Style/GlobalVars
|
51
|
+
$srcs = %w[
|
46
52
|
stream/compressor
|
47
53
|
stream/decompressor
|
48
54
|
buffer
|
@@ -52,14 +58,23 @@ sources = %w[
|
|
52
58
|
option
|
53
59
|
string
|
54
60
|
]
|
61
|
+
.map { |name| "src/#{extension_name}/#{name}.c" }
|
55
62
|
.freeze
|
56
63
|
|
57
|
-
#
|
58
|
-
$
|
59
|
-
.
|
60
|
-
.
|
64
|
+
# Removing library duplicates.
|
65
|
+
$libs = $libs.split(%r{\s})
|
66
|
+
.reject(&:empty?)
|
67
|
+
.sort
|
68
|
+
.uniq
|
69
|
+
.join " "
|
70
|
+
|
71
|
+
if ENV["CI"] || ENV["COVERAGE"]
|
72
|
+
$CFLAGS << " --coverage"
|
73
|
+
$LDFLAGS << " --coverage"
|
74
|
+
end
|
61
75
|
|
62
76
|
$CFLAGS << " -Wno-declaration-after-statement"
|
77
|
+
|
63
78
|
$VPATH << "$(srcdir)/#{extension_name}:$(srcdir)/#{extension_name}/stream"
|
64
79
|
# rubocop:enable Style/GlobalVars
|
65
80
|
|
data/lib/brs.rb
CHANGED
data/lib/brs/file.rb
CHANGED
@@ -17,9 +17,13 @@ module BRS
|
|
17
17
|
|
18
18
|
options = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
|
19
19
|
|
20
|
+
options[:size_hint] = ::File.size source
|
21
|
+
|
20
22
|
open_files(source, destination) do |source_io, destination_io|
|
21
23
|
BRS._native_compress_io source_io, destination_io, options
|
22
24
|
end
|
25
|
+
|
26
|
+
nil
|
23
27
|
end
|
24
28
|
|
25
29
|
def self.decompress(source, destination, options = {})
|
@@ -31,6 +35,8 @@ module BRS
|
|
31
35
|
open_files(source, destination) do |source_io, destination_io|
|
32
36
|
BRS._native_decompress_io source_io, destination_io, options
|
33
37
|
end
|
38
|
+
|
39
|
+
nil
|
34
40
|
end
|
35
41
|
|
36
42
|
private_class_method def self.open_files(source, destination, &_block)
|
data/lib/brs/option.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Ruby bindings for brotli library.
|
2
2
|
# Copyright (c) 2019 AUTHORS, MIT License.
|
3
3
|
|
4
|
+
require "brs_ext"
|
5
|
+
|
4
6
|
require_relative "error"
|
5
7
|
require_relative "validation"
|
6
8
|
|
@@ -14,7 +16,6 @@ module BRS
|
|
14
16
|
:lgwin => nil,
|
15
17
|
:lgblock => nil,
|
16
18
|
:disable_literal_context_modeling => nil,
|
17
|
-
:size_hint => nil,
|
18
19
|
:large_window => nil
|
19
20
|
}
|
20
21
|
.freeze
|
@@ -40,20 +41,26 @@ module BRS
|
|
40
41
|
end
|
41
42
|
|
42
43
|
quality = options[:quality]
|
43
|
-
|
44
|
+
unless quality.nil?
|
45
|
+
Validation.validate_not_negative_integer quality
|
46
|
+
raise ValidateError, "invalid quality" if quality < MIN_QUALITY || quality > MAX_QUALITY
|
47
|
+
end
|
44
48
|
|
45
49
|
lgwin = options[:lgwin]
|
46
|
-
|
50
|
+
unless lgwin.nil?
|
51
|
+
Validation.validate_not_negative_integer lgwin
|
52
|
+
raise ValidateError, "invalid lgwin" if lgwin < MIN_LGWIN || lgwin > MAX_LGWIN
|
53
|
+
end
|
47
54
|
|
48
55
|
lgblock = options[:lgblock]
|
49
|
-
|
56
|
+
unless lgblock.nil?
|
57
|
+
Validation.validate_not_negative_integer lgblock
|
58
|
+
raise ValidateError, "invalid lgblock" if lgblock < MIN_LGBLOCK || lgblock > MAX_LGBLOCK
|
59
|
+
end
|
50
60
|
|
51
61
|
disable_literal_context_modeling = options[:disable_literal_context_modeling]
|
52
62
|
Validation.validate_bool disable_literal_context_modeling unless disable_literal_context_modeling.nil?
|
53
63
|
|
54
|
-
size_hint = options[:size_hint]
|
55
|
-
Validation.validate_not_negative_integer size_hint unless size_hint.nil?
|
56
|
-
|
57
64
|
large_window = options[:large_window]
|
58
65
|
Validation.validate_bool large_window unless large_window.nil?
|
59
66
|
|
data/lib/brs/stream/abstract.rb
CHANGED
@@ -17,23 +17,19 @@ module BRS
|
|
17
17
|
|
18
18
|
include Delegates
|
19
19
|
|
20
|
-
attr_reader :io
|
21
|
-
|
22
|
-
attr_reader :external_encoding
|
23
|
-
attr_reader :internal_encoding
|
24
|
-
attr_reader :transcode_options
|
25
|
-
attr_reader :pos
|
20
|
+
attr_reader :io, :stat, :external_encoding, :internal_encoding, :transcode_options, :pos
|
21
|
+
|
26
22
|
alias tell pos
|
27
23
|
|
28
|
-
def initialize(io,
|
24
|
+
def initialize(io, options = {})
|
29
25
|
@raw_stream = create_raw_stream
|
30
26
|
|
31
27
|
Validation.validate_io io
|
32
28
|
@io = io
|
33
29
|
|
34
|
-
@stat = Stat.new @io.stat
|
30
|
+
@stat = Stat.new @io.stat if @io.respond_to? :stat
|
35
31
|
|
36
|
-
set_encoding external_encoding, internal_encoding, transcode_options
|
32
|
+
set_encoding options[:external_encoding], options[:internal_encoding], options[:transcode_options]
|
37
33
|
reset_buffer
|
38
34
|
reset_io_advise
|
39
35
|
|
@@ -50,8 +46,8 @@ module BRS
|
|
50
46
|
|
51
47
|
protected def reset_io_advise
|
52
48
|
# Both compressor and decompressor need sequential io access.
|
53
|
-
@io.advise :sequential
|
54
|
-
rescue ::Errno::ESPIPE
|
49
|
+
@io.advise :sequential if @io.respond_to? :advise
|
50
|
+
rescue ::Errno::ESPIPE
|
55
51
|
# ok
|
56
52
|
end
|
57
53
|
|
@@ -126,7 +122,8 @@ module BRS
|
|
126
122
|
def rewind
|
127
123
|
@raw_stream = create_raw_stream
|
128
124
|
|
129
|
-
@io.rewind
|
125
|
+
@io.rewind if @io.respond_to? :rewind
|
126
|
+
|
130
127
|
reset_buffer
|
131
128
|
reset_io_advise
|
132
129
|
|
@@ -19,11 +19,13 @@ module BRS
|
|
19
19
|
|
20
20
|
def flush(&writer)
|
21
21
|
write_result(&writer)
|
22
|
+
|
23
|
+
nil
|
22
24
|
end
|
23
25
|
|
24
|
-
protected def
|
26
|
+
protected def more_destination(&writer)
|
25
27
|
result_bytesize = write_result(&writer)
|
26
|
-
raise NotEnoughDestinationError, "not enough destination" if result_bytesize
|
28
|
+
raise NotEnoughDestinationError, "not enough destination" if result_bytesize.zero?
|
27
29
|
end
|
28
30
|
|
29
31
|
protected def write_result(&_writer)
|
@@ -44,6 +46,8 @@ module BRS
|
|
44
46
|
|
45
47
|
@native_stream.close
|
46
48
|
@is_closed = true
|
49
|
+
|
50
|
+
nil
|
47
51
|
end
|
48
52
|
|
49
53
|
def closed?
|
@@ -15,7 +15,11 @@ module BRS
|
|
15
15
|
BUFFER_LENGTH_NAMES = %i[destination_buffer_length].freeze
|
16
16
|
|
17
17
|
def initialize(options = {})
|
18
|
-
options
|
18
|
+
options = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
|
19
|
+
|
20
|
+
size_hint = options[:size_hint]
|
21
|
+
Validation.validate_not_negative_integer size_hint unless size_hint.nil?
|
22
|
+
|
19
23
|
native_stream = NativeCompressor.new options
|
20
24
|
|
21
25
|
super native_stream
|
@@ -35,13 +39,15 @@ module BRS
|
|
35
39
|
|
36
40
|
if need_more_destination
|
37
41
|
source = source.byteslice bytes_written, source.bytesize - bytes_written
|
38
|
-
|
42
|
+
more_destination(&writer)
|
39
43
|
next
|
40
44
|
end
|
41
45
|
|
42
46
|
unless bytes_written == source.bytesize
|
47
|
+
# :nocov:
|
43
48
|
# Compressor write should eat all provided "source" without remainder.
|
44
49
|
raise UnexpectedError, "unexpected error"
|
50
|
+
# :nocov:
|
45
51
|
end
|
46
52
|
|
47
53
|
break
|
@@ -59,7 +65,7 @@ module BRS
|
|
59
65
|
need_more_destination = @native_stream.flush
|
60
66
|
|
61
67
|
if need_more_destination
|
62
|
-
|
68
|
+
more_destination(&writer)
|
63
69
|
next
|
64
70
|
end
|
65
71
|
|
@@ -67,8 +73,6 @@ module BRS
|
|
67
73
|
end
|
68
74
|
|
69
75
|
super
|
70
|
-
|
71
|
-
nil
|
72
76
|
end
|
73
77
|
|
74
78
|
def close(&writer)
|
@@ -80,7 +84,7 @@ module BRS
|
|
80
84
|
need_more_destination = @native_stream.finish
|
81
85
|
|
82
86
|
if need_more_destination
|
83
|
-
|
87
|
+
more_destination(&writer)
|
84
88
|
next
|
85
89
|
end
|
86
90
|
|
@@ -88,8 +92,6 @@ module BRS
|
|
88
92
|
end
|
89
93
|
|
90
94
|
super
|
91
|
-
|
92
|
-
nil
|
93
95
|
end
|
94
96
|
end
|
95
97
|
end
|
@@ -34,7 +34,7 @@ module BRS
|
|
34
34
|
|
35
35
|
if need_more_destination
|
36
36
|
source = source.byteslice bytes_read, source.bytesize - bytes_read
|
37
|
-
|
37
|
+
more_destination(&writer)
|
38
38
|
next
|
39
39
|
end
|
40
40
|
|
@@ -51,8 +51,6 @@ module BRS
|
|
51
51
|
Validation.validate_proc writer
|
52
52
|
|
53
53
|
super
|
54
|
-
|
55
|
-
nil
|
56
54
|
end
|
57
55
|
|
58
56
|
def close(&writer)
|
@@ -61,8 +59,6 @@ module BRS
|
|
61
59
|
Validation.validate_proc writer
|
62
60
|
|
63
61
|
super
|
64
|
-
|
65
|
-
nil
|
66
62
|
end
|
67
63
|
end
|
68
64
|
end
|
data/lib/brs/stream/reader.rb
CHANGED
@@ -20,79 +20,60 @@ module BRS
|
|
20
20
|
|
21
21
|
initialize_source_buffer_length
|
22
22
|
reset_io_remainder
|
23
|
+
reset_need_to_flush
|
23
24
|
|
24
25
|
@lineno = 0
|
25
26
|
end
|
26
27
|
|
28
|
+
protected def create_raw_stream
|
29
|
+
Raw::Decompressor.new @options
|
30
|
+
end
|
31
|
+
|
27
32
|
protected def initialize_source_buffer_length
|
28
33
|
source_buffer_length = @options[:source_buffer_length]
|
29
34
|
Validation.validate_not_negative_integer source_buffer_length unless source_buffer_length.nil?
|
30
35
|
|
31
36
|
source_buffer_length = Buffer::DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR \
|
32
|
-
if source_buffer_length
|
37
|
+
if source_buffer_length.nil? || source_buffer_length.zero?
|
33
38
|
|
34
39
|
@source_buffer_length = source_buffer_length
|
35
40
|
end
|
36
41
|
|
37
|
-
protected def create_raw_stream
|
38
|
-
Raw::Decompressor.new @options
|
39
|
-
end
|
40
|
-
|
41
42
|
protected def reset_io_remainder
|
42
43
|
@io_remainder = ::String.new :encoding => ::Encoding::BINARY
|
43
44
|
end
|
44
45
|
|
46
|
+
protected def reset_need_to_flush
|
47
|
+
@need_to_flush = false
|
48
|
+
end
|
49
|
+
|
45
50
|
# -- synchronous --
|
46
51
|
|
47
52
|
def read(bytes_to_read = nil, out_buffer = nil)
|
48
53
|
Validation.validate_not_negative_integer bytes_to_read unless bytes_to_read.nil?
|
49
54
|
Validation.validate_string out_buffer unless out_buffer.nil?
|
50
55
|
|
51
|
-
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read == 0
|
52
|
-
|
53
56
|
unless bytes_to_read.nil?
|
57
|
+
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read.zero?
|
54
58
|
return nil if eof?
|
55
59
|
|
56
|
-
|
60
|
+
append_io_data @io.read(@source_buffer_length) while @buffer.bytesize < bytes_to_read && !@io.eof?
|
61
|
+
flush_io_data if @buffer.bytesize < bytes_to_read
|
57
62
|
|
58
63
|
return read_bytes_from_buffer bytes_to_read, out_buffer
|
59
64
|
end
|
60
65
|
|
61
|
-
|
62
|
-
|
63
|
-
result = @buffer
|
64
|
-
reset_buffer
|
65
|
-
@pos += result.bytesize
|
66
|
+
append_io_data @io.read(@source_buffer_length) until @io.eof?
|
67
|
+
flush_io_data
|
66
68
|
|
67
|
-
|
68
|
-
result = transcode_to_internal result
|
69
|
-
result = out_buffer.replace result unless out_buffer.nil?
|
70
|
-
|
71
|
-
result
|
72
|
-
end
|
73
|
-
|
74
|
-
protected def read_more_from_buffer
|
75
|
-
io_data = @io.read @source_buffer_length
|
76
|
-
append_io_data_to_buffer io_data
|
77
|
-
end
|
78
|
-
|
79
|
-
def readpartial(bytes_to_read = nil, out_buffer = nil)
|
80
|
-
raise ::EOFError if eof?
|
81
|
-
|
82
|
-
readpartial_from_buffer until @buffer.bytesize >= bytes_to_read || @io.eof?
|
83
|
-
|
84
|
-
read_bytes_from_buffer bytes_to_read, out_buffer
|
85
|
-
end
|
86
|
-
|
87
|
-
protected def readpartial_from_buffer
|
88
|
-
io_data = @io.readpartial @source_buffer_length
|
89
|
-
append_io_data_to_buffer io_data
|
69
|
+
read_buffer out_buffer
|
90
70
|
end
|
91
71
|
|
92
72
|
def rewind
|
93
73
|
raw_wrapper :close
|
94
74
|
|
95
75
|
reset_io_remainder
|
76
|
+
reset_need_to_flush
|
96
77
|
|
97
78
|
super
|
98
79
|
end
|
@@ -103,25 +84,61 @@ module BRS
|
|
103
84
|
super
|
104
85
|
end
|
105
86
|
|
87
|
+
def eof?
|
88
|
+
empty? && @io.eof?
|
89
|
+
end
|
90
|
+
|
106
91
|
# -- asynchronous --
|
107
92
|
|
93
|
+
def readpartial(bytes_to_read, out_buffer = nil)
|
94
|
+
read_more_nonblock(bytes_to_read, out_buffer) { @io.readpartial @source_buffer_length }
|
95
|
+
end
|
96
|
+
|
108
97
|
def read_nonblock(bytes_to_read, out_buffer = nil, *options)
|
109
|
-
|
98
|
+
read_more_nonblock(bytes_to_read, out_buffer) { @io.read_nonblock(@source_buffer_length, *options) }
|
99
|
+
end
|
100
|
+
|
101
|
+
protected def read_more_nonblock(bytes_to_read, out_buffer, &_block)
|
102
|
+
Validation.validate_not_negative_integer bytes_to_read
|
103
|
+
Validation.validate_string out_buffer unless out_buffer.nil?
|
104
|
+
|
105
|
+
return ::String.new :encoding => ::Encoding::BINARY if bytes_to_read.zero?
|
106
|
+
|
107
|
+
io_provided_eof_error = false
|
110
108
|
|
111
|
-
|
109
|
+
if @buffer.bytesize < bytes_to_read
|
110
|
+
begin
|
111
|
+
append_io_data yield
|
112
|
+
rescue ::EOFError
|
113
|
+
io_provided_eof_error = true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
flush_io_data if @buffer.bytesize < bytes_to_read
|
118
|
+
raise ::EOFError if empty? && io_provided_eof_error
|
112
119
|
|
113
120
|
read_bytes_from_buffer bytes_to_read, out_buffer
|
114
121
|
end
|
115
122
|
|
116
|
-
|
117
|
-
|
118
|
-
|
123
|
+
# -- common --
|
124
|
+
|
125
|
+
protected def append_io_data(io_data)
|
126
|
+
io_portion = @io_remainder + io_data
|
127
|
+
bytes_read = raw_wrapper :read, io_portion
|
128
|
+
@io_remainder = io_portion.byteslice bytes_read, io_portion.bytesize - bytes_read
|
129
|
+
|
130
|
+
# Even empty io data may require flush.
|
131
|
+
@need_to_flush = true
|
119
132
|
end
|
120
133
|
|
121
|
-
|
134
|
+
protected def flush_io_data
|
135
|
+
raw_wrapper :flush
|
122
136
|
|
123
|
-
|
124
|
-
|
137
|
+
@need_to_flush = false
|
138
|
+
end
|
139
|
+
|
140
|
+
protected def empty?
|
141
|
+
!@need_to_flush && @buffer.bytesize.zero?
|
125
142
|
end
|
126
143
|
|
127
144
|
protected def read_bytes_from_buffer(bytes_to_read, out_buffer)
|
@@ -136,18 +153,20 @@ module BRS
|
|
136
153
|
result
|
137
154
|
end
|
138
155
|
|
139
|
-
protected def
|
140
|
-
|
141
|
-
|
142
|
-
@
|
156
|
+
protected def read_buffer(out_buffer)
|
157
|
+
result = @buffer
|
158
|
+
reset_buffer
|
159
|
+
@pos += result.bytesize
|
143
160
|
|
144
|
-
|
145
|
-
|
146
|
-
|
161
|
+
result.force_encoding @external_encoding unless @external_encoding.nil?
|
162
|
+
result = transcode_to_internal result
|
163
|
+
|
164
|
+
result = out_buffer.replace result unless out_buffer.nil?
|
165
|
+
result
|
147
166
|
end
|
148
167
|
|
149
168
|
protected def transcode_to_internal(data)
|
150
|
-
data = data.encode @internal_encoding,
|
169
|
+
data = data.encode @internal_encoding, **@transcode_options unless @internal_encoding.nil?
|
151
170
|
data
|
152
171
|
end
|
153
172
|
|