ruby-lzws 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,6 +5,8 @@
5
5
  #define LZWS_EXT_STREAM_DECOMPRESSOR_H
6
6
 
7
7
  #include <lzws/decompressor/state.h>
8
+ #include <stdint.h>
9
+ #include <stdlib.h>
8
10
 
9
11
  #include "ruby.h"
10
12
 
@@ -18,9 +20,10 @@ typedef struct {
18
20
 
19
21
  VALUE lzws_ext_allocate_decompressor(VALUE klass);
20
22
  VALUE lzws_ext_initialize_decompressor(VALUE self, VALUE options);
21
- VALUE lzws_ext_decompressor_read_magic_header(VALUE self, VALUE source);
22
23
  VALUE lzws_ext_decompress(VALUE self, VALUE source);
23
24
  VALUE lzws_ext_decompressor_read_result(VALUE self);
24
25
  VALUE lzws_ext_decompressor_close(VALUE self);
25
26
 
27
+ void lzws_ext_decompressor_exports(VALUE root_module);
28
+
26
29
  #endif // LZWS_EXT_STREAM_DECOMPRESSOR_H
@@ -1,78 +1,295 @@
1
1
  // Ruby bindings for lzws library.
2
2
  // Copyright (c) 2019 AUTHORS, MIT License.
3
3
 
4
- #include <lzws/string.h>
4
+ #include "lzws_ext/string.h"
5
5
 
6
- #include "ruby.h"
6
+ #include <lzws/buffer.h>
7
+ #include <lzws/compressor/common.h>
8
+ #include <lzws/compressor/main.h>
9
+ #include <lzws/compressor/state.h>
10
+ #include <lzws/decompressor/common.h>
11
+ #include <lzws/decompressor/main.h>
12
+ #include <lzws/decompressor/state.h>
13
+ #include <stdint.h>
14
+ #include <stdlib.h>
7
15
 
8
16
  #include "lzws_ext/error.h"
9
17
  #include "lzws_ext/macro.h"
10
18
  #include "lzws_ext/option.h"
11
- #include "lzws_ext/string.h"
19
+ #include "ruby.h"
20
+
21
+ // -- buffer --
22
+
23
+ static inline VALUE create_buffer(VALUE length)
24
+ {
25
+ return rb_str_new(NULL, NUM2UINT(length));
26
+ }
27
+
28
+ #define CREATE_BUFFER(buffer, length, exception) \
29
+ VALUE buffer = rb_protect(create_buffer, UINT2NUM(length), &exception);
12
30
 
13
- #define GET_STRING(source) \
14
- Check_Type(source, T_STRING); \
15
- \
16
- const char* source_data = RSTRING_PTR(source); \
17
- size_t source_length = RSTRING_LEN(source);
31
+ static inline VALUE resize_buffer(VALUE args)
32
+ {
33
+ VALUE buffer = rb_ary_entry(args, 0);
34
+ VALUE length = rb_ary_entry(args, 1);
35
+ return rb_str_resize(buffer, NUM2UINT(length));
36
+ }
37
+
38
+ #define RESIZE_BUFFER(buffer, length, exception) \
39
+ VALUE resize_buffer_args = rb_ary_new_from_args(2, buffer, UINT2NUM(length)); \
40
+ buffer = rb_protect(resize_buffer, resize_buffer_args, &exception); \
41
+ RB_GC_GUARD(resize_buffer_args);
42
+
43
+ static inline lzws_ext_result_t increase_destination_buffer(
44
+ VALUE destination_value, size_t destination_length,
45
+ size_t* remaining_destination_buffer_length_ptr, size_t destination_buffer_length)
46
+ {
47
+ if (*remaining_destination_buffer_length_ptr == destination_buffer_length) {
48
+ // We want to write more data at once, than buffer has.
49
+ return LZWS_EXT_ERROR_NOT_ENOUGH_DESTINATION_BUFFER;
50
+ }
51
+
52
+ int exception;
53
+
54
+ RESIZE_BUFFER(destination_value, destination_length + destination_buffer_length, exception);
55
+ if (exception != 0) {
56
+ return LZWS_EXT_ERROR_ALLOCATE_FAILED;
57
+ }
58
+
59
+ *remaining_destination_buffer_length_ptr = destination_buffer_length;
60
+
61
+ return 0;
62
+ }
63
+
64
+ // -- utils --
65
+
66
+ #define GET_SOURCE_DATA(source_value) \
67
+ Check_Type(source_value, T_STRING); \
68
+ \
69
+ const char* source = RSTRING_PTR(source_value); \
70
+ size_t source_length = RSTRING_LEN(source_value); \
71
+ uint8_t* remaining_source = (uint8_t*)source; \
72
+ size_t remaining_source_length = source_length;
73
+
74
+ // -- compress --
75
+
76
+ #define BUFFERED_COMPRESS(function, ...) \
77
+ while (true) { \
78
+ uint8_t* remaining_destination_buffer = (uint8_t*)RSTRING_PTR(destination_value) + destination_length; \
79
+ size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length; \
80
+ \
81
+ result = function(__VA_ARGS__, &remaining_destination_buffer, &remaining_destination_buffer_length); \
82
+ \
83
+ if ( \
84
+ result != 0 && \
85
+ result != LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) { \
86
+ return LZWS_EXT_ERROR_UNEXPECTED; \
87
+ } \
88
+ \
89
+ destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length; \
90
+ \
91
+ if (result == LZWS_COMPRESSOR_NEEDS_MORE_DESTINATION) { \
92
+ ext_result = increase_destination_buffer( \
93
+ destination_value, destination_length, \
94
+ &remaining_destination_buffer_length, destination_buffer_length); \
95
+ \
96
+ if (ext_result != 0) { \
97
+ return ext_result; \
98
+ } \
99
+ \
100
+ continue; \
101
+ } \
102
+ \
103
+ break; \
104
+ }
105
+
106
+ static inline lzws_ext_result_t compress(
107
+ lzws_compressor_state_t* state_ptr,
108
+ uint8_t* remaining_source, size_t remaining_source_length,
109
+ VALUE destination_value, size_t destination_buffer_length)
110
+ {
111
+ lzws_result_t result;
112
+ lzws_ext_result_t ext_result;
113
+
114
+ size_t destination_length = 0;
115
+ size_t remaining_destination_buffer_length = destination_buffer_length;
116
+
117
+ BUFFERED_COMPRESS(lzws_compress, state_ptr, &remaining_source, &remaining_source_length);
118
+ BUFFERED_COMPRESS(lzws_compressor_finish, state_ptr);
119
+
120
+ int exception;
121
+
122
+ RESIZE_BUFFER(destination_value, destination_length, exception);
123
+ if (exception != 0) {
124
+ return LZWS_EXT_ERROR_ALLOCATE_FAILED;
125
+ }
126
+
127
+ return 0;
128
+ }
18
129
 
19
- VALUE lzws_ext_compress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE options)
130
+ VALUE lzws_ext_compress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value, VALUE options)
20
131
  {
21
- GET_STRING(source);
132
+ GET_SOURCE_DATA(source_value);
133
+ Check_Type(options, T_HASH);
22
134
  LZWS_EXT_GET_COMPRESSOR_OPTIONS(options);
135
+ LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
23
136
 
24
- char* destination;
25
- size_t destination_length;
137
+ lzws_compressor_state_t* state_ptr;
26
138
 
27
- lzws_result_t result = lzws_compress_string(
28
- (uint8_t*)source_data, source_length,
29
- (uint8_t**)&destination, &destination_length, buffer_length,
139
+ lzws_result_t result = lzws_compressor_get_initial_state(
140
+ &state_ptr,
30
141
  without_magic_header, max_code_bit_length, block_mode, msb, unaligned_bit_groups, quiet);
31
142
 
32
- if (result == LZWS_STRING_ALLOCATE_FAILED) {
33
- lzws_ext_raise_error("AllocateError", "allocate error");
143
+ if (result != 0) {
144
+ switch (result) {
145
+ case LZWS_COMPRESSOR_ALLOCATE_FAILED:
146
+ lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
147
+ case LZWS_COMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
148
+ lzws_ext_raise_error(LZWS_EXT_ERROR_VALIDATE_FAILED);
149
+ default:
150
+ lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
151
+ }
34
152
  }
35
- else if (result == LZWS_STRING_VALIDATE_FAILED) {
36
- lzws_ext_raise_error("ValidateError", "validate error");
153
+
154
+ if (destination_buffer_length == 0) {
155
+ destination_buffer_length = LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_COMPRESSOR;
156
+ }
157
+
158
+ int exception;
159
+
160
+ CREATE_BUFFER(destination_value, destination_buffer_length, exception);
161
+ if (exception != 0) {
162
+ lzws_compressor_free_state(state_ptr);
163
+ lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
164
+ }
165
+
166
+ lzws_ext_result_t ext_result = compress(
167
+ state_ptr,
168
+ remaining_source, remaining_source_length,
169
+ destination_value, destination_buffer_length);
170
+
171
+ lzws_compressor_free_state(state_ptr);
172
+
173
+ if (ext_result != 0) {
174
+ lzws_ext_raise_error(ext_result);
175
+ }
176
+
177
+ return destination_value;
178
+ }
179
+
180
+ // -- decompress --
181
+
182
+ static inline lzws_ext_result_t decompress(
183
+ lzws_decompressor_state_t* state_ptr,
184
+ uint8_t* remaining_source, size_t remaining_source_length,
185
+ VALUE destination_value, size_t destination_buffer_length)
186
+ {
187
+ lzws_result_t result;
188
+ lzws_ext_result_t ext_result;
189
+
190
+ size_t destination_length = 0;
191
+ size_t remaining_destination_buffer_length = destination_buffer_length;
192
+
193
+ while (true) {
194
+ uint8_t* remaining_destination_buffer = (uint8_t*)RSTRING_PTR(destination_value) + destination_length;
195
+ size_t prev_remaining_destination_buffer_length = remaining_destination_buffer_length;
196
+
197
+ result = lzws_decompress(
198
+ state_ptr,
199
+ &remaining_source, &remaining_source_length,
200
+ &remaining_destination_buffer, &remaining_destination_buffer_length);
201
+
202
+ if (
203
+ result != 0 &&
204
+ result != LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
205
+ switch (result) {
206
+ case LZWS_DECOMPRESSOR_INVALID_MAGIC_HEADER:
207
+ case LZWS_DECOMPRESSOR_INVALID_MAX_CODE_BIT_LENGTH:
208
+ return LZWS_EXT_ERROR_VALIDATE_FAILED;
209
+ case LZWS_DECOMPRESSOR_CORRUPTED_SOURCE:
210
+ return LZWS_EXT_ERROR_DECOMPRESSOR_CORRUPTED_SOURCE;
211
+ default:
212
+ return LZWS_EXT_ERROR_UNEXPECTED;
213
+ }
214
+ }
215
+
216
+ destination_length += prev_remaining_destination_buffer_length - remaining_destination_buffer_length;
217
+
218
+ if (result == LZWS_DECOMPRESSOR_NEEDS_MORE_DESTINATION) {
219
+ ext_result = increase_destination_buffer(
220
+ destination_value, destination_length,
221
+ &remaining_destination_buffer_length, destination_buffer_length);
222
+
223
+ if (ext_result != 0) {
224
+ return ext_result;
225
+ }
226
+
227
+ continue;
228
+ }
229
+
230
+ break;
37
231
  }
38
- else if (result != 0) {
39
- lzws_ext_raise_error("UnexpectedError", "unexpected error");
232
+
233
+ int exception;
234
+
235
+ RESIZE_BUFFER(destination_value, destination_length, exception);
236
+ if (exception != 0) {
237
+ return LZWS_EXT_ERROR_ALLOCATE_FAILED;
40
238
  }
41
239
 
42
- // Ruby copies string on initialization.
43
- VALUE result_string = rb_str_new(destination, destination_length);
44
- free(destination);
45
- return result_string;
240
+ return 0;
46
241
  }
47
242
 
48
- VALUE lzws_ext_decompress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source, VALUE options)
243
+ VALUE lzws_ext_decompress_string(VALUE LZWS_EXT_UNUSED(self), VALUE source_value, VALUE options)
49
244
  {
50
- GET_STRING(source);
245
+ GET_SOURCE_DATA(source_value);
246
+ Check_Type(options, T_HASH);
51
247
  LZWS_EXT_GET_DECOMPRESSOR_OPTIONS(options);
248
+ LZWS_EXT_GET_BUFFER_LENGTH_OPTION(options, destination_buffer_length);
52
249
 
53
- char* destination;
54
- size_t destination_length;
250
+ lzws_decompressor_state_t* state_ptr;
55
251
 
56
- lzws_result_t result = lzws_decompress_string(
57
- (uint8_t*)source_data, source_length,
58
- (uint8_t**)&destination, &destination_length, buffer_length,
252
+ lzws_result_t result = lzws_decompressor_get_initial_state(
253
+ &state_ptr,
59
254
  without_magic_header, msb, unaligned_bit_groups, quiet);
60
255
 
61
- if (result == LZWS_STRING_ALLOCATE_FAILED) {
62
- lzws_ext_raise_error("AllocateError", "allocate error");
256
+ if (result != 0) {
257
+ switch (result) {
258
+ case LZWS_DECOMPRESSOR_ALLOCATE_FAILED:
259
+ lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
260
+ default:
261
+ lzws_ext_raise_error(LZWS_EXT_ERROR_UNEXPECTED);
262
+ }
63
263
  }
64
- else if (result == LZWS_STRING_VALIDATE_FAILED) {
65
- lzws_ext_raise_error("ValidateError", "validate error");
264
+
265
+ if (destination_buffer_length == 0) {
266
+ destination_buffer_length = LZWS_DEFAULT_DESTINATION_BUFFER_LENGTH_FOR_DECOMPRESSOR;
66
267
  }
67
- else if (result == LZWS_STRING_DECOMPRESSOR_CORRUPTED_SOURCE) {
68
- lzws_ext_raise_error("DecompressorCorruptedSourceError", "decompressor received corrupted source");
268
+
269
+ int exception;
270
+
271
+ CREATE_BUFFER(destination_value, destination_buffer_length, exception);
272
+ if (exception != 0) {
273
+ lzws_decompressor_free_state(state_ptr);
274
+ lzws_ext_raise_error(LZWS_EXT_ERROR_ALLOCATE_FAILED);
69
275
  }
70
- else if (result != 0) {
71
- lzws_ext_raise_error("UnexpectedError", "unexpected error");
276
+
277
+ lzws_ext_result_t ext_result = decompress(
278
+ state_ptr,
279
+ remaining_source, remaining_source_length,
280
+ destination_value, destination_buffer_length);
281
+
282
+ lzws_decompressor_free_state(state_ptr);
283
+
284
+ if (ext_result != 0) {
285
+ lzws_ext_raise_error(ext_result);
72
286
  }
73
287
 
74
- // Ruby copies string on initialization.
75
- VALUE result_string = rb_str_new(destination, destination_length);
76
- free(destination);
77
- return result_string;
288
+ return destination_value;
289
+ }
290
+
291
+ void lzws_ext_string_exports(VALUE root_module)
292
+ {
293
+ rb_define_module_function(root_module, "_native_compress_string", RUBY_METHOD_FUNC(lzws_ext_compress_string), 2);
294
+ rb_define_module_function(root_module, "_native_decompress_string", RUBY_METHOD_FUNC(lzws_ext_decompress_string), 2);
78
295
  }
@@ -9,4 +9,6 @@
9
9
  VALUE lzws_ext_compress_string(VALUE self, VALUE source, VALUE options);
10
10
  VALUE lzws_ext_decompress_string(VALUE self, VALUE source, VALUE options);
11
11
 
12
+ void lzws_ext_string_exports(VALUE root_module);
13
+
12
14
  #endif // LZWS_EXT_STRING_H
data/lib/lzws/error.rb CHANGED
@@ -4,17 +4,18 @@
4
4
  module LZWS
5
5
  class BaseError < ::StandardError; end
6
6
 
7
- class ValidateError < BaseError; end
8
- class AllocateError < BaseError; end
9
- class UnexpectedError < BaseError; end
10
-
11
- class NotEnoughDestinationError < BaseError; end
12
- class UsedAfterCloseError < BaseError; end
7
+ class AllocateError < BaseError; end
8
+ class ValidateError < BaseError; end
13
9
 
10
+ class UsedAfterCloseError < BaseError; end
11
+ class NotEnoughSourceBufferError < BaseError; end
12
+ class NotEnoughDestinationBufferError < BaseError; end
13
+ class NotEnoughDestinationError < BaseError; end
14
14
  class DecompressorCorruptedSourceError < BaseError; end
15
15
 
16
- class OpenFileError < BaseError; end
17
16
  class AccessIOError < BaseError; end
18
17
  class ReadIOError < BaseError; end
19
18
  class WriteIOError < BaseError; end
19
+
20
+ class UnexpectedError < BaseError; end
20
21
  end
data/lib/lzws/file.rb CHANGED
@@ -9,11 +9,13 @@ require_relative "validation"
9
9
 
10
10
  module LZWS
11
11
  module File
12
+ BUFFER_LENGTH_NAMES = %i[source_buffer_length destination_buffer_length].freeze
13
+
12
14
  def self.compress(source, destination, options = {})
13
15
  Validation.validate_string source
14
16
  Validation.validate_string destination
15
17
 
16
- options = Option.get_compressor_options options
18
+ options = Option.get_compressor_options options, BUFFER_LENGTH_NAMES
17
19
 
18
20
  open_files(source, destination) do |source_io, destination_io|
19
21
  LZWS._native_compress_io source_io, destination_io, options
@@ -24,7 +26,7 @@ module LZWS
24
26
  Validation.validate_string source
25
27
  Validation.validate_string destination
26
28
 
27
- options = Option.get_decompressor_options options
29
+ options = Option.get_decompressor_options options, BUFFER_LENGTH_NAMES
28
30
 
29
31
  open_files(source, destination) do |source_io, destination_io|
30
32
  LZWS._native_decompress_io source_io, destination_io, options
@@ -32,25 +34,11 @@ module LZWS
32
34
  end
33
35
 
34
36
  private_class_method def self.open_files(source, destination, &_block)
35
- open_file(source, "rb") do |source_io|
36
- open_file(destination, "wb") do |destination_io|
37
+ ::File.open source, "rb" do |source_io|
38
+ ::File.open destination, "wb" do |destination_io|
37
39
  yield source_io, destination_io
38
40
  end
39
41
  end
40
42
  end
41
-
42
- private_class_method def self.open_file(path, mode, &_block)
43
- begin
44
- io = ::File.open path, mode
45
- rescue ::StandardError
46
- raise OpenFileError, "open file failed"
47
- end
48
-
49
- begin
50
- yield io
51
- ensure
52
- io.close
53
- end
54
- end
55
43
  end
56
44
  end
data/lib/lzws/option.rb CHANGED
@@ -8,11 +8,11 @@ module LZWS
8
8
  module Option
9
9
  # Default options will be compatible with UNIX compress.
10
10
 
11
+ DEFAULT_BUFFER_LENGTH = 0
11
12
  LOWEST_MAX_CODE_BIT_LENGTH = 9
12
13
  BIGGEST_MAX_CODE_BIT_LENGTH = 16
13
14
 
14
15
  DECOMPRESSOR_DEFAULTS = {
15
- :buffer_length => 0,
16
16
  :without_magic_header => false,
17
17
  :msb => false,
18
18
  :unaligned_bit_groups => false,
@@ -26,12 +26,13 @@ module LZWS
26
26
  )
27
27
  .freeze
28
28
 
29
- def self.get_compressor_options(options)
29
+ def self.get_compressor_options(options, buffer_length_names)
30
30
  Validation.validate_hash options
31
31
 
32
- options = COMPRESSOR_DEFAULTS.merge options
32
+ buffer_length_defaults = buffer_length_names.each_with_object({}) { |name, defaults| defaults[name] = DEFAULT_BUFFER_LENGTH }
33
+ options = COMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
33
34
 
34
- Validation.validate_not_negative_integer options[:buffer_length]
35
+ buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
35
36
 
36
37
  max_code_bit_length = options[:max_code_bit_length]
37
38
  Validation.validate_positive_integer max_code_bit_length
@@ -49,12 +50,14 @@ module LZWS
49
50
  options
50
51
  end
51
52
 
52
- def self.get_decompressor_options(options)
53
+ def self.get_decompressor_options(options, buffer_length_names)
53
54
  Validation.validate_hash options
54
55
 
55
- options = DECOMPRESSOR_DEFAULTS.merge options
56
+ buffer_length_defaults = buffer_length_names.each_with_object({}) { |name, defaults| defaults[name] = DEFAULT_BUFFER_LENGTH }
57
+ options = DECOMPRESSOR_DEFAULTS.merge(buffer_length_defaults).merge options
58
+
59
+ buffer_length_names.each { |name| Validation.validate_not_negative_integer options[name] }
56
60
 
57
- Validation.validate_not_negative_integer options[:buffer_length]
58
61
  Validation.validate_bool options[:without_magic_header]
59
62
  Validation.validate_bool options[:msb]
60
63
  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,6 +21,7 @@ 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
25
26
  alias tell pos
26
27
 
@@ -115,7 +116,6 @@ module LZWS
115
116
 
116
117
  protected def target_encoding
117
118
  return @internal_encoding unless @internal_encoding.nil?
118
-
119
119
  return @external_encoding unless @external_encoding.nil?
120
120
 
121
121
  ::Encoding::BINARY
@@ -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
@@ -55,28 +50,13 @@ module LZWS
55
50
  total_bytes_written
56
51
  end
57
52
 
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
53
+ def close(&writer)
54
+ return nil if closed?
75
55
 
76
56
  Validation.validate_proc writer
77
57
 
78
58
  loop do
79
- need_more_destination = @native_stream.flush
59
+ need_more_destination = @native_stream.finish
80
60
 
81
61
  if need_more_destination
82
62
  flush_destination_buffer(&writer)
@@ -86,14 +66,10 @@ module LZWS
86
66
  break
87
67
  end
88
68
 
89
- write_result(&writer)
69
+ super
90
70
 
91
71
  nil
92
72
  end
93
-
94
- protected def do_not_use_after_close
95
- raise UsedAfterCloseError, "compressor used after close" if @is_closed
96
- end
97
73
  end
98
74
  end
99
75
  end