omnizip 0.3.13 → 0.3.15

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/lib/omnizip/algorithm.rb +36 -1
  3. data/lib/omnizip/algorithms/bzip2.rb +1 -3
  4. data/lib/omnizip/algorithms/deflate.rb +1 -3
  5. data/lib/omnizip/algorithms/deflate64.rb +2 -2
  6. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +7 -8
  7. data/lib/omnizip/algorithms/lzma.rb +1 -1
  8. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +5 -1
  9. data/lib/omnizip/algorithms/lzma2.rb +4 -12
  10. data/lib/omnizip/algorithms/zstandard/constants.rb +38 -25
  11. data/lib/omnizip/algorithms/zstandard/decoder.rb +101 -136
  12. data/lib/omnizip/algorithms/zstandard/encoder.rb +81 -138
  13. data/lib/omnizip/algorithms/zstandard/frame/block.rb +17 -0
  14. data/lib/omnizip/algorithms/zstandard/frame/header.rb +42 -29
  15. data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +114 -117
  16. data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +434 -222
  17. data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
  18. data/lib/omnizip/algorithms/zstandard/fse/table.rb +98 -176
  19. data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
  20. data/lib/omnizip/algorithms/zstandard/fse.rb +21 -2
  21. data/lib/omnizip/algorithms/zstandard/huffman.rb +195 -188
  22. data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +232 -255
  23. data/lib/omnizip/algorithms/zstandard/literals.rb +170 -103
  24. data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +47 -199
  25. data/lib/omnizip/algorithms/zstandard/sequences.rb +260 -252
  26. data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
  27. data/lib/omnizip/algorithms/zstandard.rb +20 -24
  28. data/lib/omnizip/algorithms.rb +14 -1
  29. data/lib/omnizip/buffer.rb +1 -2
  30. data/lib/omnizip/commands/archive_list_command.rb +9 -7
  31. data/lib/omnizip/convenience.rb +1 -2
  32. data/lib/omnizip/entry.rb +44 -0
  33. data/lib/omnizip/extraction/selective_extractor.rb +2 -10
  34. data/lib/omnizip/filter_pipeline.rb +1 -1
  35. data/lib/omnizip/filter_registry.rb +18 -16
  36. data/lib/omnizip/filters/bcj2.rb +1 -1
  37. data/lib/omnizip/filters/bcj_arm.rb +1 -1
  38. data/lib/omnizip/filters/bcj_arm64.rb +1 -1
  39. data/lib/omnizip/filters/bcj_ia64.rb +1 -1
  40. data/lib/omnizip/filters/bcj_ppc.rb +1 -1
  41. data/lib/omnizip/filters/bcj_sparc.rb +1 -1
  42. data/lib/omnizip/filters/bcj_x86.rb +1 -1
  43. data/lib/omnizip/filters.rb +0 -2
  44. data/lib/omnizip/formats/bzip2_file.rb +0 -7
  45. data/lib/omnizip/formats/cpio/entry.rb +6 -0
  46. data/lib/omnizip/formats/cpio.rb +0 -6
  47. data/lib/omnizip/formats/gzip.rb +0 -7
  48. data/lib/omnizip/formats/iso/directory_record.rb +7 -0
  49. data/lib/omnizip/formats/iso.rb +0 -5
  50. data/lib/omnizip/formats/lzip.rb +0 -7
  51. data/lib/omnizip/formats/lzma_alone.rb +0 -6
  52. data/lib/omnizip/formats/msi/entry.rb +6 -0
  53. data/lib/omnizip/formats/msi.rb +0 -9
  54. data/lib/omnizip/formats/ole/dirent.rb +6 -0
  55. data/lib/omnizip/formats/ole.rb +0 -9
  56. data/lib/omnizip/formats/rar.rb +0 -6
  57. data/lib/omnizip/formats/rar3/reader.rb +7 -0
  58. data/lib/omnizip/formats/rar5/reader.rb +7 -0
  59. data/lib/omnizip/formats/rpm/entry.rb +6 -0
  60. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +7 -0
  61. data/lib/omnizip/formats/seven_zip.rb +0 -6
  62. data/lib/omnizip/formats/tar/entry.rb +6 -0
  63. data/lib/omnizip/formats/tar.rb +2 -10
  64. data/lib/omnizip/formats/xar/entry.rb +6 -0
  65. data/lib/omnizip/formats/xar.rb +0 -6
  66. data/lib/omnizip/formats/zip.rb +0 -6
  67. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +33 -31
  68. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +177 -163
  69. data/lib/omnizip/implementations.rb +18 -4
  70. data/lib/omnizip/io/source.rb +3 -0
  71. data/lib/omnizip/metadata/entry_metadata.rb +7 -0
  72. data/lib/omnizip/parallel/engine.rb +48 -0
  73. data/lib/omnizip/parallel/parallel_compressor.rb +5 -16
  74. data/lib/omnizip/parallel/parallel_extractor.rb +5 -16
  75. data/lib/omnizip/parallel.rb +1 -0
  76. data/lib/omnizip/profile/profile_registry.rb +1 -2
  77. data/lib/omnizip/registry.rb +0 -1
  78. data/lib/omnizip/rubyzip_compat.rb +0 -1
  79. data/lib/omnizip/temp/temp_file.rb +1 -2
  80. data/lib/omnizip/version.rb +1 -1
  81. data/lib/omnizip/zip/entry.rb +7 -0
  82. data/lib/omnizip/zip/file.rb +4 -8
  83. data/lib/omnizip.rb +1 -1
  84. metadata +7 -6
  85. data/lib/omnizip/filters/filter_base.rb +0 -6
  86. data/lib/omnizip/filters/registration.rb +0 -22
  87. data/lib/omnizip/filters/registry.rb +0 -111
  88. data/lib/omnizip/format_registry.rb +0 -100
