omnizip 0.3.8 → 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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +51 -50
- data/Gemfile +2 -0
- data/Rakefile +3 -0
- data/TODO.refactor/00-overview.md +67 -0
- data/TODO.refactor/01-registry-base-class.md +81 -0
- data/TODO.refactor/02-error-hierarchy.md +57 -0
- data/TODO.refactor/03-autoload-entry-point.md +69 -0
- data/TODO.refactor/04-filter-base-consolidation.md +49 -0
- data/TODO.refactor/05-send-private-methods.md +64 -0
- data/TODO.refactor/06-instance-variable-access.md +69 -0
- data/TODO.refactor/07-respond-to-replacement.md +91 -0
- data/TODO.refactor/08-spec-doubles.md +27 -0
- data/TODO.refactor/09-cli-shared-module.md +35 -0
- data/TODO.refactor/10-format-detector-ocp.md +34 -0
- data/TODO.refactor/11-convenience-decoupling.md +38 -0
- data/TODO.refactor/12-thread-safety.md +8 -0
- data/TODO.refactor/13-lutaml-model-migration.md +82 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -0
- data/lib/omnizip/algorithm.rb +0 -2
- data/lib/omnizip/algorithm_registry.rb +29 -57
- data/lib/omnizip/algorithms/lzma/bit_model.rb +1 -1
- data/lib/omnizip/algorithms/lzma/dictionary.rb +4 -3
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +5 -102
- data/lib/omnizip/algorithms/lzma/length_coder.rb +4 -92
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +4 -119
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +2 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +59 -29
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +20 -12
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +77 -269
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +0 -9
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +0 -15
- data/lib/omnizip/algorithms/lzma/xz_state.rb +0 -8
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +189 -968
- data/lib/omnizip/algorithms/lzma2/encoder.rb +0 -2
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +0 -2
- data/lib/omnizip/algorithms/lzma2/properties.rb +0 -2
- data/lib/omnizip/algorithms/ppmd7/model.rb +1 -1
- data/lib/omnizip/algorithms/ppmd8/context.rb +0 -2
- data/lib/omnizip/algorithms/ppmd8/model.rb +1 -1
- data/lib/omnizip/algorithms/ppmd8.rb +0 -2
- data/lib/omnizip/algorithms/ppmd_base.rb +0 -2
- data/lib/omnizip/algorithms/sevenzip_lzma2.rb +0 -5
- data/lib/omnizip/algorithms/xz_lzma2.rb +0 -5
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +3 -5
- data/lib/omnizip/algorithms.rb +1 -0
- data/lib/omnizip/archive_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +51 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +73 -0
- data/lib/omnizip/archive_handlers.rb +11 -0
- data/lib/omnizip/checksum_registry.rb +23 -96
- data/lib/omnizip/cli/shared.rb +31 -0
- data/lib/omnizip/cli.rb +6 -43
- data/lib/omnizip/commands/archive_create_command.rb +0 -6
- data/lib/omnizip/commands/archive_extract_command.rb +0 -4
- data/lib/omnizip/commands/archive_list_command.rb +0 -4
- data/lib/omnizip/commands/archive_repair_command.rb +0 -2
- data/lib/omnizip/commands/archive_verify_command.rb +0 -2
- data/lib/omnizip/commands/compress_command.rb +0 -2
- data/lib/omnizip/commands/decompress_command.rb +0 -2
- data/lib/omnizip/commands/list_command.rb +0 -2
- data/lib/omnizip/commands/metadata_command.rb +0 -5
- data/lib/omnizip/commands/parity_create_command.rb +0 -2
- data/lib/omnizip/commands/parity_repair_command.rb +0 -2
- data/lib/omnizip/commands/parity_verify_command.rb +0 -2
- data/lib/omnizip/commands/profile_list_command.rb +0 -2
- data/lib/omnizip/commands/profile_show_command.rb +0 -2
- data/lib/omnizip/convenience.rb +111 -234
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +1 -1
- data/lib/omnizip/crypto/aes256/cipher.rb +6 -1
- data/lib/omnizip/error.rb +22 -18
- data/lib/omnizip/filter.rb +5 -3
- data/lib/omnizip/filter_registry.rb +74 -98
- data/lib/omnizip/filters/bcj2/decoder.rb +196 -130
- data/lib/omnizip/filters/bcj2.rb +0 -2
- data/lib/omnizip/filters/bcj_x86.rb +0 -2
- data/lib/omnizip/filters/filter_base.rb +4 -70
- data/lib/omnizip/filters/registry.rb +0 -2
- data/lib/omnizip/format_detector.rb +21 -12
- data/lib/omnizip/format_registry.rb +79 -38
- data/lib/omnizip/formats/bzip2_file.rb +0 -2
- data/lib/omnizip/formats/cpio/entry.rb +0 -2
- data/lib/omnizip/formats/cpio/reader.rb +0 -1
- data/lib/omnizip/formats/cpio/writer.rb +0 -1
- data/lib/omnizip/formats/cpio.rb +0 -1
- data/lib/omnizip/formats/format_spec_loader.rb +1 -1
- data/lib/omnizip/formats/gzip.rb +0 -2
- data/lib/omnizip/formats/iso/directory_record.rb +6 -3
- data/lib/omnizip/formats/iso/reader.rb +2 -2
- data/lib/omnizip/formats/iso.rb +0 -1
- data/lib/omnizip/formats/lzip.rb +5 -25
- data/lib/omnizip/formats/lzma_alone.rb +7 -25
- data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
- data/lib/omnizip/formats/msi/constants.rb +157 -0
- data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
- data/lib/omnizip/formats/msi/entry.rb +128 -0
- data/lib/omnizip/formats/msi/reader.rb +301 -0
- data/lib/omnizip/formats/msi/string_pool.rb +246 -0
- data/lib/omnizip/formats/msi/table_parser.rb +244 -0
- data/lib/omnizip/formats/msi.rb +84 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +10 -1
- data/lib/omnizip/formats/ole/dirent.rb +20 -3
- data/lib/omnizip/formats/ole/header.rb +0 -1
- data/lib/omnizip/formats/ole/ranges_io.rb +21 -3
- data/lib/omnizip/formats/ole/storage.rb +19 -4
- data/lib/omnizip/formats/ole.rb +0 -2
- data/lib/omnizip/formats/rar/block_parser.rb +0 -1
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +1 -1
- data/lib/omnizip/formats/rar/decompressor.rb +38 -1
- data/lib/omnizip/formats/rar/header.rb +0 -1
- data/lib/omnizip/formats/rar/rar5/writer.rb +0 -2
- data/lib/omnizip/formats/rar/reader.rb +2 -3
- data/lib/omnizip/formats/rar/writer.rb +0 -1
- data/lib/omnizip/formats/rar.rb +2 -2
- data/lib/omnizip/formats/rpm/entry.rb +0 -1
- data/lib/omnizip/formats/rpm/header.rb +3 -8
- data/lib/omnizip/formats/rpm/lead.rb +37 -26
- data/lib/omnizip/formats/rpm/tag.rb +0 -1
- data/lib/omnizip/formats/rpm/writer.rb +0 -1
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +98 -61
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +1 -2
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +0 -1
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +0 -1
- data/lib/omnizip/formats/seven_zip/header.rb +0 -1
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +0 -1
- data/lib/omnizip/formats/seven_zip/header_writer.rb +22 -61
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +1 -1
- data/lib/omnizip/formats/seven_zip/parser.rb +14 -13
- data/lib/omnizip/formats/seven_zip/reader.rb +82 -19
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +0 -15
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +0 -1
- data/lib/omnizip/formats/seven_zip/writer.rb +22 -68
- data/lib/omnizip/formats/seven_zip.rb +63 -5
- data/lib/omnizip/formats/tar/entry.rb +0 -2
- data/lib/omnizip/formats/tar/header.rb +0 -2
- data/lib/omnizip/formats/tar/reader.rb +0 -2
- data/lib/omnizip/formats/tar/writer.rb +0 -2
- data/lib/omnizip/formats/tar.rb +0 -1
- data/lib/omnizip/formats/xar/entry.rb +0 -1
- data/lib/omnizip/formats/xar/header.rb +0 -1
- data/lib/omnizip/formats/xar/reader.rb +0 -1
- data/lib/omnizip/formats/xar/toc.rb +3 -3
- data/lib/omnizip/formats/xar/writer.rb +11 -3
- data/lib/omnizip/formats/xar.rb +0 -1
- data/lib/omnizip/formats/xz/reader.rb +7 -3
- data/lib/omnizip/formats/xz.rb +3 -40
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +4 -10
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +0 -2
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +0 -2
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +0 -1
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +0 -1
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +1 -1
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +0 -1
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +0 -1
- data/lib/omnizip/formats/xz_impl/stream_header.rb +0 -1
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +0 -2
- data/lib/omnizip/formats/zip/central_directory_header.rb +2 -3
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +0 -2
- data/lib/omnizip/formats/zip/local_file_header.rb +0 -2
- data/lib/omnizip/formats/zip/reader.rb +12 -2
- data/lib/omnizip/formats/zip/writer.rb +73 -1
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +0 -2
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +0 -2
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +0 -2
- data/lib/omnizip/formats/zip.rb +0 -1
- data/lib/omnizip/formats.rb +9 -22
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +2 -2
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +1 -1
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +0 -6
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +18 -185
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +3 -3
- data/lib/omnizip/io/source.rb +136 -0
- data/lib/omnizip/io.rb +2 -0
- data/lib/omnizip/link_handler.rb +7 -3
- data/lib/omnizip/metadata/metadata_editor.rb +1 -1
- data/lib/omnizip/models/algorithm_metadata.rb +33 -60
- data/lib/omnizip/models/compression_options.rb +40 -53
- data/lib/omnizip/models/conversion_options.rb +9 -18
- data/lib/omnizip/models/parallel_options.rb +25 -0
- data/lib/omnizip/optimization_registry.rb +8 -44
- data/lib/omnizip/parallel/job_scheduler.rb +26 -8
- data/lib/omnizip/parallel/parallel_compressor.rb +10 -20
- data/lib/omnizip/parallel/parallel_extractor.rb +20 -11
- data/lib/omnizip/parity/par2_repairer.rb +5 -5
- data/lib/omnizip/parity/par2_verifier.rb +27 -22
- data/lib/omnizip/parity.rb +4 -4
- data/lib/omnizip/password/encryption_registry.rb +11 -50
- data/lib/omnizip/password/zip_crypto_strategy.rb +1 -4
- data/lib/omnizip/pipe/stream_decompressor.rb +2 -3
- data/lib/omnizip/profile/archive_profile.rb +0 -2
- data/lib/omnizip/profile/binary_profile.rb +0 -2
- data/lib/omnizip/profile/compression_profile.rb +0 -1
- data/lib/omnizip/profile/profile_detector.rb +0 -2
- data/lib/omnizip/profile/text_profile.rb +0 -2
- data/lib/omnizip/profile.rb +0 -2
- data/lib/omnizip/registry.rb +112 -0
- data/lib/omnizip/version.rb +1 -1
- data/lib/omnizip/zip/file.rb +20 -9
- data/lib/omnizip.rb +26 -55
- data/lib/tasks/msi_test_files.rake +66 -0
- metadata +57 -6
|
@@ -35,7 +35,7 @@ module Omnizip
|
|
|
35
35
|
include Constants
|
|
36
36
|
|
|
37
37
|
attr_reader :max_order, :root_context, :current_context,
|
|
38
|
-
:restoration_method, :run_length, :glue_count
|
|
38
|
+
:restoration_method, :run_length, :glue_count, :mem_size
|
|
39
39
|
attr_accessor :order_fall, :prev_success
|
|
40
40
|
|
|
41
41
|
# Initialize the PPMd8 model
|
|
@@ -20,11 +20,6 @@
|
|
|
20
20
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
21
|
# DEALINGS IN THE SOFTWARE.
|
|
22
22
|
|
|
23
|
-
require "omnizip/algorithm"
|
|
24
|
-
require "omnizip/models/algorithm_metadata"
|
|
25
|
-
require "omnizip/algorithms/lzma2/encoder"
|
|
26
|
-
require "omnizip/algorithms/lzma2/decoder"
|
|
27
|
-
|
|
28
23
|
module Omnizip
|
|
29
24
|
module Algorithms
|
|
30
25
|
# 7-Zip LZMA2 compression algorithm.
|
|
@@ -20,11 +20,6 @@
|
|
|
20
20
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
21
|
# DEALINGS IN THE SOFTWARE.
|
|
22
22
|
|
|
23
|
-
require "omnizip/algorithm"
|
|
24
|
-
require "omnizip/models/algorithm_metadata"
|
|
25
|
-
require "omnizip/implementations/xz_utils/lzma2/encoder"
|
|
26
|
-
require "omnizip/implementations/xz_utils/lzma2/decoder"
|
|
27
|
-
|
|
28
23
|
module Omnizip
|
|
29
24
|
module Algorithms
|
|
30
25
|
# XZ Utils LZMA2 compression algorithm.
|
|
@@ -69,15 +69,15 @@ module Omnizip
|
|
|
69
69
|
|
|
70
70
|
# Parse optional fields based on descriptor bits
|
|
71
71
|
if header.window_descriptor?
|
|
72
|
-
header.
|
|
72
|
+
header.parse_window_descriptor(input)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
if header.dictionary_id?
|
|
76
|
-
header.
|
|
76
|
+
header.parse_dictionary_id(input)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
if header.content_size?
|
|
80
|
-
header.
|
|
80
|
+
header.parse_content_size(input)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
header
|
|
@@ -174,8 +174,6 @@ module Omnizip
|
|
|
174
174
|
(1 << @window_log) + (mantissa << (@window_log - 4))
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
-
private
|
|
178
|
-
|
|
179
177
|
# Parse window descriptor byte
|
|
180
178
|
def parse_window_descriptor(input)
|
|
181
179
|
byte = input.read(1).ord
|
data/lib/omnizip/algorithms.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module Omnizip
|
|
4
4
|
# Compression algorithm implementations
|
|
5
5
|
module Algorithms
|
|
6
|
+
autoload :PPMdBase, "omnizip/algorithms/ppmd_base"
|
|
6
7
|
autoload :LZMA2Const, "omnizip/algorithms/lzma2/constants"
|
|
7
8
|
autoload :LZMA, "omnizip/algorithms/lzma"
|
|
8
9
|
autoload :LZMA2, "omnizip/algorithms/lzma2"
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
# Unified archive handler interface for the Convenience module.
|
|
5
|
+
#
|
|
6
|
+
# Each format that wants to participate in Omnizip.compress_file /
|
|
7
|
+
# extract_archive / etc. registers a Handler here. The Handler exposes
|
|
8
|
+
# a small canonical API (+create+, +open+, +extract_to+, +list+) that
|
|
9
|
+
# the Convenience module calls; the Handler then delegates to the
|
|
10
|
+
# format-specific reader/writer.
|
|
11
|
+
#
|
|
12
|
+
# @example Register a format
|
|
13
|
+
# Omnizip::ArchiveHandler.register(:tar, TarHandler.new)
|
|
14
|
+
#
|
|
15
|
+
# @example Use from a caller
|
|
16
|
+
# Omnizip::ArchiveHandler.for(:tar).create(path) { |w| w.add_file(...) }
|
|
17
|
+
module ArchiveHandler
|
|
18
|
+
@handlers = {}
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
# Register a handler for a format symbol.
|
|
22
|
+
#
|
|
23
|
+
# @param format [Symbol] e.g. +:zip+, +:tar+
|
|
24
|
+
# @param handler [Object] responding to the Handler interface
|
|
25
|
+
# @return [void]
|
|
26
|
+
def register(format, handler)
|
|
27
|
+
@handlers[format.to_sym] = handler
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Look up the handler for +format+. Triggers the registered lazy
|
|
31
|
+
# load constant if the format is one of the built-ins.
|
|
32
|
+
#
|
|
33
|
+
# @param format [Symbol]
|
|
34
|
+
# @return [Object]
|
|
35
|
+
# @raise [Omnizip::UnsupportedFormatError] if +format+ is unknown
|
|
36
|
+
def for(format)
|
|
37
|
+
handler = @handlers[format.to_sym]
|
|
38
|
+
return handler if handler
|
|
39
|
+
|
|
40
|
+
trigger = LAZY_LOAD_TRIGGERS[format.to_sym]
|
|
41
|
+
if trigger
|
|
42
|
+
trigger.call
|
|
43
|
+
handler = @handlers[format.to_sym]
|
|
44
|
+
return handler if handler
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
raise Omnizip::UnsupportedFormatError,
|
|
48
|
+
"No archive handler registered for #{format.inspect}. " \
|
|
49
|
+
"Registered: #{@handlers.keys.join(', ')}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# List of registered format names.
|
|
53
|
+
#
|
|
54
|
+
# @return [Array<Symbol>]
|
|
55
|
+
def available
|
|
56
|
+
@handlers.keys
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Remove a handler (primarily for testing).
|
|
60
|
+
#
|
|
61
|
+
# @return [void]
|
|
62
|
+
def unregister(format)
|
|
63
|
+
@handlers.delete(format.to_sym)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Lazy triggers — referencing the constant autoloads the handler's
|
|
68
|
+
# file, which then self-registers at the bottom of the file.
|
|
69
|
+
LAZY_LOAD_TRIGGERS = {
|
|
70
|
+
zip: -> { Omnizip::ArchiveHandlers::ZipHandler },
|
|
71
|
+
tar: -> { Omnizip::ArchiveHandlers::TarHandler },
|
|
72
|
+
}.freeze
|
|
73
|
+
private_constant :LAZY_LOAD_TRIGGERS
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module ArchiveHandlers
|
|
5
|
+
# Adapter that exposes the canonical +create+/+open+/+extract_to+
|
|
6
|
+
# /+list+ interface for the TAR format. Wraps +Omnizip::Formats::Tar+.
|
|
7
|
+
class TarHandler
|
|
8
|
+
def create(path, &block)
|
|
9
|
+
Omnizip::Formats::Tar.create(path, &block)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def open(path, &block)
|
|
13
|
+
Omnizip::Formats::Tar.open(path, &block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def extract_to(path, output_dir, **_)
|
|
17
|
+
Omnizip::Formats::Tar.extract(path, output_dir)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def list(path, details: false, **_)
|
|
21
|
+
entries = Omnizip::Formats::Tar.list(path)
|
|
22
|
+
if details
|
|
23
|
+
entries.map do |entry|
|
|
24
|
+
{
|
|
25
|
+
name: entry.name,
|
|
26
|
+
size: entry.size,
|
|
27
|
+
directory: entry.directory?,
|
|
28
|
+
mtime: entry.mtime,
|
|
29
|
+
mode: entry.mode,
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
entries.map(&:name)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def read_entry(path, entry_name)
|
|
38
|
+
data = nil
|
|
39
|
+
Omnizip::Formats::Tar.open(path) do |reader|
|
|
40
|
+
entry = reader.entries.find { |e| e.name == entry_name }
|
|
41
|
+
raise Errno::ENOENT, "Entry not found: #{entry_name}" unless entry
|
|
42
|
+
|
|
43
|
+
data = entry.data
|
|
44
|
+
end
|
|
45
|
+
data
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
Omnizip::ArchiveHandler.register(:tar, Omnizip::ArchiveHandlers::TarHandler.new)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module ArchiveHandlers
|
|
5
|
+
# Adapter that exposes the canonical +create+/+open+/+extract_to+
|
|
6
|
+
# /+list+ interface for the ZIP format. Wraps +Omnizip::Zip::File+.
|
|
7
|
+
class ZipHandler
|
|
8
|
+
def create(path, &block)
|
|
9
|
+
Omnizip::Zip::File.create(path, &block)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def open(path, &block)
|
|
13
|
+
Omnizip::Zip::File.open(path, &block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def extract_to(path, output_dir, overwrite: false, **_)
|
|
17
|
+
extracted = []
|
|
18
|
+
Omnizip::Zip::File.open(path) do |zip|
|
|
19
|
+
zip.each do |entry|
|
|
20
|
+
dest_path = ::File.join(output_dir, entry.name)
|
|
21
|
+
on_exists = if overwrite
|
|
22
|
+
proc { true }
|
|
23
|
+
else
|
|
24
|
+
proc { |_e, p| raise "File exists: #{p}" }
|
|
25
|
+
end
|
|
26
|
+
zip.extract(entry, dest_path, &on_exists)
|
|
27
|
+
extracted << dest_path
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
extracted
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def list(path, details: false, **_)
|
|
34
|
+
Omnizip::Zip::File.open(path) do |zip|
|
|
35
|
+
if details
|
|
36
|
+
zip.entries.map do |entry|
|
|
37
|
+
{
|
|
38
|
+
name: entry.name,
|
|
39
|
+
size: entry.size,
|
|
40
|
+
compressed_size: entry.compressed_size,
|
|
41
|
+
compression_method: entry.compression_method,
|
|
42
|
+
crc: entry.crc,
|
|
43
|
+
time: entry.time,
|
|
44
|
+
directory: entry.directory?,
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
else
|
|
48
|
+
zip.names
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def read_entry(path, entry_name)
|
|
54
|
+
Omnizip::Zip::File.open(path) do |zip|
|
|
55
|
+
entry = zip.get_entry(entry_name)
|
|
56
|
+
raise Errno::ENOENT, "Entry not found: #{entry_name}" unless entry
|
|
57
|
+
|
|
58
|
+
zip.read(entry)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def add_entry(path, entry_name, source_path)
|
|
63
|
+
Omnizip::Zip::File.open(path) { |zip| zip.add(entry_name, source_path) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def remove_entry(path, entry_name)
|
|
67
|
+
Omnizip::Zip::File.open(path) { |zip| zip.remove(entry_name) }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
Omnizip::ArchiveHandler.register(:zip, Omnizip::ArchiveHandlers::ZipHandler.new)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
# Archive handler namespace. Each format ships a Handler class here
|
|
5
|
+
# that adapts its format-specific API to the canonical contract
|
|
6
|
+
# documented on +Omnizip::ArchiveHandler+.
|
|
7
|
+
module ArchiveHandlers
|
|
8
|
+
autoload :ZipHandler, "omnizip/archive_handlers/zip_handler"
|
|
9
|
+
autoload :TarHandler, "omnizip/archive_handlers/tar_handler"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -1,114 +1,41 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
4
|
-
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
-
#
|
|
6
|
-
# This file is part of Omnizip.
|
|
7
|
-
#
|
|
8
|
-
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
-
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
-
#
|
|
11
|
-
# This library is free software; you can redistribute it and/or
|
|
12
|
-
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
-
# License as published by the Free Software Foundation; either
|
|
14
|
-
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
-
#
|
|
16
|
-
# See the COPYING file for the complete text of the license.
|
|
17
|
-
#
|
|
18
|
-
|
|
19
3
|
module Omnizip
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
# The registry pattern ensures that checksum algorithms are defined in
|
|
27
|
-
# one place and can be easily extended with new implementations without
|
|
28
|
-
# modifying existing code.
|
|
29
|
-
#
|
|
30
|
-
# @example Register a new checksum algorithm
|
|
31
|
-
# ChecksumRegistry.register(:crc32, Omnizip::Checksums::Crc32)
|
|
32
|
-
#
|
|
33
|
-
# @example Get a checksum class
|
|
34
|
-
# crc_class = ChecksumRegistry.get(:crc32)
|
|
35
|
-
# checksum = crc_class.calculate("data")
|
|
36
|
-
#
|
|
37
|
-
# @example List available checksums
|
|
38
|
-
# ChecksumRegistry.available
|
|
39
|
-
# # => [:crc32, :crc64]
|
|
40
|
-
class ChecksumRegistry
|
|
41
|
-
@checksums = {}
|
|
4
|
+
class ChecksumRegistry < Omnizip::Registry
|
|
5
|
+
BUILTIN_CHECKSUMS = {
|
|
6
|
+
crc32: "Omnizip::Checksums::Crc32",
|
|
7
|
+
crc64: "Omnizip::Checksums::Crc64",
|
|
8
|
+
}.freeze
|
|
42
9
|
|
|
43
10
|
class << self
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
# Adds a new checksum implementation to the registry, making it
|
|
47
|
-
# available for use throughout the application.
|
|
48
|
-
#
|
|
49
|
-
# @param name [Symbol] unique identifier for the checksum
|
|
50
|
-
# @param checksum_class [Class] class implementing the checksum
|
|
51
|
-
# @return [void]
|
|
52
|
-
# @raise [ArgumentError] if name is already registered
|
|
53
|
-
def register(name, checksum_class)
|
|
54
|
-
name = name.to_sym
|
|
55
|
-
if @checksums.key?(name)
|
|
56
|
-
raise ArgumentError,
|
|
57
|
-
"Checksum '#{name}' is already registered"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
@checksums[name] = checksum_class
|
|
11
|
+
def not_found_error_class
|
|
12
|
+
Omnizip::UnknownChecksumError
|
|
61
13
|
end
|
|
62
14
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
# allowing for instantiation and use.
|
|
67
|
-
#
|
|
68
|
-
# @param name [Symbol] identifier of the checksum to retrieve
|
|
69
|
-
# @return [Class] the checksum class
|
|
70
|
-
# @raise [UnknownAlgorithmError] if checksum not found
|
|
71
|
-
def get(name)
|
|
72
|
-
name = name.to_sym
|
|
73
|
-
checksum_class = @checksums[name]
|
|
15
|
+
def label
|
|
16
|
+
"Checksum"
|
|
17
|
+
end
|
|
74
18
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
19
|
+
def register(name, checksum_class)
|
|
20
|
+
key = normalize_key(name)
|
|
21
|
+
existing = storage[key]
|
|
22
|
+
if existing && existing != checksum_class
|
|
23
|
+
raise ArgumentError, "Checksum '#{key}' is already registered"
|
|
79
24
|
end
|
|
80
25
|
|
|
26
|
+
synchronize { storage[key] = checksum_class }
|
|
81
27
|
checksum_class
|
|
82
28
|
end
|
|
83
29
|
|
|
84
|
-
# List all available checksum algorithms.
|
|
85
|
-
#
|
|
86
|
-
# Returns an array of registered checksum names, useful for
|
|
87
|
-
# displaying options to users or validating input.
|
|
88
|
-
#
|
|
89
|
-
# @return [Array<Symbol>] array of registered checksum names
|
|
90
30
|
def available
|
|
91
|
-
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Check if a checksum is registered.
|
|
95
|
-
#
|
|
96
|
-
# @param name [Symbol] identifier of the checksum to check
|
|
97
|
-
# @return [Boolean] true if registered, false otherwise
|
|
98
|
-
def registered?(name)
|
|
99
|
-
@checksums.key?(name.to_sym)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
# Clear all registered checksums.
|
|
103
|
-
#
|
|
104
|
-
# This method is primarily for testing purposes and should not
|
|
105
|
-
# be used in production code.
|
|
106
|
-
#
|
|
107
|
-
# @return [void]
|
|
108
|
-
# @api private
|
|
109
|
-
def clear
|
|
110
|
-
@checksums.clear
|
|
31
|
+
super.sort
|
|
111
32
|
end
|
|
112
33
|
end
|
|
113
34
|
end
|
|
114
35
|
end
|
|
36
|
+
|
|
37
|
+
Omnizip::ChecksumRegistry::BUILTIN_CHECKSUMS.each do |name, const_path|
|
|
38
|
+
Omnizip::ChecksumRegistry.register_lazy(name) do
|
|
39
|
+
Omnizip::ChecksumRegistry.register(name, Object.const_get(const_path))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
class Cli
|
|
5
|
+
# Shared helpers used by the Thor command groups defined in
|
|
6
|
+
# lib/omnizip/cli.rb (ProfileCommands, ArchiveCommands, Cli).
|
|
7
|
+
module Shared
|
|
8
|
+
# Print a formatted error message and exit nonzero.
|
|
9
|
+
#
|
|
10
|
+
# @param error [StandardError] the error to display
|
|
11
|
+
def handle_error(error)
|
|
12
|
+
warn Omnizip::CliOutputFormatter.format_error(error)
|
|
13
|
+
exit 1
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Format a byte count with a binary-unit suffix.
|
|
17
|
+
#
|
|
18
|
+
# @param bytes [Integer] the byte count
|
|
19
|
+
# @return [String] human-readable size (e.g. "1.5 MB")
|
|
20
|
+
def format_bytes(bytes)
|
|
21
|
+
return "0 B" if bytes.zero?
|
|
22
|
+
|
|
23
|
+
units = %w[B KB MB GB TB]
|
|
24
|
+
exp = (Math.log(bytes) / Math.log(1024)).to_i
|
|
25
|
+
exp = [exp, units.size - 1].min
|
|
26
|
+
|
|
27
|
+
"%.1f %s" % [bytes.to_f / (1024**exp), units[exp]]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/omnizip/cli.rb
CHANGED
|
@@ -17,22 +17,12 @@
|
|
|
17
17
|
#
|
|
18
18
|
|
|
19
19
|
require "thor"
|
|
20
|
-
require "omnizip/commands/compress_command"
|
|
21
|
-
require "omnizip/commands/decompress_command"
|
|
22
|
-
require "omnizip/commands/list_command"
|
|
23
|
-
require "omnizip/commands/archive_create_command"
|
|
24
|
-
require "omnizip/commands/archive_extract_command"
|
|
25
|
-
require "omnizip/commands/archive_list_command"
|
|
26
|
-
require "omnizip/commands/profile_list_command"
|
|
27
|
-
require "omnizip/commands/profile_show_command"
|
|
28
|
-
require "omnizip/commands/metadata_command"
|
|
29
|
-
require "omnizip/commands/archive_verify_command"
|
|
30
|
-
require "omnizip/commands/archive_repair_command"
|
|
31
|
-
require "omnizip/cli/output_formatter"
|
|
32
20
|
|
|
33
21
|
module Omnizip
|
|
34
22
|
# Profile commands subcommand group
|
|
35
23
|
class ProfileCommands < Thor
|
|
24
|
+
include Omnizip::Cli::Shared
|
|
25
|
+
|
|
36
26
|
class << self
|
|
37
27
|
def exit_on_failure?
|
|
38
28
|
true
|
|
@@ -75,17 +65,12 @@ module Omnizip
|
|
|
75
65
|
rescue StandardError => e
|
|
76
66
|
handle_error(e)
|
|
77
67
|
end
|
|
78
|
-
|
|
79
|
-
private
|
|
80
|
-
|
|
81
|
-
def handle_error(error)
|
|
82
|
-
warn Omnizip::CliOutputFormatter.format_error(error)
|
|
83
|
-
exit 1
|
|
84
|
-
end
|
|
85
68
|
end
|
|
86
69
|
|
|
87
70
|
# Archive commands subcommand group
|
|
88
71
|
class ArchiveCommands < Thor
|
|
72
|
+
include Omnizip::Cli::Shared
|
|
73
|
+
|
|
89
74
|
class << self
|
|
90
75
|
def exit_on_failure?
|
|
91
76
|
true
|
|
@@ -306,13 +291,6 @@ module Omnizip
|
|
|
306
291
|
rescue StandardError => e
|
|
307
292
|
handle_error(e)
|
|
308
293
|
end
|
|
309
|
-
|
|
310
|
-
private
|
|
311
|
-
|
|
312
|
-
def handle_error(error)
|
|
313
|
-
warn Omnizip::CliOutputFormatter.format_error(error)
|
|
314
|
-
exit 1
|
|
315
|
-
end
|
|
316
294
|
end
|
|
317
295
|
|
|
318
296
|
# Command-line interface for Omnizip.
|
|
@@ -320,6 +298,8 @@ module Omnizip
|
|
|
320
298
|
# Provides Thor-based CLI commands for compressing and decompressing
|
|
321
299
|
# files using various compression algorithms.
|
|
322
300
|
class Cli < Thor
|
|
301
|
+
include Omnizip::Cli::Shared
|
|
302
|
+
|
|
323
303
|
class << self
|
|
324
304
|
def exit_on_failure?
|
|
325
305
|
true
|
|
@@ -472,8 +452,6 @@ module Omnizip
|
|
|
472
452
|
aliases: "-v",
|
|
473
453
|
desc: "Enable verbose output"
|
|
474
454
|
def convert(source, target)
|
|
475
|
-
require "omnizip/converter"
|
|
476
|
-
|
|
477
455
|
puts "Converting #{source} to #{target}..." if options[:verbose]
|
|
478
456
|
|
|
479
457
|
result = Omnizip::Converter.convert(
|
|
@@ -553,20 +531,5 @@ module Omnizip
|
|
|
553
531
|
ensure
|
|
554
532
|
input_io.close if input_io && input != "-"
|
|
555
533
|
end
|
|
556
|
-
|
|
557
|
-
def handle_error(error)
|
|
558
|
-
warn CliOutputFormatter.format_error(error)
|
|
559
|
-
exit 1
|
|
560
|
-
end
|
|
561
|
-
|
|
562
|
-
def format_bytes(bytes)
|
|
563
|
-
return "0 B" if bytes.zero?
|
|
564
|
-
|
|
565
|
-
units = %w[B KB MB GB TB]
|
|
566
|
-
exp = (Math.log(bytes) / Math.log(1024)).to_i
|
|
567
|
-
exp = [exp, units.size - 1].min
|
|
568
|
-
|
|
569
|
-
"%.1f %s" % [bytes.to_f / (1024**exp), units[exp]]
|
|
570
|
-
end
|
|
571
534
|
end
|
|
572
535
|
end
|
|
@@ -16,9 +16,6 @@
|
|
|
16
16
|
# See the COPYING file for the complete text of the license.
|
|
17
17
|
#
|
|
18
18
|
|
|
19
|
-
require "omnizip/cli/output_formatter"
|
|
20
|
-
require "omnizip/formats/seven_zip/writer"
|
|
21
|
-
|
|
22
19
|
module Omnizip
|
|
23
20
|
module Commands
|
|
24
21
|
# Command to create .7z archives from files and directories.
|
|
@@ -123,8 +120,6 @@ module Omnizip
|
|
|
123
120
|
|
|
124
121
|
start_time = Time.now
|
|
125
122
|
|
|
126
|
-
require "omnizip/formats/rar"
|
|
127
|
-
|
|
128
123
|
writer_opts = {
|
|
129
124
|
version: version,
|
|
130
125
|
compression: compression,
|
|
@@ -388,7 +383,6 @@ module Omnizip
|
|
|
388
383
|
def parse_volume_size(size_str)
|
|
389
384
|
return nil if size_str.nil? || size_str.empty?
|
|
390
385
|
|
|
391
|
-
require "omnizip/models/split_options"
|
|
392
386
|
Omnizip::Models::SplitOptions.parse_volume_size(size_str)
|
|
393
387
|
end
|
|
394
388
|
|
|
@@ -16,10 +16,6 @@
|
|
|
16
16
|
# See the COPYING file for the complete text of the license.
|
|
17
17
|
#
|
|
18
18
|
|
|
19
|
-
require "omnizip/cli/output_formatter"
|
|
20
|
-
require "omnizip/formats/seven_zip/reader"
|
|
21
|
-
require "omnizip/extraction"
|
|
22
|
-
|
|
23
19
|
module Omnizip
|
|
24
20
|
module Commands
|
|
25
21
|
# Command to extract .7z archives to a directory.
|
|
@@ -16,10 +16,6 @@
|
|
|
16
16
|
# See the COPYING file for the complete text of the license.
|
|
17
17
|
#
|
|
18
18
|
|
|
19
|
-
require "omnizip/cli/output_formatter"
|
|
20
|
-
require "omnizip/formats/seven_zip/reader"
|
|
21
|
-
require "omnizip/extraction"
|
|
22
|
-
|
|
23
19
|
module Omnizip
|
|
24
20
|
module Commands
|
|
25
21
|
# Command to list contents of .7z archives.
|
|
@@ -18,8 +18,6 @@ module Omnizip
|
|
|
18
18
|
# @param input_path [String] Path to corrupted archive
|
|
19
19
|
# @param output_path [String] Path for repaired archive
|
|
20
20
|
def run(input_path, output_path)
|
|
21
|
-
require "omnizip/formats/rar"
|
|
22
|
-
|
|
23
21
|
raise "Archive not found: #{input_path}" unless File.exist?(input_path)
|
|
24
22
|
|
|
25
23
|
# Detect format
|