ruby-lzws 1.0.0 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,8 @@
1
1
  # Ruby bindings for lzws library.
2
2
  # Copyright (c) 2019 AUTHORS, MIT License.
3
3
 
4
+ require "lzws_ext"
5
+
4
6
  require_relative "error"
5
7
  require_relative "validation"
6
8
 
@@ -8,11 +10,11 @@ module LZWS
8
10
  module Option
9
11
  # Default options will be compatible with UNIX compress.
10
12
 
13
+ DEFAULT_BUFFER_LENGTH = 0
11
14
  LOWEST_MAX_CODE_BIT_LENGTH = 9
12
15
  BIGGEST_MAX_CODE_BIT_LENGTH = 16
13
16
 
14
17
  DECOMPRESSOR_DEFAULTS = {
15
- :buffer_length => 0,
16
18
  :without_magic_header => false,
17
19
  :msb => false,
18
20
  :unaligned_bit_groups => false,
@@ -26,19 +28,19 @@ module LZWS
26
28
  )
27
29
  .freeze
28
30
 
29
- def self.get_compressor_options(options)
31
+ def self.get_compressor_options(options, buffer_length_names)
30
32
  Validation.validate_hash options
31
33
 
32
- options = COMPRESSOR_DEFAULTS.merge options
34
+ buffer_length_defaults = buffer_length_names.each_with_object({}) { |name, defaults| defaults[name] = DEFAULT_BUFFER_LENGTH }
35
+ options = COMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
33
36
 
34
- Validation.validate_not_negative_integer options[:buffer_length]
37
+ buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
35
38
 
36
39
  max_code_bit_length = options[:max_code_bit_length]
37
40
  Validation.validate_positive_integer max_code_bit_length
38
41
 
39
42
  raise ValidateError, "invalid max code bit length" if
40
- max_code_bit_length < LOWEST_MAX_CODE_BIT_LENGTH ||
41
- max_code_bit_length > BIGGEST_MAX_CODE_BIT_LENGTH
43
+ max_code_bit_length < LOWEST_MAX_CODE_BIT_LENGTH || max_code_bit_length > BIGGEST_MAX_CODE_BIT_LENGTH
42
44
 
43
45
  Validation.validate_bool options[:without_magic_header]
44
46
  Validation.validate_bool options[:block_mode]
@@ -49,12 +51,14 @@ module LZWS
49
51
  options
50
52
  end
51
53
 
52
- def self.get_decompressor_options(options)
54
+ def self.get_decompressor_options(options, buffer_length_names)
53
55
  Validation.validate_hash options
54
56
 
55
- options = DECOMPRESSOR_DEFAULTS.merge options
57
+ buffer_length_defaults = buffer_length_names.each_with_object({}) { |name, defaults| defaults[name] = DEFAULT_BUFFER_LENGTH }
58
+ options = DECOMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
59
+
60
+ buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
56
61
 
57
- Validation.validate_not_negative_integer options[:buffer_length]
58
62
  Validation.validate_bool options[:without_magic_header]
59
63
  Validation.validate_bool options[:msb]
60
64
  Validation.validate_bool options[:unaligned_bit_groups]
@@ -9,7 +9,7 @@ require_relative "../validation"
9
9
  module LZWS
10
10
  module Stream
11
11
  class Abstract
12
- # LZWS native stream is not seekable by design.
12
+ # Native stream is not seekable by design.
13
13
  # Related methods like "seek" and "pos=" can't be implemented.
14
14
 
15
15
  # It is not possible to maintain correspondance between bytes consumed from source and bytes written to destination by design.
@@ -21,18 +21,20 @@ module LZWS
21
21
  attr_reader :stat
22
22
  attr_reader :external_encoding
23
23
  attr_reader :internal_encoding
24
+ attr_reader :transcode_options
24
25
  attr_reader :pos
26
+
25
27
  alias tell pos
26
28
 
27
- def initialize(io, external_encoding: nil, internal_encoding: nil, transcode_options: {})
29
+ def initialize(io, options = {})
28
30
  @raw_stream = create_raw_stream
29
31
 
30
32
  Validation.validate_io io
31
33
  @io = io
32
34
 
33
- @stat = Stat.new @io.stat
35
+ @stat = Stat.new @io.stat if @io.respond_to? :stat
34
36
 
35
- set_encoding external_encoding, internal_encoding, transcode_options
37
+ set_encoding options[:external_encoding], options[:internal_encoding], options[:transcode_options]
36
38
  reset_buffer
