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.
- checksums.yaml +4 -4
- 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/dictionary.rb +4 -3
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +2 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +1 -1
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +6 -5
- 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.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 +69 -53
- 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/reader.rb +1 -0
- data/lib/omnizip/formats/msi/string_pool.rb +2 -3
- data/lib/omnizip/formats/msi.rb +1 -4
- data/lib/omnizip/formats/ole/allocation_table.rb +0 -1
- data/lib/omnizip/formats/ole/dirent.rb +9 -4
- data/lib/omnizip/formats/ole/header.rb +0 -1
- data/lib/omnizip/formats/ole/ranges_io.rb +1 -1
- data/lib/omnizip/formats/ole/storage.rb +5 -6
- data/lib/omnizip/formats/ole.rb +0 -1
- 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 +1 -0
- data/lib/omnizip/formats/rar/header.rb +0 -1
- data/lib/omnizip/formats/rar/rar5/writer.rb +0 -3
- data/lib/omnizip/formats/rar/reader.rb +2 -3
- data/lib/omnizip/formats/rar/writer.rb +0 -1
- data/lib/omnizip/formats/rar.rb +0 -1
- data/lib/omnizip/formats/rpm/entry.rb +0 -1
- data/lib/omnizip/formats/rpm/header.rb +1 -6
- 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 +0 -1
- 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 +0 -1
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +1 -1
- data/lib/omnizip/formats/seven_zip/parser.rb +1 -2
- data/lib/omnizip/formats/seven_zip/reader.rb +13 -2
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +0 -1
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +0 -1
- data/lib/omnizip/formats/seven_zip/writer.rb +4 -6
- data/lib/omnizip/formats/seven_zip.rb +2 -4
- 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 +1 -2
- 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 +8 -24
- 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 +3 -4
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +0 -1
- 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 -58
- metadata +24 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# 11 — Convenience module decoupling
|
|
2
|
+
|
|
3
|
+
Priority: **medium**.
|
|
4
|
+
Status: TODO.
|
|
5
|
+
|
|
6
|
+
## Problem
|
|
7
|
+
|
|
8
|
+
`lib/omnizip/convenience.rb` (359 lines) hardcodes `Omnizip::Zip::File`
|
|
9
|
+
in 7 method bodies (lines 45, 87, 112, 149, 175, 207, 227) —
|
|
10
|
+
`compress_file`, `compress_directory`, `extract_archive`,
|
|
11
|
+
`list_archive`, `read_from_archive`, `add_to_archive`,
|
|
12
|
+
`remove_from_archive`. The codebase supports 7z, XZ, tar, gzip, bzip2,
|
|
13
|
+
RAR, but convenience methods are ZIP-only.
|
|
14
|
+
|
|
15
|
+
## Plan
|
|
16
|
+
|
|
17
|
+
1. Add a `format:` keyword argument to each convenience method.
|
|
18
|
+
Default to `:zip` for backward compatibility.
|
|
19
|
+
2. Resolve the format handler via `FormatRegistry.get(format)` and
|
|
20
|
+
delegate. If the handler doesn't expose the needed operation, raise a
|
|
21
|
+
clear `UnsupportedFormatError` describing what's missing.
|
|
22
|
+
3. Each format handler (zip, seven_zip, tar, gzip, xz, bzip2) should
|
|
23
|
+
implement a shared `Handler` interface with `#add_file`,
|
|
24
|
+
`#add_directory`, `#extract`, `#list`, `#read`, `#remove`. This
|
|
25
|
+
becomes the contract for being usable from `convenience.rb`.
|
|
26
|
+
|
|
27
|
+
## Acceptance
|
|
28
|
+
|
|
29
|
+
- Convenience methods accept `format:` and dispatch via registry.
|
|
30
|
+
- ZIP path remains the default with no behavior change.
|
|
31
|
+
- At least one non-ZIP format (e.g., tar) is wired up end-to-end.
|
|
32
|
+
|
|
33
|
+
## Scope note
|
|
34
|
+
|
|
35
|
+
Full format handler interface extraction is large. This pass:
|
|
36
|
+
1. Adds the `format:` keyword with ZIP default.
|
|
37
|
+
2. Wires tar as a second supported format (simplest after zip).
|
|
38
|
+
3. Leaves the remaining formats as documented future work.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# 12 — Thread safety
|
|
2
|
+
|
|
3
|
+
Priority: covered by track 01.
|
|
4
|
+
Status: n/a.
|
|
5
|
+
|
|
6
|
+
The `Registry` base class introduced in track 01 includes `Mutex`-based
|
|
7
|
+
synchronization around mutations (`register`, `reset!`). All migrated
|
|
8
|
+
registries inherit this for free. No standalone work.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# 13 — lutaml-model migration
|
|
2
|
+
|
|
3
|
+
Priority: **medium**.
|
|
4
|
+
Status: TODO (large; this pass establishes the pattern, full migration
|
|
5
|
+
is follow-up).
|
|
6
|
+
|
|
7
|
+
## Rule
|
|
8
|
+
|
|
9
|
+
> ALL (de)serialization goes through the framework. Declare attributes
|
|
10
|
+
> with `attribute :name, :type`. Declare wire names with a `mapping do
|
|
11
|
+
> ... end` block. Never write `def to_h` / `def from_h` / `def to_json`
|
|
12
|
+
> / `def from_json` on a model class.
|
|
13
|
+
|
|
14
|
+
## Inventory
|
|
15
|
+
|
|
16
|
+
26 `def to_h` occurrences across 22 files. 2 `def to_json`. None use
|
|
17
|
+
lutaml-model today even though the gemspec declares the dependency.
|
|
18
|
+
|
|
19
|
+
### Models (lib/omnizip/models/)
|
|
20
|
+
|
|
21
|
+
- `compression_options.rb` (`to_h`, `to_json`)
|
|
22
|
+
- `algorithm_metadata.rb` (`to_h`, `to_json`)
|
|
23
|
+
- `conversion_result.rb`
|
|
24
|
+
- `eta_result.rb`
|
|
25
|
+
- `filter_config.rb`
|
|
26
|
+
- `match_result.rb`
|
|
27
|
+
- `optimization_suggestion.rb`
|
|
28
|
+
- `parallel_options.rb`
|
|
29
|
+
- `performance_result.rb`
|
|
30
|
+
- `profile_report.rb`
|
|
31
|
+
- `progress_options.rb`
|
|
32
|
+
- `conversion_options.rb`
|
|
33
|
+
|
|
34
|
+
### Format entry/metadata classes
|
|
35
|
+
|
|
36
|
+
- `formats/xar/entry.rb`
|
|
37
|
+
- `formats/zip/unix_extra_field.rb`
|
|
38
|
+
- `formats/rpm/header.rb`
|
|
39
|
+
- `metadata/entry_metadata.rb`
|
|
40
|
+
- `metadata/archive_metadata.rb`
|
|
41
|
+
|
|
42
|
+
### Other
|
|
43
|
+
|
|
44
|
+
- `progress/operation_progress.rb`
|
|
45
|
+
- `profile/profile_registry.rb`, `custom_profile.rb`, `compression_profile.rb`
|
|
46
|
+
- `link_handler/symbolic_link.rb`, `hard_link.rb`
|
|
47
|
+
|
|
48
|
+
## Plan (this pass)
|
|
49
|
+
|
|
50
|
+
1. Establish the pattern by migrating **two representative models**:
|
|
51
|
+
`Omnizip::Models::CompressionOptions` and
|
|
52
|
+
`Omnizip::Models::AlgorithmMetadata`. Convert to lutaml-model:
|
|
53
|
+
```ruby
|
|
54
|
+
class CompressionOptions < Lutaml::Model::Serializable
|
|
55
|
+
attribute :algorithm, :string
|
|
56
|
+
attribute :level, :integer, default: 6
|
|
57
|
+
# ...
|
|
58
|
+
mapping do
|
|
59
|
+
map :algorithm, to: :algorithm
|
|
60
|
+
map :level, to: :level
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
```
|
|
64
|
+
The framework provides `to_hash`, `to_json`, `from_hash`,
|
|
65
|
+
`from_json` automatically — remove the hand-rolled versions.
|
|
66
|
+
|
|
67
|
+
2. Delete the manual `to_h` / `to_json` from those two files.
|
|
68
|
+
|
|
69
|
+
3. Document the migration recipe in this TODO file for the remaining
|
|
70
|
+
models.
|
|
71
|
+
|
|
72
|
+
## Acceptance
|
|
73
|
+
|
|
74
|
+
- Two models migrated; their specs still pass.
|
|
75
|
+
- `grep -rn "def to_h\|def to_json" lib/omnizip/models/` count drops by
|
|
76
|
+
at least 2.
|
|
77
|
+
|
|
78
|
+
## Remaining work (future pass)
|
|
79
|
+
|
|
80
|
+
Migrate the other ~24 files following the established recipe. The
|
|
81
|
+
metadata/entry classes likely share structure and may collapse into a
|
|
82
|
+
smaller set of richer models — review for MECE opportunities.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 14 — Add missing specs
|
|
2
|
+
|
|
3
|
+
Priority: **high**.
|
|
4
|
+
Status: TODO.
|
|
5
|
+
|
|
6
|
+
## Plan
|
|
7
|
+
|
|
8
|
+
Add or strengthen specs for:
|
|
9
|
+
|
|
10
|
+
1. `Omnizip::Registry` (new base class from track 01) — register / get /
|
|
11
|
+
registered? / available / reset! / thread-safety smoke test / custom
|
|
12
|
+
not-found error.
|
|
13
|
+
2. `Omnizip::Error` hierarchy (track 02) — confirm inheritance and
|
|
14
|
+
aliases.
|
|
15
|
+
3. `Omnizip::Cli::Shared` (track 09) — `handle_error` and
|
|
16
|
+
`format_bytes`.
|
|
17
|
+
4. `Omnizip::IO::Source` / `Omnizip::IO::Sink` (track 07) — adapter
|
|
18
|
+
behavior for String / StringIO / File / Pathname.
|
|
19
|
+
5. Promoted public methods (track 05) — wherever a method moves from
|
|
20
|
+
private to public, ensure a spec covers its new visibility.
|
|
21
|
+
|
|
22
|
+
## Acceptance
|
|
23
|
+
|
|
24
|
+
- All new specs pass.
|
|
25
|
+
- No `double()` introduced.
|
data/lib/omnizip/algorithm.rb
CHANGED
|
@@ -17,70 +17,42 @@
|
|
|
17
17
|
#
|
|
18
18
|
|
|
19
19
|
module Omnizip
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# @raise [ArgumentError] If name or klass is nil
|
|
32
|
-
# @return [void]
|
|
33
|
-
def register(name, klass)
|
|
34
|
-
raise ArgumentError, "Algorithm name cannot be nil" if name.nil?
|
|
35
|
-
raise ArgumentError, "Algorithm class cannot be nil" if klass.nil?
|
|
36
|
-
|
|
37
|
-
algorithms[name.to_sym] = klass
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
# Retrieve an algorithm class by name.
|
|
41
|
-
#
|
|
42
|
-
# @param name [Symbol, String] The name identifier for the algorithm
|
|
43
|
-
# @raise [UnknownAlgorithmError] If algorithm is not registered
|
|
44
|
-
# @return [Class] The registered algorithm class
|
|
45
|
-
def get(name)
|
|
46
|
-
algorithm = algorithms[name.to_sym]
|
|
47
|
-
return algorithm if algorithm
|
|
48
|
-
|
|
49
|
-
raise UnknownAlgorithmError,
|
|
50
|
-
"Unknown algorithm: #{name}. " \
|
|
51
|
-
"Available: #{available.join(', ')}"
|
|
52
|
-
end
|
|
20
|
+
class AlgorithmRegistry < Omnizip::Registry
|
|
21
|
+
BUILTIN_ALGORITHMS = {
|
|
22
|
+
lzma: "Omnizip::Algorithms::LZMA",
|
|
23
|
+
lzma2: "Omnizip::Algorithms::LZMA2",
|
|
24
|
+
ppmd7: "Omnizip::Algorithms::PPMd7",
|
|
25
|
+
ppmd8: "Omnizip::Algorithms::PPMd8",
|
|
26
|
+
bzip2: "Omnizip::Algorithms::BZip2",
|
|
27
|
+
deflate: "Omnizip::Algorithms::Deflate",
|
|
28
|
+
deflate64: "Omnizip::Algorithms::Deflate64",
|
|
29
|
+
zstandard: "Omnizip::Algorithms::Zstandard",
|
|
30
|
+
}.freeze
|
|
53
31
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
# @return [Boolean] True if algorithm is registered, false otherwise
|
|
58
|
-
def registered?(name)
|
|
59
|
-
algorithms.key?(name.to_sym)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
# Get list of all registered algorithm names.
|
|
63
|
-
#
|
|
64
|
-
# @return [Array<Symbol>] Array of registered algorithm names
|
|
65
|
-
def available
|
|
66
|
-
algorithms.keys
|
|
32
|
+
class << self
|
|
33
|
+
def not_found_error_class
|
|
34
|
+
Omnizip::UnknownAlgorithmError
|
|
67
35
|
end
|
|
68
36
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# @return [void]
|
|
72
|
-
def reset!
|
|
73
|
-
algorithms.clear
|
|
37
|
+
def label
|
|
38
|
+
"Algorithm"
|
|
74
39
|
end
|
|
75
40
|
|
|
76
|
-
|
|
41
|
+
def register(name, klass)
|
|
42
|
+
raise ArgumentError, "Algorithm name cannot be nil" if name.nil?
|
|
43
|
+
raise ArgumentError, "Algorithm class cannot be nil" if klass.nil?
|
|
77
44
|
|
|
78
|
-
|
|
79
|
-
#
|
|
80
|
-
# @return [Hash] The algorithms registry
|
|
81
|
-
def algorithms
|
|
82
|
-
@algorithms ||= {}
|
|
45
|
+
super
|
|
83
46
|
end
|
|
84
47
|
end
|
|
85
48
|
end
|
|
86
49
|
end
|
|
50
|
+
|
|
51
|
+
# Lazy triggers — explicitly re-register on each miss so the entry
|
|
52
|
+
# survives reset!. Object.const_get alone doesn't re-run the file body
|
|
53
|
+
# once the constant is loaded.
|
|
54
|
+
Omnizip::AlgorithmRegistry::BUILTIN_ALGORITHMS.each do |name, const_path|
|
|
55
|
+
Omnizip::AlgorithmRegistry.register_lazy(name) do
|
|
56
|
+
Omnizip::AlgorithmRegistry.register(name, Object.const_get(const_path))
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -6,7 +6,8 @@ module Omnizip
|
|
|
6
6
|
# Circular buffer dictionary for LZMA sliding window
|
|
7
7
|
# Ported from XZ Utils lzma_decoder.c
|
|
8
8
|
class Dictionary
|
|
9
|
-
|
|
9
|
+
attr_accessor :position, :buffer
|
|
10
|
+
attr_reader :size
|
|
10
11
|
|
|
11
12
|
def initialize(size)
|
|
12
13
|
@size = size
|
|
@@ -59,8 +60,8 @@ module Omnizip
|
|
|
59
60
|
# Clone dictionary
|
|
60
61
|
def clone
|
|
61
62
|
dict = Dictionary.new(@size)
|
|
62
|
-
dict.
|
|
63
|
-
dict.
|
|
63
|
+
dict.buffer = @buffer.dup
|
|
64
|
+
dict.position = @position
|
|
64
65
|
dict
|
|
65
66
|
end
|
|
66
67
|
end
|
|
@@ -33,7 +33,7 @@ module Omnizip
|
|
|
33
33
|
# extract the original bit values. It maintains a code value
|
|
34
34
|
# that represents the current position within the range.
|
|
35
35
|
class RangeDecoder < RangeCoder
|
|
36
|
-
attr_reader :code, :init_bytes_remaining
|
|
36
|
+
attr_reader :code, :init_bytes_remaining, :range, :stream
|
|
37
37
|
|
|
38
38
|
# Initialize the range decoder
|
|
39
39
|
#
|
|
@@ -86,7 +86,8 @@ module Omnizip
|
|
|
86
86
|
RangeDecoder = LZMA::RangeDecoder
|
|
87
87
|
SdkStateMachine = Implementations::SevenZip::LZMA::StateMachine
|
|
88
88
|
|
|
89
|
-
attr_reader :lc, :lp, :pb, :dict_size, :uncompressed_size
|
|
89
|
+
attr_reader :lc, :lp, :pb, :dict_size, :uncompressed_size,
|
|
90
|
+
:range_decoder
|
|
90
91
|
|
|
91
92
|
# XZ Utils dictionary constants (from lz_decoder.h)
|
|
92
93
|
# See: /Users/mulgogi/src/external/xz/src/liblzma/lz/lz_decoder.h
|
|
@@ -431,8 +432,8 @@ check_rc_finished: true)
|
|
|
431
432
|
#
|
|
432
433
|
# If EOPM was NOT encountered (code != 0), leftover data is expected
|
|
433
434
|
# (it's part of the compressed stream that we haven't read yet).
|
|
434
|
-
if @allow_eopm && @range_decoder&.code&.zero? && @range_decoder
|
|
435
|
-
stream = @range_decoder.
|
|
435
|
+
if @allow_eopm && @range_decoder&.code&.zero? && @range_decoder&.stream
|
|
436
|
+
stream = @range_decoder.stream
|
|
436
437
|
# Try to peek at the next byte - if available, there's data AFTER EOPM
|
|
437
438
|
begin
|
|
438
439
|
next_byte = stream.getbyte
|
|
@@ -445,9 +446,9 @@ check_rc_finished: true)
|
|
|
445
446
|
rescue IOError, EOFError
|
|
446
447
|
# Stream doesn't support peeking or is exhausted, that's fine
|
|
447
448
|
end
|
|
448
|
-
elsif !@allow_eopm && @range_decoder&.
|
|
449
|
+
elsif !@allow_eopm && @range_decoder&.stream
|
|
449
450
|
# For LZMA2 mode (EOPM not allowed): check for leftover data
|
|
450
|
-
stream = @range_decoder.
|
|
451
|
+
stream = @range_decoder.stream
|
|
451
452
|
begin
|
|
452
453
|
next_byte = stream.getbyte
|
|
453
454
|
if next_byte
|
|
@@ -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)
|