ruby-brs 1.0.1 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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/encode.h"
11
- require_header "brotli/decode.h"
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 #{name} library and #{function} function" unless find_library name, function
20
+ abort "Can't find #{function} function in #{name} library" unless find_library name, function
16
21
  end
17
22
  end
18
23
 
19
- encoder_functions = %w[
20
- BrotliEncoderCreateInstance
21
- BrotliEncoderSetParameter
22
- BrotliEncoderCompressStream
23
- BrotliEncoderHasMoreOutput
24
- BrotliEncoderIsFinished
25
- BrotliEncoderDestroyInstance
26
- ]
27
- .freeze
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 "brotlienc", encoder_functions
30
-
31
- decoder_functions = %w[
32
- BrotliDecoderCreateInstance
33
- BrotliDecoderSetParameter
34
- BrotliDecoderDecompressStream
35
- BrotliDecoderGetErrorCode
36
- BrotliDecoderDestroyInstance
37
- ]
38
- .freeze
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
- sources = %w[
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
- # rubocop:disable Style/GlobalVars
58
- $srcs = sources
59
- .map { |name| "src/#{extension_name}/#{name}.c" }
60
- .freeze
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
@@ -5,3 +5,4 @@ require_relative "brs/stream/reader"
5
5
  require_relative "brs/stream/writer"
6
6
  require_relative "brs/file"
7
7
  require_relative "brs/string"
8
+ require_relative "brs/version"
@@ -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)
@@ -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
- Validation.validate_not_negative_integer quality unless quality.nil?
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
- Validation.validate_not_negative_integer lgwin unless lgwin.nil?
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
- Validation.validate_not_negative_integer lgblock unless lgblock.nil?
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
 
@@ -17,23 +17,19 @@ module BRS
17
17
 
18
18
  include Delegates
19
19
 
20
- attr_reader :io
21
- attr_reader :stat
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, external_encoding: nil, internal_encoding: nil, transcode_options: {})
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 # rubocop:disable Lint/HandleExceptions
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 flush_destination_buffer(&writer)
26
+ protected def more_destination(&writer)
25
27
  result_bytesize = write_result(&writer)
26
- raise NotEnoughDestinationError, "not enough destination" if result_bytesize == 0
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 = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
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
- flush_destination_buffer(&writer)
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
- flush_destination_buffer(&writer)
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
- flush_destination_buffer(&writer)
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
- flush_destination_buffer(&writer)
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
@@ -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 == 0 || source_buffer_length.nil?
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
- read_more_from_buffer until @buffer.bytesize >= bytes_to_read || @io.eof?
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
- read_more_from_buffer until @io.eof?
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
- result.force_encoding @external_encoding unless @external_encoding.nil?
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
- raise ::EOFError if eof?
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
- read_more_from_buffer_nonblock(*options) until @buffer.bytesize >= bytes_to_read || @io.eof?
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
- protected def read_more_from_buffer_nonblock(*options)
117
- io_data = @io.read_nonblock @source_buffer_length, *options
118
- append_io_data_to_buffer io_data
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
- # -- common --
134
+ protected def flush_io_data
135
+ raw_wrapper :flush
122
136
 
123
- def eof?
124
- @io.eof? && @buffer.bytesize == 0
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 append_io_data_to_buffer(io_data)
140
- io_portion = @io_remainder + io_data
141
- bytes_read = raw_wrapper :read, io_portion
142
- @io_remainder = io_portion.byteslice bytes_read, io_portion.bytesize - bytes_read
156
+ protected def read_buffer(out_buffer)
157
+ result = @buffer
158
+ reset_buffer
159
+ @pos += result.bytesize
143
160
 
144
- # We should just ignore case when "io.eof?" appears but "io_remainder" is not empty.
145
- # Ancient compress implementations can write bytes from not initialized buffer parts to output.
146
- raw_wrapper :flush if @io.eof?
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, @transcode_options unless @internal_encoding.nil?
169
+ data = data.encode @internal_encoding, **@transcode_options unless @internal_encoding.nil?
151
170
  data
152
171
  end
153
172