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
@@ -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
@@ -62,9 +61,8 @@ module Omnizip
62
61
  entry.size = data_str.bytesize
63
62
  entry.mtime = Time.now
64
63
  entry.has_stream = true
65
- entry.instance_variable_set(:@_data, data_str)
66
- # Store compression options for later use
67
- entry.compression_options = options if entry.respond_to?(:compression_options=)
64
+ entry.inline_data = data_str
65
+ entry.compression_options = options
68
66
  @entries << entry
69
67
  end
70
68
 
@@ -175,7 +173,7 @@ module Omnizip
175
173
  total_size = 0
176
174
 
177
175
  files_with_data.each do |entry|
178
- data = entry.instance_variable_get(:@_data) || File.binread(entry.source_path)
176
+ data = entry.inline_data || File.binread(entry.source_path)
179
177
  combined << data
180
178
  total_size += data.bytesize
181
179
 
@@ -193,7 +191,7 @@ module Omnizip
193
191
  total_size = 0
194
192
 
195
193
  files_with_data.each do |entry|
196
- data = entry.instance_variable_get(:@_data) || File.binread(entry.source_path)
194
+ data = entry.inline_data || File.binread(entry.source_path)
197
195
 
198
196
  crc = Omnizip::Checksums::Crc32.new
199
197
  crc.update(data)
@@ -98,7 +98,7 @@ module Omnizip
98
98
  begin
99
99
  yield reader
100
100
  ensure
101
- reader.split_reader&.close if reader.respond_to?(:split_reader)
101
+ reader.split_reader&.close
102
102
  end
103
103
  end
104
104
 
@@ -177,12 +177,10 @@ module Omnizip
177
177
 
178
178
  # Auto-register .7z format when loaded
179
179
  def self.register!
180
- require "omnizip/format_registry"
181
- FormatRegistry.register(".7z", Reader)
180
+ FormatRegistry.register(".7z", "Omnizip::Formats::SevenZip::Reader")
182
181
  end
183
182
  end
184
183
  end
185
184
  end
186
185
 
187
- # Auto-register when file is loaded
188
186
  Omnizip::Formats::SevenZip.register!
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/tar"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Tar
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/tar"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Tar
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/tar"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Tar
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/tar"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Tar
@@ -73,7 +73,6 @@ module Omnizip
73
73
 
74
74
  # Register TAR format when loaded
75
75
  def register!
76
- require "omnizip/format_registry"
77
76
  FormatRegistry.register(".tar", Omnizip::Formats::Tar)
78
77
  end
79
78
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/xar"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Xar
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/xar"
4
3
  module Omnizip
5
4
  module Formats
6
5
  module Xar
@@ -3,7 +3,6 @@
3
3
  require "zlib"
4
4
  require "digest"
5
5
 
6
- require "omnizip/formats/xar"
7
6
  module Omnizip
8
7
  module Formats
9
8
  module Xar
@@ -5,7 +5,6 @@ require "zlib"
5
5
  require "time"
6
6
  require "rexml/document"
7
7
 
8
- require "omnizip/formats/xar"
9
8
  module Omnizip
10
9
  module Formats
11
10
  module Xar
@@ -224,7 +223,7 @@ module Omnizip
224
223
  def self.text_content(elem)
225
224
  return nil if elem.nil?
226
225
 
227
- text = elem.respond_to?(:text) ? elem.text : elem.to_s
226
+ text = elem.is_a?(REXML::Element) ? elem.text : elem.to_s
228
227
  text&.strip
229
228
  end
230
229
  private_class_method :text_content
@@ -4,7 +4,6 @@ require "zlib"
4
4
  require "digest"
5
5
  require "fileutils"
6
6
 
7
- require "omnizip/formats/xar"
8
7
  module Omnizip
9
8
  module Formats
10
9
  module Xar
@@ -75,7 +74,7 @@ module Omnizip
75
74
  size: stat.size,
76
75
  mtime: stat.mtime,
77
76
  atime: stat.atime,
