omnizip 0.3.1
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 +754 -0
- data/COPYING +502 -0
- data/Gemfile +17 -0
- data/LICENSE +12 -0
- data/README.adoc +1045 -0
- data/Rakefile +12 -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 +91 -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 +271 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +185 -0
- data/docs/getting-started/your-first-archive.adoc +218 -0
- data/docs/guides/advanced-features/encryption.adoc +300 -0
- data/docs/guides/advanced-features/index.adoc +49 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +246 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +320 -0
- data/docs/guides/advanced-features/streaming.adoc +212 -0
- data/docs/guides/archive-formats/gzip-format.adoc +107 -0
- data/docs/guides/archive-formats/index.adoc +130 -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/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 +113 -0
- data/docs/guides/compression-algorithms/deflate.adoc +319 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +398 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +327 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +316 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +361 -0
- data/docs/guides/creating-archives.adoc +354 -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 +218 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +188 -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/troubleshooting/index.adoc +208 -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 +130 -0
- data/lib/omnizip/algorithm_registry.rb +86 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +225 -0
- data/lib/omnizip/algorithms/bzip2/decoder.rb +193 -0
- data/lib/omnizip/algorithms/bzip2/encoder.rb +237 -0
- data/lib/omnizip/algorithms/bzip2/huffman.rb +206 -0
- data/lib/omnizip/algorithms/bzip2/mtf.rb +101 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +151 -0
- data/lib/omnizip/algorithms/bzip2.rb +130 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +38 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +46 -0
- data/lib/omnizip/algorithms/deflate.rb +128 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +153 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +98 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +354 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +142 -0
- data/lib/omnizip/algorithms/deflate64.rb +109 -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 +148 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +69 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +415 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +142 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +260 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +320 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +210 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +341 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +192 -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 +205 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +88 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +130 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +85 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +434 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +325 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +426 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +645 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +227 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +169 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +261 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +331 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +116 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +2055 -0
- data/lib/omnizip/algorithms/lzma.rb +238 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +182 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +41 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +147 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +161 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +127 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +141 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +154 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +126 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +163 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +248 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +116 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +34 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +107 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +138 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +250 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +82 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +138 -0
- data/lib/omnizip/algorithms/sevenzip_lzma2.rb +123 -0
- data/lib/omnizip/algorithms/xz_lzma2.rb +118 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +25 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +46 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +51 -0
- data/lib/omnizip/algorithms/zstandard.rb +138 -0
- data/lib/omnizip/buffer/memory_archive.rb +251 -0
- data/lib/omnizip/buffer/memory_extractor.rb +224 -0
- data/lib/omnizip/buffer.rb +176 -0
- data/lib/omnizip/checksum_registry.rb +114 -0
- data/lib/omnizip/checksums/crc32.rb +100 -0
- data/lib/omnizip/checksums/crc64.rb +101 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/verifier.rb +131 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +120 -0
- data/lib/omnizip/chunked.rb +129 -0
- data/lib/omnizip/cli/output_formatter.rb +104 -0
- data/lib/omnizip/cli.rb +572 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +427 -0
- data/lib/omnizip/commands/archive_extract_command.rb +272 -0
- data/lib/omnizip/commands/archive_list_command.rb +218 -0
- data/lib/omnizip/commands/archive_repair_command.rb +131 -0
- data/lib/omnizip/commands/archive_verify_command.rb +117 -0
- data/lib/omnizip/commands/compress_command.rb +117 -0
- data/lib/omnizip/commands/decompress_command.rb +120 -0
- data/lib/omnizip/commands/list_command.rb +53 -0
- data/lib/omnizip/commands/metadata_command.rb +153 -0
- data/lib/omnizip/commands/parity_create_command.rb +122 -0
- data/lib/omnizip/commands/parity_repair_command.rb +122 -0
- data/lib/omnizip/commands/parity_verify_command.rb +124 -0
- data/lib/omnizip/commands/profile_list_command.rb +56 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/convenience.rb +359 -0
- data/lib/omnizip/converter/conversion_registry.rb +49 -0
- data/lib/omnizip/converter/conversion_strategy.rb +121 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +97 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +112 -0
- data/lib/omnizip/converter.rb +105 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +100 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +101 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/error.rb +106 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +98 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +99 -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 +63 -0
- data/lib/omnizip/extraction/filter_chain.rb +177 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +70 -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 +240 -0
- data/lib/omnizip/extraction.rb +111 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +113 -0
- data/lib/omnizip/filter.rb +139 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +166 -0
- data/lib/omnizip/filters/bcj.rb +279 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +200 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +61 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +93 -0
- data/lib/omnizip/filters/bcj2.rb +99 -0
- data/lib/omnizip/filters/bcj_arm.rb +176 -0
- data/lib/omnizip/filters/bcj_arm64.rb +244 -0
- data/lib/omnizip/filters/bcj_ia64.rb +196 -0
- data/lib/omnizip/filters/bcj_ppc.rb +190 -0
- data/lib/omnizip/filters/bcj_sparc.rb +176 -0
- data/lib/omnizip/filters/bcj_x86.rb +193 -0
- data/lib/omnizip/filters/delta.rb +196 -0
- data/lib/omnizip/filters/filter_base.rb +72 -0
- data/lib/omnizip/filters/registry.rb +123 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/format_detector.rb +162 -0
- data/lib/omnizip/format_registry.rb +59 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +172 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +385 -0
- data/lib/omnizip/formats/cpio/reader.rb +196 -0
- data/lib/omnizip/formats/cpio/writer.rb +234 -0
- data/lib/omnizip/formats/cpio.rb +140 -0
- data/lib/omnizip/formats/format_spec_loader.rb +230 -0
- data/lib/omnizip/formats/gzip.rb +238 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +297 -0
- data/lib/omnizip/formats/iso/directory_record.rb +152 -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 +197 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +320 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +530 -0
- data/lib/omnizip/formats/iso.rb +140 -0
- data/lib/omnizip/formats/lzip.rb +175 -0
- data/lib/omnizip/formats/lzma_alone.rb +171 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +243 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +195 -0
- data/lib/omnizip/formats/rar/block_parser.rb +243 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +216 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +158 -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/ppmd/context.rb +105 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +219 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +262 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +82 -0
- data/lib/omnizip/formats/rar/decompressor.rb +238 -0
- data/lib/omnizip/formats/rar/external_writer.rb +312 -0
- data/lib/omnizip/formats/rar/header.rb +192 -0
- data/lib/omnizip/formats/rar/license_validator.rb +109 -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/parity_handler.rb +292 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +202 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +578 -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 +97 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +166 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +187 -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 +264 -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 +194 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +109 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +142 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +65 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +466 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +241 -0
- data/lib/omnizip/formats/rar/reader.rb +366 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +168 -0
- data/lib/omnizip/formats/rar/writer.rb +431 -0
- data/lib/omnizip/formats/rar.rb +205 -0
- data/lib/omnizip/formats/rar3/compressor.rb +73 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +66 -0
- data/lib/omnizip/formats/rar3/reader.rb +386 -0
- data/lib/omnizip/formats/rar3/writer.rb +219 -0
- data/lib/omnizip/formats/rar5/compressor.rb +73 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +66 -0
- data/lib/omnizip/formats/rar5/reader.rb +342 -0
- data/lib/omnizip/formats/rar5/writer.rb +214 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +150 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +114 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +142 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +144 -0
- data/lib/omnizip/formats/seven_zip/header.rb +106 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +134 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +466 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +58 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +69 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +660 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +458 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +632 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +315 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +162 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +740 -0
- data/lib/omnizip/formats/seven_zip.rb +93 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +94 -0
- data/lib/omnizip/formats/tar/header.rb +168 -0
- data/lib/omnizip/formats/tar/reader.rb +121 -0
- data/lib/omnizip/formats/tar/writer.rb +216 -0
- data/lib/omnizip/formats/tar.rb +84 -0
- data/lib/omnizip/formats/xz/reader.rb +116 -0
- data/lib/omnizip/formats/xz.rb +237 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +754 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +306 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +186 -0
- data/lib/omnizip/formats/xz_impl/constants.rb +49 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +122 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +468 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +99 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +81 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +117 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +55 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +108 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl/writer.rb +421 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +195 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +133 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +138 -0
- data/lib/omnizip/formats/zip/reader.rb +250 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +375 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +104 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +66 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +114 -0
- data/lib/omnizip/formats/zip.rb +50 -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/seven_zip/lzma/decoder.rb +421 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +465 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +288 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +200 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +141 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +519 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +723 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +750 -0
- data/lib/omnizip/io/buffered_input.rb +146 -0
- data/lib/omnizip/io/buffered_output.rb +105 -0
- data/lib/omnizip/io/stream_manager.rb +115 -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 +124 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +146 -0
- data/lib/omnizip/metadata/metadata_editor.rb +171 -0
- data/lib/omnizip/metadata/metadata_registry.rb +64 -0
- data/lib/omnizip/metadata/metadata_validator.rb +99 -0
- data/lib/omnizip/metadata.rb +57 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +73 -0
- data/lib/omnizip/models/compression_options.rb +71 -0
- data/lib/omnizip/models/conversion_options.rb +87 -0
- data/lib/omnizip/models/conversion_result.rb +135 -0
- data/lib/omnizip/models/eta_result.rb +46 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +144 -0
- data/lib/omnizip/models/filter_config.rb +183 -0
- data/lib/omnizip/models/match_result.rb +124 -0
- data/lib/omnizip/models/optimization_suggestion.rb +91 -0
- data/lib/omnizip/models/parallel_options.rb +104 -0
- data/lib/omnizip/models/performance_result.rb +79 -0
- data/lib/omnizip/models/profile_report.rb +82 -0
- data/lib/omnizip/models/progress_options.rb +38 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +81 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +203 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +347 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +329 -0
- data/lib/omnizip/parallel/worker_pool.rb +223 -0
- data/lib/omnizip/parallel.rb +149 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +196 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +73 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +133 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +123 -0
- data/lib/omnizip/parity/models/main_packet.rb +128 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +109 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +78 -0
- data/lib/omnizip/parity/par2_creator.rb +531 -0
- data/lib/omnizip/parity/par2_repairer.rb +407 -0
- data/lib/omnizip/parity/par2_verifier.rb +364 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +110 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +266 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +111 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +342 -0
- data/lib/omnizip/parity.rb +186 -0
- data/lib/omnizip/password/encryption_registry.rb +65 -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 +192 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +141 -0
- data/lib/omnizip/password.rb +87 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +174 -0
- data/lib/omnizip/pipe.rb +121 -0
- data/lib/omnizip/platform/ntfs_streams.rb +201 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +39 -0
- data/lib/omnizip/profile/balanced_profile.rb +33 -0
- data/lib/omnizip/profile/binary_profile.rb +36 -0
- data/lib/omnizip/profile/compression_profile.rb +158 -0
- data/lib/omnizip/profile/custom_profile.rb +157 -0
- data/lib/omnizip/profile/fast_profile.rb +33 -0
- data/lib/omnizip/profile/maximum_profile.rb +33 -0
- data/lib/omnizip/profile/profile_detector.rb +110 -0
- data/lib/omnizip/profile/profile_registry.rb +161 -0
- data/lib/omnizip/profile/text_profile.rb +36 -0
- data/lib/omnizip/profile.rb +190 -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 +169 -0
- data/lib/omnizip/profiler.rb +204 -0
- data/lib/omnizip/progress/callback_reporter.rb +36 -0
- data/lib/omnizip/progress/console_reporter.rb +62 -0
- data/lib/omnizip/progress/log_reporter.rb +91 -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 +190 -0
- data/lib/omnizip/progress/silent_reporter.rb +24 -0
- data/lib/omnizip/progress.rb +127 -0
- data/lib/omnizip/rubyzip_compat.rb +63 -0
- data/lib/omnizip/temp/safe_extract.rb +168 -0
- data/lib/omnizip/temp/temp_file.rb +124 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +181 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +156 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +273 -0
- data/lib/omnizip/zip/output_stream.rb +324 -0
- data/lib/omnizip.rb +156 -0
- data/readme-docs/advanced-features.adoc +515 -0
- data/readme-docs/api-usage.adoc +444 -0
- data/readme-docs/architecture.adoc +449 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +442 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +325 -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/xz-file-format-1.2.1.txt +1174 -0
- metadata +617 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
# Convenience methods for common archive operations
|
|
5
|
+
module Convenience
|
|
6
|
+
# Compress a single file to a ZIP archive
|
|
7
|
+
# @param input_path [String] Path to input file
|
|
8
|
+
# @param output_path [String] Path to output ZIP file
|
|
9
|
+
# @param options [Hash] Compression options
|
|
10
|
+
# @option options [Symbol, Omnizip::Profile::CompressionProfile] :profile
|
|
11
|
+
# Compression profile (:fast, :balanced, :maximum, :text, :binary, :archive, :auto)
|
|
12
|
+
# @option options [Symbol] :compression Compression method (:deflate, :bzip2, :lzma, :zstandard)
|
|
13
|
+
# @option options [Integer] :level Compression level (1-9)
|
|
14
|
+
# @option options [Boolean] :chunked Use chunked processing for large files
|
|
15
|
+
# @option options [Integer] :chunk_size Chunk size in bytes (default: 64MB)
|
|
16
|
+
# @option options [Integer] :max_memory Maximum memory usage (default: 256MB)
|
|
17
|
+
# @option options [Proc] :progress Progress callback
|
|
18
|
+
# @return [String] Path to created archive
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
# Omnizip.compress_file('document.txt', 'document.zip')
|
|
22
|
+
# Omnizip.compress_file('image.png', 'image.zip', compression: :lzma, level: 9)
|
|
23
|
+
# Omnizip.compress_file('huge.dat', 'huge.zip', chunked: true, max_memory: 128.megabytes)
|
|
24
|
+
# Omnizip.compress_file('data.txt', 'data.zip', profile: :fast)
|
|
25
|
+
# Omnizip.compress_file('app.exe', 'app.zip', profile: :auto)
|
|
26
|
+
def compress_file(input_path, output_path, **options)
|
|
27
|
+
unless ::File.exist?(input_path)
|
|
28
|
+
raise Errno::ENOENT,
|
|
29
|
+
"Input file not found: #{input_path}"
|
|
30
|
+
end
|
|
31
|
+
if ::File.directory?(input_path)
|
|
32
|
+
raise ArgumentError,
|
|
33
|
+
"Input is a directory: #{input_path}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Apply profile settings if specified
|
|
37
|
+
options = apply_profile(input_path, options) if options[:profile]
|
|
38
|
+
|
|
39
|
+
# Use chunked processing for large files if requested
|
|
40
|
+
if options[:chunked]
|
|
41
|
+
return Omnizip::Chunked.compress_file(input_path, output_path,
|
|
42
|
+
**options)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
Omnizip::Zip::File.create(output_path) do |zip|
|
|
46
|
+
basename = ::File.basename(input_path)
|
|
47
|
+
zip.add(basename, input_path)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
output_path
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Compress a directory to a ZIP archive
|
|
54
|
+
# @param input_dir [String] Path to input directory
|
|
55
|
+
# @param output_path [String] Path to output ZIP file
|
|
56
|
+
# @param options [Hash] Compression options
|
|
57
|
+
# @option options [Symbol, Omnizip::Profile::CompressionProfile] :profile
|
|
58
|
+
# Compression profile (:fast, :balanced, :maximum, etc.)
|
|
59
|
+
# @option options [Symbol] :compression Compression method
|
|
60
|
+
# @option options [Integer] :level Compression level (1-9)
|
|
61
|
+
# @option options [Boolean] :recursive Include subdirectories (default: true)
|
|
62
|
+
# @option options [Integer] :max_memory Maximum memory usage for large files
|
|
63
|
+
# @option options [Proc] :progress Progress callback
|
|
64
|
+
# @return [String] Path to created archive
|
|
65
|
+
#
|
|
66
|
+
# @example
|
|
67
|
+
# Omnizip.compress_directory('project/', 'backup.zip')
|
|
68
|
+
# Omnizip.compress_directory('src/', 'src.zip', compression: :lzma2, level: 9)
|
|
69
|
+
# Omnizip.compress_directory('large/', 'backup.zip', max_memory: 256.megabytes)
|
|
70
|
+
# Omnizip.compress_directory('src/', 'backup.7z', profile: :maximum)
|
|
71
|
+
def compress_directory(input_dir, output_path, recursive: true, **options)
|
|
72
|
+
unless ::File.exist?(input_dir)
|
|
73
|
+
raise Errno::ENOENT,
|
|
74
|
+
"Input directory not found: #{input_dir}"
|
|
75
|
+
end
|
|
76
|
+
unless ::File.directory?(input_dir)
|
|
77
|
+
raise ArgumentError,
|
|
78
|
+
"Input is not a directory: #{input_dir}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Apply profile settings if specified (use first file for auto-detection)
|
|
82
|
+
if options[:profile]
|
|
83
|
+
first_file = find_first_file(input_dir)
|
|
84
|
+
apply_profile(first_file, options)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
Omnizip::Zip::File.create(output_path) do |zip|
|
|
88
|
+
add_directory_contents(zip, input_dir, "", recursive: recursive)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
output_path
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Extract a ZIP archive to a directory
|
|
95
|
+
# @param archive_path [String] Path to ZIP archive
|
|
96
|
+
# @param output_dir [String] Path to output directory
|
|
97
|
+
# @param options [Hash] Extraction options
|
|
98
|
+
# @option options [Boolean] :overwrite Overwrite existing files (default: false)
|
|
99
|
+
# @return [Array<String>] List of extracted file paths
|
|
100
|
+
#
|
|
101
|
+
# @example
|
|
102
|
+
# Omnizip.extract_archive('backup.zip', 'restore/')
|
|
103
|
+
# Omnizip.extract_archive('archive.zip', 'output/', overwrite: true)
|
|
104
|
+
def extract_archive(archive_path, output_dir, overwrite: false, **_options)
|
|
105
|
+
unless ::File.exist?(archive_path)
|
|
106
|
+
raise Errno::ENOENT,
|
|
107
|
+
"Archive not found: #{archive_path}"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
extracted_files = []
|
|
111
|
+
|
|
112
|
+
Omnizip::Zip::File.open(archive_path) do |zip|
|
|
113
|
+
zip.each do |entry|
|
|
114
|
+
dest_path = ::File.join(output_dir, entry.name)
|
|
115
|
+
|
|
116
|
+
# Handle overwrite option
|
|
117
|
+
on_exists = if overwrite
|
|
118
|
+
proc { true }
|
|
119
|
+
else
|
|
120
|
+
proc { |_e, path| raise "File exists: #{path}" }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
zip.extract(entry, dest_path, &on_exists)
|
|
124
|
+
extracted_files << dest_path
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
extracted_files
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# List contents of a ZIP archive
|
|
132
|
+
# @param archive_path [String] Path to ZIP archive
|
|
133
|
+
# @param options [Hash] Listing options
|
|
134
|
+
# @option options [Boolean] :details Include detailed information (default: false)
|
|
135
|
+
# @return [Array<String>, Array<Hash>] List of entry names or detailed info
|
|
136
|
+
#
|
|
137
|
+
# @example
|
|
138
|
+
# Omnizip.list_archive('backup.zip')
|
|
139
|
+
# # => ["file1.txt", "file2.txt", "dir/"]
|
|
140
|
+
#
|
|
141
|
+
# Omnizip.list_archive('backup.zip', details: true)
|
|
142
|
+
# # => [{name: "file1.txt", size: 1024, compressed_size: 512, ...}, ...]
|
|
143
|
+
def list_archive(archive_path, details: false, **_options)
|
|
144
|
+
unless ::File.exist?(archive_path)
|
|
145
|
+
raise Errno::ENOENT,
|
|
146
|
+
"Archive not found: #{archive_path}"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
Omnizip::Zip::File.open(archive_path) do |zip|
|
|
150
|
+
if details
|
|
151
|
+
zip.entries.map do |entry|
|
|
152
|
+
{
|
|
153
|
+
name: entry.name,
|
|
154
|
+
size: entry.size,
|
|
155
|
+
compressed_size: entry.compressed_size,
|
|
156
|
+
compression_method: entry.compression_method,
|
|
157
|
+
crc: entry.crc,
|
|
158
|
+
time: entry.time,
|
|
159
|
+
directory: entry.directory?,
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
else
|
|
163
|
+
zip.names
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Read a single file from a ZIP archive
|
|
169
|
+
# @param archive_path [String] Path to ZIP archive
|
|
170
|
+
# @param entry_name [String] Name of entry to read
|
|
171
|
+
# @return [String] Contents of the file
|
|
172
|
+
#
|
|
173
|
+
# @example
|
|
174
|
+
# content = Omnizip.read_from_archive('backup.zip', 'config.yml')
|
|
175
|
+
def read_from_archive(archive_path, entry_name)
|
|
176
|
+
unless ::File.exist?(archive_path)
|
|
177
|
+
raise Errno::ENOENT,
|
|
178
|
+
"Archive not found: #{archive_path}"
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
Omnizip::Zip::File.open(archive_path) do |zip|
|
|
182
|
+
entry = zip.get_entry(entry_name)
|
|
183
|
+
raise Errno::ENOENT, "Entry not found: #{entry_name}" unless entry
|
|
184
|
+
|
|
185
|
+
zip.read(entry)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# Add a file to an existing ZIP archive
|
|
190
|
+
# @param archive_path [String] Path to ZIP archive
|
|
191
|
+
# @param entry_name [String] Name for entry in archive
|
|
192
|
+
# @param source_path [String] Path to source file
|
|
193
|
+
# @return [String] Path to archive
|
|
194
|
+
#
|
|
195
|
+
# @example
|
|
196
|
+
# Omnizip.add_to_archive('backup.zip', 'new_file.txt', 'path/to/new_file.txt')
|
|
197
|
+
def add_to_archive(archive_path, entry_name, source_path)
|
|
198
|
+
unless ::File.exist?(archive_path)
|
|
199
|
+
raise Errno::ENOENT,
|
|
200
|
+
"Archive not found: #{archive_path}"
|
|
201
|
+
end
|
|
202
|
+
unless ::File.exist?(source_path)
|
|
203
|
+
raise Errno::ENOENT,
|
|
204
|
+
"Source file not found: #{source_path}"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
Omnizip::Zip::File.open(archive_path) do |zip|
|
|
208
|
+
zip.add(entry_name, source_path)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
archive_path
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Remove a file from a ZIP archive
|
|
215
|
+
# @param archive_path [String] Path to ZIP archive
|
|
216
|
+
# @param entry_name [String] Name of entry to remove
|
|
217
|
+
# @return [String] Path to archive
|
|
218
|
+
#
|
|
219
|
+
# @example
|
|
220
|
+
# Omnizip.remove_from_archive('backup.zip', 'old_file.txt')
|
|
221
|
+
def remove_from_archive(archive_path, entry_name)
|
|
222
|
+
unless ::File.exist?(archive_path)
|
|
223
|
+
raise Errno::ENOENT,
|
|
224
|
+
"Archive not found: #{archive_path}"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
Omnizip::Zip::File.open(archive_path) do |zip|
|
|
228
|
+
zip.remove(entry_name)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
archive_path
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Create a RAR archive
|
|
235
|
+
# @param archive_path [String] Path to output RAR file
|
|
236
|
+
# @param options [Hash] Creation options
|
|
237
|
+
# @option options [Integer] :version RAR version (4 or 5, default: 5 for pure Ruby)
|
|
238
|
+
# @option options [Symbol] :compression For RAR5: :store, :lzma, :auto (default: :store)
|
|
239
|
+
# @option options [Integer] :level For RAR5: LZMA compression level 1-5 (default: 3)
|
|
240
|
+
# @option options [Boolean] :include_mtime Include modification time (RAR5 only, default: false)
|
|
241
|
+
# @option options [Boolean] :include_crc32 Include CRC32 checksum (RAR5 only, default: false)
|
|
242
|
+
# @yield [writer] RAR writer instance
|
|
243
|
+
# @return [String] Path to created archive
|
|
244
|
+
#
|
|
245
|
+
# @example Create RAR5 archive with STORE compression
|
|
246
|
+
# Omnizip.create_rar('backup.rar') do |rar|
|
|
247
|
+
# rar.add_file('document.pdf')
|
|
248
|
+
# end
|
|
249
|
+
#
|
|
250
|
+
# @example Create RAR5 with LZMA compression
|
|
251
|
+
# Omnizip.create_rar('backup.rar', compression: :lzma, level: 5) do |rar|
|
|
252
|
+
# rar.add_file('data.txt')
|
|
253
|
+
# end
|
|
254
|
+
#
|
|
255
|
+
# @example Create RAR5 with optional fields
|
|
256
|
+
# Omnizip.create_rar('backup.rar',
|
|
257
|
+
# compression: :lzma,
|
|
258
|
+
# level: 3,
|
|
259
|
+
# include_mtime: true,
|
|
260
|
+
# include_crc32: true
|
|
261
|
+
# ) do |rar|
|
|
262
|
+
# rar.add_file('important.doc')
|
|
263
|
+
# end
|
|
264
|
+
# rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
|
|
265
|
+
def create_rar(archive_path, **options, &block)
|
|
266
|
+
# Default to RAR5 (pure Ruby) unless explicitly specified
|
|
267
|
+
options[:version] ||= 5
|
|
268
|
+
|
|
269
|
+
Omnizip::Formats::Rar.create(archive_path, options, &block)
|
|
270
|
+
end
|
|
271
|
+
# rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
|
|
272
|
+
|
|
273
|
+
private
|
|
274
|
+
|
|
275
|
+
# Apply compression profile to options
|
|
276
|
+
#
|
|
277
|
+
# @param file_path [String, nil] File path for auto-detection
|
|
278
|
+
# @param options [Hash] Compression options
|
|
279
|
+
# @return [Hash] Updated options with profile settings
|
|
280
|
+
def apply_profile(file_path, options)
|
|
281
|
+
profile_spec = options.delete(:profile)
|
|
282
|
+
return options unless profile_spec
|
|
283
|
+
|
|
284
|
+
# Get the profile
|
|
285
|
+
profile = case profile_spec
|
|
286
|
+
when :auto
|
|
287
|
+
# Auto-detect based on file
|
|
288
|
+
file_path ? Omnizip::Profile.detect(file_path) : Omnizip::Profile.get(:balanced)
|
|
289
|
+
when Symbol
|
|
290
|
+
# Get by name
|
|
291
|
+
Omnizip::Profile.get(profile_spec) || Omnizip::Profile.get(:balanced)
|
|
292
|
+
when Omnizip::Profile::CompressionProfile
|
|
293
|
+
# Use the profile directly
|
|
294
|
+
profile_spec
|
|
295
|
+
else
|
|
296
|
+
Omnizip::Profile.get(:balanced)
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Apply profile to options
|
|
300
|
+
profile.apply_to(options)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# Find first file in directory for profile detection
|
|
304
|
+
#
|
|
305
|
+
# @param dir_path [String] Directory path
|
|
306
|
+
# @return [String, nil] Path to first file or nil
|
|
307
|
+
def find_first_file(dir_path)
|
|
308
|
+
Dir.foreach(dir_path) do |entry|
|
|
309
|
+
next if [".", ".."].include?(entry)
|
|
310
|
+
|
|
311
|
+
full_path = ::File.join(dir_path, entry)
|
|
312
|
+
return full_path if ::File.file?(full_path)
|
|
313
|
+
|
|
314
|
+
# Check subdirectories
|
|
315
|
+
if ::File.directory?(full_path)
|
|
316
|
+
result = find_first_file(full_path)
|
|
317
|
+
return result if result
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
nil
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# Recursively add directory contents to archive
|
|
324
|
+
def add_directory_contents(zip, base_dir, relative_path, recursive: true)
|
|
325
|
+
dir_path = ::File.join(base_dir, relative_path)
|
|
326
|
+
|
|
327
|
+
Dir.foreach(dir_path) do |entry|
|
|
328
|
+
next if [".", ".."].include?(entry)
|
|
329
|
+
|
|
330
|
+
full_path = ::File.join(dir_path, entry)
|
|
331
|
+
|
|
332
|
+
# Create archive path (strip leading separator if at root)
|
|
333
|
+
archive_path = if relative_path.empty?
|
|
334
|
+
entry
|
|
335
|
+
else
|
|
336
|
+
::File.join(relative_path, entry)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
if ::File.directory?(full_path)
|
|
340
|
+
# Add directory entry with trailing slash
|
|
341
|
+
dir_entry_name = archive_path.end_with?("/") ? archive_path : "#{archive_path}/"
|
|
342
|
+
zip.add(dir_entry_name)
|
|
343
|
+
|
|
344
|
+
# Recursively add contents if requested
|
|
345
|
+
if recursive
|
|
346
|
+
add_directory_contents(zip, base_dir, archive_path,
|
|
347
|
+
recursive: recursive)
|
|
348
|
+
end
|
|
349
|
+
else
|
|
350
|
+
# Add file with its data
|
|
351
|
+
zip.add(archive_path, full_path)
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Extend Omnizip module with convenience methods
|
|
358
|
+
extend Convenience
|
|
359
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
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
|
+
# Detect format from file extension
|
|
64
|
+
# @param path [String] File path
|
|
65
|
+
# @return [Symbol] Format
|
|
66
|
+
def detect_format(path)
|
|
67
|
+
ext = File.extname(path).downcase
|
|
68
|
+
case ext
|
|
69
|
+
when ".zip"
|
|
70
|
+
:zip
|
|
71
|
+
when ".7z"
|
|
72
|
+
:seven_zip
|
|
73
|
+
else
|
|
74
|
+
raise ArgumentError, "Unknown format for file: #{path}"
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Create conversion result
|
|
79
|
+
# @param start_time [Time] Start time
|
|
80
|
+
# @param entry_count [Integer] Number of entries
|
|
81
|
+
# @return [ConversionResult] Result object
|
|
82
|
+
def create_result(start_time, entry_count)
|
|
83
|
+
require_relative "../models/conversion_result"
|
|
84
|
+
|
|
85
|
+
duration = Time.now - start_time
|
|
86
|
+
source_size = File.size(source_path)
|
|
87
|
+
target_size = File.size(target_path)
|
|
88
|
+
|
|
89
|
+
Omnizip::Models::ConversionResult.new(
|
|
90
|
+
source_path: source_path,
|
|
91
|
+
target_path: target_path,
|
|
92
|
+
source_format: source_format,
|
|
93
|
+
target_format: target_format,
|
|
94
|
+
source_size: source_size,
|
|
95
|
+
target_size: target_size,
|
|
96
|
+
duration: duration,
|
|
97
|
+
entry_count: entry_count,
|
|
98
|
+
warnings: warnings,
|
|
99
|
+
)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Check if metadata is compatible between formats
|
|
103
|
+
# @param entry [Entry] Entry to check
|
|
104
|
+
# @return [Boolean] True if fully compatible
|
|
105
|
+
def metadata_compatible?(_entry)
|
|
106
|
+
# ZIP supports most metadata
|
|
107
|
+
# 7z has limited metadata support
|
|
108
|
+
case [source_format, target_format]
|
|
109
|
+
when %i[zip seven_zip]
|
|
110
|
+
# Some metadata loss (comments, extra fields)
|
|
111
|
+
false
|
|
112
|
+
when %i[seven_zip zip]
|
|
113
|
+
# Can preserve most 7z metadata in ZIP
|
|
114
|
+
true
|
|
115
|
+
else
|
|
116
|
+
true
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "conversion_strategy"
|
|
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
|
+
0
|
|
14
|
+
|
|
15
|
+
require_relative "../formats/seven_zip"
|
|
16
|
+
require_relative "../zip/file"
|
|
17
|
+
|
|
18
|
+
# Open source 7z archive
|
|
19
|
+
reader = Omnizip::Formats::SevenZip::Reader.new(source_path)
|
|
20
|
+
reader.read
|
|
21
|
+
|
|
22
|
+
# Collect entries
|
|
23
|
+
entries_data = collect_seven_zip_entries(reader)
|
|
24
|
+
entry_count = entries_data.size
|
|
25
|
+
|
|
26
|
+
# Create target ZIP archive
|
|
27
|
+
create_zip(entries_data)
|
|
28
|
+
|
|
29
|
+
create_result(start_time, entry_count)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Get source format
|
|
33
|
+
# @return [Symbol] Source format (:seven_zip)
|
|
34
|
+
def source_format
|
|
35
|
+
:seven_zip
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Get target format
|
|
39
|
+
# @return [Symbol] Target format (:zip)
|
|
40
|
+
def target_format
|
|
41
|
+
:zip
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Check if can convert
|
|
45
|
+
# @param source [String] Source file
|
|
46
|
+
# @param target [String] Target file
|
|
47
|
+
# @return [Boolean] True if can convert
|
|
48
|
+
def self.can_convert?(source, target)
|
|
49
|
+
source.end_with?(".7z") && target.end_with?(".zip")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def collect_seven_zip_entries(reader)
|
|
55
|
+
entries = []
|
|
56
|
+
|
|
57
|
+
reader.entries.each do |entry|
|
|
58
|
+
data = {
|
|
59
|
+
name: entry.name,
|
|
60
|
+
content: nil,
|
|
61
|
+
mtime: entry.mtime || Time.now,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# Extract entry data
|
|
65
|
+
unless entry.name.end_with?("/")
|
|
66
|
+
File.open(source_path, "rb") do |io|
|
|
67
|
+
data[:content] = reader.send(:extract_entry_data, io, entry)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
entries << data
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
entries
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def create_zip(entries)
|
|
78
|
+
Omnizip::Zip::File.create(target_path) do |zip|
|
|
79
|
+
entries.each do |entry_data|
|
|
80
|
+
if entry_data[:name].end_with?("/")
|
|
81
|
+
# Directory entry
|
|
82
|
+
zip.add(entry_data[:name])
|
|
83
|
+
else
|
|
84
|
+
# File entry
|
|
85
|
+
zip.add(entry_data[:name]) { entry_data[:content] }
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Set archive comment if preserving metadata
|
|
90
|
+
if options.preserve_metadata
|
|
91
|
+
zip.comment = "Converted from 7z by Omnizip"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|