omnizip 0.3.9 → 0.3.10

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 (182) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.refactor/00-overview.md +67 -0
  3. data/TODO.refactor/01-registry-base-class.md +81 -0
  4. data/TODO.refactor/02-error-hierarchy.md +57 -0
  5. data/TODO.refactor/03-autoload-entry-point.md +69 -0
  6. data/TODO.refactor/04-filter-base-consolidation.md +49 -0
  7. data/TODO.refactor/05-send-private-methods.md +64 -0
  8. data/TODO.refactor/06-instance-variable-access.md +69 -0
  9. data/TODO.refactor/07-respond-to-replacement.md +91 -0
  10. data/TODO.refactor/08-spec-doubles.md +27 -0
  11. data/TODO.refactor/09-cli-shared-module.md +35 -0
  12. data/TODO.refactor/10-format-detector-ocp.md +34 -0
  13. data/TODO.refactor/11-convenience-decoupling.md +38 -0
  14. data/TODO.refactor/12-thread-safety.md +8 -0
  15. data/TODO.refactor/13-lutaml-model-migration.md +82 -0
  16. data/TODO.refactor/14-add-missing-specs.md +25 -0
  17. data/lib/omnizip/algorithm.rb +0 -2
  18. data/lib/omnizip/algorithm_registry.rb +29 -57
  19. data/lib/omnizip/algorithms/lzma/dictionary.rb +4 -3
  20. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +2 -0
  21. data/lib/omnizip/algorithms/lzma/range_decoder.rb +1 -1
  22. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +6 -5
  23. data/lib/omnizip/algorithms/lzma2/encoder.rb +0 -2
  24. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +0 -2
  25. data/lib/omnizip/algorithms/lzma2/properties.rb +0 -2
  26. data/lib/omnizip/algorithms/ppmd7/model.rb +1 -1
  27. data/lib/omnizip/algorithms/ppmd8/context.rb +0 -2
  28. data/lib/omnizip/algorithms/ppmd8/model.rb +1 -1
  29. data/lib/omnizip/algorithms/ppmd8.rb +0 -2
  30. data/lib/omnizip/algorithms/ppmd_base.rb +0 -2
  31. data/lib/omnizip/algorithms/sevenzip_lzma2.rb +0 -5
  32. data/lib/omnizip/algorithms/xz_lzma2.rb +0 -5
  33. data/lib/omnizip/algorithms/zstandard/frame/header.rb +3 -5
  34. data/lib/omnizip/algorithms.rb +1 -0
  35. data/lib/omnizip/archive_handler.rb +75 -0
  36. data/lib/omnizip/archive_handlers/tar_handler.rb +51 -0
  37. data/lib/omnizip/archive_handlers/zip_handler.rb +73 -0
  38. data/lib/omnizip/archive_handlers.rb +11 -0
  39. data/lib/omnizip/checksum_registry.rb +23 -96
  40. data/lib/omnizip/cli/shared.rb +31 -0
  41. data/lib/omnizip/cli.rb +6 -43
  42. data/lib/omnizip/commands/archive_create_command.rb +0 -6
  43. data/lib/omnizip/commands/archive_extract_command.rb +0 -4
  44. data/lib/omnizip/commands/archive_list_command.rb +0 -4
  45. data/lib/omnizip/commands/archive_repair_command.rb +0 -2
  46. data/lib/omnizip/commands/archive_verify_command.rb +0 -2
  47. data/lib/omnizip/commands/compress_command.rb +0 -2
  48. data/lib/omnizip/commands/decompress_command.rb +0 -2
  49. data/lib/omnizip/commands/list_command.rb +0 -2
  50. data/lib/omnizip/commands/metadata_command.rb +0 -5
  51. data/lib/omnizip/commands/parity_create_command.rb +0 -2
  52. data/lib/omnizip/commands/parity_repair_command.rb +0 -2
  53. data/lib/omnizip/commands/parity_verify_command.rb +0 -2
  54. data/lib/omnizip/commands/profile_list_command.rb +0 -2
  55. data/lib/omnizip/commands/profile_show_command.rb +0 -2
  56. data/lib/omnizip/convenience.rb +111 -234
  57. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +1 -1
  58. data/lib/omnizip/crypto/aes256/cipher.rb +6 -1
  59. data/lib/omnizip/error.rb +22 -18
  60. data/lib/omnizip/filter.rb +5 -3
  61. data/lib/omnizip/filter_registry.rb +74 -98
  62. data/lib/omnizip/filters/bcj2.rb +0 -2
  63. data/lib/omnizip/filters/bcj_x86.rb +0 -2
  64. data/lib/omnizip/filters/filter_base.rb +4 -70
  65. data/lib/omnizip/filters/registry.rb +0 -2
  66. data/lib/omnizip/format_detector.rb +21 -12
  67. data/lib/omnizip/format_registry.rb +69 -53
  68. data/lib/omnizip/formats/bzip2_file.rb +0 -2
  69. data/lib/omnizip/formats/cpio/entry.rb +0 -2
  70. data/lib/omnizip/formats/cpio/reader.rb +0 -1
  71. data/lib/omnizip/formats/cpio/writer.rb +0 -1
  72. data/lib/omnizip/formats/cpio.rb +0 -1
  73. data/lib/omnizip/formats/format_spec_loader.rb +1 -1
  74. data/lib/omnizip/formats/gzip.rb +0 -2
  75. data/lib/omnizip/formats/iso/directory_record.rb +6 -3
  76. data/lib/omnizip/formats/iso/reader.rb +2 -2
  77. data/lib/omnizip/formats/iso.rb +0 -1
  78. data/lib/omnizip/formats/lzip.rb +5 -25
  79. data/lib/omnizip/formats/lzma_alone.rb +7 -25
  80. data/lib/omnizip/formats/msi/reader.rb +1 -0
  81. data/lib/omnizip/formats/msi/string_pool.rb +2 -3
  82. data/lib/omnizip/formats/msi.rb +1 -4
  83. data/lib/omnizip/formats/ole/allocation_table.rb +0 -1
  84. data/lib/omnizip/formats/ole/dirent.rb +9 -4
  85. data/lib/omnizip/formats/ole/header.rb +0 -1
  86. data/lib/omnizip/formats/ole/ranges_io.rb +1 -1
  87. data/lib/omnizip/formats/ole/storage.rb +5 -6
  88. data/lib/omnizip/formats/ole.rb +0 -1
  89. data/lib/omnizip/formats/rar/block_parser.rb +0 -1
  90. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +1 -1
  91. data/lib/omnizip/formats/rar/decompressor.rb +1 -0
  92. data/lib/omnizip/formats/rar/header.rb +0 -1
  93. data/lib/omnizip/formats/rar/rar5/writer.rb +0 -3
  94. data/lib/omnizip/formats/rar/reader.rb +2 -3
  95. data/lib/omnizip/formats/rar/writer.rb +0 -1
  96. data/lib/omnizip/formats/rar.rb +0 -1
  97. data/lib/omnizip/formats/rpm/entry.rb +0 -1
  98. data/lib/omnizip/formats/rpm/header.rb +1 -6
  99. data/lib/omnizip/formats/rpm/lead.rb +37 -26
  100. data/lib/omnizip/formats/rpm/tag.rb +0 -1
  101. data/lib/omnizip/formats/rpm/writer.rb +0 -1
  102. data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +0 -1
  103. data/lib/omnizip/formats/seven_zip/coder_chain.rb +1 -2
  104. data/lib/omnizip/formats/seven_zip/encoded_header.rb +0 -1
  105. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +0 -1
  106. data/lib/omnizip/formats/seven_zip/header.rb +0 -1
  107. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +0 -1
  108. data/lib/omnizip/formats/seven_zip/header_writer.rb +0 -1
  109. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +1 -1
  110. data/lib/omnizip/formats/seven_zip/parser.rb +1 -2
  111. data/lib/omnizip/formats/seven_zip/reader.rb +13 -2
  112. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +0 -1
  113. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +0 -1
  114. data/lib/omnizip/formats/seven_zip/writer.rb +4 -6
  115. data/lib/omnizip/formats/seven_zip.rb +2 -4
  116. data/lib/omnizip/formats/tar/entry.rb +0 -2
  117. data/lib/omnizip/formats/tar/header.rb +0 -2
  118. data/lib/omnizip/formats/tar/reader.rb +0 -2
  119. data/lib/omnizip/formats/tar/writer.rb +0 -2
  120. data/lib/omnizip/formats/tar.rb +0 -1
  121. data/lib/omnizip/formats/xar/entry.rb +0 -1
  122. data/lib/omnizip/formats/xar/header.rb +0 -1
  123. data/lib/omnizip/formats/xar/reader.rb +0 -1
  124. data/lib/omnizip/formats/xar/toc.rb +1 -2
  125. data/lib/omnizip/formats/xar/writer.rb +11 -3
  126. data/lib/omnizip/formats/xar.rb +0 -1
  127. data/lib/omnizip/formats/xz/reader.rb +7 -3
  128. data/lib/omnizip/formats/xz.rb +3 -40
  129. data/lib/omnizip/formats/xz_impl/block_decoder.rb +4 -10
  130. data/lib/omnizip/formats/xz_impl/block_encoder.rb +0 -2
  131. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +0 -2
  132. data/lib/omnizip/formats/xz_impl/index_decoder.rb +0 -1
  133. data/lib/omnizip/formats/xz_impl/index_encoder.rb +0 -1
  134. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +1 -1
  135. data/lib/omnizip/formats/xz_impl/stream_footer.rb +0 -1
  136. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +0 -1
  137. data/lib/omnizip/formats/xz_impl/stream_header.rb +0 -1
  138. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +0 -2
  139. data/lib/omnizip/formats/zip/central_directory_header.rb +2 -3
  140. data/lib/omnizip/formats/zip/end_of_central_directory.rb +0 -2
  141. data/lib/omnizip/formats/zip/local_file_header.rb +0 -2
  142. data/lib/omnizip/formats/zip/reader.rb +12 -2
  143. data/lib/omnizip/formats/zip/writer.rb +73 -1
  144. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +0 -2
  145. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +0 -2
  146. data/lib/omnizip/formats/zip/zip64_extra_field.rb +0 -2
  147. data/lib/omnizip/formats/zip.rb +0 -1
  148. data/lib/omnizip/formats.rb +8 -24
  149. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +2 -2
  150. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +1 -1
  151. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +0 -6
  152. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +3 -4
  153. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +0 -1
  154. data/lib/omnizip/io/source.rb +136 -0
  155. data/lib/omnizip/io.rb +2 -0
  156. data/lib/omnizip/link_handler.rb +7 -3
  157. data/lib/omnizip/metadata/metadata_editor.rb +1 -1
  158. data/lib/omnizip/models/algorithm_metadata.rb +33 -60
  159. data/lib/omnizip/models/compression_options.rb +40 -53
  160. data/lib/omnizip/models/conversion_options.rb +9 -18
  161. data/lib/omnizip/models/parallel_options.rb +25 -0
  162. data/lib/omnizip/optimization_registry.rb +8 -44
  163. data/lib/omnizip/parallel/job_scheduler.rb +26 -8
  164. data/lib/omnizip/parallel/parallel_compressor.rb +10 -20
  165. data/lib/omnizip/parallel/parallel_extractor.rb +20 -11
  166. data/lib/omnizip/parity/par2_repairer.rb +5 -5
  167. data/lib/omnizip/parity/par2_verifier.rb +27 -22
  168. data/lib/omnizip/parity.rb +4 -4
  169. data/lib/omnizip/password/encryption_registry.rb +11 -50
  170. data/lib/omnizip/password/zip_crypto_strategy.rb +1 -4
  171. data/lib/omnizip/pipe/stream_decompressor.rb +2 -3
  172. data/lib/omnizip/profile/archive_profile.rb +0 -2
  173. data/lib/omnizip/profile/binary_profile.rb +0 -2
  174. data/lib/omnizip/profile/compression_profile.rb +0 -1
  175. data/lib/omnizip/profile/profile_detector.rb +0 -2
  176. data/lib/omnizip/profile/text_profile.rb +0 -2
  177. data/lib/omnizip/profile.rb +0 -2
  178. data/lib/omnizip/registry.rb +112 -0
  179. data/lib/omnizip/version.rb +1 -1
  180. data/lib/omnizip/zip/file.rb +20 -9
  181. data/lib/omnizip.rb +26 -58
  182. metadata +24 -2
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "stringio"
4
- require "omnizip/algorithms/lzma"
5
- require "omnizip/format_registry"
6
4
 