78
- ctime: stat.ctime.respond_to?(:to_time) ? stat.ctime.to_time : stat.ctime,
77
+ ctime: to_time(stat.ctime),
79
78
  })
80
79
 
81
80
  # Check for hardlink
@@ -114,7 +113,7 @@ module Omnizip
114
113
  gid: stat.gid,
115
114
  mtime: stat.mtime,
116
115
  atime: stat.atime,
117
- ctime: stat.ctime.respond_to?(:to_time) ? stat.ctime.to_time : stat.ctime,
116
+ ctime: to_time(stat.ctime),
118
117
  })
119
118
 
120
119
  add_entry(entry)
@@ -254,6 +253,15 @@ module Omnizip
254
253
 
255
254
  private
256
255
 
256
+ # Coerce a ctime value (File::Stat returns Time on Unix, may
257
+ # return other types on Windows) into a Time.
258
+ def to_time(value)
259
+ return value if value.is_a?(Time)
260
+ return value.to_time if value.is_a?(Date) || value.is_a?(DateTime)
261
+
262
+ value
263
+ end
264
+
257
265
  # Read file data and add to heap
258
266
  #
259
267
  # @param entry [Entry] Entry to populate
@@ -142,7 +142,6 @@ module Omnizip
142
142
 
143
143
  # Auto-register XAR format when loaded
144
144
  def register!
145
- require "omnizip/format_registry"
146
145
  FormatRegistry.register(".xar", Reader)
147
146
  end
148
147
  end
@@ -36,7 +36,7 @@ module Omnizip
36
36
  def initialize(input)
37
37
  @input = if input.is_a?(String)
38
38
  File.open(input, "rb")
39
- elsif input.respond_to?(:read)
39
+ elsif input.is_a?(::IO) || input.is_a?(StringIO)
40
40
  input
41
41
  else
42
42
  raise ArgumentError,
@@ -56,14 +56,18 @@ module Omnizip
56
56
 
57
57
  # Close the input stream if we opened it
58
58
  def close
59
- @input.close if @input.respond_to?(:close) && !@input.closed?
59
+ @input.close unless @input.closed?
60
+ rescue IOError
61
+ nil
60
62
  end
61
63
 
62
64
  # Check if reader is open
63
65
  #
64
66
  # @return [Boolean] True if input is open
65
67
  def closed?
66
- @input.respond_to?(:closed?) ? @input.closed? : false
68
+ @input.closed?
69
+ rescue IOError
70
+ true
67
71
  end
68
72
 
69
73
  # Read in a streaming fashion (for large files)
@@ -17,10 +17,6 @@ module Omnizip
17
17
  # @option options [Integer] :dict_size Dictionary size (default: 8MB to match XZ Utils preset 6)
18
18
  # @option options [Integer] :check Check type (default: CRC64)
19
19
  def create(input, output = nil, options = {})
