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,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
# This file is part of Omnizip.
|
|
7
|
+
#
|
|
8
|
+
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
+
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# See the COPYING file for the complete text of the license.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
require_relative "../cli/output_formatter"
|
|
20
|
+
|
|
21
|
+
module Omnizip
|
|
22
|
+
module Commands
|
|
23
|
+
# Command to list available compression algorithms.
|
|
24
|
+
class ListCommand
|
|
25
|
+
attr_reader :options
|
|
26
|
+
|
|
27
|
+
# Initialize list command with options.
|
|
28
|
+
#
|
|
29
|
+
# @param options [Hash] Command options from Thor
|
|
30
|
+
def initialize(options = {})
|
|
31
|
+
@options = options
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Execute the list command.
|
|
35
|
+
#
|
|
36
|
+
# @return [void]
|
|
37
|
+
def run
|
|
38
|
+
algorithms = fetch_algorithms
|
|
39
|
+
output = CliOutputFormatter.format_algorithms_table(algorithms)
|
|
40
|
+
puts output
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def fetch_algorithms
|
|
46
|
+
AlgorithmRegistry.available.map do |name|
|
|
47
|
+
algorithm_class = AlgorithmRegistry.get(name)
|
|
48
|
+
algorithm_class.metadata
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../cli/output_formatter"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Commands
|
|
7
|
+
# Metadata command implementation
|
|
8
|
+
class MetadataCommand
|
|
9
|
+
attr_reader :options
|
|
10
|
+
|
|
11
|
+
def initialize(options = {})
|
|
12
|
+
@options = options
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Run the metadata command
|
|
16
|
+
# @param archive_path [String] Path to archive
|
|
17
|
+
# @param pattern [String, nil] Optional pattern to match entries
|
|
18
|
+
def run(archive_path, pattern = nil)
|
|
19
|
+
require_relative "../zip/file"
|
|
20
|
+
require_relative "../metadata"
|
|
21
|
+
|
|
22
|
+
unless File.exist?(archive_path)
|
|
23
|
+
raise Errno::ENOENT, "Archive not found: #{archive_path}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
Omnizip::Zip::File.open(archive_path) do |archive|
|
|
27
|
+
if options[:show]
|
|
28
|
+
show_metadata(archive, pattern)
|
|
29
|
+
else
|
|
30
|
+
edit_metadata(archive, pattern)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
puts "Metadata updated successfully" unless options[:show]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def show_metadata(archive, pattern)
|
|
40
|
+
if pattern
|
|
41
|
+
# Show entry metadata
|
|
42
|
+
entry = archive.get_entry(pattern)
|
|
43
|
+
unless entry
|
|
44
|
+
warn "Entry not found: #{pattern}"
|
|
45
|
+
return
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
show_entry_metadata(entry)
|
|
49
|
+
else
|
|
50
|
+
# Show archive metadata
|
|
51
|
+
show_archive_metadata(archive)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def show_archive_metadata(archive)
|
|
56
|
+
metadata = archive.metadata
|
|
57
|
+
puts "Archive: #{archive.name}"
|
|
58
|
+
puts "Comment: #{metadata.comment}" unless metadata.comment.empty?
|
|
59
|
+
puts "Created: #{metadata.created_at}" if metadata.created_at
|
|
60
|
+
puts "Modified: #{metadata.modified_at}" if metadata.modified_at
|
|
61
|
+
puts "Entries: #{metadata.entry_count} (#{metadata.file_count} files, #{metadata.directory_count} dirs)"
|
|
62
|
+
puts "Total size: #{format_size(metadata.total_size)}"
|
|
63
|
+
puts "Compressed: #{format_size(metadata.total_compressed_size)}"
|
|
64
|
+
puts "Ratio: #{(metadata.compression_ratio * 100).round(1)}%"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def show_entry_metadata(entry)
|
|
68
|
+
metadata = entry.metadata
|
|
69
|
+
puts "Entry: #{entry.name}"
|
|
70
|
+
puts "Comment: #{metadata.comment}" unless metadata.comment.empty?
|
|
71
|
+
puts "Modified: #{metadata.mtime}"
|
|
72
|
+
puts "Permissions: 0#{metadata.unix_permissions.to_s(8)}"
|
|
73
|
+
puts "Size: #{format_size(entry.size)}"
|
|
74
|
+
puts "Compressed: #{format_size(entry.compressed_size)}"
|
|
75
|
+
puts "CRC32: 0x#{entry.crc.to_s(16).upcase}"
|
|
76
|
+
puts "Type: #{entry.directory? ? 'Directory' : 'File'}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def edit_metadata(archive, pattern)
|
|
80
|
+
if pattern
|
|
81
|
+
edit_entry_metadata(archive, pattern)
|
|
82
|
+
else
|
|
83
|
+
edit_archive_metadata(archive)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
archive.save_metadata
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def edit_archive_metadata(archive)
|
|
90
|
+
metadata = archive.metadata
|
|
91
|
+
|
|
92
|
+
if options[:comment]
|
|
93
|
+
metadata.comment = options[:comment]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def edit_entry_metadata(archive, pattern)
|
|
98
|
+
entries = if pattern.include?("*") || pattern.include?("?")
|
|
99
|
+
# Glob pattern
|
|
100
|
+
archive.entries.select { |e| File.fnmatch(pattern, e.name) }
|
|
101
|
+
else
|
|
102
|
+
# Single entry
|
|
103
|
+
[archive.get_entry(pattern)].compact
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
if entries.empty?
|
|
107
|
+
warn "No entries match pattern: #{pattern}"
|
|
108
|
+
return
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
entries.each do |entry|
|
|
112
|
+
metadata = entry.metadata
|
|
113
|
+
|
|
114
|
+
metadata.comment = options[:comment] if options[:comment]
|
|
115
|
+
metadata.mtime = parse_time(options[:set_mtime]) if options[:set_mtime]
|
|
116
|
+
metadata.unix_permissions = parse_permissions(options[:chmod]) if options[:chmod]
|
|
117
|
+
metadata.attributes = options[:set_attribute].to_sym if options[:set_attribute]
|
|
118
|
+
|
|
119
|
+
entry.save_metadata
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
puts "Updated #{entries.size} #{entries.size == 1 ? 'entry' : 'entries'}" if options[:verbose]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def parse_time(time_str)
|
|
126
|
+
return Time.now if time_str == "now"
|
|
127
|
+
|
|
128
|
+
Time.parse(time_str)
|
|
129
|
+
rescue ArgumentError => e
|
|
130
|
+
raise ArgumentError, "Invalid time format: #{time_str} (#{e.message})"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def parse_permissions(perms_str)
|
|
134
|
+
# Handle octal (755) or decimal
|
|
135
|
+
if perms_str.start_with?("0")
|
|
136
|
+
perms_str.to_i(8)
|
|
137
|
+
else
|
|
138
|
+
perms_str.to_i
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def format_size(bytes)
|
|
143
|
+
return "0 B" if bytes.zero?
|
|
144
|
+
|
|
145
|
+
units = %w[B KB MB GB TB]
|
|
146
|
+
exp = (Math.log(bytes) / Math.log(1024)).to_i
|
|
147
|
+
exp = [exp, units.size - 1].min
|
|
148
|
+
|
|
149
|
+
"%.1f %s" % [bytes.to_f / (1024**exp), units[exp]]
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../parity"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Commands
|
|
7
|
+
# Command to create PAR2 parity files
|
|
8
|
+
class ParityCreateCommand
|
|
9
|
+
# @return [Array<String>] Files to protect
|
|
10
|
+
attr_reader :files
|
|
11
|
+
|
|
12
|
+
# @return [Hash] Command options
|
|
13
|
+
attr_reader :options
|
|
14
|
+
|
|
15
|
+
# Initialize command
|
|
16
|
+
#
|
|
17
|
+
# @param files [Array<String>] Files or patterns to protect
|
|
18
|
+
# @param options [Hash] Command options
|
|
19
|
+
def initialize(files, options = {})
|
|
20
|
+
@files = files
|
|
21
|
+
@options = default_options.merge(options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Execute command
|
|
25
|
+
#
|
|
26
|
+
# @return [Integer] Exit code (0 for success)
|
|
27
|
+
def run
|
|
28
|
+
validate_inputs!
|
|
29
|
+
|
|
30
|
+
progress = create_progress_callback if @options[:verbose]
|
|
31
|
+
|
|
32
|
+
created_files = []
|
|
33
|
+
@files.each do |file_pattern|
|
|
34
|
+
par2_files = Parity.create(
|
|
35
|
+
file_pattern,
|
|
36
|
+
redundancy: @options[:redundancy],
|
|
37
|
+
block_size: @options[:block_size],
|
|
38
|
+
output_dir: @options[:output_dir],
|
|
39
|
+
progress: progress,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
created_files.concat(par2_files)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
report_success(created_files)
|
|
46
|
+
0
|
|
47
|
+
rescue StandardError => e
|
|
48
|
+
report_error(e)
|
|
49
|
+
1
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
# Default command options
|
|
55
|
+
#
|
|
56
|
+
# @return [Hash] Default options
|
|
57
|
+
def default_options
|
|
58
|
+
{
|
|
59
|
+
redundancy: 5,
|
|
60
|
+
block_size: Parity::Par2Creator::DEFAULT_BLOCK_SIZE,
|
|
61
|
+
output_dir: nil,
|
|
62
|
+
verbose: false,
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Validate command inputs
|
|
67
|
+
#
|
|
68
|
+
# @raise [ArgumentError] if inputs invalid
|
|
69
|
+
def validate_inputs!
|
|
70
|
+
raise ArgumentError, "No files specified" if @files.empty?
|
|
71
|
+
|
|
72
|
+
unless @options[:redundancy].between?(0, 100)
|
|
73
|
+
raise ArgumentError, "Redundancy must be 0-100%"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Create progress callback
|
|
78
|
+
#
|
|
79
|
+
# @return [Proc] Progress callback
|
|
80
|
+
def create_progress_callback
|
|
81
|
+
->(percent, message) do
|
|
82
|
+
puts "[#{percent.to_s.rjust(3)}%] #{message}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Report successful creation
|
|
87
|
+
#
|
|
88
|
+
# @param files [Array<String>] Created files
|
|
89
|
+
def report_success(files)
|
|
90
|
+
puts "\n✓ Created #{files.size} PAR2 file(s):"
|
|
91
|
+
files.each do |file|
|
|
92
|
+
size = File.size(file)
|
|
93
|
+
puts " - #{File.basename(file)} (#{format_size(size)})"
|
|
94
|
+
end
|
|
95
|
+
puts "\nRedundancy: #{@options[:redundancy]}%"
|
|
96
|
+
puts "Block size: #{format_size(@options[:block_size])}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Report error
|
|
100
|
+
#
|
|
101
|
+
# @param error [Exception] Error that occurred
|
|
102
|
+
def report_error(error)
|
|
103
|
+
puts "\n✗ Failed to create PAR2 files:"
|
|
104
|
+
puts " #{error.message}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Format byte size for display
|
|
108
|
+
#
|
|
109
|
+
# @param bytes [Integer] Size in bytes
|
|
110
|
+
# @return [String] Formatted size
|
|
111
|
+
def format_size(bytes)
|
|
112
|
+
if bytes < 1024
|
|
113
|
+
"#{bytes} B"
|
|
114
|
+
elsif bytes < 1024 * 1024
|
|
115
|
+
"#{(bytes / 1024.0).round(1)} KB"
|
|
116
|
+
else
|
|
117
|
+
"#{(bytes / (1024.0 * 1024)).round(1)} MB"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../parity"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Commands
|
|
7
|
+
# Command to repair files using PAR2
|
|
8
|
+
class ParityRepairCommand
|
|
9
|
+
# @return [String] PAR2 file path
|
|
10
|
+
attr_reader :par2_file
|
|
11
|
+
|
|
12
|
+
# @return [Hash] Command options
|
|
13
|
+
attr_reader :options
|
|
14
|
+
|
|
15
|
+
# Initialize command
|
|
16
|
+
#
|
|
17
|
+
# @param par2_file [String] Path to .par2 index file
|
|
18
|
+
# @param options [Hash] Command options
|
|
19
|
+
def initialize(par2_file, options = {})
|
|
20
|
+
@par2_file = par2_file
|
|
21
|
+
@options = default_options.merge(options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Execute command
|
|
25
|
+
#
|
|
26
|
+
# @return [Integer] Exit code (0 for success)
|
|
27
|
+
def run
|
|
28
|
+
validate_inputs!
|
|
29
|
+
|
|
30
|
+
puts "Repairing files with PAR2: #{File.basename(@par2_file)}"
|
|
31
|
+
puts
|
|
32
|
+
|
|
33
|
+
progress = create_progress_callback if @options[:verbose]
|
|
34
|
+
|
|
35
|
+
result = Parity.repair(
|
|
36
|
+
@par2_file,
|
|
37
|
+
output_dir: @options[:output_dir],
|
|
38
|
+
progress: progress,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
display_results(result)
|
|
42
|
+
|
|
43
|
+
result.success? ? 0 : 1
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
report_error(e)
|
|
46
|
+
1
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
# Default command options
|
|
52
|
+
#
|
|
53
|
+
# @return [Hash] Default options
|
|
54
|
+
def default_options
|
|
55
|
+
{
|
|
56
|
+
output_dir: nil,
|
|
57
|
+
verbose: false,
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Validate command inputs
|
|
62
|
+
#
|
|
63
|
+
# @raise [ArgumentError] if inputs invalid
|
|
64
|
+
def validate_inputs!
|
|
65
|
+
unless File.exist?(@par2_file)
|
|
66
|
+
raise ArgumentError, "PAR2 file not found: #{@par2_file}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Create progress callback
|
|
71
|
+
#
|
|
72
|
+
# @return [Proc] Progress callback
|
|
73
|
+
def create_progress_callback
|
|
74
|
+
->(percent, message) do
|
|
75
|
+
puts "[#{percent.to_s.rjust(3)}%] #{message}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Display repair results
|
|
80
|
+
#
|
|
81
|
+
# @param result [Omnizip::Parity::Par2Repairer::RepairResult]
|
|
82
|
+
def display_results(result)
|
|
83
|
+
if result.success?
|
|
84
|
+
puts "✓ Repair successful"
|
|
85
|
+
puts
|
|
86
|
+
|
|
87
|
+
if result.recovered_files.any?
|
|
88
|
+
puts "Recovered files (#{result.recovered_files.size}):"
|
|
89
|
+
result.recovered_files.each do |file|
|
|
90
|
+
puts " - #{file}"
|
|
91
|
+
end
|
|
92
|
+
else
|
|
93
|
+
puts "No repairs needed - all files were intact"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
puts
|
|
97
|
+
puts "Recovered blocks: #{result.recovered_blocks}"
|
|
98
|
+
else
|
|
99
|
+
puts "✗ Repair failed"
|
|
100
|
+
puts
|
|
101
|
+
puts "Error: #{result.error_message}"
|
|
102
|
+
puts
|
|
103
|
+
|
|
104
|
+
if result.unrecoverable.any?
|
|
105
|
+
puts "Unrecoverable files (#{result.unrecoverable.size}):"
|
|
106
|
+
result.unrecoverable.each do |file|
|
|
107
|
+
puts " - #{file}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Report error
|
|
114
|
+
#
|
|
115
|
+
# @param error [Exception] Error that occurred
|
|
116
|
+
def report_error(error)
|
|
117
|
+
puts "\n✗ Repair failed:"
|
|
118
|
+
puts " #{error.message}"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../parity"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Commands
|
|
7
|
+
# Command to verify files using PAR2
|
|
8
|
+
class ParityVerifyCommand
|
|
9
|
+
# @return [String] PAR2 file path
|
|
10
|
+
attr_reader :par2_file
|
|
11
|
+
|
|
12
|
+
# @return [Hash] Command options
|
|
13
|
+
attr_reader :options
|
|
14
|
+
|
|
15
|
+
# Initialize command
|
|
16
|
+
#
|
|
17
|
+
# @param par2_file [String] Path to .par2 index file
|
|
18
|
+
# @param options [Hash] Command options
|
|
19
|
+
def initialize(par2_file, options = {})
|
|
20
|
+
@par2_file = par2_file
|
|
21
|
+
@options = default_options.merge(options)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Execute command
|
|
25
|
+
#
|
|
26
|
+
# @return [Integer] Exit code (0 if all OK, 1 if damage, 2 if error)
|
|
27
|
+
def run
|
|
28
|
+
validate_inputs!
|
|
29
|
+
|
|
30
|
+
puts "Verifying files with PAR2: #{File.basename(@par2_file)}"
|
|
31
|
+
puts
|
|
32
|
+
|
|
33
|
+
result = Parity.verify(@par2_file)
|
|
34
|
+
|
|
35
|
+
display_results(result)
|
|
36
|
+
|
|
37
|
+
# Exit code based on results
|
|
38
|
+
if result.all_ok?
|
|
39
|
+
0
|
|
40
|
+
elsif result.repairable?
|
|
41
|
+
1 # Damage but repairable
|
|
42
|
+
else
|
|
43
|
+
2 # Damage not repairable
|
|
44
|
+
end
|
|
45
|
+
rescue StandardError => e
|
|
46
|
+
report_error(e)
|
|
47
|
+
2
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Default command options
|
|
53
|
+
#
|
|
54
|
+
# @return [Hash] Default options
|
|
55
|
+
def default_options
|
|
56
|
+
{
|
|
57
|
+
verbose: false,
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Validate command inputs
|
|
62
|
+
#
|
|
63
|
+
# @raise [ArgumentError] if inputs invalid
|
|
64
|
+
def validate_inputs!
|
|
65
|
+
unless File.exist?(@par2_file)
|
|
66
|
+
raise ArgumentError, "PAR2 file not found: #{@par2_file}"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Display verification results
|
|
71
|
+
#
|
|
72
|
+
# @param result [Omnizip::Parity::Par2Verifier::VerificationResult]
|
|
73
|
+
def display_results(result)
|
|
74
|
+
if result.all_ok?
|
|
75
|
+
puts "✓ All files verified successfully"
|
|
76
|
+
puts
|
|
77
|
+
puts "Total blocks: #{result.total_blocks}"
|
|
78
|
+
puts "Recovery blocks available: #{result.recovery_blocks}"
|
|
79
|
+
else
|
|
80
|
+
puts "✗ File corruption detected"
|
|
81
|
+
puts
|
|
82
|
+
|
|
83
|
+
if result.damaged_files.any?
|
|
84
|
+
puts "Damaged files (#{result.damaged_files.size}):"
|
|
85
|
+
result.damaged_files.each do |file|
|
|
86
|
+
puts " - #{file}"
|
|
87
|
+
end
|
|
88
|
+
puts
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
if result.missing_files.any?
|
|
92
|
+
puts "Missing files (#{result.missing_files.size}):"
|
|
93
|
+
result.missing_files.each do |file|
|
|
94
|
+
puts " - #{file}"
|
|
95
|
+
end
|
|
96
|
+
puts
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
puts "Damaged blocks: #{result.damaged_blocks.size}"
|
|
100
|
+
puts "Total blocks: #{result.total_blocks}"
|
|
101
|
+
puts "Recovery blocks available: #{result.recovery_blocks}"
|
|
102
|
+
puts
|
|
103
|
+
|
|
104
|
+
if result.repairable?
|
|
105
|
+
puts "✓ Damage is repairable"
|
|
106
|
+
puts " Run repair command to fix files:"
|
|
107
|
+
puts " omnizip parity repair #{@par2_file}"
|
|
108
|
+
else
|
|
109
|
+
puts "✗ Damage exceeds recovery capacity"
|
|
110
|
+
puts " Cannot repair: insufficient recovery blocks"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Report error
|
|
116
|
+
#
|
|
117
|
+
# @param error [Exception] Error that occurred
|
|
118
|
+
def report_error(error)
|
|
119
|
+
puts "\n✗ Verification failed:"
|
|
120
|
+
puts " #{error.message}"
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../cli/output_formatter"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Commands
|
|
7
|
+
# Command to list available compression profiles
|
|
8
|
+
class ProfileListCommand
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
profiles = Omnizip::Profile.registry.all.sort_by(&:name)
|
|
15
|
+
|
|
16
|
+
if @options[:verbose]
|
|
17
|
+
list_detailed(profiles)
|
|
18
|
+
else
|
|
19
|
+
list_simple(profiles)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def list_simple(profiles)
|
|
26
|
+
puts "Available compression profiles:"
|
|
27
|
+
puts ""
|
|
28
|
+
|
|
29
|
+
profiles.each do |profile|
|
|
30
|
+
default_marker = profile.name == :balanced ? " [default]" : ""
|
|
31
|
+
puts format(
|
|
32
|
+
" %-12s - %s%s",
|
|
33
|
+
profile.name,
|
|
34
|
+
profile.description,
|
|
35
|
+
default_marker,
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def list_detailed(profiles)
|
|
41
|
+
puts "Available compression profiles:"
|
|
42
|
+
puts ""
|
|
43
|
+
|
|
44
|
+
profiles.each do |profile|
|
|
45
|
+
puts "Profile: #{profile.name}"
|
|
46
|
+
puts " Algorithm: #{profile.algorithm}"
|
|
47
|
+
puts " Level: #{profile.level}"
|
|
48
|
+
puts " Filter: #{profile.filter || 'none'}"
|
|
49
|
+
puts " Solid: #{profile.solid}"
|
|
50
|
+
puts " Description: #{profile.description}"
|
|
51
|
+
puts ""
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../cli/output_formatter"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Commands
|
|
7
|
+
# Command to show details of a specific compression profile
|
|
8
|
+
class ProfileShowCommand
|
|
9
|
+
def initialize(options = {})
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run(profile_name)
|
|
14
|
+
profile_sym = profile_name.to_sym
|
|
15
|
+
profile = Omnizip::Profile.get(profile_sym)
|
|
16
|
+
|
|
17
|
+
unless profile
|
|
18
|
+
warn "Profile '#{profile_name}' not found"
|
|
19
|
+
warn ""
|
|
20
|
+
warn "Available profiles:"
|
|
21
|
+
Omnizip::Profile.list.each { |name| warn " - #{name}" }
|
|
22
|
+
exit 1
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
display_profile(profile)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def display_profile(profile)
|
|
31
|
+
puts "Profile: #{profile.name}"
|
|
32
|
+
puts "Algorithm: #{profile.algorithm}"
|
|
33
|
+
puts "Level: #{profile.level}"
|
|
34
|
+
puts "Filter: #{profile.filter || 'none'}"
|
|
35
|
+
puts "Solid: #{profile.solid}"
|
|
36
|
+
puts "Description: #{profile.description}"
|
|
37
|
+
|
|
38
|
+
return unless profile.respond_to?(:base_profile) && profile.base_profile
|
|
39
|
+
|
|
40
|
+
puts "Based on: #{profile.base_profile.name}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|