7
5
  module Omnizip
8
6
  module Formats
@@ -76,21 +74,7 @@ module Omnizip
76
74
  # @option options [Boolean] :concatenated If true, decode concatenated .lz members (default: false)
77
75
  # @return [String, nil] Decompressed data (if output is nil)
78
76
  def decompress(input, output = nil, options = {})
79
- # Handle raw data string vs file path vs IO object
80
- data = if input.respond_to?(:read)
81
- # Already an IO object
82
- input.read
83
- elsif input.is_a?(String)
84
- # Could be file path or raw data
85
- if !input.include?("\0") && File.exist?(input)
86
- File.binread(input)
87
- else
88
- input.b
89
- end
90
- else
91
- raise ArgumentError,
92
- "Input must be a String or IO object"
93
- end
77
+ data = Omnizip::IO::Source.for(input).read
94
78
 
95
79
  # Decode using LzipDecoder
96
80
  decoder = Omnizip::Algorithms::LZMA::LzipDecoder.new(
@@ -100,11 +84,7 @@ module Omnizip
100
84
  result = decoder.decode_stream
101
85
 
102
86
  if output
103
- if output.respond_to?(:write)
104
- output.write(result)
105
- else
106
- File.binwrite(output, result)
107
- end
87
+ Omnizip::IO::Sink.for(output).write(result)
108
88
  else
109
89
  result
110
90
  end
@@ -146,9 +126,9 @@ module Omnizip
146
126
 
147
127
  # Return metadata
148
128
  {
149
- version: decoder.instance_variable_get(:@version),
150
- dict_size: decoder.instance_variable_get(:@dict_size),
151
- member_size: decoder.instance_variable_get(:@member_size),
129
+ version: decoder.version,
130
+ dict_size: decoder.dict_size,
131
+ member_size: decoder.member_size,
152
132
  }
153
133
  end
154
134
 
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "stringio"
4
- require "omnizip/algorithms/lzma"
5
- require "omnizip/format_registry"
6
4
 
7
5
  module Omnizip
8
6
  module Formats
@@ -66,19 +64,7 @@ module Omnizip
66
64
  # @option options [Boolean] :picky If true, reject files unlikely to be .lzma (default: false)
67
65
  # @return [String, nil] Decompressed data (if output is nil)
68
66
  def decompress(input, output = nil, options = {})
69
- # Handle raw data string vs file path
70
- data = if input.respond_to?(:read)
71
- input.read
72
- elsif input.is_a?(String)
73
- if !input.include?("\0") && File.exist?(input)
74
- File.binread(input)
75
- else
76
- input.b
77
- end
78
- else
79
- raise ArgumentError,
80
- "Input must be a String or IO object"
81
- end
67
+ data = Omnizip::IO::Source.for(input).read
82
68
 
83
69
  # Decode using LzmaAloneDecoder
84
70
  decoder = Omnizip::Algorithms::LZMA::LzmaAloneDecoder.new(
@@ -88,11 +74,7 @@ module Omnizip
88
74
  result = decoder.decode_stream
89
75
 
90
76
  if output
91
- if output.respond_to?(:write)
92
- output.write(result)
93
- else
94
- File.binwrite(output, result)
95
- end
77
+ Omnizip::IO::Sink.for(output).write(result)
96
78
  else
97
79
  result
98
80
  end
@@ -149,11 +131,11 @@ module Omnizip
149
131
 
150
132
  # Return metadata
151
133
  {
152
- lc: decoder.instance_variable_get(:@lc),
153
- lp: decoder.instance_variable_get(:@lp),
154
- pb: decoder.instance_variable_get(:@pb),
155
- dict_size: decoder.instance_variable_get(:@dict_size),
156
- uncompressed_size: decoder.instance_variable_get(:@uncompressed_size),
134
+ lc: decoder.lc,
135
+ lp: decoder.lp,
136
+ pb: decoder.pb,
137
+ dict_size: decoder.dict_size,
138
+ uncompressed_size: decoder.uncompressed_size,
157
139
  }
158
140
  end
159
141
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "fileutils"
4
4
  require "tempfile"
5
+ require "tmpdir"
5
6
 
6
7
  module Omnizip
7
8
  module Formats
@@ -86,9 +86,8 @@ module Omnizip
86
86
  candidates = []
87
87
 
88
88
  # Try encoded name from the map first (set by Reader)
89
- stream_name_map = instance_variable_get(:@stream_name_map)
90
- if stream_name_map&.key?(base_name)
91
- candidates << stream_name_map[base_name]
89
+ if @stream_name_map&.key?(base_name)
90
+ candidates << @stream_name_map[base_name]
92
91
  end
93
92
 
94
93
  # Try with standard prefix bytes
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/ole"
4
- require "omnizip/formats/msi/constants"
5
-
6
3
  module Omnizip
7
4
  module Formats
8
5
  # MSI (Microsoft Installer) format support
@@ -15,6 +12,7 @@ module Omnizip
15
12
  # - String pool for interned strings
16
13
  # - Embedded cabinets (in _Streams or direct OLE streams)
17
14
  module Msi
15
+ autoload :Constants, "omnizip/formats/msi/constants"
18
16
  autoload :Entry, "omnizip/formats/msi/entry"
19
17
  autoload :StringPool, "omnizip/formats/msi/string_pool"
20
18
  autoload :TableParser, "omnizip/formats/msi/table_parser"
@@ -74,7 +72,6 @@ module Omnizip
74
72
  #
75
73
  # This overrides OLE's .msi registration.
76
74
  def register!
77
- require "omnizip/format_registry"
78
75
  FormatRegistry.register(".msi", self)
79
76
  FormatRegistry.register(".msp", self)
80
77
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "set"
4
4
 
5
- require "omnizip/formats/ole"
6
5
  module Omnizip
7
6
  module Formats
8
7
  module Ole
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/ole"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Ole
@@ -74,6 +73,12 @@ module Omnizip
74
73
  # @return [Array<Dirent>] Child entries (for directories)
75
74
  attr_reader :parent
76
75
 
76
+ # Public read access to the per-dirent name lookup hash. Used by
77
+ # children to update the parent's index when their name changes.
78
+ def name_lookup
79
+ @name_lookup ||= {}
80
+ end
81
+
77
82
  # @return [Integer, nil] Index in dirent array (used during loading)
78
83
  attr_accessor :idx
79
84
 
@@ -154,7 +159,7 @@ module Omnizip
154
159
  # @param value [String] Entry name
155
160
  def name=(value)
156
161
  if @parent
157
- map = @parent.instance_variable_get(:@name_lookup)
162
+ map = @parent.name_lookup
158
163
  map&.delete(@name)
159
164
  map&.store(value, self)
160
165
  end
@@ -314,7 +319,7 @@ module Omnizip
314
319
  raise Errno::EISDIR unless file?
315
320
 
316
321
  io = RangesIOMigrateable.new(self, mode)
317
- @modify_time = Time.now if io.respond_to?(:writeable?) && io.writeable?
322
+ @modify_time = Time.now if io.is_a?(RangesIOMigrateable) && io.writeable?
318
323
 
319
324
  if block_given?
320
325
  begin
@@ -371,7 +376,7 @@ module Omnizip
371
376
  # Call this when done with the dirent to release memory.
372
377
  # @return [void]
373
378
  def free
374
- @children&.each { |child| child.free if child.respond_to?(:free) }
379
+ @children&.each { |child| child.free if child.is_a?(Dirent) }
375
380
  @children = nil
376
381
  @parent = nil
377
382
  @ole = nil
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/ole"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Ole
@@ -179,7 +179,7 @@ module Omnizip
179
179
  # @param data [String] Data to write
180
180
  # @return [Integer] Bytes written
181
181
  def write(data)
182
- data = data.dup.force_encoding(Encoding::ASCII_8BIT) if data.respond_to?(:encoding)
182
+ data = data.dup.force_encoding(Encoding::ASCII_8BIT) if data.is_a?(String)
183
183
  return 0 if data.empty?
184
184
 
185
185
  # Grow if needed
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "set"
4
4
 
5
- require "omnizip/formats/ole"
6
5
  module Omnizip
7
6
  module Formats
8
7
  module Ole
@@ -80,7 +79,7 @@ module Omnizip
80
79
  end
81
80
 
82
81
  # Force binary encoding
83
- @io.set_encoding(Encoding::ASCII_8BIT) if @io.respond_to?(:set_encoding)
82
+ @io.set_encoding(Encoding::ASCII_8BIT) if @io.is_a?(::IO)
84
83
 
85
84
  # Determine if writable
86
85
  @writeable = determine_writeable(mode)
@@ -185,11 +184,11 @@ module Omnizip
185
184
  # Call this to release memory while keeping the IO open.
186
185
  # @return [void]
187
186
  def free
188
- @sb_file&.free if @sb_file.respond_to?(:free)
187
+ @sb_file&.free
189
188
  @sb_file = nil
190
- @sbat&.free if @sbat.respond_to?(:free)
189
+ @sbat&.free
191
190
  @sbat = nil
192
- @bbat&.free if @bbat.respond_to?(:free)
191
+ @bbat&.free
193
192
  @bbat = nil
194
193
  @dirents = nil
195
194
  @root = nil
@@ -458,7 +457,7 @@ module Omnizip
458
457
  else
459
458
  begin
460
459
  @io.flush
461
- @io.write_nonblock("") if @io.respond_to?(:write_nonblock)
460
+ @io.write_nonblock("") if @io.is_a?(::IO)
462
461
  true
463
462
  rescue IOError, Errno::EBADF
464
463
  false
@@ -119,7 +119,6 @@ module Omnizip
119
119
 
120
120
  # Register OLE format in registry
121
121
  def register!
122
- require "omnizip/format_registry"
123
122
  FormatRegistry.register(".ole", Storage)
124
123
  FormatRegistry.register(".doc", Storage)
125
124
  FormatRegistry.register(".xls", Storage)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/rar"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Rar
@@ -52,7 +52,7 @@ module Omnizip
52
52
 
53
53
  # Accessor for memory size (for testing)
54
54
  def memory_size
55
- @model.instance_variable_get(:@mem_size)
55
+ @model.mem_size
56
56
  end
57
57
 
58
58
  # Initialize the RAR PPMd encoder
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "English"
4
+ require "tmpdir"
4
5
  module Omnizip
5
6
  module Formats
6
7
  module Rar
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/rar"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Rar
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/parity/par2_creator"
4
- require "omnizip/formats/rar/rar5/header"
5
-
6
3
  module Omnizip
7
4
  module Formats
8
5
  module Rar
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "fileutils"
4
4
 
5
- require "omnizip/formats/rar"
6
5
  module Omnizip
7
6
  module Formats
8
7
  module Rar
@@ -243,7 +242,7 @@ module Omnizip
243
242
  return false unless @header.version == 4
244
243
 
245
244
  # Check if we have the compression method
246
- return false unless entry.respond_to?(:method) && entry.method
245
+ return false if entry.nil? || entry.method.nil?
247
246
 
248
247
  # All RAR4 methods are supported by our Dispatcher
249
248
  true
@@ -261,7 +260,7 @@ module Omnizip
261
260
  File.open(output_path, "wb") do |output|
262
261
  # For now, assume METHOD_STORE (0x30)
263
262
  # Real implementation would get method from entry
264
- method = entry.respond_to?(:method) ? entry.method : 0x30
263
+ method = entry.method || 0x30
265
264
 
266
265
  Compression::Dispatcher.decompress(method, compressed_data, output)
267
266
  end
@@ -4,7 +4,6 @@ require "fileutils"
4
4
  require "zlib"
5
5
  require "stringio"
6
6
 
7
- require "omnizip/formats/rar"
8
7
  module Omnizip
9
8
  module Formats
10
9
  module Rar
@@ -164,7 +164,6 @@ module Omnizip
164
164
 
165
165
  # Auto-register .rar format
166
166
  def register!
167
- require "omnizip/format_registry"
168
167
  FormatRegistry.register(".rar", "Omnizip::Formats::Rar::Reader")
169
168
  end
170
169
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/rpm"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Rpm
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/rpm"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Rpm
@@ -32,9 +31,7 @@ module Omnizip
32
31
  # @return [Header] Parsed header object
33
32
  # @raise [ArgumentError] If magic is invalid
34
33
  def self.parse(io)
35
- new.tap do |header|
36
- header.send(:parse!, io)
37
- end
34
+ new.tap { |header| header.parse!(io) }
38
35
  end
39
36
 
40
37
  # Get tag value by name
@@ -73,8 +70,6 @@ module Omnizip
73
70
  end
74
71
  end
75
72
 
76
- private
77
-
78
73
  def parse!(io)
79
74
  # Read header header (16 bytes)
80
75
  header_data = io.read(HEADER_HEADER_SIZE)
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/rpm"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Rpm
@@ -39,6 +38,22 @@ module Omnizip
39
38
  # @return [Integer] Total length (always 96)
40
39
  attr_reader :length
41
40
 
41
+ # Initialize a parsed lead. All attributes are required; use
42
+ # +Lead.parse(io)+ for the typical read path.
43
+ def initialize(magic:, major_version:, minor_version:, type:,
44
+ architecture:, name:, os:, signature_type:,
45
+ length: LEAD_SIZE)
46
+ @magic = magic
47
+ @major_version = major_version
48
+ @minor_version = minor_version
49
+ @type = type
50
+ @architecture = architecture
51
+ @name = name
52
+ @os = os
53
+ @signature_type = signature_type
54
+ @length = length
55
+ end
56
+
42
57
  # Parse lead from IO
43
58
  #
44
59
  # @param io [IO] Input stream positioned at lead
@@ -49,31 +64,27 @@ module Omnizip
49
64
  raise ArgumentError, "Failed to read RPM lead" unless data
50
65
  raise ArgumentError, "Truncated RPM lead" if data.bytesize < LEAD_SIZE
51
66
 
52
- new.tap do |lead|
53
- lead.instance_variable_set(:@length, LEAD_SIZE)
54
-
55
- # Unpack lead structure
56
- # A4 = 4-byte string (magic)
57
- # CC = 2 unsigned chars (major, minor)
58
- # n = big-endian short (type)
59
- # n = big-endian short (architecture)
60
- # A66 = 66-byte string (name)
61
- # n = big-endian short (os)
62
- # n = big-endian short (signature_type)
63
- # A16 = 16-byte reserved
64
- fields = data.unpack("A4 CC n n A66 n n A16")
65
-
66
- lead.instance_variable_set(:@magic, fields[0])
67
- lead.instance_variable_set(:@major_version, fields[1])
68
- lead.instance_variable_set(:@minor_version, fields[2])
69
- lead.instance_variable_set(:@type, fields[3])
70
- lead.instance_variable_set(:@architecture, fields[4])
71
- lead.instance_variable_set(:@name, fields[5].strip)
72
- lead.instance_variable_set(:@os, fields[6])
73
- lead.instance_variable_set(:@signature_type, fields[7])
74
-
75
- lead.validate!
76
- end
67
+ # Unpack lead structure
68
+ # A4 = 4-byte string (magic)
69
+ # CC = 2 unsigned chars (major, minor)
70
+ # n = big-endian short (type)
71
+ # n = big-endian short (architecture)
72
+ # A66 = 66-byte string (name)
73
+ # n = big-endian short (os)
74
+ # n = big-endian short (signature_type)
75
+ # A16 = 16-byte reserved
76
+ magic, major, minor, type, arch, name, os, sig_type = data.unpack("A4 CC n n A66 n n A16")
77
+
78
+ new(
79
+ magic: magic,
80
+ major_version: major,
81
+ minor_version: minor,
82
+ type: type,
83
+ architecture: arch,
84
+ name: name.strip,
85
+ os: os,
86
+ signature_type: sig_type,
87
+ ).tap(&:validate!)
77
88
  end
78
89
 
79
90
  # Validate lead structure
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/rpm"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Rpm
@@ -5,7 +5,6 @@ require "zlib"
5
5
  require "stringio"
6
6
  require "digest"
7
7
 
8
- require "omnizip/formats/rpm"
9
8
  module Omnizip
10
9
  module Formats
11
10
  module Rpm
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "stringio"
4
4
 
5
- require "omnizip/formats/seven_zip"
6
5
  module Omnizip
7
6
  module Formats
8
7
  module SevenZip
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/seven_zip"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module SevenZip
@@ -134,7 +133,7 @@ module Omnizip
134
133
  decompressor = algo_class.new
135
134
  # Pass properties if algorithm supports them
136
135
  # Some algorithms (LZMA2) need properties
137
- if chain_config[:properties] && !chain_config[:properties].empty? && decompressor.respond_to?(:properties=)
136
+ if chain_config[:properties] && !chain_config[:properties].empty? && decompressor.is_a?(Omnizip::Algorithms::LZMA2)
138
137
  decompressor.properties = chain_config[:properties]
139
138
  end
140
139
 
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/seven_zip"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module SevenZip
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/seven_zip"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module SevenZip
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/seven_zip"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module SevenZip
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "openssl"
4
4
 
5
- require "omnizip/formats/seven_zip"
6
5
  module Omnizip
7
6
  module Formats
8
7
  module SevenZip
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/seven_zip"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module SevenZip
@@ -10,7 +10,7 @@ module Omnizip
10
10
  attr_accessor :name, :size, :compressed_size, :crc, :is_dir,
11
11
  :is_empty, :is_anti, :has_stream, :mtime, :atime,
12
12
  :ctime, :attributes, :folder_index, :file_index,
13
- :source_path
13
+ :source_path, :inline_data, :compression_options
14
14
 
15
15
  # Initialize file entry
16
16
  def initialize
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/seven_zip"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module SevenZip
@@ -570,7 +569,7 @@ module Omnizip
570
569
  time_val = read_uint64
571
570
  # Convert Windows FILETIME to Ruby Time
572
571
  # (100-nanosecond intervals since 1601-01-01)
573
- entry.send(:"#{attr}=", windows_time_to_unix(time_val))
572
+ entry.public_send(:"#{attr}=", windows_time_to_unix(time_val))
574
573
  end
575
574
  end
576
575
 
@@ -174,6 +174,17 @@ module Omnizip
174
174
  encrypted? && !@password.nil?
175
175
  end
176
176
 
177
+ # Extract raw entry payload from the archive. Public so converters
178
+ # and parallel extractors can reuse the stream-positioning +
179
+ # decompression logic.
180
+ #
181
+ # @param io [IO] Archive file handle
182
+ # @param entry [Models::FileEntry] Entry to extract
183
+ # @return [String] Extracted bytes
184
+ def extract_entry_data(io, entry)
185
+ extract_entry_data_private(io, entry)
186
+ end
187
+
177
188
  private
178
189
 
179
190
  # Parse .7z archive structure
@@ -386,12 +397,12 @@ module Omnizip
386
397
  end
387
398
  end
388
399
 
389
- # Extract entry data
400
+ # Extract entry data (private implementation)
390
401
  #
391
402
  # @param io [IO] Archive file handle
392
403
  # @param entry [Models::FileEntry] Entry to extract
393
404
  # @return [String] Extracted data
394
- def extract_entry_data(io, entry)
405
+ def extract_entry_data_private(io, entry)
395
406
  return "" unless entry.has_stream?
396
407
  return "" unless @stream_info
397
408
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "fileutils"
4
4
 
5
- require "omnizip/formats/seven_zip"
6
5
  module Omnizip
7
6
  module Formats
8
7
  module SevenZip
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/seven_zip"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module SevenZip