20
- require "omnizip/formats/xz_impl"
21
- require "omnizip/formats/xz_const"
22
- require "omnizip/formats/xz_impl/stream_encoder"
23
-
24
20
  encoder = ::Omnizip::Formats::XzImpl::StreamEncoder.new(
25
21
  check_type: options[:check] || ::Omnizip::Formats::XzConst::CHECK_CRC64,
26
22
  dict_size: options[:dict_size] || (64 * 1024 * 1024),
@@ -29,11 +25,7 @@ module Omnizip
29
25
  compressed = encoder.encode(input)
30
26
 
31
27
  if output
32
- if output.respond_to?(:write)
33
- output.write(compressed)
34
- else
35
- File.binwrite(output, compressed)
36
- end
28
+ Omnizip::IO::Sink.for(output).write(compressed)
37
29
  else
38
30
  compressed
39
31
  end
@@ -72,42 +64,13 @@ module Omnizip
72
64
  # @param options [Hash] Options (reserved for future use)
73
65
  # @return [String, nil] Decompressed data (if output is nil)
74
66
  def decompress(input, output = nil, _options = {})
75
- # Handle raw data string vs file path
76
- data = if input.respond_to?(:read)
77
- # Already an IO object - read content
78
- if input.respond_to?(:size)
79
- # Seekable IO (File, etc.) - read without consuming
80
- original_pos = input.pos
81
- content = input.read
82
- input.seek(original_pos)
83
- else
84
- # Non-seekable IO - read and consume
85
- content = input.read
86
- end
87
- content
88
- elsif input.is_a?(String)
89
- # Could be file path or raw data
90
- # If string contains null byte, it's definitely data (not a path)
91
- # Also check if it's a valid file path first
92
- if !input.include?("\0") && File.exist?(input)
93
- File.binread(input)
94
- else
95
- input.b
96
- end
97
- else
98
- raise ArgumentError,
99
- "Input must be a String or IO object"
100
- end
67
+ data = Omnizip::IO::Source.for(input).read
101
68
 
102
69
  # Detect format and decode
103
70
  decompressed = decode_lzma_data(data)
104
71
 
105
72
  if output
106
- if output.respond_to?(:write)
107
- output.write(decompressed)
108
- else
109
- File.binwrite(output, decompressed)
110
- end
73
+ Omnizip::IO::Sink.for(output).write(decompressed)
111
74
  nil
112
75
  else
113
76
  decompressed
@@ -567,11 +567,8 @@ module Omnizip
567
567
 
568
568
  # Create LZMA2 decoder with raw_mode for XZ format
569
569
  decoder = Omnizip::Implementations::XZUtils::LZMA2::Decoder.new(input_buffer,
570
- raw_mode: true)
571
-
572
- # Set dict_size directly since we skipped property byte reading
573
- decoder.instance_variable_set(:@dict_size, dict_size)
574
- decoder.instance_variable_set(:@properties, Omnizip::Algorithms::LZMA2::Properties.new(dict_size))
570
+ raw_mode: true,
571
+ dict_size: dict_size)
575
572
 
576
573
  # Decode stream
577
574
  uncompressed_data = decoder.decode_stream
@@ -623,11 +620,8 @@ module Omnizip
623
620
 
624
621
  # Create LZMA2 decoder with raw_mode for XZ format
625
622
  decoder = Omnizip::Implementations::XZUtils::LZMA2::Decoder.new(input_buffer,
626
- raw_mode: true)
627
-
628
- # Set dict_size directly since we skipped property byte reading
629
- decoder.instance_variable_set(:@dict_size, dict_size)
630
- decoder.instance_variable_set(:@properties, Omnizip::Algorithms::LZMA2::Properties.new(dict_size))
623
+ raw_mode: true,
624
+ dict_size: dict_size)
631
625
 
632
626
  # Decode stream
633
627
  decoder.decode_stream
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "stringio"
4
- require "omnizip/algorithms/xz_lzma2"
5
- require "omnizip/checksums/crc64"
6
4
  require "zlib"
7
5
 
8
6
  module Omnizip
@@ -22,8 +22,6 @@
22
22
 
23
23
  require "stringio"
24
24
  require "zlib"
25
- require "omnizip/error"
26
- require "omnizip/checksums/verifier"
27
25
 
28
26
  module Omnizip
29
27
  module Formats
@@ -22,7 +22,6 @@
22
22
 
23
23
  require "stringio"
24
24
  require "zlib"
25
- require "omnizip/error"
26
25
 
27
26
  module Omnizip
28
27
  module Formats
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "stringio"
4
4
  require "zlib"
5
- require "omnizip/error"
6
5
 
7
6
  module Omnizip
8
7
  module Formats
@@ -25,7 +25,7 @@ module Omnizip
25
25
  output.set_encoding(Encoding::BINARY)
26
26
 
27
27
  # Read input data
28
- input_data = input.respond_to?(:read) ? input.read : input.to_s
28
+ input_data = Omnizip::IO::Source.for(input).read
29
29
  input_data = input_data.dup.force_encoding(Encoding::BINARY)
30
30
 
31
31
  # 1. Write Stream Header
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "zlib"
4
- require "omnizip/error"
5
4
 
6
5
  module Omnizip
7
6
  module Formats
@@ -21,7 +21,6 @@
21
21
  # DEALINGS IN THE SOFTWARE.