37
39
  reset_io_advise
38
40
 
@@ -49,8 +51,8 @@ module LZWS
49
51
 
50
52
  protected def reset_io_advise
51
53
  # Both compressor and decompressor need sequential io access.
52
- @io.advise :sequential
53
- rescue ::Errno::ESPIPE # rubocop:disable Lint/HandleExceptions
54
+ @io.advise :sequential if @io.respond_to? :advise
55
+ rescue ::Errno::ESPIPE
54
56
  # ok
55
57
  end
56
58
 
@@ -115,7 +117,6 @@ module LZWS
115
117
 
116
118
  protected def target_encoding
117
119
  return @internal_encoding unless @internal_encoding.nil?
118
-
119
120
  return @external_encoding unless @external_encoding.nil?
120
121
 
121
122
  ::Encoding::BINARY
@@ -126,7 +127,8 @@ module LZWS
126
127
  def rewind
127
128
  @raw_stream = create_raw_stream
128
129
 
129
- @io.rewind
130
+ @io.rewind if @io.respond_to? :rewind
131
+
130
132
  reset_buffer
131
133
  reset_io_advise
132
134
 
@@ -4,6 +4,7 @@
4
4
  require "lzws_ext"
5
5
 
6
6
  require_relative "../../error"
7
+ require_relative "../../validation"
7
8
 
8
9
  module LZWS
9
10
  module Stream
@@ -14,19 +15,16 @@ module LZWS
14
15
  @is_closed = false
15
16
  end
16
17
 
17
- def close(&writer)
18
- return nil if @is_closed
18
+ # -- write --
19
19
 
20
- flush(&writer)
20
+ def flush(&writer)
21
+ do_not_use_after_close
21
22
 
22
- @native_stream.close
23
- @is_closed = true
23
+ Validation.validate_proc writer
24
24
 
25
- nil
26
- end
25
+ write_result(&writer)
27
26
 
28
- def closed?
29
- @is_closed
27
+ nil
30
28
  end
31
29
 
32
30
  protected def flush_destination_buffer(&writer)
@@ -40,6 +38,23 @@ module LZWS
40
38
 
41
39
  result.bytesize
42
40
  end
41
+
42
+ # -- close --
43
+
44
+ protected def do_not_use_after_close
45
+ raise UsedAfterCloseError, "used after close" if closed?
46
+ end
47
+
48
+ def close(&writer)
49
+ write_result(&writer)
50
+
51
+ @native_stream.close
52
+ @is_closed = true
53
+ end
54
+
55
+ def closed?
56
+ @is_closed
57
+ end
43
58
  end
44
59
  end
45
60
  end
@@ -12,13 +12,13 @@ module LZWS
12
12
  module Stream
13
13
  module Raw
14
14
  class Compressor < Abstract
15
+ BUFFER_LENGTH_NAMES = %i[destination_buffer_length].freeze
16
+
15
17
  def initialize(options = {})
16
- options = Option.get_compressor_options options
18
+ options = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
17
19
  native_stream = NativeCompressor.new options
18
20
 
19
21
  super native_stream
20
-
21
- @need_to_write_magic_header = !options[:without_magic_header]
22
22
  end
23
23
 
24
24
  def write(source, &writer)
@@ -27,11 +27,6 @@ module LZWS
27
27
  Validation.validate_string source
28
28
  Validation.validate_proc writer
29
29
 
30
- if @need_to_write_magic_header
31
- write_magic_header(&writer)
32
- @need_to_write_magic_header = false
33
- end
34
-
35
30
  total_bytes_written = 0
36
31
 
37
32
  loop do
@@ -45,8 +40,10 @@ module LZWS
45
40
  end
46
41
 
47
42
  unless bytes_written == source.bytesize
43
+ # :nocov:
48
44
  # Compressor write should eat all provided "source" without remainder.
49
45
  raise UnexpectedError, "unexpected error"
46
+ # :nocov:
50
47
  end
51
48
 
52
49
  break
@@ -55,28 +52,13 @@ module LZWS
55
52
  total_bytes_written
56
53
  end
57
54
 
58
- protected def write_magic_header(&writer)
59
- loop do
60
- need_more_destination = @native_stream.write_magic_header
61
-
62
- if need_more_destination
63
- flush_destination_buffer(&writer)
64
- next
65
- end
66
-
67
- break
68
- end
69
-
70
- nil
71
- end
72
-
73
- def flush(&writer)
74
- do_not_use_after_close
55
+ def close(&writer)
56
+ return nil if closed?
75
57
 
