omnizip 0.4.7-x86_64-linux
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +293 -0
- data/CHANGELOG.md +1647 -0
- data/CONTEXT.md +68 -0
- data/COPYING +502 -0
- data/Gemfile +19 -0
- data/LICENSE +12 -0
- data/README.adoc +1327 -0
- data/Rakefile +15 -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 +237 -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 +158 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -0
- data/benchmark/README.md +260 -0
- data/benchmark/benchmark_suite.rb +125 -0
- data/benchmark/compression_bench.rb +181 -0
- data/benchmark/filter_bench.rb +180 -0
- data/benchmark/models/benchmark_result.rb +59 -0
- data/benchmark/models/comparison_result.rb +69 -0
- data/benchmark/profile_suite.rb +167 -0
- data/benchmark/reporter.rb +150 -0
- data/benchmark/run_benchmarks.rb +66 -0
- data/benchmark/test_data.rb +137 -0
- data/config/formats/rar3_spec.yml +92 -0
- data/config/formats/rar5_spec.yml +102 -0
- data/docs/.github/workflows/docs.yml +142 -0
- data/docs/.gitignore +21 -0
- data/docs/.lychee.toml +67 -0
- data/docs/Gemfile +13 -0
- data/docs/RAR_WRITE_SUPPORT.md +26 -0
- data/docs/README.md +101 -0
- data/docs/_config.yml +112 -0
- data/docs/assets/logo.svg +1 -0
- data/docs/assets/omnizip-logo.pdf +1540 -11
- data/docs/comparison/feature-matrix.adoc +694 -0
- data/docs/comparison/index.adoc +113 -0
- data/docs/comparison/vs-7zip.adoc +309 -0
- data/docs/comparison/vs-peazip.adoc +77 -0
- data/docs/comparison/vs-rubyzip.adoc +342 -0
- data/docs/comparison/vs-winrar.adoc +100 -0
- data/docs/compatibility.adoc +579 -0
- data/docs/concepts/index.adoc +129 -0
- data/docs/developer/architecture.adoc +256 -0
- data/docs/developer/contributing.adoc +158 -0
- data/docs/developer/index.adoc +25 -0
- data/docs/developer/testing.adoc +212 -0
- data/docs/getting-started/basic-usage.adoc +263 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +183 -0
- data/docs/getting-started/your-first-archive.adoc +219 -0
- data/docs/guides/advanced-features/encryption.adoc +277 -0
- data/docs/guides/advanced-features/index.adoc +59 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
- data/docs/guides/advanced-features/streaming.adoc +142 -0
- data/docs/guides/archive-formats/gzip-format.adoc +105 -0
- data/docs/guides/archive-formats/index.adoc +160 -0
- data/docs/guides/archive-formats/ole-format.adoc +151 -0
- data/docs/guides/archive-formats/rar-format.adoc +104 -0
- data/docs/guides/archive-formats/rar5.adoc +521 -0
- data/docs/guides/archive-formats/rpm-format.adoc +108 -0
- data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
- data/docs/guides/archive-formats/tar-format.adoc +106 -0
- data/docs/guides/archive-formats/xz-format.adoc +118 -0
- data/docs/guides/archive-formats/zip-format.adoc +35 -0
- data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
- data/docs/guides/compression-algorithms/deflate.adoc +313 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +394 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
- data/docs/guides/creating-archives.adoc +348 -0
- data/docs/guides/extracting-archives.adoc +53 -0
- data/docs/guides/format-conversion.adoc +64 -0
- data/docs/guides/index.adoc +49 -0
- data/docs/guides/migration-rubyzip.adoc +217 -0
- data/docs/guides/parity-archives.adoc +605 -0
- data/docs/guides/performance-tuning.adoc +88 -0
- data/docs/index.adoc +228 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +187 -0
- data/docs/reference/cli/compress-command.adoc +114 -0
- data/docs/reference/cli/overview.adoc +140 -0
- data/docs/reference/index.adoc +26 -0
- data/docs/resources/faq.adoc +185 -0
- data/docs/resources/quick-reference.adoc +222 -0
- data/docs/rust-backend.md +0 -0
- data/docs/troubleshooting/index.adoc +207 -0
- data/docs/xar_format.md +216 -0
- data/examples/api_comparison.rb +205 -0
- data/examples/deflate64_example.rb +96 -0
- data/examples/par2_demo.rb +121 -0
- data/examples/quick_start_native.rb +150 -0
- data/examples/quick_start_rubyzip.rb +115 -0
- data/examples/rubyzip_compatibility_demo.rb +194 -0
- data/exe/omnizip +27 -0
- data/lib/omnizip/algorithm.rb +176 -0
- data/lib/omnizip/algorithm_registry.rb +65 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
- data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
- data/lib/omnizip/algorithms/bzip2.rb +108 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
- data/lib/omnizip/algorithms/deflate.rb +135 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
- data/lib/omnizip/algorithms/deflate64.rb +118 -0
- data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
- data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
- data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
- data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
- data/lib/omnizip/algorithms/lzma/match.rb +32 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
- data/lib/omnizip/algorithms/lzma.rb +266 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +133 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +146 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +122 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
- data/lib/omnizip/algorithms/registration.rb +28 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
- data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
- data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
- data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
- data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
- data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
- data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
- data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
- data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +210 -0
- data/lib/omnizip/algorithms.rb +35 -0
- data/lib/omnizip/archive/builder.rb +48 -0
- data/lib/omnizip/archive/reader_session.rb +67 -0
- data/lib/omnizip/archive.rb +86 -0
- data/lib/omnizip/archive_handler.rb +82 -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/ole_handler.rb +37 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
- data/lib/omnizip/archive_handlers.rb +18 -0
- data/lib/omnizip/backends.rb +160 -0
- data/lib/omnizip/buffer/memory_archive.rb +246 -0
- data/lib/omnizip/buffer/memory_extractor.rb +234 -0
- data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
- data/lib/omnizip/buffer.rb +187 -0
- data/lib/omnizip/checksum_registry.rb +41 -0
- data/lib/omnizip/checksums/crc32.rb +101 -0
- data/lib/omnizip/checksums/crc64.rb +102 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/registration.rb +16 -0
- data/lib/omnizip/checksums/verifier.rb +130 -0
- data/lib/omnizip/checksums.rb +11 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +123 -0
- data/lib/omnizip/chunked.rb +123 -0
- data/lib/omnizip/cli/output_formatter.rb +112 -0
- data/lib/omnizip/cli.rb +604 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +245 -0
- data/lib/omnizip/commands/archive_extract_command.rb +231 -0
- data/lib/omnizip/commands/archive_list_command.rb +204 -0
- data/lib/omnizip/commands/archive_repair_command.rb +129 -0
- data/lib/omnizip/commands/archive_verify_command.rb +115 -0
- data/lib/omnizip/commands/compress_command.rb +115 -0
- data/lib/omnizip/commands/decompress_command.rb +149 -0
- data/lib/omnizip/commands/list_command.rb +51 -0
- data/lib/omnizip/commands/metadata_command.rb +215 -0
- data/lib/omnizip/commands/parity_create_command.rb +114 -0
- data/lib/omnizip/commands/parity_repair_command.rb +120 -0
- data/lib/omnizip/commands/parity_verify_command.rb +122 -0
- data/lib/omnizip/commands/profile_list_command.rb +54 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/commands.rb +21 -0
- data/lib/omnizip/convenience.rb +389 -0
- data/lib/omnizip/converter/conversion_registry.rb +50 -0
- data/lib/omnizip/converter/conversion_strategy.rb +108 -0
- data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
- data/lib/omnizip/converter.rb +124 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/crypto.rb +11 -0
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/error.rb +110 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
- data/lib/omnizip/eta/rate_calculator.rb +104 -0
- data/lib/omnizip/eta/sample_history.rb +143 -0
- data/lib/omnizip/eta/time_estimator.rb +106 -0
- data/lib/omnizip/eta.rb +68 -0
- data/lib/omnizip/extraction/filter_chain.rb +179 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
- data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
- data/lib/omnizip/extraction/regex_pattern.rb +50 -0
- data/lib/omnizip/extraction/selective_extractor.rb +247 -0
- data/lib/omnizip/extraction.rb +115 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +117 -0
- data/lib/omnizip/filter.rb +141 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +113 -0
- data/lib/omnizip/filters/bcj.rb +277 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
- data/lib/omnizip/filters/bcj2.rb +93 -0
- data/lib/omnizip/filters/bcj_arm.rb +174 -0
- data/lib/omnizip/filters/bcj_arm64.rb +242 -0
- data/lib/omnizip/filters/bcj_ia64.rb +194 -0
- data/lib/omnizip/filters/bcj_ppc.rb +188 -0
- data/lib/omnizip/filters/bcj_sparc.rb +174 -0
- data/lib/omnizip/filters/bcj_x86.rb +191 -0
- data/lib/omnizip/filters/delta.rb +195 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/filters.rb +20 -0
- data/lib/omnizip/format_detector.rb +166 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +159 -0
- data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +389 -0
- data/lib/omnizip/formats/cpio/reader.rb +194 -0
- data/lib/omnizip/formats/cpio/writer.rb +232 -0
- data/lib/omnizip/formats/cpio.rb +132 -0
- data/lib/omnizip/formats/format_spec_loader.rb +228 -0
- data/lib/omnizip/formats/gzip.rb +236 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
- data/lib/omnizip/formats/iso/directory_record.rb +162 -0
- data/lib/omnizip/formats/iso/joliet.rb +204 -0
- data/lib/omnizip/formats/iso/path_table.rb +125 -0
- data/lib/omnizip/formats/iso/reader.rb +194 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +543 -0
- data/lib/omnizip/formats/iso.rb +133 -0
- data/lib/omnizip/formats/lzip.rb +161 -0
- data/lib/omnizip/formats/lzma_alone.rb +149 -0
- 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 +134 -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 +73 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
- data/lib/omnizip/formats/ole/constants.rb +61 -0
- data/lib/omnizip/formats/ole/dirent.rb +439 -0
- data/lib/omnizip/formats/ole/header.rb +199 -0
- data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
- data/lib/omnizip/formats/ole/storage.rb +482 -0
- data/lib/omnizip/formats/ole/types/variant.rb +338 -0
- data/lib/omnizip/formats/ole.rb +143 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
- data/lib/omnizip/formats/rar/block_parser.rb +282 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
- data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
- data/lib/omnizip/formats/rar/compression.rb +17 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +88 -0
- data/lib/omnizip/formats/rar/decompressor.rb +316 -0
- data/lib/omnizip/formats/rar/external_writer.rb +311 -0
- data/lib/omnizip/formats/rar/header.rb +209 -0
- data/lib/omnizip/formats/rar/license_validator.rb +111 -0
- data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
- data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
- data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
- data/lib/omnizip/formats/rar/models.rb +14 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
- data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
- data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
- data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
- data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
- data/lib/omnizip/formats/rar/reader.rb +377 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
- data/lib/omnizip/formats/rar/writer.rb +437 -0
- data/lib/omnizip/formats/rar.rb +193 -0
- data/lib/omnizip/formats/rar3/compressor.rb +71 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar3/reader.rb +107 -0
- data/lib/omnizip/formats/rar3/writer.rb +220 -0
- data/lib/omnizip/formats/rar3.rb +15 -0
- data/lib/omnizip/formats/rar5/compressor.rb +71 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar5/reader.rb +130 -0
- data/lib/omnizip/formats/rar5/writer.rb +65 -0
- data/lib/omnizip/formats/rar5.rb +15 -0
- data/lib/omnizip/formats/rpm/constants.rb +58 -0
- data/lib/omnizip/formats/rpm/entry.rb +106 -0
- data/lib/omnizip/formats/rpm/header.rb +106 -0
- data/lib/omnizip/formats/rpm/lead.rb +132 -0
- data/lib/omnizip/formats/rpm/tag.rb +228 -0
- data/lib/omnizip/formats/rpm/writer.rb +652 -0
- data/lib/omnizip/formats/rpm.rb +458 -0
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
- data/lib/omnizip/formats/seven_zip/header.rb +102 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/models.rb +20 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
- data/lib/omnizip/formats/seven_zip.rb +179 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +98 -0
- data/lib/omnizip/formats/tar/header.rb +206 -0
- data/lib/omnizip/formats/tar/reader.rb +119 -0
- data/lib/omnizip/formats/tar/writer.rb +212 -0
- data/lib/omnizip/formats/tar.rb +74 -0
- data/lib/omnizip/formats/xar/constants.rb +119 -0
- data/lib/omnizip/formats/xar/entry.rb +268 -0
- data/lib/omnizip/formats/xar/header.rb +223 -0
- data/lib/omnizip/formats/xar/reader.rb +400 -0
- data/lib/omnizip/formats/xar/toc.rb +570 -0
- data/lib/omnizip/formats/xar/writer.rb +461 -0
- data/lib/omnizip/formats/xar.rb +145 -0
- data/lib/omnizip/formats/xz/reader.rb +121 -0
- data/lib/omnizip/formats/xz/writer.rb +416 -0
- data/lib/omnizip/formats/xz.rb +210 -0
- data/lib/omnizip/formats/xz_const.rb +49 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl.rb +52 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
- data/lib/omnizip/formats/zip/reader.rb +376 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +489 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/formats.rb +29 -0
- data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
- data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
- data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
- data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
- data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
- data/lib/omnizip/implementations/base.rb +19 -0
- data/lib/omnizip/implementations/rust/archive.rb +93 -0
- data/lib/omnizip/implementations/rust/library.rb +221 -0
- data/lib/omnizip/implementations/rust.rb +26 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
- data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
- data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
- data/lib/omnizip/implementations/seven_zip.rb +11 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
- data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
- data/lib/omnizip/implementations/xz_utils.rb +10 -0
- data/lib/omnizip/implementations.rb +25 -0
- data/lib/omnizip/io/buffered_input.rb +147 -0
- data/lib/omnizip/io/buffered_output.rb +106 -0
- data/lib/omnizip/io/source.rb +143 -0
- data/lib/omnizip/io/stream_manager.rb +117 -0
- data/lib/omnizip/io.rb +15 -0
- data/lib/omnizip/link_handler/hard_link.rb +79 -0
- data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
- data/lib/omnizip/link_handler.rb +129 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +153 -0
- data/lib/omnizip/metadata/metadata_editor.rb +169 -0
- data/lib/omnizip/metadata/metadata_registry.rb +71 -0
- data/lib/omnizip/metadata/metadata_validator.rb +101 -0
- data/lib/omnizip/metadata.rb +58 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +41 -0
- data/lib/omnizip/models/attribute_apply.rb +40 -0
- data/lib/omnizip/models/compression_options.rb +53 -0
- data/lib/omnizip/models/conversion_options.rb +79 -0
- data/lib/omnizip/models/conversion_result.rb +141 -0
- data/lib/omnizip/models/eta_result.rb +45 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +142 -0
- data/lib/omnizip/models/filter_config.rb +148 -0
- data/lib/omnizip/models/match_result.rb +141 -0
- data/lib/omnizip/models/optimization_suggestion.rb +95 -0
- data/lib/omnizip/models/parallel_options.rb +116 -0
- data/lib/omnizip/models/performance_result.rb +85 -0
- data/lib/omnizip/models/profile_report.rb +116 -0
- data/lib/omnizip/models/progress_options.rb +39 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +45 -0
- data/lib/omnizip/parallel/engine.rb +52 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +225 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
- data/lib/omnizip/parallel/thread_pool.rb +60 -0
- data/lib/omnizip/parallel/worker_pool.rb +227 -0
- data/lib/omnizip/parallel.rb +156 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +71 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
- data/lib/omnizip/parity/models/main_packet.rb +126 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +102 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
- data/lib/omnizip/parity/models.rb +27 -0
- data/lib/omnizip/parity/par2_creator.rb +496 -0
- data/lib/omnizip/parity/par2_repairer.rb +409 -0
- data/lib/omnizip/parity/par2_verifier.rb +373 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
- data/lib/omnizip/parity.rb +207 -0
- data/lib/omnizip/password/encryption_registry.rb +26 -0
- data/lib/omnizip/password/encryption_strategy.rb +96 -0
- data/lib/omnizip/password/password_validator.rb +129 -0
- data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
- data/lib/omnizip/password.rb +88 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
- data/lib/omnizip/pipe.rb +120 -0
- data/lib/omnizip/platform/ntfs_streams.rb +200 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +36 -0
- data/lib/omnizip/profile/balanced_profile.rb +31 -0
- data/lib/omnizip/profile/binary_profile.rb +33 -0
- data/lib/omnizip/profile/compression_profile.rb +157 -0
- data/lib/omnizip/profile/custom_profile.rb +155 -0
- data/lib/omnizip/profile/fast_profile.rb +31 -0
- data/lib/omnizip/profile/maximum_profile.rb +31 -0
- data/lib/omnizip/profile/profile_detector.rb +108 -0
- data/lib/omnizip/profile/profile_registry.rb +160 -0
- data/lib/omnizip/profile/text_profile.rb +33 -0
- data/lib/omnizip/profile.rb +261 -0
- data/lib/omnizip/profiler/memory_profiler.rb +66 -0
- data/lib/omnizip/profiler/method_profiler.rb +49 -0
- data/lib/omnizip/profiler/report_generator.rb +158 -0
- data/lib/omnizip/profiler.rb +192 -0
- data/lib/omnizip/progress/callback_reporter.rb +34 -0
- data/lib/omnizip/progress/console_reporter.rb +59 -0
- data/lib/omnizip/progress/log_reporter.rb +89 -0
- data/lib/omnizip/progress/operation_progress.rb +118 -0
- data/lib/omnizip/progress/progress_bar.rb +156 -0
- data/lib/omnizip/progress/progress_reporter.rb +40 -0
- data/lib/omnizip/progress/progress_tracker.rb +215 -0
- data/lib/omnizip/progress/silent_reporter.rb +22 -0
- data/lib/omnizip/progress.rb +131 -0
- data/lib/omnizip/registry.rb +111 -0
- data/lib/omnizip/rubyzip_compat.rb +61 -0
- data/lib/omnizip/temp/safe_extract.rb +124 -0
- data/lib/omnizip/temp/temp_file.rb +123 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +184 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +160 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +270 -0
- data/lib/omnizip/zip/output_stream.rb +320 -0
- data/lib/omnizip/zip.rb +23 -0
- data/lib/omnizip.rb +157 -0
- data/lib/tasks/msi_test_files.rake +66 -0
- data/lib/tasks/platform_gems.rake +147 -0
- data/lib/tasks/rust_backend.rake +48 -0
- data/readme-docs/advanced-features.adoc +514 -0
- data/readme-docs/api-usage.adoc +445 -0
- data/readme-docs/architecture.adoc +450 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +446 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +316 -0
- data/readme-docs/installation.adoc +228 -0
- data/readme-docs/par2-archives.adoc +608 -0
- data/readme-docs/performance-profiler.adoc +389 -0
- data/readme-docs/preprocessing-filters.adoc +280 -0
- data/vendor/libomnizip_ffi.so +0 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +768 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
# Convenience methods for common archive operations.
|
|
5
|
+
#
|
|
6
|
+
# All public methods accept an optional +format:+ keyword (default
|
|
7
|
+
# +:zip+) that selects the underlying archive handler via
|
|
8
|
+
# +Omnizip::ArchiveHandler+. New formats gain access to the convenience
|
|
9
|
+
# API by registering a handler; no edits to this file are needed.
|
|
10
|
+
module Convenience
|
|
11
|
+
DEFAULT_FORMAT = :zip
|
|
12
|
+
|
|
13
|
+
# Compress a single file into an archive.
|
|
14
|
+
#
|
|
15
|
+
# @param input_path [String] Path to input file
|
|
16
|
+
# @param output_path [String] Path to output archive
|
|
17
|
+
# @param format [Symbol] Archive format (default +:zip+)
|
|
18
|
+
# @param options [Hash] Compression / format-specific options
|
|
19
|
+
# @return [String] +output_path+
|
|
20
|
+
def compress_file(input_path, output_path, format: DEFAULT_FORMAT, **options)
|
|
21
|
+
unless ::File.exist?(input_path)
|
|
22
|
+
raise Errno::ENOENT, "Input file not found: #{input_path}"
|
|
23
|
+
end
|
|
24
|
+
if ::File.directory?(input_path)
|
|
25
|
+
raise ArgumentError, "Input is a directory: #{input_path}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
options = Omnizip::Profile.apply(options, paths: input_path)
|
|
29
|
+
|
|
30
|
+
if options[:chunked]
|
|
31
|
+
return Omnizip::Chunked.compress_file(input_path, output_path, **options)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Single-file compression formats route by output extension
|
|
35
|
+
# (unless an archive format was requested explicitly): writing
|
|
36
|
+
# output.lzma through the archive path silently produced a ZIP
|
|
37
|
+
# under a foreign extension.
|
|
38
|
+
if format == DEFAULT_FORMAT && (handler = single_file_handler(output_path))
|
|
39
|
+
handler.call(input_path, output_path, options)
|
|
40
|
+
return output_path
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Omnizip::ArchiveHandler.for(resolve_archive_format(output_path, format)).create(output_path, **options) do |archive|
|
|
44
|
+
archive.add(::File.basename(input_path), input_path)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
output_path
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Decompress a single-file compressed stream (the counterpart of
|
|
51
|
+
# #compress_file). The format is resolved from the input
|
|
52
|
+
# extension: .gz, .bz2, .xz, .lzma, .lz.
|
|
53
|
+
#
|
|
54
|
+
# @param compressed_path [String] Path to the compressed file
|
|
55
|
+
# @param output_path [String] Path to write the decompressed data
|
|
56
|
+
# @return [String] +output_path+
|
|
57
|
+
def decompress_file(compressed_path, output_path)
|
|
58
|
+
require_archive!(compressed_path)
|
|
59
|
+
|
|
60
|
+
decompressor = SINGLE_FILE_DECOMPRESSORS[::File.extname(compressed_path).downcase]
|
|
61
|
+
unless decompressor
|
|
62
|
+
raise Omnizip::UnsupportedFormatError,
|
|
63
|
+
"decompress_file supports #{SINGLE_FILE_DECOMPRESSORS.keys.join(', ')}; " \
|
|
64
|
+
"use extract_archive for archive formats"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
decompressor.call(compressed_path, output_path)
|
|
68
|
+
output_path
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Compress a directory into an archive.
|
|
72
|
+
#
|
|
73
|
+
# @param input_dir [String] Path to input directory
|
|
74
|
+
# @param output_path [String] Path to output archive
|
|
75
|
+
# @param format [Symbol] Archive format (default +:zip+)
|
|
76
|
+
# @param recursive [Boolean] Include subdirectories (default +true+)
|
|
77
|
+
# @param options [Hash] Compression / format-specific options
|
|
78
|
+
# @return [String] +output_path+
|
|
79
|
+
def compress_directory(input_dir, output_path, format: DEFAULT_FORMAT,
|
|
80
|
+
recursive: true, **options)
|
|
81
|
+
unless ::File.exist?(input_dir)
|
|
82
|
+
raise Errno::ENOENT, "Input directory not found: #{input_dir}"
|
|
83
|
+
end
|
|
84
|
+
unless ::File.directory?(input_dir)
|
|
85
|
+
raise ArgumentError, "Input is not a directory: #{input_dir}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# A directory cannot be written through a single-file stream
|
|
89
|
+
# format; routing it to the default would silently produce a
|
|
90
|
+
# ZIP under a foreign extension.
|
|
91
|
+
if format == DEFAULT_FORMAT && single_file_handler(output_path)
|
|
92
|
+
raise Omnizip::UnsupportedFormatError,
|
|
93
|
+
"#{::File.extname(output_path).downcase} is a single-file " \
|
|
94
|
+
"stream format and cannot contain a directory; use an " \
|
|
95
|
+
"archive format (.zip/.tar/.7z) or compress entries " \
|
|
96
|
+
"individually"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
options = Omnizip::Profile.apply(options, paths: input_dir)
|
|
100
|
+
|
|
101
|
+
Omnizip::ArchiveHandler.for(resolve_archive_format(output_path, format)).create(output_path, **options) do |archive|
|
|
102
|
+
add_directory_contents(archive, input_dir, "", recursive: recursive)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
output_path
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Extract an archive to a directory.
|
|
109
|
+
#
|
|
110
|
+
# @param archive_path [String] Path to archive
|
|
111
|
+
# @param output_dir [String] Output directory
|
|
112
|
+
# @param format [Symbol] Archive format (default +:zip+)
|
|
113
|
+
# @param overwrite [Boolean] Overwrite existing files (default +false+)
|
|
114
|
+
# @param options [Hash] Format-specific extraction options
|
|
115
|
+
# @return [Array<String>] Extracted file paths
|
|
116
|
+
def extract_archive(archive_path, output_dir, format: DEFAULT_FORMAT,
|
|
117
|
+
overwrite: false, **options)
|
|
118
|
+
require_archive!(archive_path)
|
|
119
|
+
Omnizip::ArchiveHandler.for(resolve_archive_format(archive_path, format, writing: false))
|
|
120
|
+
.extract_to(archive_path, output_dir,
|
|
121
|
+
overwrite: overwrite, **options)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# List contents of an archive.
|
|
125
|
+
#
|
|
126
|
+
# @param archive_path [String] Path to archive
|
|
127
|
+
# @param format [Symbol] Archive format (default +:zip+)
|
|
128
|
+
# @param details [Boolean] Include detailed info (default +false+)
|
|
129
|
+
# @param options [Hash] Format-specific listing options
|
|
130
|
+
# @return [Array<String>, Array<Hash>]
|
|
131
|
+
def list_archive(archive_path, format: DEFAULT_FORMAT, details: false,
|
|
132
|
+
**options)
|
|
133
|
+
require_archive!(archive_path)
|
|
134
|
+
Omnizip::ArchiveHandler.for(resolve_archive_format(archive_path, format, writing: false))
|
|
135
|
+
.list(archive_path, details: details, **options)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Read a single entry from an archive.
|
|
139
|
+
#
|
|
140
|
+
# @param archive_path [String] Path to archive
|
|
141
|
+
# @param entry_name [String] Entry to read
|
|
142
|
+
# @param format [Symbol] Archive format (default +:zip+)
|
|
143
|
+
# @return [String] Entry contents
|
|
144
|
+
def read_from_archive(archive_path, entry_name, format: DEFAULT_FORMAT)
|
|
145
|
+
require_archive!(archive_path)
|
|
146
|
+
Omnizip::ArchiveHandler.for(resolve_archive_format(archive_path, format, writing: false)).read_entry(archive_path, entry_name)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Add a file to an existing archive.
|
|
150
|
+
#
|
|
151
|
+
# @param archive_path [String] Path to archive
|
|
152
|
+
# @param entry_name [String] Entry name in archive
|
|
153
|
+
# @param source_path [String] Path to source file
|
|
154
|
+
# @param format [Symbol] Archive format (default +:zip+)
|
|
155
|
+
# @return [String] +archive_path+
|
|
156
|
+
def add_to_archive(archive_path, entry_name, source_path,
|
|
157
|
+
format: DEFAULT_FORMAT)
|
|
158
|
+
require_archive!(archive_path)
|
|
159
|
+
unless ::File.exist?(source_path)
|
|
160
|
+
raise Errno::ENOENT, "Source file not found: #{source_path}"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
resolved = resolve_archive_format(archive_path, format)
|
|
164
|
+
handler = Omnizip::ArchiveHandler.for(resolved)
|
|
165
|
+
# allowed: handler is a registered duck; missing add_entry raises below
|
|
166
|
+
if handler.respond_to?(:add_entry)
|
|
167
|
+
handler.add_entry(archive_path, entry_name, source_path)
|
|
168
|
+
else
|
|
169
|
+
raise Omnizip::UnsupportedFormatError,
|
|
170
|
+
"Format #{resolved.inspect} does not support adding entries"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
archive_path
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Remove an entry from an existing archive.
|
|
177
|
+
#
|
|
178
|
+
# @param archive_path [String] Path to archive
|
|
179
|
+
# @param entry_name [String] Entry to remove
|
|
180
|
+
# @param format [Symbol] Archive format (default +:zip+)
|
|
181
|
+
# @return [String] +archive_path+
|
|
182
|
+
def remove_from_archive(archive_path, entry_name, format: DEFAULT_FORMAT)
|
|
183
|
+
require_archive!(archive_path)
|
|
184
|
+
resolved = resolve_archive_format(archive_path, format)
|
|
185
|
+
handler = Omnizip::ArchiveHandler.for(resolved)
|
|
186
|
+
# allowed: handler is a registered duck; missing remove_entry raises below
|
|
187
|
+
unless handler.respond_to?(:remove_entry)
|
|
188
|
+
raise Omnizip::UnsupportedFormatError,
|
|
189
|
+
"Format #{resolved.inspect} does not support removing entries"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
handler.remove_entry(archive_path, entry_name)
|
|
193
|
+
archive_path
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Create a RAR archive through the RAR handler. RAR5 unless
|
|
197
|
+
# +version: 4+; the block yields the same generic writer
|
|
198
|
+
# interface as +Archive.create+ (+add+/+add_data+/+add_directory+).
|
|
199
|
+
#
|
|
200
|
+
# @param archive_path [String] Path to output archive
|
|
201
|
+
# @param options [Hash] RAR writer options
|
|
202
|
+
# @return [String, Array<String>] Path(s) of the created archive
|
|
203
|
+
# rubocop:disable-next Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
|
|
204
|
+
def create_rar(archive_path, **options, &block)
|
|
205
|
+
options[:version] ||= 5
|
|
206
|
+
Omnizip::ArchiveHandler.for(:rar).create(archive_path, **options, &block)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Extension -> single-file compressor map. Each lambda takes
|
|
210
|
+
# (input_path, output_path, options). These formats are streams,
|
|
211
|
+
# not archives, so they bypass ArchiveHandler.
|
|
212
|
+
# Extensions naming archive formats with a registered handler;
|
|
213
|
+
# routed when the caller did not pass an explicit +format:+.
|
|
214
|
+
ARCHIVE_FORMAT_EXTENSIONS = {
|
|
215
|
+
".zip" => :zip,
|
|
216
|
+
".tar" => :tar,
|
|
217
|
+
".7z" => :seven_zip,
|
|
218
|
+
".rar" => :rar,
|
|
219
|
+
}.freeze
|
|
220
|
+
|
|
221
|
+
# Extensions naming formats with read-only convenience routing.
|
|
222
|
+
# Writing them a ZIP under a foreign name was silent corruption;
|
|
223
|
+
# creation raises truthfully instead (the format-level writers
|
|
224
|
+
# exist for CPIO/ISO but are not part of the archive API; RAR
|
|
225
|
+
# moved to the writable routes when its handler gained create).
|
|
226
|
+
READ_ONLY_FORMAT_EXTENSIONS = %w[.iso .cpio .rpm .xar .msi].freeze
|
|
227
|
+
|
|
228
|
+
# Extensions whose format has a READ-ONLY handler: extraction and
|
|
229
|
+
# listing route to it, while creation keeps raising.
|
|
230
|
+
READ_ARCHIVE_FORMAT_EXTENSIONS = {
|
|
231
|
+
".rar" => :rar,
|
|
232
|
+
".cpio" => :cpio,
|
|
233
|
+
".iso" => :iso,
|
|
234
|
+
".rpm" => :rpm,
|
|
235
|
+
".xar" => :xar,
|
|
236
|
+
".msi" => :ole,
|
|
237
|
+
}.freeze
|
|
238
|
+
|
|
239
|
+
# Extension -> single-file decompressor. Each lambda takes
|
|
240
|
+
# (compressed_path, output_path) and writes the decompressed
|
|
241
|
+
# bytes; these formats are streams, not archives, so they bypass
|
|
242
|
+
# ArchiveHandler (mirrors SINGLE_FILE_COMPRESSORS). Xz exposes a
|
|
243
|
+
# path-based decompress rather than a stream one.
|
|
244
|
+
SINGLE_FILE_DECOMPRESSORS = {
|
|
245
|
+
".gz" => lambda do |compressed, output|
|
|
246
|
+
::File.open(compressed, "rb") do |input_io|
|
|
247
|
+
::File.open(output, "wb") do |output_io|
|
|
248
|
+
Omnizip::Formats::Gzip.decompress_stream(input_io, output_io)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end,
|
|
252
|
+
".bz2" => lambda do |compressed, output|
|
|
253
|
+
::File.open(compressed, "rb") do |input_io|
|
|
254
|
+
::File.open(output, "wb") do |output_io|
|
|
255
|
+
Omnizip::Formats::Bzip2File.decompress_stream(input_io, output_io)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end,
|
|
259
|
+
".xz" => lambda do |compressed, output|
|
|
260
|
+
::File.binwrite(output, Omnizip::Formats::Xz.decompress(compressed))
|
|
261
|
+
end,
|
|
262
|
+
".lzma" => lambda do |compressed, output|
|
|
263
|
+
::File.open(compressed, "rb") do |input_io|
|
|
264
|
+
::File.open(output, "wb") do |output_io|
|
|
265
|
+
Omnizip::Formats::LzmaAlone.decompress_stream(input_io, output_io)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end,
|
|
269
|
+
".lz" => lambda do |compressed, output|
|
|
270
|
+
::File.open(compressed, "rb") do |input_io|
|
|
271
|
+
::File.open(output, "wb") do |output_io|
|
|
272
|
+
Omnizip::Formats::Lzip.decompress_stream(input_io, output_io)
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end,
|
|
276
|
+
".zst" => lambda do |compressed, output|
|
|
277
|
+
::File.open(compressed, "rb") do |input_io|
|
|
278
|
+
::File.open(output, "wb") do |output_io|
|
|
279
|
+
Omnizip::Algorithms::Zstandard.new.decompress(input_io, output_io)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
end,
|
|
283
|
+
}.freeze
|
|
284
|
+
|
|
285
|
+
SINGLE_FILE_COMPRESSORS = {
|
|
286
|
+
".gz" => lambda do |input, output, options|
|
|
287
|
+
Omnizip::Formats::Gzip.compress(input, output, options)
|
|
288
|
+
end,
|
|
289
|
+
".bz2" => lambda do |input, output, options|
|
|
290
|
+
Omnizip::Formats::Bzip2File.compress(input, output, options)
|
|
291
|
+
end,
|
|
292
|
+
".xz" => lambda do |input, output, options|
|
|
293
|
+
Omnizip::Formats::Xz.create(::File.binread(input), output, options)
|
|
294
|
+
end,
|
|
295
|
+
".lzma" => lambda do |input, output, options|
|
|
296
|
+
::File.open(input, "rb") do |input_io|
|
|
297
|
+
::File.open(output, "wb") do |output_io|
|
|
298
|
+
Omnizip::Formats::LzmaAlone.compress_stream(input_io, output_io,
|
|
299
|
+
options)
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end,
|
|
303
|
+
".lz" => lambda do |input, output, options|
|
|
304
|
+
::File.open(input, "rb") do |input_io|
|
|
305
|
+
::File.open(output, "wb") do |output_io|
|
|
306
|
+
Omnizip::Formats::Lzip.compress_stream(input_io, output_io,
|
|
307
|
+
options)
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end,
|
|
311
|
+
".zst" => lambda do |input, output, options|
|
|
312
|
+
::File.open(input, "rb") do |input_io|
|
|
313
|
+
::File.open(output, "wb") do |output_io|
|
|
314
|
+
Omnizip::Algorithms::Zstandard.new.compress(input_io, output_io,
|
|
315
|
+
options)
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end,
|
|
319
|
+
}.freeze
|
|
320
|
+
|
|
321
|
+
# The single-file compressor matching the output extension, or nil.
|
|
322
|
+
def single_file_handler(output_path)
|
|
323
|
+
ext = ::File.extname(output_path).downcase
|
|
324
|
+
SINGLE_FILE_COMPRESSORS[ext]
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Archive format for a path: an explicit +format+ wins unless it
|
|
328
|
+
# is the default; otherwise the extension routes. Known-but-
|
|
329
|
+
# unwritable extensions raise instead of receiving a mislabeled
|
|
330
|
+
# ZIP. +writing:+ false (read operations) additionally routes
|
|
331
|
+
# extensions with read-only handlers.
|
|
332
|
+
def resolve_archive_format(path, format, writing: true)
|
|
333
|
+
return format unless format == DEFAULT_FORMAT
|
|
334
|
+
|
|
335
|
+
ext = ::File.extname(path).downcase
|
|
336
|
+
routed = ARCHIVE_FORMAT_EXTENSIONS[ext]
|
|
337
|
+
routed ||= READ_ARCHIVE_FORMAT_EXTENSIONS[ext] unless writing
|
|
338
|
+
return routed if routed
|
|
339
|
+
|
|
340
|
+
if READ_ONLY_FORMAT_EXTENSIONS.include?(ext)
|
|
341
|
+
raise Omnizip::UnsupportedFormatError,
|
|
342
|
+
"#{ext} archives cannot be written by the convenience " \
|
|
343
|
+
"API (read-only support); use the format-specific reader"
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
DEFAULT_FORMAT
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
private
|
|
350
|
+
|
|
351
|
+
def require_archive!(archive_path)
|
|
352
|
+
return if ::File.exist?(archive_path)
|
|
353
|
+
|
|
354
|
+
raise Errno::ENOENT, "Archive not found: #{archive_path}"
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Recursively add directory contents to an archive. The +archive+
|
|
358
|
+
# argument is whatever the handler's +#create+ block yields (e.g.
|
|
359
|
+
# +Omnizip::Zip::File+ or +Omnizip::Formats::Tar::Writer+) and must
|
|
360
|
+
# respond to +#add(entry_name, src_path = nil)+.
|
|
361
|
+
def add_directory_contents(archive, base_dir, relative_path, recursive: true)
|
|
362
|
+
dir_path = ::File.join(base_dir, relative_path)
|
|
363
|
+
|
|
364
|
+
Dir.foreach(dir_path) do |entry|
|
|
365
|
+
next if [".", ".."].include?(entry)
|
|
366
|
+
|
|
367
|
+
full_path = ::File.join(dir_path, entry)
|
|
368
|
+
archive_path = if relative_path.empty?
|
|
369
|
+
entry
|
|
370
|
+
else
|
|
371
|
+
::File.join(relative_path, entry)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
if ::File.directory?(full_path)
|
|
375
|
+
dir_entry_name = archive_path.end_with?("/") ? archive_path : "#{archive_path}/"
|
|
376
|
+
archive.add(dir_entry_name)
|
|
377
|
+
if recursive
|
|
378
|
+
add_directory_contents(archive, base_dir, archive_path,
|
|
379
|
+
recursive: recursive)
|
|
380
|
+
end
|
|
381
|
+
else
|
|
382
|
+
archive.add(archive_path, full_path)
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
extend Convenience
|
|
389
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Converter
|
|
5
|
+
# Registry for conversion strategies
|
|
6
|
+
class ConversionRegistry
|
|
7
|
+
@strategies = []
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# Register a conversion strategy
|
|
11
|
+
# @param strategy_class [Class] Strategy class
|
|
12
|
+
def register(strategy_class)
|
|
13
|
+
@strategies << strategy_class unless @strategies.include?(strategy_class)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Find strategy for source and target formats
|
|
17
|
+
# @param source [String] Source file path
|
|
18
|
+
# @param target [String] Target file path
|
|
19
|
+
# @return [Class, nil] Strategy class or nil
|
|
20
|
+
def find_strategy(source, target)
|
|
21
|
+
@strategies.find { |strategy| strategy.can_convert?(source, target) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Get all registered strategies
|
|
25
|
+
# @return [Array<Class>] List of strategy classes
|
|
26
|
+
def strategies
|
|
27
|
+
@strategies
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Check if conversion is supported
|
|
31
|
+
# @param source [String] Source file path
|
|
32
|
+
# @param target [String] Target file path
|
|
33
|
+
# @return [Boolean] True if supported
|
|
34
|
+
def supported?(source, target)
|
|
35
|
+
!find_strategy(source, target).nil?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Reset registry (for testing)
|
|
39
|
+
def reset
|
|
40
|
+
@strategies = []
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Register built-in strategies
|
|
46
|
+
ConversionRegistry.register(ZipToSevenZipStrategy)
|
|
47
|
+
ConversionRegistry.register(SevenZipToZipStrategy)
|
|
48
|
+
ConversionRegistry.register(ExtractRepackStrategy)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Converter
|
|
5
|
+
# Base class for archive format conversion strategies
|
|
6
|
+
class ConversionStrategy
|
|
7
|
+
attr_reader :source_path, :target_path, :options
|
|
8
|
+
|
|
9
|
+
# Initialize conversion strategy
|
|
10
|
+
# @param source_path [String] Source archive path
|
|
11
|
+
# @param target_path [String] Target archive path
|
|
12
|
+
# @param options [ConversionOptions] Conversion options
|
|
13
|
+
def initialize(source_path, target_path, options)
|
|
14
|
+
@source_path = source_path
|
|
15
|
+
@target_path = target_path
|
|
16
|
+
@options = options
|
|
17
|
+
@warnings = []
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Perform the conversion
|
|
21
|
+
# @return [ConversionResult] Conversion result
|
|
22
|
+
# @raise [NotImplementedError] Subclasses must implement
|
|
23
|
+
def convert
|
|
24
|
+
raise NotImplementedError, "#{self.class} must implement #convert"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Get source format
|
|
28
|
+
# @return [Symbol] Source format
|
|
29
|
+
# @raise [NotImplementedError] Subclasses must implement
|
|
30
|
+
def source_format
|
|
31
|
+
raise NotImplementedError, "#{self.class} must implement #source_format"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get target format
|
|
35
|
+
# @return [Symbol] Target format
|
|
36
|
+
# @raise [NotImplementedError] Subclasses must implement
|
|
37
|
+
def target_format
|
|
38
|
+
raise NotImplementedError, "#{self.class} must implement #target_format"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Check if this strategy can handle the conversion
|
|
42
|
+
# @param source [String] Source file path
|
|
43
|
+
# @param target [String] Target file path
|
|
44
|
+
# @return [Boolean] True if can handle
|
|
45
|
+
def self.can_convert?(_source, _target)
|
|
46
|
+
false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
# Add a warning message
|
|
52
|
+
# @param message [String] Warning message
|
|
53
|
+
def add_warning(message)
|
|
54
|
+
@warnings << message
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Get all warnings
|
|
58
|
+
# @return [Array<String>] List of warnings
|
|
59
|
+
def warnings
|
|
60
|
+
@warnings
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Repack the extracted tree under +extracted_dir+ into a new
|
|
64
|
+
# archive at +target_path+ through the Archive facade (the
|
|
65
|
+
# format is resolved from the target's extension). Directory
|
|
66
|
+
# entries are implied by file paths, matching every strategy's
|
|
67
|
+
# treatment. Returns the number of file entries written.
|
|
68
|
+
#
|
|
69
|
+
# @param extracted_dir [String] Directory of extracted entries
|
|
70
|
+
# @param write_options [Hash] Format writer options
|
|
71
|
+
# @return [Integer] Number of file entries written
|
|
72
|
+
def repack_tree(extracted_dir, **write_options)
|
|
73
|
+
count = 0
|
|
74
|
+
Omnizip::Archive.create(target_path, **write_options) do |archive|
|
|
75
|
+
Dir.glob(File.join(extracted_dir, "**", "*")).each do |path|
|
|
76
|
+
next if File.directory?(path)
|
|
77
|
+
|
|
78
|
+
archive.add_file(path, path.delete_prefix("#{extracted_dir}/"))
|
|
79
|
+
count += 1
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
count
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Create conversion result
|
|
86
|
+
# @param start_time [Time] Start time
|
|
87
|
+
# @param entry_count [Integer] Number of entries
|
|
88
|
+
# @return [ConversionResult] Result object
|
|
89
|
+
def create_result(start_time, entry_count)
|
|
90
|
+
duration = Time.now - start_time
|
|
91
|
+
source_size = File.size(source_path)
|
|
92
|
+
target_size = File.size(target_path)
|
|
93
|
+
|
|
94
|
+
Omnizip::Models::ConversionResult.new(
|
|
95
|
+
source_path: source_path,
|
|
96
|
+
target_path: target_path,
|
|
97
|
+
source_format: source_format,
|
|
98
|
+
target_format: target_format,
|
|
99
|
+
source_size: source_size,
|
|
100
|
+
target_size: target_size,
|
|
101
|
+
duration: duration,
|
|
102
|
+
entry_count: entry_count,
|
|
103
|
+
warnings: warnings,
|
|
104
|
+
)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string: true
|
|
2
|
+
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Converter
|
|
7
|
+
# Fallback conversion strategy: extract any routed source format
|
|
8
|
+
# and repack the tree into any writable target format, both
|
|
9
|
+
# through the handler registry. Registered after the direct
|
|
10
|
+
# entry-copy strategies, which keep precedence for their pairs.
|
|
11
|
+
class ExtractRepackStrategy < ConversionStrategy
|
|
12
|
+
WRITABLE_FORMATS = %i[zip seven_zip tar rar].freeze
|
|
13
|
+
|
|
14
|
+
# Any routed source extension converts to any writable target
|
|
15
|
+
def self.can_convert?(source, _target)
|
|
16
|
+
!source_format_for(source).nil? &&
|
|
17
|
+
WRITABLE_FORMATS.include?(target_format_for(_target))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Routed read-side format for an extension, or nil
|
|
21
|
+
def self.source_format_for(path)
|
|
22
|
+
ext = File.extname(path).downcase
|
|
23
|
+
Convenience::ARCHIVE_FORMAT_EXTENSIONS[ext] ||
|
|
24
|
+
Convenience::READ_ARCHIVE_FORMAT_EXTENSIONS[ext]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Writable format for a target extension, or nil
|
|
28
|
+
def self.target_format_for(path)
|
|
29
|
+
Convenience::ARCHIVE_FORMAT_EXTENSIONS[File.extname(path).downcase]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def convert
|
|
33
|
+
start_time = Time.now
|
|
34
|
+
|
|
35
|
+
Dir.mktmpdir("omnizip_convert_repack") do |tmp|
|
|
36
|
+
extracted = Omnizip.extract_archive(source_path, tmp)
|
|
37
|
+
repack_tree(tmp)
|
|
38
|
+
create_result(start_time, extracted.size)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def source_format
|
|
43
|
+
self.class.source_format_for(source_path) || :unknown
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def target_format
|
|
47
|
+
self.class.target_format_for(target_path) || :unknown
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Converter
|
|
7
|
+
# Convert 7-Zip archives to ZIP format
|
|
8
|
+
class SevenZipToZipStrategy < ConversionStrategy
|
|
9
|
+
# Perform 7z to ZIP conversion
|
|
10
|
+
# @return [ConversionResult] Conversion result
|
|
11
|
+
def convert
|
|
12
|
+
start_time = Time.now
|
|
13
|
+
|
|
14
|
+
entry_count = Dir.mktmpdir("omnizip_convert") do |tmp|
|
|
15
|
+
Omnizip.extract_archive(source_path, tmp)
|
|
16
|
+
repack_tree(tmp)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
create_result(start_time, entry_count)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Get source format
|
|
23
|
+
# @return [Symbol] Source format (:seven_zip)
|
|
24
|
+
def source_format
|
|
25
|
+
:seven_zip
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get target format
|
|
29
|
+
# @return [Symbol] Target format (:zip)
|
|
30
|
+
def target_format
|
|
31
|
+
:zip
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Check if can convert
|
|
35
|
+
# @param source [String] Source file
|
|
36
|
+
# @param target [String] Target file
|
|
37
|
+
# @return [Boolean] True if can convert
|
|
38
|
+
def self.can_convert?(source, target)
|
|
39
|
+
source.end_with?(".7z") && target.end_with?(".zip")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tmpdir"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Converter
|
|
7
|
+
# Convert ZIP archives to 7-Zip format
|
|
8
|
+
class ZipToSevenZipStrategy < ConversionStrategy
|
|
9
|
+
# Perform ZIP to 7z conversion
|
|
10
|
+
# @return [ConversionResult] Conversion result
|
|
11
|
+
def convert
|
|
12
|
+
start_time = Time.now
|
|
13
|
+
|
|
14
|
+
entry_count = Dir.mktmpdir("omnizip_convert_zip") do |tmp|
|
|
15
|
+
# Directories are implied by extracted file paths
|
|
16
|
+
Omnizip.extract_archive(source_path, tmp)
|
|
17
|
+
repack_tree(tmp, **writer_options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
create_result(start_time, entry_count)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Get source format
|
|
24
|
+
# @return [Symbol] Source format (:zip)
|
|
25
|
+
def source_format
|
|
26
|
+
:zip
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get target format
|
|
30
|
+
# @return [Symbol] Target format (:seven_zip)
|
|
31
|
+
def target_format
|
|
32
|
+
:seven_zip
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Check if can convert
|
|
36
|
+
# @param source [String] Source file
|
|
37
|
+
# @param target [String] Target file
|
|
38
|
+
# @return [Boolean] True if can convert
|
|
39
|
+
def self.can_convert?(source, target)
|
|
40
|
+
source.end_with?(".zip") && target.end_with?(".7z")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# SevenZip::Writer takes algorithm/level/solid as keywords
|
|
46
|
+
def writer_options
|
|
47
|
+
{
|
|
48
|
+
algorithm: options.compression || :lzma2,
|
|
49
|
+
level: options.compression_level || 5,
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|