22
22
 
23
23
  require "zlib"
24
- require "omnizip/error"
25
24
 
26
25
  module Omnizip
27
26
  module Formats
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "zlib"
4
- require "omnizip/error"
5
4
 
6
5
  module Omnizip
7
6
  module Formats
@@ -21,8 +21,6 @@
21
21
  # DEALINGS IN THE SOFTWARE.
22
22
 
23
23
  require "zlib"
24
- require "omnizip/error"
25
- require "omnizip/checksums/verifier"
26
24
 
27
25
  module Omnizip
28
26
  module Formats
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/zip"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Zip
@@ -14,7 +12,8 @@ module Omnizip
14
12
  :crc32, :compressed_size, :uncompressed_size,
15
13
  :filename_length, :extra_field_length, :comment_length,
16
14
  :disk_number_start, :internal_attributes, :external_attributes,
17
- :local_header_offset, :filename, :extra_field, :comment
15
+ :local_header_offset, :filename, :extra_field, :comment,
16
+ :cached_original_data
18
17
 
19
18
  def initialize(
20
19
  signature: CENTRAL_DIRECTORY_SIGNATURE,
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/zip"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Zip
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/zip"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Zip
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/zip"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Zip
@@ -149,6 +147,18 @@ dereference_links: false)
149
147
  end
150
148
  end
151
149
 
150
+ # Decompress +compressed_data+ according to +method+. Public API
151
+ # for callers (e.g., ParallelExtractor) that hold raw compressed
152
+ # payload outside an entry stream.
153
+ #
154
+ # @param compressed_data [String] Compressed bytes
155
+ # @param method [Integer] ZIP compression method code
156
+ # @param uncompressed_size [Integer] Expected uncompressed size
157
+ # @return [String] Decompressed bytes
158
+ def decompress(compressed_data, method, uncompressed_size)
159
+ decompress_data(compressed_data, method, uncompressed_size)
160
+ end
161
+
152
162
  private
153
163
 
154
164
  # Read central directory entries
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
- require "omnizip/formats/zip"
5
4
 
6
5
  module Omnizip
7
6
  module Formats
@@ -112,6 +111,79 @@ module Omnizip
112
111
  end
113
112
  end
114
113
 
114
+ # Add an entry whose payload is already compressed. Bypasses
115
+ # per-entry compression in +#write+, so +#write_precompressed+
116
+ # must be used instead of +#write+ to emit the archive.
117
+ #
118
+ # @param filename [String] Entry name in the archive
119
+ # @param uncompressed_size [Integer] Size before compression
120
+ # @param compressed_size [Integer] Size of +compressed_data+
121
+ # @param crc32 [Integer] CRC32 of the uncompressed data
122
+ # @param compressed_data [String] Pre-compressed payload
123
+ # @param stat [File::Stat, nil] Optional stat for the source file
124
+ def add_precompressed_entry(filename:, uncompressed_size:,
125
+ compressed_size:, crc32:,
126
+ compressed_data:, stat: nil)
127
+ entry = create_entry(
128
+ filename: filename,
129
+ uncompressed_data: "",
130
+ stat: stat,
131
+ )
132
+ entry[:compressed_size] = compressed_size
133
+ entry[:uncompressed_size] = uncompressed_size
134
+ entry[:crc32] = crc32
135
+ entry[:compressed_data] = compressed_data
136
+ @entries << entry
137
+ entry
138
+ end
139
+
140
+ # Write the archive using pre-compressed entry payloads (set
141
+ # via +#add_precompressed_entry+).
142
+ #
143
+ # @param compression_method [Integer] ZIP compression method
144
+ # code recorded in the headers
145
+ def write_precompressed(compression_method: COMPRESSION_DEFLATE)
146
+ File.open(file_path, "wb") do |io|
147
+ write_precompressed_to_io(io, compression_method: compression_method)
148
+ end
149
+ end
150
+
151
+ def write_precompressed_to_io(io, compression_method: COMPRESSION_DEFLATE)
152
+ local_header_offsets = []
153
+
154
+ entries.each do |entry|
155
+ offset = io.pos
156
+ local_header_offsets << offset
157
+
158
+ local_header = create_local_header(entry, compression_method)
159
+ local_header.compressed_size = entry[:compressed_size]
160
+ local_header.uncompressed_size = entry[:uncompressed_size]
161
+ local_header.crc32 = entry[:crc32]
162
+ io.write(local_header.to_binary)
163
+ io.write(entry[:compressed_data]) unless entry[:directory]
164
+ end
165
+
166
+ central_directory_offset = io.pos
167
+
168
+ entries.each_with_index do |entry, index|
169
+ central_header = create_central_header(
170
+ entry,
171
+ compression_method,
172
+ local_header_offsets[index],
173
+ )
174
+ io.write(central_header.to_binary)
175
+ end
176
+
177
+ central_directory_size = io.pos - central_directory_offset
178
+
179
+ eocd = create_eocd(
180
+ total_entries: entries.size,
181
+ central_directory_size: central_directory_size,
182
+ central_directory_offset: central_directory_offset,
183
+ )
184
+ io.write(eocd.to_binary)
185
+ end
186
+
115
187
  # Write to an IO object
