omnizip 0.3.37 → 0.3.38
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -9
- data/docs/guides/archive-formats/gzip-format.adoc +2 -4
- data/docs/guides/archive-formats/ole-format.adoc +54 -219
- data/docs/guides/archive-formats/rar5.adoc +15 -15
- data/docs/guides/archive-formats/rpm-format.adoc +48 -189
- data/docs/reference/api/overview.adoc +16 -17
- data/docs/troubleshooting/index.adoc +1 -4
- data/lib/omnizip/archive_handler.rb +2 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
- data/lib/omnizip/archive_handlers.rb +2 -0
- data/lib/omnizip/cli.rb +25 -0
- data/lib/omnizip/convenience.rb +6 -4
- data/lib/omnizip/formats/iso/directory_builder.rb +24 -0
- data/lib/omnizip/formats/iso/reader.rb +2 -2
- data/lib/omnizip/formats/iso/writer.rb +20 -4
- data/lib/omnizip/formats/iso.rb +3 -1
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +5 -3
- data/lib/omnizip/formats/rar/rar5/header.rb +50 -33
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +17 -34
- data/lib/omnizip/formats/rar/rar5/vint.rb +25 -37
- data/lib/omnizip/formats/rar/rar5/writer.rb +50 -14
- data/lib/omnizip/formats/rar.rb +5 -3
- data/lib/omnizip/formats/seven_zip/parser.rb +22 -7
- data/lib/omnizip/formats/seven_zip/writer.rb +78 -19
- data/lib/omnizip/version.rb +1 -1
- metadata +3 -1
|
@@ -60,7 +60,9 @@ module Omnizip
|
|
|
60
60
|
entry.source_path = nil
|
|
61
61
|
entry.size = data_str.bytesize
|
|
62
62
|
entry.mtime = Time.now
|
|
63
|
-
|
|
63
|
+
# Zero-length data has no stream: readers identify it as an
|
|
64
|
+
# empty file through kEmptyStream + kEmptyFile.
|
|
65
|
+
entry.has_stream = data_str.bytesize.positive?
|
|
64
66
|
entry.inline_data = data_str
|
|
65
67
|
entry.compression_options = options
|
|
66
68
|
@entries << entry
|
|
@@ -280,7 +282,7 @@ module Omnizip
|
|
|
280
282
|
end
|
|
281
283
|
|
|
282
284
|
def build_solid_streams_info(metadata, unpack_size, compressed_size,
|
|
283
|
-
|
|
285
|
+
_num_files)
|
|
284
286
|
# kPackInfo property (0x06)
|
|
285
287
|
metadata << [PropertyId::PACK_INFO].pack("C")
|
|
286
288
|
metadata << write_number(0) # Pack position
|
|
@@ -313,37 +315,44 @@ num_files)
|
|
|
313
315
|
# kEnd for UnpackInfo
|
|
314
316
|
metadata << [PropertyId::K_END].pack("C")
|
|
315
317
|
|
|
316
|
-
# kSubStreamsInfo
|
|
318
|
+
# kSubStreamsInfo describes exactly the entries WITH a
|
|
319
|
+
# stream: directory entries (empty-stream) are excluded,
|
|
320
|
+
# or readers reject the header.
|
|
317
321
|
metadata << [PropertyId::SUBSTREAMS_INFO].pack("C")
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
322
|
+
stream_files = @entries.select(&:has_stream?)
|
|
323
|
+
# Write the explicit form whenever any entry lacks a
|
|
324
|
+
# stream (directory entries): without kNumUnpackStreams,
|
|
325
|
+
# readers assume one substream per file and reject the
|
|
326
|
+
# digest count.
|
|
327
|
+
if stream_files.size > 1 || stream_files.size != @entries.size
|
|
328
|
+
|
|
329
|
+
# NUM_UNPACK_STREAM - number of substreams in this folder
|
|
321
330
|
metadata << [PropertyId::NUM_UNPACK_STREAM].pack("C")
|
|
322
|
-
metadata << write_number(
|
|
331
|
+
metadata << write_number(stream_files.size)
|
|
323
332
|
|
|
324
|
-
# SIZE - size of each
|
|
325
|
-
# Per 7-Zip spec: only write numSubstreams-1 sizes, last
|
|
326
|
-
# from folder's unpack size minus sum
|
|
333
|
+
# SIZE - size of each substream except the last one
|
|
334
|
+
# Per 7-Zip spec: only write numSubstreams-1 sizes, last
|
|
335
|
+
# is calculated from folder's unpack size minus the sum
|
|
327
336
|
metadata << [PropertyId::SIZE].pack("C")
|
|
328
|
-
|
|
337
|
+
stream_files[0..-2].each do |entry|
|
|
329
338
|
metadata << write_number(entry.size)
|
|
330
339
|
end
|
|
331
340
|
|
|
332
341
|
# CRCs
|
|
333
342
|
metadata << [PropertyId::CRC].pack("C")
|
|
334
343
|
metadata << [1].pack("C") # All defined
|
|
335
|
-
|
|
344
|
+
stream_files.each do |entry|
|
|
336
345
|
# Use 0 for entries without CRC (empty files)
|
|
337
346
|
crc = entry.crc || 0
|
|
338
347
|
metadata << [crc].pack("V")
|
|
339
348
|
end
|
|
340
349
|
|
|
341
350
|
else
|
|
342
|
-
# Single
|
|
351
|
+
# Single substream: CRC goes in SubStreamsInfo
|
|
343
352
|
metadata << [PropertyId::CRC].pack("C")
|
|
344
353
|
metadata << [1].pack("C") # All defined
|
|
345
354
|
# Use 0 for entries without CRC (empty files)
|
|
346
|
-
crc =
|
|
355
|
+
crc = stream_files.first&.crc || 0
|
|
347
356
|
metadata << [crc].pack("V")
|
|
348
357
|
end
|
|
349
358
|
metadata << [PropertyId::K_END].pack("C")
|
|
@@ -396,12 +405,13 @@ num_files)
|
|
|
396
405
|
# kEnd for UnpackInfo
|
|
397
406
|
metadata << [PropertyId::K_END].pack("C")
|
|
398
407
|
|
|
399
|
-
# kSubStreamsInfo -
|
|
408
|
+
# kSubStreamsInfo - CRC for each substream. Each folder
|
|
409
|
+
# holds exactly one substream here, so digests cover only
|
|
410
|
+
# the entries WITH a stream (directory entries have none).
|
|
400
411
|
metadata << [PropertyId::SUBSTREAMS_INFO].pack("C")
|
|
401
412
|
metadata << [PropertyId::CRC].pack("C")
|
|
402
413
|
metadata << [1].pack("C") # All defined
|
|
403
|
-
@entries.each do |entry|
|
|
404
|
-
# Use 0 for entries without CRC (empty files)
|
|
414
|
+
@entries.select(&:has_stream?).each do |entry|
|
|
405
415
|
crc = entry.crc || 0
|
|
406
416
|
metadata << [crc].pack("V")
|
|
407
417
|
end
|
|
@@ -438,6 +448,34 @@ num_files)
|
|
|
438
448
|
# Number of files
|
|
439
449
|
metadata << write_number(@entries.size)
|
|
440
450
|
|
|
451
|
+
# Build EMPTY_STREAM property (0x0E) — written first, like
|
|
452
|
+
# 7-Zip itself: readers derive the directory flag from it;
|
|
453
|
+
# without it, directory entries are extracted as (invalid)
|
|
454
|
+
# files. Format: [EMPTY_STREAM] [size] [bit vector]
|
|
455
|
+
empty_bits = @entries.map { |e| !e.has_stream? }
|
|
456
|
+
if empty_bits.any?
|
|
457
|
+
# kEmptyStream carries the raw bit bytes only — NO
|
|
458
|
+
# all-defined marker byte (verified against 7-Zip's own
|
|
459
|
+
# -mhc=off output; a marker byte here shifts the whole
|
|
460
|
+
# header for strict readers).
|
|
461
|
+
empty_data = write_bit_bytes(empty_bits)
|
|
462
|
+
metadata << [PropertyId::EMPTY_STREAM].pack("C")
|
|
463
|
+
metadata << write_number(empty_data.bytesize)
|
|
464
|
+
metadata << empty_data
|
|
465
|
+
|
|
466
|
+
# kEmptyFile distinguishes zero-byte files from
|
|
467
|
+
# directories among the empty-stream entries.
|
|
468
|
+
empty_file_bits = @entries.map do |e|
|
|
469
|
+
!e.has_stream? && !e.is_dir
|
|
470
|
+
end
|
|
471
|
+
if empty_file_bits.any?
|
|
472
|
+
ef_data = write_bit_bytes(empty_file_bits)
|
|
473
|
+
metadata << [PropertyId::EMPTY_FILE].pack("C")
|
|
474
|
+
metadata << write_number(ef_data.bytesize)
|
|
475
|
+
metadata << ef_data
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
|
|
441
479
|
# Build NAME property (0x11)
|
|
442
480
|
# Format: [NAME] [size] [external] [UTF-16LE names with null terminators]
|
|
443
481
|
name_data = String.new(encoding: "BINARY")
|
|
@@ -474,8 +512,8 @@ num_files)
|
|
|
474
512
|
# Build WIN_ATTRIB property (0x15) - comes after MTIME per 7-Zip spec
|
|
475
513
|
# Format: [WIN_ATTRIB] [size] [defined bits] [external] [attributes]
|
|
476
514
|
attr_data = String.new(encoding: "BINARY")
|
|
477
|
-
@entries.each do |
|
|
478
|
-
attr_data << FILE_ATTRIBUTE_ARCHIVE
|
|
515
|
+
@entries.each do |entry|
|
|
516
|
+
attr_data << [entry.attributes || FILE_ATTRIBUTE_ARCHIVE.unpack1("V")].pack("V")
|
|
479
517
|
end
|
|
480
518
|
|
|
481
519
|
metadata << [PropertyId::WIN_ATTRIB].pack("C")
|
|
@@ -671,6 +709,27 @@ next_header_data)
|
|
|
671
709
|
# 110xxxxx BYTE y[2] : value = (xxxxx << 16) + y
|
|
672
710
|
# 1110xxxx BYTE y[3] : value = (xxxx << 24) + y
|
|
673
711
|
# ...up to 8 bytes total
|
|
712
|
+
# Raw MSB-first packed bit bytes, no marker
|
|
713
|
+
def write_bit_bytes(bits)
|
|
714
|
+
bytes = Array.new((bits.size + 7) / 8, 0)
|
|
715
|
+
bits.each_with_index do |bit, i|
|
|
716
|
+
bytes[i / 8] |= (1 << (7 - (i % 8))) if bit
|
|
717
|
+
end
|
|
718
|
+
bytes.pack("C*")
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
# Bit vector with an all-defined marker byte, MSB-first
|
|
722
|
+
# packing (same layout as HeaderWriter's)
|
|
723
|
+
def write_bit_vector(bits)
|
|
724
|
+
return [1].pack("C") if bits.all?
|
|
725
|
+
|
|
726
|
+
bytes = Array.new((bits.size + 7) / 8, 0)
|
|
727
|
+
bits.each_with_index do |bit, i|
|
|
728
|
+
bytes[i / 8] |= (1 << (7 - (i % 8))) if bit
|
|
729
|
+
end
|
|
730
|
+
[0].pack("C") + bytes.pack("C*")
|
|
731
|
+
end
|
|
732
|
+
|
|
674
733
|
def write_number(value)
|
|
675
734
|
# Single byte encoding (0-127)
|
|
676
735
|
return [value].pack("C") if value < 0x80
|
data/lib/omnizip/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.3.38
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -324,6 +324,8 @@ files:
|
|
|
324
324
|
- lib/omnizip/archive/reader_session.rb
|
|
325
325
|
- lib/omnizip/archive_handler.rb
|
|
326
326
|
- lib/omnizip/archive_handlers.rb
|
|
327
|
+
- lib/omnizip/archive_handlers/cpio_handler.rb
|
|
328
|
+
- lib/omnizip/archive_handlers/iso_handler.rb
|
|
327
329
|
- lib/omnizip/archive_handlers/rar_handler.rb
|
|
328
330
|
- lib/omnizip/archive_handlers/seven_zip_handler.rb
|
|
329
331
|
- lib/omnizip/archive_handlers/tar_handler.rb
|