76
58
  Validation.validate_proc writer
77
59
 
78
60
  loop do
79
- need_more_destination = @native_stream.flush
61
+ need_more_destination = @native_stream.finish
80
62
 
81
63
  if need_more_destination
82
64
  flush_destination_buffer(&writer)
@@ -86,14 +68,10 @@ module LZWS
86
68
  break
87
69
  end
88
70
 
89
- write_result(&writer)
71
+ super
90
72
 
91
73
  nil
92
74
  end
93
-
94
- protected def do_not_use_after_close
95
- raise UsedAfterCloseError, "compressor used after close" if @is_closed
96
- end
97
75
  end
98
76
  end
99
77
  end
@@ -4,7 +4,6 @@
4
4
  require "lzws_ext"
5
5
 
6
6
  require_relative "abstract"
7
- require_relative "../../error"
8
7
  require_relative "../../option"
9
8
  require_relative "../../validation"
10
9
 
@@ -12,13 +11,13 @@ module LZWS
12
11
  module Stream
13
12
  module Raw
14
13
  class Decompressor < Abstract
14
+ BUFFER_LENGTH_NAMES = %i[destination_buffer_length].freeze
15
+
15
16
  def initialize(options = {})
16
- options = Option.get_decompressor_options options
17
+ options = Option.get_decompressor_options options, BUFFER_LENGTH_NAMES
17
18
  native_stream = NativeDecompressor.new options
18
19
 
19
20
  super native_stream
20
-
21
- @need_to_read_magic_header = !options[:without_magic_header]
22
21
  end
23
22
 
24
23
  def read(source, &writer)
@@ -29,19 +28,6 @@ module LZWS
29
28
 
30
29
  total_bytes_read = 0
31
30
 
32
- if @need_to_read_magic_header
33
- bytes_read = @native_stream.read_magic_header source
34
- if bytes_read == 0
35
- # Decompressor is not able to read full magic header.
36
- return 0
37
- end
38
-
39
- total_bytes_read += bytes_read
40
- source = source.byteslice bytes_read, source.bytesize - bytes_read
41
-
42
- @need_to_read_magic_header = false
43
- end
44
-
45
31
  loop do
46
32
  bytes_read, need_more_destination = @native_stream.read source
47
33
  total_bytes_read += bytes_read
@@ -59,19 +45,15 @@ module LZWS
59
45
  total_bytes_read
60
46
  end
61
47
 
62
- def flush(&writer)
63
- do_not_use_after_close
48
+ def close(&writer)
49
+ return nil if closed?
64
50
 
65
51
  Validation.validate_proc writer
66
52
 
67
- write_result(&writer)
53
+ super
68
54
 
69
55
  nil
70
56
  end
71
-
72
- protected def do_not_use_after_close
73
- raise UsedAfterCloseError, "decompressor used after close" if @is_closed
74
- end
75
57
  end
76
58
  end
77
59
  end
@@ -11,8 +11,6 @@ module LZWS
11
11
  class Reader < Abstract
12
12
  include ReaderHelpers
13
13
 
14
- DEFAULT_IO_PORTION_BYTESIZE = 1 << 15 # 32 KB
15
-
16
14
  attr_accessor :lineno
17
15
 
18
16
  def initialize(source_io, options = {}, *args)
@@ -20,17 +18,22 @@ module LZWS
20
18
 
21
19
  super source_io, *args
22
20
 
23
- io_portion_bytesize = @options[:io_portion_bytesize]
24
- @options.delete :io_portion_bytesize
25
-
26
- Validation.validate_positive_integer io_portion_bytesize unless io_portion_bytesize.nil?
27
- @io_portion_bytesize = io_portion_bytesize || DEFAULT_IO_PORTION_BYTESIZE
28
-
21
+ initialize_source_buffer_length
29
22
  reset_io_remainder
30
23
 
31
24
  @lineno = 0
32
25
  end
33
26
 
27
+ protected def initialize_source_buffer_length
28
+ source_buffer_length = @options[:source_buffer_length]
29
+ Validation.validate_not_negative_integer source_buffer_length unless source_buffer_length.nil?
30
+
31
+ source_buffer_length = Buffer::DEFAULT_SOURCE_BUFFER_LENGTH_FOR_DECOMPRESSOR \
32
+ if source_buffer_length == 0 || source_buffer_length.nil?
33
+
34
+ @source_buffer_length = source_buffer_length
35
+ end
36
+
34
37
  protected def create_raw_stream