116
188
  def write_to_io(io, compression_method: COMPRESSION_DEFLATE, level: 6)
117
189
  local_header_offsets = []
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/zip"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Zip
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/zip"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Zip
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "omnizip/formats/zip"
4
-
5
3
  module Omnizip
6
4
  module Formats
7
5
  module Zip
@@ -47,7 +47,6 @@ module Omnizip
47
47
 
48
48
  # Auto-register .zip format when loaded
49
49
  def register!
50
- require "omnizip/format_registry"
51
50
  FormatRegistry.register(".zip", Omnizip::Formats::Zip)
52
51
  end
53
52
  end
@@ -2,42 +2,26 @@
2
2
 
3
3
  module Omnizip
4
4
  module Formats
5
- # Archive format support
6
- #
7
- # This module contains format-specific autoload declarations.
8
- # Less commonly used formats are autoloaded for lazy loading.
9
-
10
- # Format specification loader
11
5
  autoload :FormatSpecLoader, "omnizip/formats/format_spec_loader"
12
6
 
13
- # CPIO archive format
14
- autoload :Cpio, "omnizip/formats/cpio"
7
+ autoload :SevenZip, "omnizip/formats/seven_zip"
8
+ autoload :Zip, "omnizip/formats/zip"
9
+ autoload :Rar, "omnizip/formats/rar"
10
+ autoload :Tar, "omnizip/formats/tar"
11
+ autoload :Gzip, "omnizip/formats/gzip"
12
+ autoload :Bzip2File, "omnizip/formats/bzip2_file"
13
+ autoload :Xz, "omnizip/formats/xz"
15
14
 
16
- # RPM package format
15
+ autoload :Cpio, "omnizip/formats/cpio"
17
16
  autoload :Rpm, "omnizip/formats/rpm"
18
-
19
- # OLE compound documents (MSI, DOC, XLS, PPT)
20
17
  autoload :Ole, "omnizip/formats/ole"
21
-
22
- # MSI (Microsoft Installer) - overrides OLE's .msi registration
23
18
  autoload :Msi, "omnizip/formats/msi"
24
-
25
- # XAR archive format
26
19
  autoload :Xar, "omnizip/formats/xar"
27
-
28
- # ISO 9660 CD-ROM format
29
20
  autoload :Iso, "omnizip/formats/iso"
30
-
31
- # LZMA alone format
32
21
  autoload :LzmaAlone, "omnizip/formats/lzma_alone"
33
-
34
- # LZIP format
35
22
  autoload :Lzip, "omnizip/formats/lzip"
36
23
 
37
- # XZ format constants (at Formats level for cross-module access)
38
24
  autoload :XzConst, "omnizip/formats/xz_const"
39
-
40
- # XZ implementation details
41
25
  autoload :XzImpl, "omnizip/formats/xz_impl"
42
26
  end
43
27
  end