omnizip 0.3.20 → 0.3.22

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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.refactor/00-overview.md +2 -2
  3. data/TODO.refactor/07-respond-to-replacement.md +225 -79
  4. data/lib/omnizip/algorithm.rb +2 -2
  5. data/lib/omnizip/algorithms/bzip2.rb +1 -0
  6. data/lib/omnizip/algorithms/deflate.rb +1 -0
  7. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +3 -3
  8. data/lib/omnizip/algorithms/lzma.rb +11 -5
  9. data/lib/omnizip/algorithms/lzma2/encoder.rb +2 -0
  10. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +2 -0
  11. data/lib/omnizip/algorithms/lzma2.rb +2 -0
  12. data/lib/omnizip/algorithms/ppmd7.rb +2 -0
  13. data/lib/omnizip/algorithms/ppmd_base.rb +2 -0
  14. data/lib/omnizip/algorithms/registration.rb +1 -1
  15. data/lib/omnizip/algorithms/zstandard/decoder.rb +62 -3
  16. data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
  17. data/lib/omnizip/algorithms/zstandard/encoder.rb +110 -30
  18. data/lib/omnizip/algorithms/zstandard/match_finder.rb +21 -5
  19. data/lib/omnizip/algorithms/zstandard.rb +52 -0
  20. data/lib/omnizip/chunked/writer.rb +3 -0
  21. data/lib/omnizip/commands/archive_extract_command.rb +3 -1
  22. data/lib/omnizip/commands/archive_list_command.rb +4 -3
  23. data/lib/omnizip/commands/profile_show_command.rb +2 -0
  24. data/lib/omnizip/convenience.rb +2 -0
  25. data/lib/omnizip/extraction/filter_chain.rb +4 -0
  26. data/lib/omnizip/extraction/selective_extractor.rb +7 -0
  27. data/lib/omnizip/file_type.rb +4 -0
  28. data/lib/omnizip/formats/ole.rb +2 -0
  29. data/lib/omnizip/formats/rar/decompressor.rb +1 -0
  30. data/lib/omnizip/formats/rar/license_validator.rb +2 -0
  31. data/lib/omnizip/formats/rar/reader.rb +1 -2
  32. data/lib/omnizip/formats/rpm.rb +1 -0
  33. data/lib/omnizip/formats/seven_zip/writer.rb +8 -0
  34. data/lib/omnizip/formats/tar/reader.rb +2 -0
  35. data/lib/omnizip/formats/xar/reader.rb +2 -0
  36. data/lib/omnizip/formats/xar/writer.rb +1 -0
  37. data/lib/omnizip/formats/xz.rb +2 -0
  38. data/lib/omnizip/formats/xz_impl/block_decoder.rb +3 -0
  39. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +8 -0
  40. data/lib/omnizip/formats/zip/reader.rb +2 -0
  41. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +1 -0
  42. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +4 -9
  43. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +1 -16
  44. data/lib/omnizip/io/buffered_input.rb +1 -0
  45. data/lib/omnizip/io/buffered_output.rb +1 -0
  46. data/lib/omnizip/io/source.rb +4 -0
  47. data/lib/omnizip/io/stream_manager.rb +3 -1
  48. data/lib/omnizip/link_handler.rb +2 -0
  49. data/lib/omnizip/metadata/metadata_validator.rb +2 -0
  50. data/lib/omnizip/models/filter_config.rb +2 -0
  51. data/lib/omnizip/version.rb +1 -1
  52. data/lib/omnizip/zip/file.rb +1 -1
  53. data/lib/omnizip/zip/input_stream.rb +2 -1
  54. metadata +2 -1
@@ -77,6 +77,7 @@ module Omnizip
77
77
  end
78
78
 
79
79
  def set_encoding(enc)
80
+ # allowed: caller-supplied IO; String streams lack set_encoding
80
81
  @stream.set_encoding(enc) if @stream.respond_to?(:set_encoding)
81
82
  end
82
83
  end
@@ -110,7 +111,9 @@ module Omnizip
110
111
 
111
112
  if ENV["XZ_BLOCK_DEBUG"]
112
113
  warn "DEBUG: decode - compressed_size=#{compressed_size.inspect}, check_type=#{@check_type}"