35
38
  Raw::Decompressor.new @options
36
39
  end
@@ -50,12 +53,12 @@ module LZWS
50
53
  unless bytes_to_read.nil?
51
54
  return nil if eof?
52
55
 
53
- read_more_from_buffer until @buffer.bytesize >= bytes_to_read || @io.eof?
56
+ read_more_to_buffer until @buffer.bytesize >= bytes_to_read || @io.eof?
54
57
 
55
58
  return read_bytes_from_buffer bytes_to_read, out_buffer
56
59
  end
57
60
 
58
- read_more_from_buffer until @io.eof?
61
+ read_more_to_buffer until @io.eof?
59
62
 
60
63
  result = @buffer
61
64
  reset_buffer
@@ -68,21 +71,21 @@ module LZWS
68
71
  result
69
72
  end
70
73
 
71
- protected def read_more_from_buffer
72
- io_data = @io.read @io_portion_bytesize
74
+ protected def read_more_to_buffer
75
+ io_data = @io.read @source_buffer_length
73
76
  append_io_data_to_buffer io_data
74
77
  end
75
78
 
76
79
  def readpartial(bytes_to_read = nil, out_buffer = nil)
77
80
  raise ::EOFError if eof?
78
81
 
79
- readpartial_from_buffer until @buffer.bytesize >= bytes_to_read || @io.eof?
82
+ readpartial_to_buffer until @buffer.bytesize >= bytes_to_read || @io.eof?
80
83
 
81
84
  read_bytes_from_buffer bytes_to_read, out_buffer
82
85
  end
83
86
 
84
- protected def readpartial_from_buffer
85
- io_data = @io.readpartial @io_portion_bytesize
87
+ protected def readpartial_to_buffer
88
+ io_data = @io.readpartial @source_buffer_length
86
89
  append_io_data_to_buffer io_data
87
90
  end
88
91
 
@@ -105,13 +108,13 @@ module LZWS
105
108
  def read_nonblock(bytes_to_read, out_buffer = nil, *options)
106
109
  raise ::EOFError if eof?
107
110
 
108
- read_more_from_buffer_nonblock(*options) until @buffer.bytesize >= bytes_to_read || @io.eof?
111
+ read_more_to_buffer_nonblock(*options) until @buffer.bytesize >= bytes_to_read || @io.eof?
109
112
 
110
113
  read_bytes_from_buffer bytes_to_read, out_buffer
111
114
  end
112
115
 
113
- protected def read_more_from_buffer_nonblock(*options)
114
- io_data = @io.read_nonblock @io_portion_bytesize, *options
116
+ protected def read_more_to_buffer_nonblock(*options)
117
+ io_data = @io.read_nonblock @source_buffer_length, *options
115
118
  append_io_data_to_buffer io_data
116
119
  end
117
120
 
@@ -144,7 +147,7 @@ module LZWS
144
147
  end
145
148
 
146
149
  protected def transcode_to_internal(data)
147
- data = data.encode @internal_encoding, @transcode_options unless @internal_encoding.nil?
150
+ data = data.encode @internal_encoding, **@transcode_options unless @internal_encoding.nil?
148
151
  data
149
152
  end
150
153
 
@@ -1,6 +1,8 @@
1
1
  # Ruby bindings for lzws library.
2
2
  # Copyright (c) 2019 AUTHORS, MIT License.
3
3
 
4
+ require "English"
5
+
4
6
  require_relative "../validation"
5
7
 
6
8
  module LZWS
@@ -156,7 +158,7 @@ module LZWS
156
158
  protected def ungetstring(string)
157
159
  Validation.validate_string string
158
160
 
159
- string = ::String.new string, :encoding => @internal_encoding
161
+ string = ::String.new string, :encoding => @internal_encoding unless @internal_encoding.nil?
160
162
  string = transcode_to_external string unless @external_encoding.nil?
161
163
 
162
164
  string.force_encoding ::Encoding::BINARY
@@ -172,8 +174,8 @@ module LZWS
172
174
  Validation.validate_string file_path
173
175
  Validation.validate_proc block
174
176
 
175
- ::File.open file_path, "rb" do |file|
176
- reader = new file, *args
177
+ ::File.open file_path, "rb" do |io|
178
+ reader = new io, *args
177
179
 
178
180
  begin
179
181
  yield reader