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,578 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Formats
|
|
7
|
+
module Rar
|
|
8
|
+
module Rar5
|
|
9
|
+
module Compression
|
|
10
|
+
# RAR5 LZSS compression method
|
|
11
|
+
#
|
|
12
|
+
# RAR5 compression methods 1-5 use a proprietary LZSS-based algorithm
|
|
13
|
+
# with Huffman coding. This is the algorithm used by official RAR tools.
|
|
14
|
+
#
|
|
15
|
+
# Based on libarchive/archive_read_support_format_rar5.c
|
|
16
|
+
#
|
|
17
|
+
class Lzss
|
|
18
|
+
# Compression method identifiers
|
|
19
|
+
METHOD_STORE = 0
|
|
20
|
+
METHOD_FASTEST = 1
|
|
21
|
+
METHOD_FAST = 2
|
|
22
|
+
METHOD_NORMAL = 3
|
|
23
|
+
METHOD_GOOD = 4
|
|
24
|
+
METHOD_BEST = 5
|
|
25
|
+
|
|
26
|
+
# Huffman code constants (from libarchive)
|
|
27
|
+
HUFF_BC = 20 # Number of bit length codes
|
|
28
|
+
HUFF_NC = 306 # Number of literal/length codes
|
|
29
|
+
HUFF_DC = 64 # Number of distance codes
|
|
30
|
+
HUFF_LDC = 16 # Number of low distance codes
|
|
31
|
+
HUFF_RC = 44 # Number of repeat codes
|
|
32
|
+
HUFF_TABLE_SIZE = HUFF_NC + HUFF_DC + HUFF_LDC + HUFF_RC
|
|
33
|
+
|
|
34
|
+
# Distance cache size
|
|
35
|
+
DIST_CACHE_SIZE = 4
|
|
36
|
+
|
|
37
|
+
# Minimum match length
|
|
38
|
+
MIN_MATCH = 3
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
# Check if LZSS compression is available for official RAR compatibility
|
|
42
|
+
#
|
|
43
|
+
# @return [Boolean] true if implemented
|
|
44
|
+
def available?
|
|
45
|
+
# Full LZSS decoder is now implemented
|
|
46
|
+
# Encoder is not yet compatible with official RAR tools
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Compress data using RAR5 LZSS
|
|
51
|
+
#
|
|
52
|
+
# @param data [String] Data to compress
|
|
53
|
+
# @param options [Hash] Compression options
|
|
54
|
+
# @option options [Integer] :level Compression level (1-5)
|
|
55
|
+
# @option options [Integer] :dict_size Dictionary size
|
|
56
|
+
# @return [Hash] Hash with :data, :properties, and :method
|
|
57
|
+
def compress(data, options = {})
|
|
58
|
+
level = options[:level] || METHOD_NORMAL
|
|
59
|
+
options[:dict_size] || dictionary_size_for_level(level)
|
|
60
|
+
|
|
61
|
+
# For now, use STORE method until encoder is compatible
|
|
62
|
+
# with official RAR tools
|
|
63
|
+
{
|
|
64
|
+
data: data,
|
|
65
|
+
properties: nil,
|
|
66
|
+
method: METHOD_STORE,
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Decompress RAR5 LZSS data
|
|
71
|
+
#
|
|
72
|
+
# @param data [String] Compressed data
|
|
73
|
+
# @param options [Hash] Decompression options
|
|
74
|
+
# @option options [Integer] :uncompressed_size Expected size
|
|
75
|
+
# @option options [Integer] :window_size Dictionary size
|
|
76
|
+
# @return [String] Decompressed data
|
|
77
|
+
def decompress(data, options = {})
|
|
78
|
+
uncompressed_size = options[:uncompressed_size]
|
|
79
|
+
window_size = options[:window_size] || (1 << 20) # Default 1MB
|
|
80
|
+
|
|
81
|
+
decoder = Decoder.new(data, window_size)
|
|
82
|
+
decoder.decode(uncompressed_size)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Get compression method identifier
|
|
86
|
+
#
|
|
87
|
+
# @param level [Integer] Compression level (1-5)
|
|
88
|
+
# @return [Integer] Method ID
|
|
89
|
+
def method_id(level = METHOD_NORMAL)
|
|
90
|
+
level.clamp(METHOD_FASTEST, METHOD_BEST)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Get compression info VINT value
|
|
94
|
+
#
|
|
95
|
+
# @param level [Integer] Compression level (1-5)
|
|
96
|
+
# @return [Integer] Compression info value
|
|
97
|
+
def compression_info(level = METHOD_NORMAL)
|
|
98
|
+
method = method_id(level)
|
|
99
|
+
method & 0x3F
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# Get dictionary size for compression level
|
|
105
|
+
def dictionary_size_for_level(level)
|
|
106
|
+
1 << case level
|
|
107
|
+
when 1 then 18 # 256 KB
|
|
108
|
+
when 2 then 20 # 1 MB
|
|
109
|
+
when 3 then 22 # 4 MB
|
|
110
|
+
when 4 then 23 # 8 MB
|
|
111
|
+
when 5 then 24 # 16 MB
|
|
112
|
+
else 22 # 4 MB default
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Bit reader for reading individual bits from compressed data
|
|
118
|
+
#
|
|
119
|
+
class BitReader
|
|
120
|
+
def initialize(data)
|
|
121
|
+
@data = data
|
|
122
|
+
@byte_pos = 0
|
|
123
|
+
@bit_pos = 0
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Read up to 16 bits
|
|
127
|
+
def read_bits(num_bits)
|
|
128
|
+
return 0 if num_bits.zero?
|
|
129
|
+
|
|
130
|
+
result = 0
|
|
131
|
+
bits_read = 0
|
|
132
|
+
|
|
133
|
+
while bits_read < num_bits
|
|
134
|
+
return nil if @byte_pos >= @data.bytesize
|
|
135
|
+
|
|
136
|
+
byte = @data.getbyte(@byte_pos)
|
|
137
|
+
bits_available = 8 - @bit_pos
|
|
138
|
+
bits_needed = num_bits - bits_read
|
|
139
|
+
bits_to_read = [bits_available, bits_needed].min
|
|
140
|
+
|
|
141
|
+
mask = ((1 << bits_to_read) - 1) << @bit_pos
|
|
142
|
+
bits = (byte & mask) >> @bit_pos
|
|
143
|
+
|
|
144
|
+
result |= bits << bits_read
|
|
145
|
+
bits_read += bits_to_read
|
|
146
|
+
@bit_pos += bits_to_read
|
|
147
|
+
|
|
148
|
+
if @bit_pos >= 8
|
|
149
|
+
@bit_pos = 0
|
|
150
|
+
@byte_pos += 1
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
result
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Skip specified number of bits
|
|
158
|
+
def skip_bits(num_bits)
|
|
159
|
+
@bit_pos += num_bits
|
|
160
|
+
while @bit_pos >= 8
|
|
161
|
+
@bit_pos -= 8
|
|
162
|
+
@byte_pos += 1
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Read 32 bits
|
|
167
|
+
def read_bits_32(num_bits)
|
|
168
|
+
return 0 if num_bits.zero?
|
|
169
|
+
|
|
170
|
+
result = 0
|
|
171
|
+
bits_read = 0
|
|
172
|
+
|
|
173
|
+
while bits_read < num_bits && @byte_pos < @data.bytesize
|
|
174
|
+
byte = @data.getbyte(@byte_pos)
|
|
175
|
+
bits_available = 8 - @bit_pos
|
|
176
|
+
bits_needed = num_bits - bits_read
|
|
177
|
+
bits_to_read = [bits_available, bits_needed].min
|
|
178
|
+
|
|
179
|
+
mask = ((1 << bits_to_read) - 1) << @bit_pos
|
|
180
|
+
bits = (byte & mask) >> @bit_pos
|
|
181
|
+
|
|
182
|
+
result |= bits << bits_read
|
|
183
|
+
bits_read += bits_to_read
|
|
184
|
+
@bit_pos += bits_to_read
|
|
185
|
+
|
|
186
|
+
if @bit_pos >= 8
|
|
187
|
+
@bit_pos = 0
|
|
188
|
+
@byte_pos += 1
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
result
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def end_of_data?(block_size)
|
|
196
|
+
@byte_pos >= block_size || (@byte_pos == block_size - 1 && @bit_pos >= 8)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
attr_accessor :byte_pos, :bit_pos
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Huffman decode table
|
|
203
|
+
#
|
|
204
|
+
class HuffmanTable
|
|
205
|
+
attr_reader :size, :decode_len, :decode_pos, :decode_num
|
|
206
|
+
|
|
207
|
+
def initialize(size)
|
|
208
|
+
@size = size
|
|
209
|
+
@decode_len = Array.new(16, 0)
|
|
210
|
+
@decode_pos = Array.new(16, 0)
|
|
211
|
+
@decode_num = Array.new(size, 0)
|
|
212
|
+
@quick_bits = 0
|
|
213
|
+
@quick_len = Array.new(65536, 0)
|
|
214
|
+
@quick_num = Array.new(65536, 0)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Build decode tables from bit lengths
|
|
218
|
+
# Based on libarchive's create_decode_tables()
|
|
219
|
+
def build(bit_lengths)
|
|
220
|
+
# Count codes for each bit length
|
|
221
|
+
len_count = Array.new(16, 0)
|
|
222
|
+
bit_lengths.each do |len|
|
|
223
|
+
len_count[len] += 1 if len.positive? && len < 16
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Calculate decode_len and decode_pos
|
|
227
|
+
@decode_pos[0] = 0
|
|
228
|
+
@decode_len[0] = 0
|
|
229
|
+
|
|
230
|
+
upper_limit = 0
|
|
231
|
+
(1..15).each do |i|
|
|
232
|
+
upper_limit = (upper_limit + len_count[i]) << 1
|
|
233
|
+
@decode_len[i] = upper_limit << (16 - i)
|
|
234
|
+
@decode_pos[i] = @decode_pos[i - 1] + len_count[i - 1]
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Fill decode_num
|
|
238
|
+
decode_pos_copy = @decode_pos.dup
|
|
239
|
+
bit_lengths.each_with_index do |len, symbol|
|
|
240
|
+
next unless len.positive? && len < 16
|
|
241
|
+
|
|
242
|
+
pos = decode_pos_copy[len]
|
|
243
|
+
@decode_num[pos] = symbol if pos < @size
|
|
244
|
+
decode_pos_copy[len] += 1
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Build quick lookup table
|
|
248
|
+
@quick_bits = 10 # Use 10 bits for quick lookup
|
|
249
|
+
build_quick_table(bit_lengths)
|
|
250
|
+
|
|
251
|
+
true
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Decode a symbol from bit reader
|
|
255
|
+
def decode(bit_reader)
|
|
256
|
+
# Read 16 bits for lookup
|
|
257
|
+
bit_field = bit_reader.read_bits(16)
|
|
258
|
+
return nil if bit_field.nil?
|
|
259
|
+
|
|
260
|
+
# Quick lookup
|
|
261
|
+
if @quick_len[bit_field].positive?
|
|
262
|
+
bit_reader.skip_bits(@quick_len[bit_field])
|
|
263
|
+
return @quick_num[bit_field]
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
# Full decode
|
|
267
|
+
bits = 15
|
|
268
|
+
(1..14).each do |i|
|
|
269
|
+
if bit_field < @decode_len[i]
|
|
270
|
+
bits = i
|
|
271
|
+
break
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
bit_reader.skip_bits(bits)
|
|
276
|
+
|
|
277
|
+
dist = bit_field - @decode_len[bits - 1]
|
|
278
|
+
dist >>= (16 - bits)
|
|
279
|
+
pos = @decode_pos[bits] + dist
|
|
280
|
+
|
|
281
|
+
pos < @size ? @decode_num[pos] : 0
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
private
|
|
285
|
+
|
|
286
|
+
def build_quick_table(bit_lengths)
|
|
287
|
+
quick_bits = @quick_bits
|
|
288
|
+
|
|
289
|
+
# Find maximum bit length for quick table
|
|
290
|
+
bit_lengths.each_with_index do |len, symbol|
|
|
291
|
+
next unless len.positive? && len <= quick_bits
|
|
292
|
+
|
|
293
|
+
# Calculate code for this symbol
|
|
294
|
+
code = 0
|
|
295
|
+
(0...len).each do |_i|
|
|
296
|
+
code = (code << 1) | 1 # Simplified - should use actual codes
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Fill quick table entries
|
|
300
|
+
extra_bits = quick_bits - len
|
|
301
|
+
(0...(1 << extra_bits)).each do |extra|
|
|
302
|
+
index = (code << extra_bits) | extra
|
|
303
|
+
next if index >= @quick_len.size
|
|
304
|
+
|
|
305
|
+
@quick_len[index] = len
|
|
306
|
+
@quick_num[index] = symbol
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# RAR5 LZSS Decoder
|
|
313
|
+
#
|
|
314
|
+
# Based on libarchive's do_uncompress_block()
|
|
315
|
+
#
|
|
316
|
+
class Decoder
|
|
317
|
+
def initialize(data, window_size)
|
|
318
|
+
@data = data.dup.force_encoding(Encoding::BINARY)
|
|
319
|
+
@window_size = window_size
|
|
320
|
+
@window_mask = window_size - 1
|
|
321
|
+
@window = "\x00" * window_size
|
|
322
|
+
@output = StringIO.new
|
|
323
|
+
@output.set_encoding(Encoding::BINARY)
|
|
324
|
+
@write_ptr = 0
|
|
325
|
+
@dist_cache = [0, 0, 0, 0] # Distance cache
|
|
326
|
+
@last_len = 0
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Decode the compressed data
|
|
330
|
+
#
|
|
331
|
+
# @param expected_size [Integer, nil] Expected uncompressed size
|
|
332
|
+
# @return [String] Decompressed data
|
|
333
|
+
def decode(expected_size = nil)
|
|
334
|
+
return "" if @data.empty?
|
|
335
|
+
|
|
336
|
+
@bit_reader = BitReader.new(@data)
|
|
337
|
+
|
|
338
|
+
# Parse block header
|
|
339
|
+
parse_block_header
|
|
340
|
+
|
|
341
|
+
return @output.string unless @table_present
|
|
342
|
+
|
|
343
|
+
# Parse Huffman tables
|
|
344
|
+
return @output.string unless parse_huffman_tables
|
|
345
|
+
|
|
346
|
+
# Decode data
|
|
347
|
+
decode_data(expected_size)
|
|
348
|
+
|
|
349
|
+
@output.string
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
private
|
|
353
|
+
|
|
354
|
+
def parse_block_header
|
|
355
|
+
flags = @bit_reader.read_bits(8)
|
|
356
|
+
return unless flags
|
|
357
|
+
|
|
358
|
+
@table_present = flags.anybits?(0x01)
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
def parse_huffman_tables
|
|
362
|
+
# Parse bit lengths for BC table (20 codes)
|
|
363
|
+
bit_lengths_bc = parse_bit_lengths(HUFF_BC)
|
|
364
|
+
return false unless bit_lengths_bc
|
|
365
|
+
|
|
366
|
+
# Build BC table
|
|
367
|
+
@table_bc = HuffmanTable.new(HUFF_BC)
|
|
368
|
+
@table_bc.build(bit_lengths_bc)
|
|
369
|
+
|
|
370
|
+
# Parse main table using BC table
|
|
371
|
+
table_data = Array.new(HUFF_TABLE_SIZE, 0)
|
|
372
|
+
idx = 0
|
|
373
|
+
|
|
374
|
+
while idx < HUFF_TABLE_SIZE
|
|
375
|
+
num = @table_bc.decode(@bit_reader)
|
|
376
|
+
return false if num.nil?
|
|
377
|
+
|
|
378
|
+
if num < 16
|
|
379
|
+
# Direct value
|
|
380
|
+
table_data[idx] = num
|
|
381
|
+
idx += 1
|
|
382
|
+
elsif num < 18
|
|
383
|
+
# Repeat previous code
|
|
384
|
+
count = num == 16 ? @bit_reader.read_bits(3) + 3 : @bit_reader.read_bits(7) + 11
|
|
385
|
+
return false if count.nil? || idx.zero?
|
|
386
|
+
|
|
387
|
+
count.times do
|
|
388
|
+
break if idx >= HUFF_TABLE_SIZE
|
|
389
|
+
|
|
390
|
+
table_data[idx] = table_data[idx - 1]
|
|
391
|
+
idx += 1
|
|
392
|
+
end
|
|
393
|
+
else
|
|
394
|
+
# Fill with zeros
|
|
395
|
+
count = num == 18 ? @bit_reader.read_bits(3) + 3 : @bit_reader.read_bits(7) + 11
|
|
396
|
+
return false if count.nil?
|
|
397
|
+
|
|
398
|
+
count.times do
|
|
399
|
+
break if idx >= HUFF_TABLE_SIZE
|
|
400
|
+
|
|
401
|
+
table_data[idx] = 0
|
|
402
|
+
idx += 1
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# Build individual tables
|
|
408
|
+
@table_ld = HuffmanTable.new(HUFF_NC)
|
|
409
|
+
@table_ld.build(table_data[0, HUFF_NC])
|
|
410
|
+
|
|
411
|
+
@table_dd = HuffmanTable.new(HUFF_DC)
|
|
412
|
+
@table_dd.build(table_data[HUFF_NC, HUFF_DC])
|
|
413
|
+
|
|
414
|
+
@table_ldd = HuffmanTable.new(HUFF_LDC)
|
|
415
|
+
@table_ldd.build(table_data[HUFF_NC + HUFF_DC, HUFF_LDC])
|
|
416
|
+
|
|
417
|
+
@table_rd = HuffmanTable.new(HUFF_RC)
|
|
418
|
+
@table_rd.build(table_data[HUFF_NC + HUFF_DC + HUFF_LDC, HUFF_RC])
|
|
419
|
+
|
|
420
|
+
true
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def parse_bit_lengths(count)
|
|
424
|
+
lengths = Array.new(count, 0)
|
|
425
|
+
idx = 0
|
|
426
|
+
0xF0
|
|
427
|
+
4
|
|
428
|
+
|
|
429
|
+
while idx < count
|
|
430
|
+
byte = @bit_reader.read_bits(8)
|
|
431
|
+
return nil if byte.nil?
|
|
432
|
+
|
|
433
|
+
# This is a simplified version
|
|
434
|
+
# The actual libarchive uses nibble-based RLE
|
|
435
|
+
lengths[idx] = byte & 0x0F
|
|
436
|
+
idx += 1
|
|
437
|
+
break if idx >= count
|
|
438
|
+
|
|
439
|
+
lengths[idx] = (byte >> 4) & 0x0F
|
|
440
|
+
idx += 1
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
lengths
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def decode_data(expected_size)
|
|
447
|
+
while !@bit_reader.end_of_data?(@data.bytesize) &&
|
|
448
|
+
(expected_size.nil? || @output.pos < expected_size)
|
|
449
|
+
|
|
450
|
+
num = @table_ld.decode(@bit_reader)
|
|
451
|
+
break if num.nil?
|
|
452
|
+
|
|
453
|
+
if num < 256
|
|
454
|
+
# Literal byte
|
|
455
|
+
write_byte(num)
|
|
456
|
+
elsif num == 256
|
|
457
|
+
# Filter - skip for now
|
|
458
|
+
skip_filter
|
|
459
|
+
elsif num == 257
|
|
460
|
+
# Repeat last match
|
|
461
|
+
if @last_len.positive?
|
|
462
|
+
copy_string(@last_len, @dist_cache[0])
|
|
463
|
+
end
|
|
464
|
+
elsif num < 262
|
|
465
|
+
# Use distance cache entry
|
|
466
|
+
cache_idx = num - 258
|
|
467
|
+
dist = dist_cache_touch(cache_idx)
|
|
468
|
+
|
|
469
|
+
len_slot = @table_rd.decode(@bit_reader)
|
|
470
|
+
break if len_slot.nil?
|
|
471
|
+
|
|
472
|
+
len = decode_code_length(len_slot)
|
|
473
|
+
copy_string(len, dist) if len.positive?
|
|
474
|
+
else
|
|
475
|
+
# Regular match
|
|
476
|
+
len = decode_code_length(num - 262)
|
|
477
|
+
break if len <= 0
|
|
478
|
+
|
|
479
|
+
dist_slot = @table_dd.decode(@bit_reader)
|
|
480
|
+
break if dist_slot.nil?
|
|
481
|
+
|
|
482
|
+
dist = decode_distance(dist_slot)
|
|
483
|
+
break if dist <= 0
|
|
484
|
+
|
|
485
|
+
dist_cache_push(dist)
|
|
486
|
+
@last_len = len
|
|
487
|
+
copy_string(len, dist)
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
def decode_code_length(slot)
|
|
493
|
+
return slot + MIN_MATCH if slot < 16
|
|
494
|
+
|
|
495
|
+
# Extended length encoding
|
|
496
|
+
extra_bits = (slot - 12) / 2
|
|
497
|
+
base = ((2 + (slot & 1)) << extra_bits)
|
|
498
|
+
extra = @bit_reader.read_bits(extra_bits)
|
|
499
|
+
return 0 if extra.nil?
|
|
500
|
+
|
|
501
|
+
base + extra + MIN_MATCH
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def decode_distance(slot)
|
|
505
|
+
return 0 if slot >= 64
|
|
506
|
+
|
|
507
|
+
if slot < 4
|
|
508
|
+
return slot + 1
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
dbits = (slot / 2) - 1
|
|
512
|
+
dist = 2 | (slot & 1)
|
|
513
|
+
dist = (dist << dbits) | (1 << dbits)
|
|
514
|
+
|
|
515
|
+
if dbits >= 4
|
|
516
|
+
# Read extra bits and low distance
|
|
517
|
+
add = @bit_reader.read_bits_32(dbits - 4)
|
|
518
|
+
dist += add << 4 if add
|
|
519
|
+
|
|
520
|
+
low_dist = @table_ldd.decode(@bit_reader)
|
|
521
|
+
return 0 if low_dist.nil?
|
|
522
|
+
|
|
523
|
+
dist += low_dist
|
|
524
|
+
elsif dbits.positive?
|
|
525
|
+
add = @bit_reader.read_bits(dbits)
|
|
526
|
+
dist += add if add
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
# Adjust length based on distance
|
|
530
|
+
dist
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
def dist_cache_push(dist)
|
|
534
|
+
@dist_cache[3] = @dist_cache[2]
|
|
535
|
+
@dist_cache[2] = @dist_cache[1]
|
|
536
|
+
@dist_cache[1] = @dist_cache[0]
|
|
537
|
+
@dist_cache[0] = dist
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
def dist_cache_touch(idx)
|
|
541
|
+
dist = @dist_cache[idx]
|
|
542
|
+
if idx.positive?
|
|
543
|
+
# Move to front
|
|
544
|
+
(idx...DIST_CACHE_SIZE).each do |i|
|
|
545
|
+
@dist_cache[i] = @dist_cache[i + 1] if i + 1 < DIST_CACHE_SIZE
|
|
546
|
+
end
|
|
547
|
+
@dist_cache[0] = dist
|
|
548
|
+
end
|
|
549
|
+
dist
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def write_byte(byte)
|
|
553
|
+
@output.putc(byte)
|
|
554
|
+
@window[@write_ptr & @window_mask] = byte.chr
|
|
555
|
+
@write_ptr += 1
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
def copy_string(length, distance)
|
|
559
|
+
return if distance <= 0 || distance > @write_ptr
|
|
560
|
+
|
|
561
|
+
length.times do
|
|
562
|
+
read_idx = (@write_ptr - distance) & @window_mask
|
|
563
|
+
byte = @window.getbyte(read_idx)
|
|
564
|
+
write_byte(byte)
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
def skip_filter
|
|
569
|
+
# Skip filter data - simplified implementation
|
|
570
|
+
@bit_reader.skip_bits(16)
|
|
571
|
+
end
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
end
|
|
577
|
+
end
|
|
578
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Rar
|
|
6
|
+
module Rar5
|
|
7
|
+
module Compression
|
|
8
|
+
# STORE compression method (uncompressed)
|
|
9
|
+
#
|
|
10
|
+
# This is the simplest compression method - it stores data without
|
|
11
|
+
# any compression. The "compressed" size equals the original size.
|
|
12
|
+
#
|
|
13
|
+
# @example Compress data
|
|
14
|
+
# compressed = Store.compress("Hello, World!")
|
|
15
|
+
# compressed # => "Hello, World!"
|
|
16
|
+
class Store
|
|
17
|
+
# Compression method identifier
|
|
18
|
+
METHOD = 0
|
|
19
|
+
|
|
20
|
+
# Compress data (passthrough for STORE)
|
|
21
|
+
#
|
|
22
|
+
# @param data [String] Data to compress
|
|
23
|
+
# @param _options [Hash] Options (ignored for STORE)
|
|
24
|
+
# @return [String] Uncompressed data
|
|
25
|
+
def self.compress(data, _options = {})
|
|
26
|
+
data
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Decompress data (passthrough for STORE)
|
|
30
|
+
#
|
|
31
|
+
# @param data [String] Data to decompress
|
|
32
|
+
# @param _options [Hash] Options (ignored for STORE)
|
|
33
|
+
# @return [String] Original data
|
|
34
|
+
def self.decompress(data, _options = {})
|
|
35
|
+
data
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Get compression method identifier
|
|
39
|
+
#
|
|
40
|
+
# @return [Integer] Method ID (0 for STORE)
|
|
41
|
+
def self.method_id
|
|
42
|
+
METHOD
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Get compression info VINT value
|
|
46
|
+
#
|
|
47
|
+
# For STORE, this is just the method ID (0)
|
|
48
|
+
# Bits 0-5: method (0=STORE)
|
|
49
|
+
# Bits 6+: version (0 for STORE)
|
|
50
|
+
#
|
|
51
|
+
# @return [Integer] Compression info value
|
|
52
|
+
def self.compression_info
|
|
53
|
+
METHOD
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Rar
|
|
6
|
+
module Rar5
|
|
7
|
+
# CRC32 calculation for RAR5 format
|
|
8
|
+
class CRC32
|
|
9
|
+
POLYNOMIAL = 0xEDB88320
|
|
10
|
+
|
|
11
|
+
# Generate CRC32 lookup table
|
|
12
|
+
def self.generate_table
|
|
13
|
+
@generate_table ||= (0..255).map do |i|
|
|
14
|
+
crc = i
|
|
15
|
+
8.times do
|
|
16
|
+
crc = (crc >> 1) ^ ((crc & 1) * POLYNOMIAL)
|
|
17
|
+
end
|
|
18
|
+
crc
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Calculate CRC32 for data
|
|
23
|
+
# @param data [String] Binary data
|
|
24
|
+
# @return [Integer] 32-bit CRC
|
|
25
|
+
def self.calculate(data)
|
|
26
|
+
table = generate_table
|
|
27
|
+
crc = 0xFFFFFFFF
|
|
28
|
+
|
|
29
|
+
data.bytes.each do |byte|
|
|
30
|
+
crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
crc ^ 0xFFFFFFFF
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|