114
+ # allowed: debug output under XZ_BLOCK_DEBUG
113
115
  warn "DEBUG: @input.class=#{@input.class}, @input.respond_to?(:pos)=#{@input.respond_to?(:pos)}"
116
+ # allowed: debug output under XZ_BLOCK_DEBUG
114
117
  pos = @input.respond_to?(:pos) ? @input.pos : "N/A"
115
118
  warn "DEBUG: @input.pos=#{pos}"
116
119
  end
@@ -46,6 +46,7 @@ module Omnizip
46
46
 
47
47
  # Store original input and file size for backward_size validation (if available)
48
48
  original_input = input
49
+ # allowed: caller-supplied IO; only sized streams get validated
49
50
  original_file_size = input.size if input.respond_to?(:size)
50
51
 
51
52
  output, block_count, final_input, block_sizes = decode_blocks(input,
@@ -57,6 +58,7 @@ module Omnizip
57
58
  # multiples of four bytes...If the stored value does not match the real size of
58
59
  # the Index field, the decoder MUST indicate an error."
59
60
  # Reference: /Users/mulgogi/src/external/xz/src/liblzma/common/stream_decoder.c
61
+ # allowed: caller-supplied IO; footer check needs seeking
60
62
  if original_input.respond_to?(:seek) && original_file_size&.positive?
61
63
  # Use original input and file size for validation
62
64
  validate_backward_size_from_footer(original_input,
@@ -138,6 +140,7 @@ module Omnizip
138
140
  # @param byte [Integer] Byte to restore
139
141
  # @raise [RuntimeError] If IO doesn't support ungetbyte
140
142
  def self.restore_byte(input, byte)
143
+ # allowed: caller-supplied IO; FormatError follows when unsupported
141
144
  return input.ungetbyte(byte) if input.respond_to?(:ungetbyte)
142
145
 
143
146
  raise FormatError,
@@ -227,6 +230,7 @@ module Omnizip
227
230
  # @param check_type [Symbol] Expected checksum type
228
231
  # @param index_size [Integer, nil] Actual index size for backward_size validation
229
232
  def self.verify_footer_if_seekable(input, check_type, index_size = nil)
233
+ # allowed: caller-supplied IO; skipped on non-seekable streams
230
234
  return unless input.respond_to?(:seek) && input.respond_to?(:size) && input.size
231
235
 
232
236
  original_pos = input.pos
@@ -290,6 +294,7 @@ module Omnizip
290
294
  # @param input [IO] Input stream
291
295
  # @raise [FormatError] If there's invalid trailing data
292
296
  def self.verify_no_trailing_data(input)
297
+ # allowed: caller-supplied IO; needs byte-level positioning
293
298
  return unless input.respond_to?(:pos) && input.respond_to?(:getbyte)
294
299
 
295
300
  # Skip stream padding (null bytes)
@@ -304,6 +309,7 @@ module Omnizip
304
309
  else
305
310
  # Non-zero byte found - this should be a new stream or it's invalid
306
311
  # Restore the byte and check if it's a valid stream header
312
+ # allowed: caller-supplied IO capability probe
307
313
  input.ungetbyte(byte) if input.respond_to?(:ungetbyte)
308
314
 
309
315
  # Stream padding must be a multiple of 4 bytes
@@ -345,6 +351,7 @@ module Omnizip
345
351
  end
346
352
 
347
353
  # Restore the bytes we read
354
+ # allowed: caller-supplied IO capability probe
348
355
  if input.respond_to?(:ungetbyte)
349
356
  potential_header.reverse_each do |b|
350
357
  input.ungetbyte(b)
@@ -381,6 +388,7 @@ module Omnizip
381
388
  # @raise [FormatError] If backward_size points to invalid position
382
389
  def self.validate_backward_size_from_footer(input, file_size,
383
390
  _index_size)
391
+ # allowed: caller-supplied IO; skipped on non-seekable streams
384
392
  return unless input.respond_to?(:seek)
385
393
  return if file_size.nil? || file_size.zero?
386
394
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "fileutils"
4
+
3
5
  module Omnizip
4
6
  module Formats
5
7
  module Zip
@@ -121,6 +121,7 @@ module Omnizip
121
121
  # For raw mode, return actual decode bytes (excluding flush padding)
122
122
  if @raw_mode
123
123
  [@output.string, @range_encoder.bytes_for_decode]
124
+ # allowed: caller-supplied output; any #string sink buffers
124
125
  elsif @output.respond_to?(:string)
125
126
  # For File output, just return bytes written (don't try to read back)
126
127
  # For StringIO, return the string and its size
@@ -416,16 +416,11 @@ module Omnizip
416
416
 
417
417
  if @lzma2_debug
418
418
  warn "DEBUG: decompress_lzma_chunk - After set_input, checking range_decoder..."
419
- # Check if the decoder has a range_decoder variable
420
- if @lzma_decoder.respond_to?(:range_decoder)
421
- range_decoder = @lzma_decoder.range_decoder
422
- if range_decoder
423
- warn " range_decoder exists: code=0x#{range_decoder.code.to_s(16)}, range=0x#{range_decoder.range.to_s(16)}, init_bytes_remaining=#{range_decoder.init_bytes_remaining}"
424
- else
425
- warn " range_decoder is nil"
426
- end
419
+ range_decoder = @lzma_decoder.range_decoder
420
+ if range_decoder
421
+ warn " range_decoder exists: code=0x#{range_decoder.code.to_s(16)}, range=0x#{range_decoder.range.to_s(16)}, init_bytes_remaining=#{range_decoder.init_bytes_remaining}"
427
422
  else
428
- warn " @range_decoder not defined yet"
423
+ warn " range_decoder is nil"
429
424
  end
430
425
  end
431
426
  else
@@ -33,19 +33,6 @@ module Omnizip
33
33
  #
34
34
  # Ported from XZ Utils liblzma/lzma2_encoder.c
35
35
  #
36
- # Compatibility helper for Ruby 3.0-3.1 where String#byteslice doesn't exist
37
- module StringCompat
38
- if "".respond_to?(:byteslice)
39
- def self.byteslice(string, start, length)
40
- string.byteslice(start, length)
41
- end
42
- else
43
- def self.byteslice(string, start, length)
44
- string.bytes[start, length]&.pack("C*") || ""
45
- end
46
- end
47
- end
48
-
49
36
  # Constants
50
37
  UINT32_MAX = 0xFFFFFFFF
51
38
  REPS = 4
@@ -364,11 +351,9 @@ module Omnizip
364
351
 
365
352
  # Write to output stream
366
353
  if out_pos.value.positive?
367
- # Use StringCompat.byteslice for Ruby 3.0-3.1 compatibility
368
354
  # Ruby's [] operator has a bug with null bytes that can return extra bytes
369
355
  # See: https://bugs.ruby-lang.org/issues/15985
370
- output.write(StringCompat.byteslice(temp_buffer, 0,
371
- out_pos.value))
356
+ output.write(temp_buffer.byteslice(0, out_pos.value))
372
357
  end
373
358
 
374
359
  # Return the number of bytes written
@@ -76,6 +76,7 @@ module Omnizip
76
76
  #
77
77
  # @return [void]
78
78
  def close
79
+ # allowed: caller-supplied source may not be closeable
79
80
  @source.close if @source.respond_to?(:close)
80
81
  end
81
82
 
@@ -84,6 +84,7 @@ module Omnizip
84
84
  # @return [void]
85
85
  def close
86
86
  flush
87
+ # allowed: caller-supplied destination may not be closeable
87
88
  @destination.close if @destination.respond_to?(:close)
88
89
  end
89
90
 
@@ -31,6 +31,7 @@ module Omnizip
31
31
  when ::IO, ::StringIO, ::Tempfile then new(input)
32
32
  when String then StringSource.new(input)
33
33
  else
34
+ # allowed: boundary validation; duck-typing ends at this adapter
34
35
  unless input.respond_to?(:read)
35
36
  raise ArgumentError,
36
37
  "Cannot adapt #{input.inspect} to Omnizip::IO::Source"
@@ -56,6 +57,7 @@ module Omnizip
56
57
  end
57
58
 
58
59
  def close
60
+ # allowed: wrapped object may be a read-only duck with no close
59
61
  @io.close if @io.respond_to?(:close)
60
62
  end
61
63
 
@@ -98,6 +100,7 @@ module Omnizip
98
100
  when ::IO, ::StringIO, ::Tempfile then new(output)
99
101
  when String then PathSink.new(output)
100
102
  else
103
+ # allowed: boundary validation; duck-typing ends at this adapter
101
104
  unless output.respond_to?(:write)
102
105
  raise ArgumentError,
103
106
  "Cannot adapt #{output.inspect} to Omnizip::IO::Sink"
@@ -116,6 +119,7 @@ module Omnizip
116
119
  end
117
120
 
118
121
  def close
122
+ # allowed: wrapped object may be a write-only duck with no close
119
123
  @io.close if @io.respond_to?(:close)
120
124
  end
121
125
 
@@ -71,13 +71,14 @@ module Omnizip
71
71
  #
72
72
  # @return [void]
73
73
  def close
74
- @source.close if @owned && @source.respond_to?(:close)
74
+ @source.close if @owned
75
75
  end
76
76
 
77
77
  # Check if source is at end.
78
78
  #
79
79
  # @return [Boolean] True if at EOF
80
80
  def eof?
81
+ # allowed: write-only sources have no eof?
81
82
  @source.eof? if @source.respond_to?(:eof?)
82
83
  end
83
84
 
@@ -103,6 +104,7 @@ module Omnizip
103
104
  end
104
105
 
105
106
  def validate_io_interface(source)
107
+ # allowed: boundary validation of a caller-supplied IO-like object
106
108
  if source.respond_to?(:read) || source.respond_to?(:write)
107
109
  source
108
110
  else
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "fileutils"
4
+
3
5
  module Omnizip
4
6
  # Handles symbolic and hard link operations with platform detection
5
7
  module LinkHandler
@@ -9,6 +9,8 @@ module Omnizip
9
9
  # @raise [ArgumentError] If metadata is invalid
10
10
  def validate_entry(metadata)
11
11
  validate_comment(metadata.comment) if metadata.comment
12
+ # validate_entry is public API.
13
+ # allowed: metadata need only expose what it validates
12
14
  validate_time(metadata.mtime) if metadata.respond_to?(:mtime)
13
15
  validate_permissions(metadata.unix_permissions) if metadata.unix_permissions
14
16
 
@@ -94,6 +94,8 @@ module Omnizip
94
94
  # @raise [NotImplementedError] If filter doesn't support id_for_format
95
95
  def id_for_format(format)
96
96
  filter = filter_instance
97
+ # FilterRegistry accepts any class, with no inheritance check.
98
+ # allowed: keeps NotImplementedError for filters without the method
97
99
  if filter.respond_to?(:id_for_format)
98
100
  filter.id_for_format(format)
99
101
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Omnizip
4
- VERSION = "0.3.20"
4
+ VERSION = "0.3.22"
5
5
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
+ require "stringio"
4
5
 
5
6
  module Omnizip
6
7
  module Zip
@@ -102,7 +103,6 @@ module Omnizip
102
103
  content = read_entry_data(entry)
103
104
 
104
105
  if block
105
- require "stringio"
106
106
  StringIO.open(content, "rb", &block)
107
107
  else
108
108
  content
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "stringio"
4
+
3
5
  module Omnizip
4
6
  module Zip
5
7
  # Rubyzip-compatible InputStream class
@@ -88,7 +90,6 @@ module Omnizip
88
90
  @current_entry.compression_method,
89
91
  @current_entry.size,
90
92
  )
91
- require "stringio"
92
93
  @current_entry_io = StringIO.new(decompressed, "rb")
93
94
  end
94
95
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnizip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.20
4
+ version: 0.3.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -301,6 +301,7 @@ files:
301
301
  - lib/omnizip/algorithms/zstandard.rb
302
302
  - lib/omnizip/algorithms/zstandard/constants.rb
303
303
  - lib/omnizip/algorithms/zstandard/decoder.rb
304
+ - lib/omnizip/algorithms/zstandard/dictionary.rb
304
305
  - lib/omnizip/algorithms/zstandard/encoder.rb
305
306
  - lib/omnizip/algorithms/zstandard/frame.rb
306
307
  - lib/omnizip/algorithms/zstandard/frame/block.rb