@@ -138,13 +138,7 @@ module Omnizip
138
138
  uncompressed_size: decoder.uncompressed_size,
139
139
  }
140
140
  end
141
-
142
- # Register LZMA_Alone format when loaded
143
- def register!
144
- FormatRegistry.register(".lzma", Omnizip::Formats::LzmaAlone)
145
- end
146
141
  end
147
142
  end
148
143
  end
149
144
  end
150
-
@@ -8,8 +8,14 @@ module Omnizip
8
8
  # Represents a single file within an MSI package.
9
9
  # File information is assembled from File, Component, and Directory tables.
10
10
  class Entry
11
+ include Omnizip::Entry
11
12
  include Omnizip::Formats::Msi::Constants
12
13
 
14
+ def entry_name = path
15
+ def entry_directory? = false
16
+ def entry_size = size
17
+ def entry_mtime = nil
18
+
13
19
  # @return [String] Full installation path
14
20
  attr_accessor :path
15
21
 
@@ -67,16 +67,7 @@ module Omnizip
67
67
  def info(path)
68
68
  open(path, &:info)
69
69
  end
70
-
71
- # Register MSI format with format registry
72
- #
73
- # This overrides OLE's .msi registration.
74
- def register!
75
- FormatRegistry.register(".msi", self)
76
- FormatRegistry.register(".msp", self)
77
- end
78
70
  end
79
71
  end
80
72
  end
81
73
  end
82
-
@@ -8,8 +8,14 @@ module Omnizip
8
8
  # Represents a file or directory entry in an OLE compound document.
9
9
  # Each dirent is 128 bytes and contains metadata about the entry.
10
10
  class Dirent
11
+ include Omnizip::Entry
11
12
  include Omnizip::Formats::Ole::Constants
12
13
 
14
+ def entry_name = name
15
+ def entry_directory? = dir?
16
+ def entry_size = nil
17
+ def entry_mtime = modify_time
18
+
13
19
  # Pack format for dirent structure
14
20
  PACK = "a64 v C C V3 a16 V a8 a8 V2 a4"
15
21
 
@@ -117,14 +117,6 @@ module Omnizip
117
117
  end
118
118
  end
119
119
 
120
- # Register OLE format in registry
121
- def register!
122
- FormatRegistry.register(".ole", Storage)
123
- FormatRegistry.register(".doc", Storage)
124
- FormatRegistry.register(".xls", Storage)
125
- FormatRegistry.register(".ppt", Storage)
126
- end
127
-
128
120
  private
129
121
 
130
122
  # Recursively extract dirent to directory
@@ -147,4 +139,3 @@ module Omnizip
147
139
  end
148
140
  end
149
141
  end
150
-
@@ -161,13 +161,7 @@ module Omnizip
161
161
  def repair(archive_path, output_path)
162
162
  ArchiveRepairer.new.repair(archive_path, output_path)
