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,292 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Rar
|
|
6
|
+
# RAR parity operations handler
|
|
7
|
+
# Reads parity data and performs recovery calculations
|
|
8
|
+
class ParityHandler
|
|
9
|
+
attr_reader :recovery_record, :parity_blocks
|
|
10
|
+
|
|
11
|
+
# Initialize parity handler
|
|
12
|
+
#
|
|
13
|
+
# @param recovery_record [RecoveryRecord] Recovery record instance
|
|
14
|
+
def initialize(recovery_record)
|
|
15
|
+
@recovery_record = recovery_record
|
|
16
|
+
@parity_blocks = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Load parity data from .rev files
|
|
20
|
+
#
|
|
21
|
+
# @param rev_files [Array<String>] Paths to .rev files
|
|
22
|
+
# @return [Boolean] true if loaded successfully
|
|
23
|
+
def load_parity_data(rev_files)
|
|
24
|
+
@parity_blocks = []
|
|
25
|
+
|
|
26
|
+
rev_files.each do |rev_file|
|
|
27
|
+
blocks = parse_rev_file(rev_file)
|
|
28
|
+
@parity_blocks.concat(blocks) if blocks
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
@parity_blocks.any?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Verify archive blocks using parity
|
|
35
|
+
#
|
|
36
|
+
# @param archive_path [String] Path to archive
|
|
37
|
+
# @param block_indices [Array<Integer>] Blocks to verify
|
|
38
|
+
# @return [Hash] Verification results
|
|
39
|
+
def verify_blocks(archive_path, block_indices = nil)
|
|
40
|
+
if @parity_blocks.empty?
|
|
41
|
+
return { verified: false,
|
|
42
|
+
error: "No parity data" }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
blocks_to_check = block_indices || (0...total_blocks).to_a
|
|
46
|
+
corrupted_blocks = []
|
|
47
|
+
|
|
48
|
+
blocks_to_check.each do |index|
|
|
49
|
+
corrupted_blocks << index unless verify_block(archive_path, index)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
verified: corrupted_blocks.empty?,
|
|
54
|
+
total: blocks_to_check.size,
|
|
55
|
+
ok: blocks_to_check.size - corrupted_blocks.size,
|
|
56
|
+
corrupted: corrupted_blocks,
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Calculate parity for a block
|
|
61
|
+
#
|
|
62
|
+
# @param data [String] Binary data
|
|
63
|
+
# @param block_index [Integer] Block index
|
|
64
|
+
# @return [String] Parity data
|
|
65
|
+
def calculate_parity(data, block_index)
|
|
66
|
+
# Basic XOR parity for simple recovery
|
|
67
|
+
# In production, would use Reed-Solomon
|
|
68
|
+
parity = data.bytes.reduce(0) { |acc, byte| acc ^ byte }
|
|
69
|
+
[parity, block_index].pack("CN")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Recover corrupted block
|
|
73
|
+
#
|
|
74
|
+
# @param archive_path [String] Path to archive
|
|
75
|
+
# @param block_index [Integer] Block to recover
|
|
76
|
+
# @return [String, nil] Recovered data or nil
|
|
77
|
+
def recover_block(archive_path, block_index)
|
|
78
|
+
return nil unless can_recover?(block_index)
|
|
79
|
+
|
|
80
|
+
if @recovery_record.version == 5
|
|
81
|
+
recover_rar5_block(archive_path, block_index)
|
|
82
|
+
else
|
|
83
|
+
recover_rar4_block(archive_path, block_index)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Check if block can be recovered
|
|
88
|
+
#
|
|
89
|
+
# @param block_index [Integer] Block index
|
|
90
|
+
# @return [Boolean] true if recoverable
|
|
91
|
+
def can_recover?(block_index)
|
|
92
|
+
return false if @parity_blocks.empty?
|
|
93
|
+
|
|
94
|
+
# Can recover if we have parity data for this block
|
|
95
|
+
@parity_blocks.any? { |p| p[:index] == block_index }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Get total number of blocks
|
|
99
|
+
#
|
|
100
|
+
# @return [Integer] Total blocks
|
|
101
|
+
def total_blocks
|
|
102
|
+
return 0 if @recovery_record.block_size.zero?
|
|
103
|
+
|
|
104
|
+
(@recovery_record.protected_size / @recovery_record.block_size.to_f).ceil
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Get parity block by index
|
|
108
|
+
#
|
|
109
|
+
# @param index [Integer] Block index
|
|
110
|
+
# @return [Hash, nil] Parity block data
|
|
111
|
+
def parity_block(index)
|
|
112
|
+
@parity_blocks.find { |p| p[:index] == index }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
# Parse .rev file
|
|
118
|
+
#
|
|
119
|
+
# @param rev_file [String] Path to .rev file
|
|
120
|
+
# @return [Array<Hash>, nil] Parity blocks
|
|
121
|
+
def parse_rev_file(rev_file)
|
|
122
|
+
return nil unless File.exist?(rev_file)
|
|
123
|
+
|
|
124
|
+
blocks = []
|
|
125
|
+
|
|
126
|
+
File.open(rev_file, "rb") do |io|
|
|
127
|
+
# Check RAR signature in .rev file
|
|
128
|
+
signature = io.read(7)
|
|
129
|
+
return nil unless valid_rev_signature?(signature)
|
|
130
|
+
|
|
131
|
+
# Parse recovery blocks
|
|
132
|
+
until io.eof?
|
|
133
|
+
block = parse_parity_block(io)
|
|
134
|
+
break unless block
|
|
135
|
+
|
|
136
|
+
blocks << block
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
blocks
|
|
141
|
+
rescue StandardError
|
|
142
|
+
nil
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Check if valid .rev file signature
|
|
146
|
+
#
|
|
147
|
+
# @param signature [String] File signature
|
|
148
|
+
# @return [Boolean] true if valid
|
|
149
|
+
def valid_rev_signature?(signature)
|
|
150
|
+
return false unless signature
|
|
151
|
+
|
|
152
|
+
bytes = signature.bytes
|
|
153
|
+
bytes[0..3] == [0x52, 0x61, 0x72, 0x21] # "Rar!"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Parse parity block from .rev file
|
|
157
|
+
#
|
|
158
|
+
# @param io [IO] Input stream
|
|
159
|
+
# @return [Hash, nil] Parity block data
|
|
160
|
+
def parse_parity_block(io)
|
|
161
|
+
# Read block header
|
|
162
|
+
block_size = io.read(4)&.unpack1("V")
|
|
163
|
+
return nil unless block_size
|
|
164
|
+
|
|
165
|
+
block_index = io.read(4)&.unpack1("V")
|
|
166
|
+
checksum = io.read(4)&.unpack1("V")
|
|
167
|
+
|
|
168
|
+
# Read parity data
|
|
169
|
+
parity_data = io.read(block_size - 12)
|
|
170
|
+
return nil unless parity_data
|
|
171
|
+
|
|
172
|
+
{
|
|
173
|
+
index: block_index,
|
|
174
|
+
size: block_size,
|
|
175
|
+
checksum: checksum,
|
|
176
|
+
data: parity_data,
|
|
177
|
+
}
|
|
178
|
+
rescue StandardError
|
|
179
|
+
nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Verify single block
|
|
183
|
+
#
|
|
184
|
+
# @param archive_path [String] Path to archive
|
|
185
|
+
# @param block_index [Integer] Block index
|
|
186
|
+
# @return [Boolean] true if block is valid
|
|
187
|
+
def verify_block(archive_path, block_index)
|
|
188
|
+
parity = parity_block(block_index)
|
|
189
|
+
return true unless parity # No parity, assume OK
|
|
190
|
+
|
|
191
|
+
# Read block from archive
|
|
192
|
+
block_data = read_archive_block(archive_path, block_index)
|
|
193
|
+
return false unless block_data
|
|
194
|
+
|
|
195
|
+
# Calculate checksum
|
|
196
|
+
calculated = calculate_block_checksum(block_data)
|
|
197
|
+
calculated == parity[:checksum]
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Read block from archive
|
|
201
|
+
#
|
|
202
|
+
# @param archive_path [String] Path to archive
|
|
203
|
+
# @param block_index [Integer] Block index
|
|
204
|
+
# @return [String, nil] Block data
|
|
205
|
+
def read_archive_block(archive_path, block_index)
|
|
206
|
+
return nil unless File.exist?(archive_path)
|
|
207
|
+
|
|
208
|
+
block_size = @recovery_record.block_size
|
|
209
|
+
offset = block_index * block_size
|
|
210
|
+
|
|
211
|
+
File.open(archive_path, "rb") do |io|
|
|
212
|
+
io.seek(offset)
|
|
213
|
+
io.read(block_size)
|
|
214
|
+
end
|
|
215
|
+
rescue StandardError
|
|
216
|
+
nil
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Calculate block checksum
|
|
220
|
+
#
|
|
221
|
+
# @param data [String] Block data
|
|
222
|
+
# @return [Integer] CRC32 checksum
|
|
223
|
+
def calculate_block_checksum(data)
|
|
224
|
+
Zlib.crc32(data)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Recover RAR5 block using Reed-Solomon
|
|
228
|
+
#
|
|
229
|
+
# @param archive_path [String] Path to archive
|
|
230
|
+
# @param block_index [Integer] Block index
|
|
231
|
+
# @return [String, nil] Recovered data
|
|
232
|
+
def recover_rar5_block(archive_path, block_index)
|
|
233
|
+
parity = parity_block(block_index)
|
|
234
|
+
return nil unless parity
|
|
235
|
+
|
|
236
|
+
# Read corrupted block
|
|
237
|
+
block_data = read_archive_block(archive_path, block_index)
|
|
238
|
+
return nil unless block_data
|
|
239
|
+
|
|
240
|
+
# Use Reed-Solomon decoding
|
|
241
|
+
# This is a placeholder - real implementation would use
|
|
242
|
+
# reed-solomon gem or similar
|
|
243
|
+
recover_with_reed_solomon(block_data, parity[:data])
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Recover RAR4 block using old recovery method
|
|
247
|
+
#
|
|
248
|
+
# @param archive_path [String] Path to archive
|
|
249
|
+
# @param block_index [Integer] Block index
|
|
250
|
+
# @return [String, nil] Recovered data
|
|
251
|
+
def recover_rar4_block(archive_path, block_index)
|
|
252
|
+
parity = parity_block(block_index)
|
|
253
|
+
return nil unless parity
|
|
254
|
+
|
|
255
|
+
# Read corrupted block
|
|
256
|
+
block_data = read_archive_block(archive_path, block_index)
|
|
257
|
+
return nil unless block_data
|
|
258
|
+
|
|
259
|
+
# Simple XOR recovery for RAR4
|
|
260
|
+
recover_with_xor(block_data, parity[:data])
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Recover data using Reed-Solomon (RAR5)
|
|
264
|
+
#
|
|
265
|
+
# @param corrupted_data [String] Corrupted block
|
|
266
|
+
# @param parity_data [String] Parity information
|
|
267
|
+
# @return [String, nil] Recovered data
|
|
268
|
+
def recover_with_reed_solomon(_corrupted_data, _parity_data)
|
|
269
|
+
# Placeholder for Reed-Solomon recovery
|
|
270
|
+
# Real implementation would use reed-solomon gem
|
|
271
|
+
# For now, return nil to indicate recovery not available
|
|
272
|
+
nil
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Recover data using XOR (RAR4)
|
|
276
|
+
#
|
|
277
|
+
# @param corrupted_data [String] Corrupted block
|
|
278
|
+
# @param parity_data [String] Parity information
|
|
279
|
+
# @return [String] Recovered data
|
|
280
|
+
def recover_with_xor(corrupted_data, parity_data)
|
|
281
|
+
# Simple XOR recovery
|
|
282
|
+
result = corrupted_data.bytes.map.with_index do |byte, i|
|
|
283
|
+
parity_byte = parity_data.bytes[i % parity_data.size]
|
|
284
|
+
byte ^ parity_byte
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
result.pack("C*")
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
require_relative "../../../../algorithms/lzma"
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Formats
|
|
8
|
+
module Rar
|
|
9
|
+
module Rar5
|
|
10
|
+
module Compression
|
|
11
|
+
# LZMA compression method for RAR5
|
|
12
|
+
#
|
|
13
|
+
# This adapter uses the existing LZMA implementation with
|
|
14
|
+
# RAR5-specific parameters and encoding.
|
|
15
|
+
#
|
|
16
|
+
# RAR5 compression methods (from spec):
|
|
17
|
+
# - 0: STORE (no compression)
|
|
18
|
+
# - 1: FASTEST
|
|
19
|
+
# - 2: FAST
|
|
20
|
+
# - 3: NORMAL
|
|
21
|
+
# - 4: GOOD
|
|
22
|
+
# - 5: BEST
|
|
23
|
+
#
|
|
24
|
+
# For methods 1-5, RAR5 uses LZMA compression with different
|
|
25
|
+
# dictionary sizes and compression levels.
|
|
26
|
+
#
|
|
27
|
+
# @example Compress data with LZMA
|
|
28
|
+
# compressed = Lzma.compress("Hello, World!", level: 5)
|
|
29
|
+
class Lzma
|
|
30
|
+
# Compression method identifier for RAR5
|
|
31
|
+
# Methods 1-5 all use LZMA with different parameters
|
|
32
|
+
METHOD_FASTEST = 1
|
|
33
|
+
METHOD_FAST = 2
|
|
34
|
+
METHOD_NORMAL = 3
|
|
35
|
+
METHOD_GOOD = 4
|
|
36
|
+
METHOD_BEST = 5
|
|
37
|
+
|
|
38
|
+
# Compress data using LZMA
|
|
39
|
+
#
|
|
40
|
+
# @param data [String] Data to compress
|
|
41
|
+
# @param options [Hash] Compression options
|
|
42
|
+
# @option options [Integer] :level Compression level (1-5, default: 3)
|
|
43
|
+
# @return [Hash] Hash with :data (compressed) and :properties (9 bytes for extra area)
|
|
44
|
+
def self.compress(data, options = {})
|
|
45
|
+
level = options[:level] || METHOD_NORMAL
|
|
46
|
+
|
|
47
|
+
# Create StringIO streams for LZMA
|
|
48
|
+
input = StringIO.new(data)
|
|
49
|
+
output = StringIO.new
|
|
50
|
+
output.set_encoding(Encoding::BINARY)
|
|
51
|
+
|
|
52
|
+
# Create LZMA encoder with RAR5-appropriate settings
|
|
53
|
+
lzma = Algorithms::LZMA.new
|
|
54
|
+
lzma_options = build_lzma_options(level)
|
|
55
|
+
|
|
56
|
+
# Build encoder options hash that LZMA encoder will accept
|
|
57
|
+
encoder_options = {
|
|
58
|
+
dict_size: lzma_options.dict_size,
|
|
59
|
+
lc: lzma_options.lc,
|
|
60
|
+
lp: lzma_options.lp,
|
|
61
|
+
pb: lzma_options.pb,
|
|
62
|
+
level: level,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
# Compress using LZMA with RAR5 parameters
|
|
66
|
+
lzma.compress(input, output, encoder_options)
|
|
67
|
+
|
|
68
|
+
# The LZMA encoder outputs:
|
|
69
|
+
# - 1 byte: properties (lc, lp, pb)
|
|
70
|
+
# - 4 bytes: dictionary size (little-endian)
|
|
71
|
+
# - 8 bytes: uncompressed size (little-endian)
|
|
72
|
+
# - remaining: compressed data
|
|
73
|
+
#
|
|
74
|
+
# RAR5 stores properties in file header extra area (type 0x03),
|
|
75
|
+
# so we extract them separately
|
|
76
|
+
compressed_with_header = output.string
|
|
77
|
+
|
|
78
|
+
if compressed_with_header.bytesize > 13
|
|
79
|
+
# Extract LZMA properties for RAR5 extra area
|
|
80
|
+
# RAR5 stores: property byte (1) + dict size (4) = 5 bytes
|
|
81
|
+
# NOT the uncompressed size (which is in the next 8 bytes of LZMA header)
|
|
82
|
+
properties = compressed_with_header[0, 5]
|
|
83
|
+
|
|
84
|
+
# Extract raw LZMA stream (skip 13-byte header)
|
|
85
|
+
compressed_data = compressed_with_header[13..]
|
|
86
|
+
|
|
87
|
+
{
|
|
88
|
+
data: compressed_data,
|
|
89
|
+
properties: properties,
|
|
90
|
+
}
|
|
91
|
+
else
|
|
92
|
+
# Edge case: if compression produced less than 13 bytes (extremely rare),
|
|
93
|
+
# return original data uncompressed with nil properties
|
|
94
|
+
warn "LZMA output too small (#{compressed_with_header.bytesize} bytes), using STORE"
|
|
95
|
+
{
|
|
96
|
+
data: data,
|
|
97
|
+
properties: nil,
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Decompress LZMA-compressed data
|
|
103
|
+
#
|
|
104
|
+
# @param data [String] Compressed data (raw LZMA stream without header)
|
|
105
|
+
# @param options [Hash] Decompression options
|
|
106
|
+
# @option options [String] :properties The 5-byte properties from compress (property byte + dict size)
|
|
107
|
+
# @option options [Integer] :uncompressed_size Expected uncompressed size (optional, for EOS marker mode)
|
|
108
|
+
# @return [String] Decompressed data
|
|
109
|
+
def self.decompress(data, options = {})
|
|
110
|
+
properties = options[:properties]
|
|
111
|
+
uncompressed_size = options[:uncompressed_size]
|
|
112
|
+
|
|
113
|
+
# Reconstruct the 13-byte LZMA header if properties are provided
|
|
114
|
+
if properties && properties.bytesize >= 5
|
|
115
|
+
# properties contains: 1 byte props + 4 bytes dict size
|
|
116
|
+
# We need to add 8 bytes for uncompressed size
|
|
117
|
+
header = properties.dup
|
|
118
|
+
header += if uncompressed_size
|
|
119
|
+
# Add uncompressed size as 8-byte little-endian
|
|
120
|
+
[uncompressed_size].pack("Q<")
|
|
121
|
+
else
|
|
122
|
+
# Use -1 (0xFFFFFFFFFFFFFFFF) to indicate EOS marker mode
|
|
123
|
+
[0xFFFFFFFFFFFFFFFF].pack("Q<")
|
|
124
|
+
end
|
|
125
|
+
full_data = header + data
|
|
126
|
+
else
|
|
127
|
+
# Assume data already has header (backward compatibility)
|
|
128
|
+
full_data = data
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
input = StringIO.new(full_data)
|
|
132
|
+
output = StringIO.new
|
|
133
|
+
output.set_encoding(Encoding::BINARY)
|
|
134
|
+
|
|
135
|
+
# Use SDK decoder since RAR5 LZMA was compressed with SDK encoder
|
|
136
|
+
require_relative "../../../../implementations/seven_zip/lzma/decoder"
|
|
137
|
+
decoder = Implementations::SevenZip::LZMA::Decoder.new(input)
|
|
138
|
+
decoder.decode_stream(output)
|
|
139
|
+
|
|
140
|
+
output.string
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Get compression method identifier for level
|
|
144
|
+
#
|
|
145
|
+
# @param level [Integer] Compression level (1-5)
|
|
146
|
+
# @return [Integer] Method ID
|
|
147
|
+
def self.method_id(level = METHOD_NORMAL)
|
|
148
|
+
level.clamp(METHOD_FASTEST, METHOD_BEST)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Get compression info VINT value
|
|
152
|
+
#
|
|
153
|
+
# For RAR5, compression_info encodes:
|
|
154
|
+
# - Bits 0-5: compression method (1-5 for LZMA)
|
|
155
|
+
# - Bits 6+: version (0 for now)
|
|
156
|
+
#
|
|
157
|
+
# @param level [Integer] Compression level (1-5)
|
|
158
|
+
# @return [Integer] Compression info value
|
|
159
|
+
def self.compression_info(level = METHOD_NORMAL)
|
|
160
|
+
method = method_id(level)
|
|
161
|
+
method & 0x3F # Bits 0-5 only
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Build LZMA options based on RAR5 compression level
|
|
165
|
+
#
|
|
166
|
+
# @param level [Integer] RAR5 compression level (1-5)
|
|
167
|
+
# @return [LzmaOptions] LZMA encoder options object
|
|
168
|
+
def self.build_lzma_options(level)
|
|
169
|
+
# RAR5 compression levels map to LZMA parameters
|
|
170
|
+
# These are approximations based on typical RAR behavior
|
|
171
|
+
dict_size = 1 << case level
|
|
172
|
+
when 1 then 18 # 256 KB (fastest)
|
|
173
|
+
when 2 then 20 # 1 MB (fast)
|
|
174
|
+
when 3 then 22 # 4 MB (normal)
|
|
175
|
+
when 4 then 23 # 8 MB (good)
|
|
176
|
+
when 5 then 24 # 16 MB (best)
|
|
177
|
+
else 22 # default: 4 MB
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# RAR5 uses specific LZMA parameters: lc=1, lp=2, pb=0
|
|
181
|
+
# (Different from standalone LZMA which typically uses lc=3, lp=0, pb=2)
|
|
182
|
+
LzmaOptions.new(level, dict_size, lc: 1, lp: 2, pb: 0)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Simple options class for LZMA parameters
|
|
186
|
+
class LzmaOptions
|
|
187
|
+
attr_reader :level, :dict_size, :lc, :lp, :pb
|
|
188
|
+
|
|
189
|
+
def initialize(level, dict_size, lc: 3, lp: 0, pb: 2)
|
|
190
|
+
@level = level
|
|
191
|
+
@dict_size = dict_size
|
|
192
|
+
@lc = lc
|
|
193
|
+
@lp = lp
|
|
194
|
+
@pb = pb
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|