163
163
  end
164
-
165
- # Auto-register .rar format
166
- def register!
167
- FormatRegistry.register(".rar", "Omnizip::Formats::Rar::Reader")
168
- end
169
164
  end
170
165
  end
171
166
  end
172
167
  end
173
-
@@ -361,10 +361,17 @@ module Omnizip
361
361
 
362
362
  # RAR archive entry model
363
363
  class Entry
364
+ include Omnizip::Entry
365
+
364
366
  attr_accessor :name, :compressed_size, :uncompressed_size, :crc32,
365
367
  :compression_method, :modified_time, :attributes,
366
368
  :encrypted, :data_offset, :host_os, :salt
367
369
 
370
+ def entry_name = name
371
+ def entry_directory? = false
372
+ def entry_size = uncompressed_size
373
+ def entry_mtime = modified_time
374
+
368
375
  def initialize(name: nil, compressed_size: nil, uncompressed_size: nil,
369
376
  crc32: nil, compression_method: nil, modified_time: nil,
370
377
  attributes: nil, encrypted: nil, data_offset: nil,
@@ -316,10 +316,17 @@ module Omnizip
316
316
 
317
317
  # RAR v5 archive entry model
318
318
  class Entry
319
+ include Omnizip::Entry
320
+
319
321
  attr_accessor :name, :compressed_size, :uncompressed_size, :crc32,
320
322
  :compression_method, :modified_time, :attributes,
321
323
  :encrypted, :data_offset, :host_os, :is_directory
322
324
 
325
+ def entry_name = name
326
+ def entry_directory? = is_directory
327
+ def entry_size = uncompressed_size
328
+ def entry_mtime = modified_time
329
+
323
330
  def initialize(name: nil, compressed_size: nil, uncompressed_size: nil,
324
331
  crc32: nil, compression_method: nil, modified_time: nil,
325
332
  attributes: nil, encrypted: nil, data_offset: nil,
@@ -8,8 +8,14 @@ module Omnizip
8
8
  # Represents a single file within an RPM package.
9
9
  # File information is assembled from multiple header tags.
10
10
  class Entry
11
+ include Omnizip::Entry
11
12
  include Omnizip::Formats::Rpm::Constants
12
13
 
14
+ def entry_name = path
15
+ def entry_directory? = mode && ::File.directory?(mode)
16
+ def entry_size = size
17
+ def entry_mtime = mtime
18
+
13
19
  # @return [String] File path
14
20
  attr_accessor :path
15
21
 
@@ -7,11 +7,18 @@ module Omnizip
7
7
  # Represents a file entry in .7z archive
8
8
  # Contains file metadata, attributes, and extraction information
9
9
  class FileEntry
10
+ include Omnizip::Entry
11
+
10
12
  attr_accessor :name, :size, :compressed_size, :crc, :is_dir,
11
13
  :is_empty, :is_anti, :has_stream, :mtime, :atime,
12
14
  :ctime, :attributes, :folder_index, :file_index,
13
15
  :source_path, :inline_data, :compression_options
14
16
 
17
+ def entry_name = name
18
+ def entry_directory? = is_dir
19
+ def entry_size = size
20
+ def entry_mtime = mtime
21
+
15
22
  # Initialize file entry
16
23
  def initialize
17
24
  @name = nil
@@ -174,12 +174,6 @@ module Omnizip
174
174
  rescue StandardError
175
175
  false
176
176
  end
177
-
178
- # Auto-register .7z format when loaded
179
- def self.register!
180
- FormatRegistry.register(".7z", "Omnizip::Formats::SevenZip::Reader")
181
- end
182
177
  end
183
178
  end
184
179
  end
185
-
@@ -7,12 +7,18 @@ module Omnizip
7
7
  #
8
8
  # Represents a single entry (file, directory, link) in a TAR archive
9
9
  class Entry
10
+ include Omnizip::Entry
10
11
  include Omnizip::Formats::Tar::Constants
11
12
 
12
13
  attr_accessor :name, :mode, :uid, :gid, :size, :mtime, :typeflag,
13
14
  :linkname, :uname, :gname, :devmajor, :devminor, :prefix
14
15
  attr_reader :data
15
16
 
17
+ def entry_name = name
18
+ def entry_directory? = directory?
19
+ def entry_size = size
20
+ def entry_mtime = mtime
21
+
16
22
  # Initialize a new TAR entry
17
23
  #
18
24
  # @param name [String] Entry name/path
@@ -36,22 +36,20 @@ module Omnizip
36
36
  # @param file_path [String] Path to TAR archive
37
37
  # @yield [Reader] TAR reader instance
38
38
  # @return [Reader] TAR reader instance
39
- # rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
39
+ # rubocop:disable-next Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
40
40
  def open(file_path, &block)
41
41
  Reader.open(file_path, &block)
42
42
  end
43
- # rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
44
43
 
45
44
  # Create a TAR archive
46
45
  #
47
46
  # @param file_path [String] Path to output TAR archive
48
47
  # @yield [Writer] TAR writer instance
49
48
  # @return [Writer] TAR writer instance
50
- # rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
49
+ # rubocop:disable-next Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
51
50
  def create(file_path, &block)
52
51
  Writer.create(file_path, &block)
53
52
  end
54
- # rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
55
53
 
56
54
  # Extract a TAR archive
57
55
  #
@@ -70,13 +68,7 @@ module Omnizip
70
68
  reader = read(file_path)
71
69
  reader.list_entries
72
70
  end
73
-
74
- # Register TAR format when loaded
75
- def register!
76
- FormatRegistry.register(".tar", Omnizip::Formats::Tar)
77
- end
78
71
  end
79
72
  end
80
73
  end
81
74
  end
82
-
@@ -8,8 +8,14 @@ module Omnizip
8
8
  # Represents a single file/directory/link in a XAR archive.
9
9
  # Each entry has metadata and optional data.
10
10
  class Entry
11
+ include Omnizip::Entry
11
12
  include Omnizip::Formats::Xar::Constants
12
13
 
14
+ def entry_name = name
15
+ def entry_directory? = type == :directory
16
+ def entry_size = size
17
+ def entry_mtime = mtime
18
+
13
19
  attr_accessor :id, :name, :type, :mode, :uid, :gid, :user, :group,
14
20
  :size, :ctime, :mtime, :atime,
15
21
  :data_offset, :data_length, :data_size, :data_encoding,
@@ -139,13 +139,7 @@ module Omnizip
139
139
  def info(path)
140
140
  open(path, &:info) # rubocop:disable Security/Open
141
141
  end
142
-
143
- # Auto-register XAR format when loaded
144
- def register!
145
- FormatRegistry.register(".xar", Reader)
146
- end
147
142
  end
148
143
  end
149
144
  end
150
145
  end
151
-
@@ -44,13 +44,7 @@ module Omnizip
44
44
  reader = read(file_path)
45
45
  reader.list_entries
46
46
  end
47
-
48
- # Auto-register .zip format when loaded
49
- def register!
50
- FormatRegistry.register(".zip", Omnizip::Formats::Zip)
51
- end
52
47
  end
53
48
  end
54
49
  end
55
50
  end
56
-
@@ -326,7 +326,9 @@ _input_data)
326
326
  prob_is_rep = @models.is_rep[@state.value]
327
327
  encoder.queue_bit(prob_is_rep, 0)
328
328
 
329
- @state.update_match!(distance)
329
+ # Reps are stored 0-based (distance - 1), matching the decoder's
330
+ # rep0 convention.
331
+ @state.update_match!(distance - 1)
330
332
 
331
333
  encode_match_length(length, pos_state, encoder)
332
334
  encode_distance(distance, length, encoder)
@@ -362,39 +364,36 @@ _input_data)
362
364
 
363
365
  prob_is_rep2 = @models.is_rep2[@state.value]
364
366
  encoder.queue_bit(prob_is_rep2, rep - 2)
365
-
366
- if rep == 3
367
- @state.reps[3] = @state.reps[2]
368
- end
369
-
370
- @state.reps[2] = @state.reps[1]
371
367
  end
372
368
 
373
- @state.reps[1] = @state.reps[0]
374
-
369
+ # XZ Utils rep_match: capture the selected distance BEFORE
370
+ # rotating, then shift reps down.
375
371
  distance = @state.reps[rep]
376
-
377
- if distance.nil?
378
- raise "Distance is nil for rep #{rep}, reps=#{@state.reps.inspect}"
379
- end
380
-
372
+ rep.downto(1) { |i| @state.reps[i] = @state.reps[i - 1] }
381
373
  @state.reps[0] = distance
382
374
  end
383
375
 
384
376
  if length == 1
385
377
  @state.update_short_rep!
386
378
  else
387
- encode_match_length(length, pos_state, encoder)
379
+ # Rep matches use their own length models (decoder's
380
+ # rep_length_coder).
381
+ encode_match_length(length, pos_state, encoder,
382
+ @models.rep_len_encoder)
388
383
  @state.update_long_rep!
389
384
  end
390
385
 
391
- last_byte_pos = match_pos - @state.reps[0] + length - 1
386
+ # Last byte of the match region in the stream
387
+ last_byte_pos = match_pos + length - 1
392
388
  @prev_byte = @match_finder.buffer.getbyte(last_byte_pos) if last_byte_pos >= 0 && last_byte_pos < @match_finder.buffer.bytesize
393
389
  end
394
390
 
395
391
  def get_literal_state(pos, prev_byte)
396
392
  literal_mask = (0x100 << @lp) - (0x100 >> @lc)
397
- ((((pos << 8) + prev_byte) & literal_mask) << @lc)
393
+ # Factor of 3: each literal context owns a 0x300-sized subcoder
394
+ # (XZ Utils literal_subcoder macro); must match the decoder's
395
+ # base_offset = 3 * (lit_state << lc).
396
+ 3 * ((((pos << 8) + prev_byte) & literal_mask) << @lc)
398
397
  end
399
398
 
400
399
  def encode_normal_literal(literal_offset, symbol, encoder)
@@ -426,28 +425,31 @@ encoder)
426
425
  end
427
426
  end
428
427
 
429
- def encode_match_length(length, pos_state, encoder)
428
+ # len_encoder selects the length model set: match_len_encoder for
429
+ # normal matches, rep_len_encoder for repeated matches.
430
+ def encode_match_length(length, pos_state, encoder,
431
+ len_encoder = @models.match_len_encoder)
430
432
  len = length - 2
431
433
 
432
434
  if len < 8
433
- encoder.queue_bit(@models.match_len_encoder.choice, 0)
434
- encode_bittree(@models.match_len_encoder.low[pos_state], 3, len,
435
- encoder)
435
+ encoder.queue_bit(len_encoder.choice, 0)
436
+ encode_bittree(len_encoder.low[pos_state], 3, len, encoder)
436
437
  elsif len < 16
437
- encoder.queue_bit(@models.match_len_encoder.choice, 1)
438
- encoder.queue_bit(@models.match_len_encoder.choice2, 0)
439
- encode_bittree(@models.match_len_encoder.mid[pos_state], 3,
440
- len - 8, encoder)
438
+ encoder.queue_bit(len_encoder.choice, 1)
439
+ encoder.queue_bit(len_encoder.choice2, 0)
440
+ encode_bittree(len_encoder.mid[pos_state], 3, len - 8, encoder)
441
441
  else
442
- encoder.queue_bit(@models.match_len_encoder.choice, 1)
443
- encoder.queue_bit(@models.match_len_encoder.choice2, 1)
444
- encode_bittree(@models.match_len_encoder.high, 8, len - 16,
445
- encoder)
442
+ encoder.queue_bit(len_encoder.choice, 1)
443
+ encoder.queue_bit(len_encoder.choice2, 1)
444
+ encode_bittree(len_encoder.high, 8, len - 16, encoder)
446
445
  end
447
446
  end
448
447
 
449
448
  def encode_distance(distance, length, encoder)
450
- dist_slot = get_dist_slot(distance)
449
+ # get_dist_slot expects a 0-based distance (xz fastpos.h:
450
+ # dist 4 -> slot 4, dist 5 -> slot 4).
451
+ dist0 = distance - 1
452
+ dist_slot = get_dist_slot(dist0)
451
453
  len_state = [length - 2, 3].min
452
454
 
453
455
  encode_bittree(@models.dist_slot[len_state], 6, dist_slot, encoder)
@@ -455,7 +457,7 @@ encoder)
455
457
  if dist_slot >= 4
456
458
  footer_bits = (dist_slot >> 1) - 1
457
459
  base = (2 | (dist_slot & 1)) << footer_bits
458
- dist_reduced = distance - base
460
+ dist_reduced = dist0 - base
459
461
 
460
462
  if dist_slot < 14
461
463
  encode_bittree_reverse(@models.dist_special, dist_reduced,