omnizip 0.4.7-x86_64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +293 -0
- data/CHANGELOG.md +1647 -0
- data/CONTEXT.md +68 -0
- data/COPYING +502 -0
- data/Gemfile +19 -0
- data/LICENSE +12 -0
- data/README.adoc +1327 -0
- data/Rakefile +15 -0
- data/TODO.refactor/00-overview.md +67 -0
- data/TODO.refactor/01-registry-base-class.md +81 -0
- data/TODO.refactor/02-error-hierarchy.md +57 -0
- data/TODO.refactor/03-autoload-entry-point.md +69 -0
- data/TODO.refactor/04-filter-base-consolidation.md +49 -0
- data/TODO.refactor/05-send-private-methods.md +64 -0
- data/TODO.refactor/06-instance-variable-access.md +69 -0
- data/TODO.refactor/07-respond-to-replacement.md +237 -0
- data/TODO.refactor/08-spec-doubles.md +27 -0
- data/TODO.refactor/09-cli-shared-module.md +35 -0
- data/TODO.refactor/10-format-detector-ocp.md +34 -0
- data/TODO.refactor/11-convenience-decoupling.md +38 -0
- data/TODO.refactor/12-thread-safety.md +8 -0
- data/TODO.refactor/13-lutaml-model-migration.md +158 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -0
- data/benchmark/README.md +260 -0
- data/benchmark/benchmark_suite.rb +125 -0
- data/benchmark/compression_bench.rb +181 -0
- data/benchmark/filter_bench.rb +180 -0
- data/benchmark/models/benchmark_result.rb +59 -0
- data/benchmark/models/comparison_result.rb +69 -0
- data/benchmark/profile_suite.rb +167 -0
- data/benchmark/reporter.rb +150 -0
- data/benchmark/run_benchmarks.rb +66 -0
- data/benchmark/test_data.rb +137 -0
- data/config/formats/rar3_spec.yml +92 -0
- data/config/formats/rar5_spec.yml +102 -0
- data/docs/.github/workflows/docs.yml +142 -0
- data/docs/.gitignore +21 -0
- data/docs/.lychee.toml +67 -0
- data/docs/Gemfile +13 -0
- data/docs/RAR_WRITE_SUPPORT.md +26 -0
- data/docs/README.md +101 -0
- data/docs/_config.yml +112 -0
- data/docs/assets/logo.svg +1 -0
- data/docs/assets/omnizip-logo.pdf +1540 -11
- data/docs/comparison/feature-matrix.adoc +694 -0
- data/docs/comparison/index.adoc +113 -0
- data/docs/comparison/vs-7zip.adoc +309 -0
- data/docs/comparison/vs-peazip.adoc +77 -0
- data/docs/comparison/vs-rubyzip.adoc +342 -0
- data/docs/comparison/vs-winrar.adoc +100 -0
- data/docs/compatibility.adoc +579 -0
- data/docs/concepts/index.adoc +129 -0
- data/docs/developer/architecture.adoc +256 -0
- data/docs/developer/contributing.adoc +158 -0
- data/docs/developer/index.adoc +25 -0
- data/docs/developer/testing.adoc +212 -0
- data/docs/getting-started/basic-usage.adoc +263 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +183 -0
- data/docs/getting-started/your-first-archive.adoc +219 -0
- data/docs/guides/advanced-features/encryption.adoc +277 -0
- data/docs/guides/advanced-features/index.adoc +59 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
- data/docs/guides/advanced-features/streaming.adoc +142 -0
- data/docs/guides/archive-formats/gzip-format.adoc +105 -0
- data/docs/guides/archive-formats/index.adoc +160 -0
- data/docs/guides/archive-formats/ole-format.adoc +151 -0
- data/docs/guides/archive-formats/rar-format.adoc +104 -0
- data/docs/guides/archive-formats/rar5.adoc +521 -0
- data/docs/guides/archive-formats/rpm-format.adoc +108 -0
- data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
- data/docs/guides/archive-formats/tar-format.adoc +106 -0
- data/docs/guides/archive-formats/xz-format.adoc +118 -0
- data/docs/guides/archive-formats/zip-format.adoc +35 -0
- data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
- data/docs/guides/compression-algorithms/deflate.adoc +313 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +394 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
- data/docs/guides/creating-archives.adoc +348 -0
- data/docs/guides/extracting-archives.adoc +53 -0
- data/docs/guides/format-conversion.adoc +64 -0
- data/docs/guides/index.adoc +49 -0
- data/docs/guides/migration-rubyzip.adoc +217 -0
- data/docs/guides/parity-archives.adoc +605 -0
- data/docs/guides/performance-tuning.adoc +88 -0
- data/docs/index.adoc +228 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +187 -0
- data/docs/reference/cli/compress-command.adoc +114 -0
- data/docs/reference/cli/overview.adoc +140 -0
- data/docs/reference/index.adoc +26 -0
- data/docs/resources/faq.adoc +185 -0
- data/docs/resources/quick-reference.adoc +222 -0
- data/docs/rust-backend.md +0 -0
- data/docs/troubleshooting/index.adoc +207 -0
- data/docs/xar_format.md +216 -0
- data/examples/api_comparison.rb +205 -0
- data/examples/deflate64_example.rb +96 -0
- data/examples/par2_demo.rb +121 -0
- data/examples/quick_start_native.rb +150 -0
- data/examples/quick_start_rubyzip.rb +115 -0
- data/examples/rubyzip_compatibility_demo.rb +194 -0
- data/exe/omnizip +27 -0
- data/lib/omnizip/algorithm.rb +176 -0
- data/lib/omnizip/algorithm_registry.rb +65 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
- data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
- data/lib/omnizip/algorithms/bzip2.rb +108 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
- data/lib/omnizip/algorithms/deflate.rb +135 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
- data/lib/omnizip/algorithms/deflate64.rb +118 -0
- data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
- data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
- data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
- data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
- data/lib/omnizip/algorithms/lzma/match.rb +32 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
- data/lib/omnizip/algorithms/lzma.rb +266 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +133 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +146 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +122 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
- data/lib/omnizip/algorithms/registration.rb +28 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
- data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
- data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
- data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
- data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
- data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
- data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
- data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
- data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +210 -0
- data/lib/omnizip/algorithms.rb +35 -0
- data/lib/omnizip/archive/builder.rb +48 -0
- data/lib/omnizip/archive/reader_session.rb +67 -0
- data/lib/omnizip/archive.rb +86 -0
- data/lib/omnizip/archive_handler.rb +82 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
- data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
- data/lib/omnizip/archive_handlers.rb +18 -0
- data/lib/omnizip/backends.rb +160 -0
- data/lib/omnizip/buffer/memory_archive.rb +246 -0
- data/lib/omnizip/buffer/memory_extractor.rb +234 -0
- data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
- data/lib/omnizip/buffer.rb +187 -0
- data/lib/omnizip/checksum_registry.rb +41 -0
- data/lib/omnizip/checksums/crc32.rb +101 -0
- data/lib/omnizip/checksums/crc64.rb +102 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/registration.rb +16 -0
- data/lib/omnizip/checksums/verifier.rb +130 -0
- data/lib/omnizip/checksums.rb +11 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +123 -0
- data/lib/omnizip/chunked.rb +123 -0
- data/lib/omnizip/cli/output_formatter.rb +112 -0
- data/lib/omnizip/cli.rb +604 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +245 -0
- data/lib/omnizip/commands/archive_extract_command.rb +231 -0
- data/lib/omnizip/commands/archive_list_command.rb +204 -0
- data/lib/omnizip/commands/archive_repair_command.rb +129 -0
- data/lib/omnizip/commands/archive_verify_command.rb +115 -0
- data/lib/omnizip/commands/compress_command.rb +115 -0
- data/lib/omnizip/commands/decompress_command.rb +149 -0
- data/lib/omnizip/commands/list_command.rb +51 -0
- data/lib/omnizip/commands/metadata_command.rb +215 -0
- data/lib/omnizip/commands/parity_create_command.rb +114 -0
- data/lib/omnizip/commands/parity_repair_command.rb +120 -0
- data/lib/omnizip/commands/parity_verify_command.rb +122 -0
- data/lib/omnizip/commands/profile_list_command.rb +54 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/commands.rb +21 -0
- data/lib/omnizip/convenience.rb +389 -0
- data/lib/omnizip/converter/conversion_registry.rb +50 -0
- data/lib/omnizip/converter/conversion_strategy.rb +108 -0
- data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
- data/lib/omnizip/converter.rb +124 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/crypto.rb +11 -0
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/error.rb +110 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
- data/lib/omnizip/eta/rate_calculator.rb +104 -0
- data/lib/omnizip/eta/sample_history.rb +143 -0
- data/lib/omnizip/eta/time_estimator.rb +106 -0
- data/lib/omnizip/eta.rb +68 -0
- data/lib/omnizip/extraction/filter_chain.rb +179 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
- data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
- data/lib/omnizip/extraction/regex_pattern.rb +50 -0
- data/lib/omnizip/extraction/selective_extractor.rb +247 -0
- data/lib/omnizip/extraction.rb +115 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +117 -0
- data/lib/omnizip/filter.rb +141 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +113 -0
- data/lib/omnizip/filters/bcj.rb +277 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
- data/lib/omnizip/filters/bcj2.rb +93 -0
- data/lib/omnizip/filters/bcj_arm.rb +174 -0
- data/lib/omnizip/filters/bcj_arm64.rb +242 -0
- data/lib/omnizip/filters/bcj_ia64.rb +194 -0
- data/lib/omnizip/filters/bcj_ppc.rb +188 -0
- data/lib/omnizip/filters/bcj_sparc.rb +174 -0
- data/lib/omnizip/filters/bcj_x86.rb +191 -0
- data/lib/omnizip/filters/delta.rb +195 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/filters.rb +20 -0
- data/lib/omnizip/format_detector.rb +166 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +159 -0
- data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +389 -0
- data/lib/omnizip/formats/cpio/reader.rb +194 -0
- data/lib/omnizip/formats/cpio/writer.rb +232 -0
- data/lib/omnizip/formats/cpio.rb +132 -0
- data/lib/omnizip/formats/format_spec_loader.rb +228 -0
- data/lib/omnizip/formats/gzip.rb +236 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
- data/lib/omnizip/formats/iso/directory_record.rb +162 -0
- data/lib/omnizip/formats/iso/joliet.rb +204 -0
- data/lib/omnizip/formats/iso/path_table.rb +125 -0
- data/lib/omnizip/formats/iso/reader.rb +194 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +543 -0
- data/lib/omnizip/formats/iso.rb +133 -0
- data/lib/omnizip/formats/lzip.rb +161 -0
- data/lib/omnizip/formats/lzma_alone.rb +149 -0
- data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
- data/lib/omnizip/formats/msi/constants.rb +157 -0
- data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
- data/lib/omnizip/formats/msi/entry.rb +134 -0
- data/lib/omnizip/formats/msi/reader.rb +301 -0
- data/lib/omnizip/formats/msi/string_pool.rb +246 -0
- data/lib/omnizip/formats/msi/table_parser.rb +244 -0
- data/lib/omnizip/formats/msi.rb +73 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
- data/lib/omnizip/formats/ole/constants.rb +61 -0
- data/lib/omnizip/formats/ole/dirent.rb +439 -0
- data/lib/omnizip/formats/ole/header.rb +199 -0
- data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
- data/lib/omnizip/formats/ole/storage.rb +482 -0
- data/lib/omnizip/formats/ole/types/variant.rb +338 -0
- data/lib/omnizip/formats/ole.rb +143 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
- data/lib/omnizip/formats/rar/block_parser.rb +282 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
- data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
- data/lib/omnizip/formats/rar/compression.rb +17 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +88 -0
- data/lib/omnizip/formats/rar/decompressor.rb +316 -0
- data/lib/omnizip/formats/rar/external_writer.rb +311 -0
- data/lib/omnizip/formats/rar/header.rb +209 -0
- data/lib/omnizip/formats/rar/license_validator.rb +111 -0
- data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
- data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
- data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
- data/lib/omnizip/formats/rar/models.rb +14 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
- data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
- data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
- data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
- data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
- data/lib/omnizip/formats/rar/reader.rb +377 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
- data/lib/omnizip/formats/rar/writer.rb +437 -0
- data/lib/omnizip/formats/rar.rb +193 -0
- data/lib/omnizip/formats/rar3/compressor.rb +71 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar3/reader.rb +107 -0
- data/lib/omnizip/formats/rar3/writer.rb +220 -0
- data/lib/omnizip/formats/rar3.rb +15 -0
- data/lib/omnizip/formats/rar5/compressor.rb +71 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar5/reader.rb +130 -0
- data/lib/omnizip/formats/rar5/writer.rb +65 -0
- data/lib/omnizip/formats/rar5.rb +15 -0
- data/lib/omnizip/formats/rpm/constants.rb +58 -0
- data/lib/omnizip/formats/rpm/entry.rb +106 -0
- data/lib/omnizip/formats/rpm/header.rb +106 -0
- data/lib/omnizip/formats/rpm/lead.rb +132 -0
- data/lib/omnizip/formats/rpm/tag.rb +228 -0
- data/lib/omnizip/formats/rpm/writer.rb +652 -0
- data/lib/omnizip/formats/rpm.rb +458 -0
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
- data/lib/omnizip/formats/seven_zip/header.rb +102 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/models.rb +20 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
- data/lib/omnizip/formats/seven_zip.rb +179 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +98 -0
- data/lib/omnizip/formats/tar/header.rb +206 -0
- data/lib/omnizip/formats/tar/reader.rb +119 -0
- data/lib/omnizip/formats/tar/writer.rb +212 -0
- data/lib/omnizip/formats/tar.rb +74 -0
- data/lib/omnizip/formats/xar/constants.rb +119 -0
- data/lib/omnizip/formats/xar/entry.rb +268 -0
- data/lib/omnizip/formats/xar/header.rb +223 -0
- data/lib/omnizip/formats/xar/reader.rb +400 -0
- data/lib/omnizip/formats/xar/toc.rb +570 -0
- data/lib/omnizip/formats/xar/writer.rb +461 -0
- data/lib/omnizip/formats/xar.rb +145 -0
- data/lib/omnizip/formats/xz/reader.rb +121 -0
- data/lib/omnizip/formats/xz/writer.rb +416 -0
- data/lib/omnizip/formats/xz.rb +210 -0
- data/lib/omnizip/formats/xz_const.rb +49 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl.rb +52 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
- data/lib/omnizip/formats/zip/reader.rb +376 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +489 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/formats.rb +29 -0
- data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
- data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
- data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
- data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
- data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
- data/lib/omnizip/implementations/base.rb +19 -0
- data/lib/omnizip/implementations/rust/archive.rb +93 -0
- data/lib/omnizip/implementations/rust/library.rb +221 -0
- data/lib/omnizip/implementations/rust.rb +26 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
- data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
- data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
- data/lib/omnizip/implementations/seven_zip.rb +11 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
- data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
- data/lib/omnizip/implementations/xz_utils.rb +10 -0
- data/lib/omnizip/implementations.rb +25 -0
- data/lib/omnizip/io/buffered_input.rb +147 -0
- data/lib/omnizip/io/buffered_output.rb +106 -0
- data/lib/omnizip/io/source.rb +143 -0
- data/lib/omnizip/io/stream_manager.rb +117 -0
- data/lib/omnizip/io.rb +15 -0
- data/lib/omnizip/link_handler/hard_link.rb +79 -0
- data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
- data/lib/omnizip/link_handler.rb +129 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +153 -0
- data/lib/omnizip/metadata/metadata_editor.rb +169 -0
- data/lib/omnizip/metadata/metadata_registry.rb +71 -0
- data/lib/omnizip/metadata/metadata_validator.rb +101 -0
- data/lib/omnizip/metadata.rb +58 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +41 -0
- data/lib/omnizip/models/attribute_apply.rb +40 -0
- data/lib/omnizip/models/compression_options.rb +53 -0
- data/lib/omnizip/models/conversion_options.rb +79 -0
- data/lib/omnizip/models/conversion_result.rb +141 -0
- data/lib/omnizip/models/eta_result.rb +45 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +142 -0
- data/lib/omnizip/models/filter_config.rb +148 -0
- data/lib/omnizip/models/match_result.rb +141 -0
- data/lib/omnizip/models/optimization_suggestion.rb +95 -0
- data/lib/omnizip/models/parallel_options.rb +116 -0
- data/lib/omnizip/models/performance_result.rb +85 -0
- data/lib/omnizip/models/profile_report.rb +116 -0
- data/lib/omnizip/models/progress_options.rb +39 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +45 -0
- data/lib/omnizip/parallel/engine.rb +52 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +225 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
- data/lib/omnizip/parallel/thread_pool.rb +60 -0
- data/lib/omnizip/parallel/worker_pool.rb +227 -0
- data/lib/omnizip/parallel.rb +156 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +71 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
- data/lib/omnizip/parity/models/main_packet.rb +126 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +102 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
- data/lib/omnizip/parity/models.rb +27 -0
- data/lib/omnizip/parity/par2_creator.rb +496 -0
- data/lib/omnizip/parity/par2_repairer.rb +409 -0
- data/lib/omnizip/parity/par2_verifier.rb +373 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
- data/lib/omnizip/parity.rb +207 -0
- data/lib/omnizip/password/encryption_registry.rb +26 -0
- data/lib/omnizip/password/encryption_strategy.rb +96 -0
- data/lib/omnizip/password/password_validator.rb +129 -0
- data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
- data/lib/omnizip/password.rb +88 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
- data/lib/omnizip/pipe.rb +120 -0
- data/lib/omnizip/platform/ntfs_streams.rb +200 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +36 -0
- data/lib/omnizip/profile/balanced_profile.rb +31 -0
- data/lib/omnizip/profile/binary_profile.rb +33 -0
- data/lib/omnizip/profile/compression_profile.rb +157 -0
- data/lib/omnizip/profile/custom_profile.rb +155 -0
- data/lib/omnizip/profile/fast_profile.rb +31 -0
- data/lib/omnizip/profile/maximum_profile.rb +31 -0
- data/lib/omnizip/profile/profile_detector.rb +108 -0
- data/lib/omnizip/profile/profile_registry.rb +160 -0
- data/lib/omnizip/profile/text_profile.rb +33 -0
- data/lib/omnizip/profile.rb +261 -0
- data/lib/omnizip/profiler/memory_profiler.rb +66 -0
- data/lib/omnizip/profiler/method_profiler.rb +49 -0
- data/lib/omnizip/profiler/report_generator.rb +158 -0
- data/lib/omnizip/profiler.rb +192 -0
- data/lib/omnizip/progress/callback_reporter.rb +34 -0
- data/lib/omnizip/progress/console_reporter.rb +59 -0
- data/lib/omnizip/progress/log_reporter.rb +89 -0
- data/lib/omnizip/progress/operation_progress.rb +118 -0
- data/lib/omnizip/progress/progress_bar.rb +156 -0
- data/lib/omnizip/progress/progress_reporter.rb +40 -0
- data/lib/omnizip/progress/progress_tracker.rb +215 -0
- data/lib/omnizip/progress/silent_reporter.rb +22 -0
- data/lib/omnizip/progress.rb +131 -0
- data/lib/omnizip/registry.rb +111 -0
- data/lib/omnizip/rubyzip_compat.rb +61 -0
- data/lib/omnizip/temp/safe_extract.rb +124 -0
- data/lib/omnizip/temp/temp_file.rb +123 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +184 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +160 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +270 -0
- data/lib/omnizip/zip/output_stream.rb +320 -0
- data/lib/omnizip/zip.rb +23 -0
- data/lib/omnizip.rb +157 -0
- data/lib/tasks/msi_test_files.rake +66 -0
- data/lib/tasks/platform_gems.rake +147 -0
- data/lib/tasks/rust_backend.rake +48 -0
- data/readme-docs/advanced-features.adoc +514 -0
- data/readme-docs/api-usage.adoc +445 -0
- data/readme-docs/architecture.adoc +450 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +446 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +316 -0
- data/readme-docs/installation.adoc +228 -0
- data/readme-docs/par2-archives.adoc +608 -0
- data/readme-docs/performance-profiler.adoc +389 -0
- data/readme-docs/preprocessing-filters.adoc +280 -0
- data/vendor/libomnizip_ffi.so +0 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +768 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025 Ribose Inc.
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
6
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
7
|
+
# to deal in the Software without restriction, including without limitation
|
|
8
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
9
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
10
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
|
+
# DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
require "stringio"
|
|
24
|
+
|
|
25
|
+
module Omnizip
|
|
26
|
+
module Implementations
|
|
27
|
+
module XZUtils
|
|
28
|
+
module LZMA2
|
|
29
|
+
# XZ Utils LZMA2 decoder implementation.
|
|
30
|
+
#
|
|
31
|
+
# This is the original Decoder moved from algorithms/lzma2/decoder.rb
|
|
32
|
+
# to the new namespace structure.
|
|
33
|
+
class Decoder
|
|
34
|
+
include Omnizip::Algorithms::LZMA2Const
|
|
35
|
+
|
|
36
|
+
attr_reader :dict_size
|
|
37
|
+
|
|
38
|
+
# Initialize the decoder
|
|
39
|
+
#
|
|
40
|
+
# @param input [IO] Input stream of compressed data
|
|
41
|
+
# @param options [Hash] Decoding options
|
|
42
|
+
# @option options [Boolean] :raw_mode If true, skip property byte reading (for XZ format)
|
|
43
|
+
# @option options [Integer] :dict_size Dictionary size to use (required for raw_mode)
|
|
44
|
+
def initialize(input, options = {})
|
|
45
|
+
@input = input
|
|
46
|
+
@options = options
|
|
47
|
+
@raw_mode = options[:raw_mode] || false
|
|
48
|
+
|
|
49
|
+
if @raw_mode
|
|
50
|
+
# In raw_mode (XZ format), property byte is provided by caller
|
|
51
|
+
# Only dict_size comes from the XZ filter properties
|
|
52
|
+
@dict_size = options[:dict_size] || (8 * 1024 * 1024)
|
|
53
|
+
@properties = Omnizip::Algorithms::LZMA2::Properties.new(@dict_size)
|
|
54
|
+
else
|
|
55
|
+
read_property_byte
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Decode a compressed stream
|
|
60
|
+
#
|
|
61
|
+
# XZ Utils pattern (lzma2_decoder.c):
|
|
62
|
+
# - LZMA decoder is created ONCE and reused across all chunks
|
|
63
|
+
# - State (dictionary, probability models) persists between chunks
|
|
64
|
+
# - Reset only when control byte indicates new properties (control >= 0xC0)
|
|
65
|
+
#
|
|
66
|
+
# @return [String] Decompressed data
|
|
67
|
+
def decode_stream
|
|
68
|
+
output_io = StringIO.new
|
|
69
|
+
output_io.set_encoding("ASCII-8BIT")
|
|
70
|
+
|
|
71
|
+
# XZ Utils pattern: Create LZMA decoder ONCE (lzma2_decoder_init)
|
|
72
|
+
# The decoder will be reused across all chunks
|
|
73
|
+
@lzma_decoder = nil
|
|
74
|
+
@need_properties = true # First LZMA chunk needs properties (XZ Utils line 45)
|
|
75
|
+
@need_dictionary_reset = true # First chunk must reset dictionary (XZ Utils line 43)
|
|
76
|
+
|
|
77
|
+
chunk_num = 0
|
|
78
|
+
loop do
|
|
79
|
+
control = read_control_byte
|
|
80
|
+
|
|
81
|
+
break if control == CONTROL_END
|
|
82
|
+
|
|
83
|
+
# XZ Utils pattern (lzma2_decoder.c:75-82):
|
|
84
|
+
# Dictionary reset is needed if control >= 0xE0 or control == 1
|
|
85
|
+
# If dictionary reset is needed but control doesn't do it, error
|
|
86
|
+
# Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:75-82
|
|
87
|
+
if control >= 0xE0 || control == CONTROL_UNCOMPRESSED_RESET
|
|
88
|
+
@need_properties = true
|
|
89
|
+
@need_dictionary_reset = true
|
|
90
|
+
elsif @need_dictionary_reset
|
|
91
|
+
raise Omnizip::FormatError,
|
|
92
|
+
"LZMA2 dictionary reset required but not performed (control=0x#{control.to_s(16).upcase})"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# XZ Utils pattern (lzma2_decoder.c:121-126):
|
|
96
|
+
# Clear dictionary reset flag. The actual dict_reset is handled
|
|
97
|
+
# by the LZMA decoder when processing the chunk data.
|
|
98
|
+
# Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:121-127
|
|
99
|
+
if @need_dictionary_reset
|
|
100
|
+
@need_dictionary_reset = false
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# XZ Utils pattern (lzma2_decoder.c:84-110):
|
|
104
|
+
# For LZMA chunks (control >= 0x80), validate properties requirements
|
|
105
|
+
# Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:98-99
|
|
106
|
+
if control >= 0x80
|
|
107
|
+
if control >= 0xC0
|
|
108
|
+
# New properties present - properties will be read below
|
|
109
|
+
@need_properties = false
|
|
110
|
+
elsif @need_properties
|
|
111
|
+
# LZMA chunk without properties but properties are needed
|
|
112
|
+
# This happens after dictionary reset when next chunk must have properties
|
|
113
|
+
raise Omnizip::FormatError,
|
|
114
|
+
"LZMA2 properties required but not provided (control=0x#{control.to_s(16).upcase})"
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
chunk_data = decode_chunk(control, chunk_num)
|
|
119
|
+
|
|
120
|
+
# XZ Utils pattern: Uncompressed chunks ALWAYS produce output
|
|
121
|
+
# Dictionary reset chunks (control == 1) initialize the dictionary
|
|
122
|
+
# with the chunk data, then the dictionary is flushed to output
|
|
123
|
+
# So we should NEVER skip output for valid chunks
|
|
124
|
+
# Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:121-127
|
|
125
|
+
output_io.write(chunk_data)
|
|
126
|
+
chunk_num += 1
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
output_io.string.force_encoding("ASCII-8BIT")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
private
|
|
133
|
+
|
|
134
|
+
# Read and parse LZMA2 property byte
|
|
135
|
+
#
|
|
136
|
+
# @return [void]
|
|
137
|
+
# @raise [Omnizip::FormatError] If property byte is invalid
|
|
138
|
+
def read_property_byte
|
|
139
|
+
prop_byte = @input.getbyte
|
|
140
|
+
raise Omnizip::FormatError, "Invalid LZMA2 header" if prop_byte.nil?
|
|
141
|
+
|
|
142
|
+
@properties = Omnizip::Algorithms::LZMA2::Properties.from_byte(prop_byte)
|
|
143
|
+
@dict_size = @properties.actual_dict_size
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Read control byte
|
|
147
|
+
#
|
|
148
|
+
# @return [Integer] Control byte value
|
|
149
|
+
# @raise [Omnizip::IOError] If stream ends unexpectedly
|
|
150
|
+
def read_control_byte
|
|
151
|
+
byte = @input.getbyte
|
|
152
|
+
raise Omnizip::IOError, "Unexpected end of stream" if byte.nil?
|
|
153
|
+
|
|
154
|
+
byte
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Decode chunk based on control byte
|
|
158
|
+
#
|
|
159
|
+
# XZ Utils pattern (lzma2_decoder.c:75-102):
|
|
160
|
+
# - control >= 0xE0 or control == 1: Dictionary reset + properties needed
|
|
161
|
+
# - control >= 0xC0: State reset + properties
|
|
162
|
+
# - control >= 0xA0: State reset only
|
|
163
|
+
# - control >= 0x80: LZMA chunk (no reset)
|
|
164
|
+
# - control == 0x01 or 0x02: Uncompressed chunk
|
|
165
|
+
# - control > 2 and < 0x80: INVALID (LZMA2_DATA_ERROR)
|
|
166
|
+
#
|
|
167
|
+
# @param control [Integer] Control byte
|
|
168
|
+
# @param chunk_num [Integer] Chunk sequence number
|
|
169
|
+
# @return [String] Decoded chunk data
|
|
170
|
+
def decode_chunk(control, chunk_num)
|
|
171
|
+
# XZ Utils pattern (lzma2_decoder.c:138-140):
|
|
172
|
+
# Invalid control values: control > 2 and < 0x80 are invalid
|
|
173
|
+
# Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:138-140
|
|
174
|
+
if control > 2 && control < 0x80
|
|
175
|
+
raise Omnizip::FormatError,
|
|
176
|
+
"Invalid LZMA2 control byte: 0x#{control.to_s(16).upcase} " \
|
|
177
|
+
"(valid ranges: 0x00-0x02, 0x80-0xFF)"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
if uncompressed_chunk?(control)
|
|
181
|
+
decode_uncompressed_chunk(control)
|
|
182
|
+
else
|
|
183
|
+
decode_compressed_chunk(control, chunk_num)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Check if control byte indicates uncompressed chunk
|
|
188
|
+
#
|
|
189
|
+
# @param control [Integer] Control byte
|
|
190
|
+
# @return [Boolean] True if uncompressed
|
|
191
|
+
def uncompressed_chunk?(control)
|
|
192
|
+
[CONTROL_UNCOMPRESSED_RESET,
|
|
193
|
+
CONTROL_UNCOMPRESSED].include?(control)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Decode uncompressed chunk
|
|
197
|
+
#
|
|
198
|
+
# XZ Utils pattern (lzma2_decoder.c:193-200):
|
|
199
|
+
# - Copy from input to the dictionary as is using dict_write()
|
|
200
|
+
# - This ensures subsequent compressed chunks can reference the data
|
|
201
|
+
# - If LZMA decoder exists, add data to dictionary directly
|
|
202
|
+
# - If LZMA decoder doesn't exist, store data in @uncompressed_buffer
|
|
203
|
+
#
|
|
204
|
+
# @param control [Integer] Control byte
|
|
205
|
+
# @return [String] Uncompressed data
|
|
206
|
+
def decode_uncompressed_chunk(_control)
|
|
207
|
+
# Read uncompressed size (2 bytes, big-endian)
|
|
208
|
+
size = read_size_bytes(2) + 1
|
|
209
|
+
|
|
210
|
+
# Read uncompressed data
|
|
211
|
+
data = @input.read(size)
|
|
212
|
+
|
|
213
|
+
if data.nil? || data.bytesize != size
|
|
214
|
+
raise Omnizip::IOError,
|
|
215
|
+
"Unexpected end of stream"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# XZ Utils pattern: Copy from input to the dictionary as is.
|
|
219
|
+
# Reference: lzma2_decoder.c:195 - dict_write(dict, in, in_pos, in_size, &coder->compressed_size)
|
|
220
|
+
#
|
|
221
|
+
# If the LZMA decoder exists, add the data to its dictionary directly
|
|
222
|
+
# Otherwise, store it in @uncompressed_buffer for later use
|
|
223
|
+
if @lzma_decoder
|
|
224
|
+
# LZMA decoder exists - add data to its dictionary
|
|
225
|
+
@lzma_decoder.add_to_dictionary(data)
|
|
226
|
+
else
|
|
227
|
+
# LZMA decoder doesn't exist yet - store data for later
|
|
228
|
+
# This will be added to the dictionary when the first compressed chunk arrives
|
|
229
|
+
@uncompressed_buffer ||= String.new(encoding: "ASCII-8BIT")
|
|
230
|
+
@uncompressed_buffer << data
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
data
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Decode compressed chunk
|
|
237
|
+
#
|
|
238
|
+
# XZ Utils pattern (lzma2_decoder.c:84-103, 154-161, 163-191):
|
|
239
|
+
# - control >= 0xC0: New properties present, call decoder.reset()
|
|
240
|
+
# - control >= 0xA0: State reset only
|
|
241
|
+
# - control >= 0x80: LZMA chunk with explicit uncompressed/compressed size
|
|
242
|
+
# - control 0x03-0x7F: INVALID (rejected in decode_chunk)
|
|
243
|
+
# - LZMA decoder is created once and reused across all chunks
|
|
244
|
+
#
|
|
245
|
+
# @param control [Integer] Control byte
|
|
246
|
+
# @param chunk_num [Integer] Chunk sequence number
|
|
247
|
+
# @return [String] Decompressed data
|
|
248
|
+
def decode_compressed_chunk(control, chunk_num)
|
|
249
|
+
if control >= 0x80
|
|
250
|
+
# Compressed chunk with explicit uncompressed/compressed size
|
|
251
|
+
# Read uncompressed size (2 bytes, big-endian)
|
|
252
|
+
# High 3 bits are in bits 2-0 of the control byte (bits 19-17 of uncompressed size)
|
|
253
|
+
uncompressed_low_bytes = [@input.getbyte, @input.getbyte]
|
|
254
|
+
uncompressed_low = (uncompressed_low_bytes[0] << 8) | uncompressed_low_bytes[1]
|
|
255
|
+
# XZ Utils lzma2_decoder.c:87: (control & 0x1F) << 16, then += each byte
|
|
256
|
+
# High 5 bits of (uncompressed_size - 1) are in bits 4-0 of control byte
|
|
257
|
+
uncompressed_high = control & 0x1F
|
|
258
|
+
uncompressed_size = (uncompressed_high << 16) + uncompressed_low + 1
|
|
259
|
+
|
|
260
|
+
# Read compressed size (2 bytes, big-endian)
|
|
261
|
+
compressed_size = read_size_bytes(2) + 1
|
|
262
|
+
else
|
|
263
|
+
# This should never be reached because control bytes 0x03-0x7F are
|
|
264
|
+
# rejected in decode_chunk() before this method is called.
|
|
265
|
+
# Control bytes < 0x80 should only be 0x01 or 0x02, which are
|
|
266
|
+
# handled by decode_uncompressed_chunk(), not this method.
|
|
267
|
+
raise Omnizip::FormatError,
|
|
268
|
+
"Invalid LZMA2 control byte: 0x#{control.to_s(16).upcase} " \
|
|
269
|
+
"(control < 0x80 but not 0x01 or 0x02)"
|
|
270
|
+
end
|
|
271
|
+
# Note: For control >= 0x80, compressed_data will be read below.
|
|
272
|
+
# For control < 0x80 (unreachable), this method raises above.
|
|
273
|
+
|
|
274
|
+
# Read properties byte
|
|
275
|
+
# LZMA2 format: Properties byte is ONLY present for control >= 0xC0
|
|
276
|
+
# For control >= 0xA0 but < 0xC0, use default properties (no properties byte)
|
|
277
|
+
# For control < 0xA0 (but >= 0x80), use previous properties (no properties byte)
|
|
278
|
+
# Reference: XZ Utils lzma2_decoder.c:92-96, 154-160
|
|
279
|
+
if control >= 0xC0
|
|
280
|
+
# New properties present - read properties byte
|
|
281
|
+
properties = @input.getbyte
|
|
282
|
+
if properties.nil?
|
|
283
|
+
raise Omnizip::IOError,
|
|
284
|
+
"Unexpected end of stream"
|
|
285
|
+
end
|
|
286
|
+
else
|
|
287
|
+
# No properties byte for control >= 0xA0 but < 0xC0
|
|
288
|
+
# Use default properties for LZMA2
|
|
289
|
+
properties = nil
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
if control >= 0x80
|
|
293
|
+
# Read compressed data
|
|
294
|
+
compressed_data = @input.read(compressed_size)
|
|
295
|
+
if compressed_data.nil? || compressed_data.bytesize != compressed_size
|
|
296
|
+
raise Omnizip::IOError, "Unexpected end of stream"
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Decompress using LZMA
|
|
301
|
+
# Pass control byte to handle decoder creation/reset logic
|
|
302
|
+
decompress_lzma_chunk(compressed_data, uncompressed_size, properties,
|
|
303
|
+
control, chunk_num)
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# Decompress LZMA chunk
|
|
307
|
+
#
|
|
308
|
+
# XZ Utils pattern (lzma2_decoder.c:92-103, 154-191):
|
|
309
|
+
# - Create LZMA decoder on first chunk or when control >= 0xC0
|
|
310
|
+
# - Call decoder.reset() when new properties are present (control >= 0xC0)
|
|
311
|
+
# - Reuse decoder state across chunks (preserves probability models)
|
|
312
|
+
# - Reset range decoder between chunks (lzma_decoder.c:1014-1017)
|
|
313
|
+
#
|
|
314
|
+
# @param compressed_data [String] Compressed data (no LZMA header)
|
|
315
|
+
# @param expected_size [Integer] Expected decompressed size (from LZMA2 chunk header)
|
|
316
|
+
# @param properties [Integer, nil] LZMA properties byte from LZMA2 chunk (if present)
|
|
317
|
+
# @param control [Integer] LZMA2 control byte for this chunk
|
|
318
|
+
# @param chunk_num [Integer] Chunk sequence number
|
|
319
|
+
# @return [String] Decompressed data
|
|
320
|
+
def decompress_lzma_chunk(compressed_data, expected_size, properties,
|
|
321
|
+
control, chunk_num)
|
|
322
|
+
# XZ Utils pattern (lzma2_decoder.c:140-141):
|
|
323
|
+
# Pass the chunk's uncompressed_size to the LZMA decoder.
|
|
324
|
+
# The block header's uncompressed_size is for validation only.
|
|
325
|
+
# For simple compressed chunks (control < 0x80), expected_size is nil,
|
|
326
|
+
# which means decode until LZMA end-of-stream marker.
|
|
327
|
+
lzma_uncompressed_size = expected_size || 0xFFFFFFFFFFFFFFFF # UNKNOWN = decode until EOS
|
|
328
|
+
|
|
329
|
+
# Decode lc, lp, pb from LZMA chunk properties byte
|
|
330
|
+
# In XZ format, the chunk properties byte is inside the compressed chunk
|
|
331
|
+
# and contains: (pb * 9 * 5) + (lp * 9) + lc
|
|
332
|
+
# Reference: /tmp/xz-source/src/liblzma/lzma/lzma_decoder.c:1199-1209
|
|
333
|
+
if properties && properties >= 0
|
|
334
|
+
# Decode lc, lp, pb from chunk properties byte using XZ Utils formula
|
|
335
|
+
pb = properties / (9 * 5)
|
|
336
|
+
remainder = properties - (pb * 9 * 5)
|
|
337
|
+
lp = remainder / 9
|
|
338
|
+
lc = remainder - (lp * 9)
|
|
339
|
+
else
|
|
340
|
+
# Default values when no properties present
|
|
341
|
+
# XZ Utils defaults: lc=3, lp=0, pb=2
|
|
342
|
+
lc = 3
|
|
343
|
+
lp = 0
|
|
344
|
+
pb = 2
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# XZ Utils pattern: Create/reuse LZMA decoder across chunks
|
|
348
|
+
# lzma2_decoder.c:92-103, 154-161: Handle decoder creation and reset
|
|
349
|
+
#
|
|
350
|
+
# IMPORTANT: We need to handle the case where the first chunk(s) are
|
|
351
|
+
# uncompressed. The uncompressed data must be added to the LZMA decoder's
|
|
352
|
+
# dictionary BEFORE we create the decoder, so we'll pass it as preloaded data.
|
|
353
|
+
if chunk_num.zero? || !@lzma_decoder
|
|
354
|
+
# First chunk - create LZMA decoder in lzma2_mode
|
|
355
|
+
# NO LZMA HEADER - pass compressed data directly
|
|
356
|
+
# XZ Utils: lzma_lz_decoder_create + lzma_lzma_decoder_create
|
|
357
|
+
input_buffer = StringIO.new(compressed_data)
|
|
358
|
+
input_buffer.set_encoding("ASCII-8BIT")
|
|
359
|
+
|
|
360
|
+
# Check if we have uncompressed data to preload into the dictionary
|
|
361
|
+
preloaded_data = @uncompressed_buffer if @uncompressed_buffer && !@uncompressed_buffer.empty?
|
|
362
|
+
|
|
363
|
+
@lzma_decoder = Omnizip::Algorithms::XzUtilsDecoder.new(input_buffer,
|
|
364
|
+
lzma2_mode: true,
|
|
365
|
+
lc: lc,
|
|
366
|
+
lp: lp,
|
|
367
|
+
pb: pb,
|
|
368
|
+
dict_size: @dict_size,
|
|
369
|
+
uncompressed_size: lzma_uncompressed_size,
|
|
370
|
+
preloaded_data: preloaded_data) # Pass uncompressed data to preload
|
|
371
|
+
|
|
372
|
+
# Clear uncompressed buffer after passing to decoder
|
|
373
|
+
@uncompressed_buffer = nil if preloaded_data
|
|
374
|
+
else
|
|
375
|
+
# Subsequent chunks - reuse decoder, reset if needed
|
|
376
|
+
# XZ Utils lzma2_decoder.c:92-96, 154-161
|
|
377
|
+
|
|
378
|
+
# Determine if dictionary should be preserved
|
|
379
|
+
# Use the same logic as at line 414 for consistency
|
|
380
|
+
# XZ Utils LZMA2 control byte decoding (lzma2_decoder.c:75-79):
|
|
381
|
+
# - control >= 0xE0: LZMA2 compressed + reset dictionary + properties byte present
|
|
382
|
+
# - control = 0x01: end of chunk marker
|
|
383
|
+
# XZ Utils sets need_dictionary_reset = true ONLY for control >= 0xE0 || control == 1
|
|
384
|
+
# Therefore, dict_reset is ONLY called for control >= 0xE0 || control == 1
|
|
385
|
+
# - control = 0xC0: LZMA2 compressed + state reset + default properties (NO dict reset!)
|
|
386
|
+
# - control < 0x80: LZMA2 uncompressed
|
|
387
|
+
# - 0x80 <= control < 0xC0: LZMA2 compressed + preserve dictionary
|
|
388
|
+
# Note: chunk_num >= 1 here (not the first chunk)
|
|
389
|
+
preserve_dict = !(control >= 0xE0 || control == 1)
|
|
390
|
+
|
|
391
|
+
if control >= 0xC0
|
|
392
|
+
# New properties present - reset decoder with new properties
|
|
393
|
+
@lzma_decoder.reset(new_lc: lc, new_lp: lp, new_pb: pb,
|
|
394
|
+
preserve_dict: preserve_dict)
|
|
395
|
+
|
|
396
|
+
# Pass compressed data directly (NO LZMA HEADER)
|
|
397
|
+
input_buffer = StringIO.new(compressed_data)
|
|
398
|
+
input_buffer.set_encoding("ASCII-8BIT")
|
|
399
|
+
|
|
400
|
+
@lzma_decoder.set_input(input_buffer)
|
|
401
|
+
elsif control >= 0xA0
|
|
402
|
+
# State reset only (no new properties)
|
|
403
|
+
# IMPORTANT: XZ Utils source code (lzma2_decoder.c:107-109) shows that
|
|
404
|
+
# for control >= 0xA0, it calls coder->lzma.reset(), which resets
|
|
405
|
+
# rep distances to 0 (see lzma_decoder.c:1071-1074).
|
|
406
|
+
#
|
|
407
|
+
# A rep match with distance=0 is valid - it means "copy the last byte"
|
|
408
|
+
# (distance 0 from the current position, i.e., the byte just written).
|
|
409
|
+
@lzma_decoder.reset(preserve_dict: preserve_dict)
|
|
410
|
+
|
|
411
|
+
# Pass compressed data directly (NO LZMA HEADER)
|
|
412
|
+
input_buffer = StringIO.new(compressed_data)
|
|
413
|
+
input_buffer.set_encoding("ASCII-8BIT")
|
|
414
|
+
|
|
415
|
+
@lzma_decoder.set_input(input_buffer)
|
|
416
|
+
|
|
417
|
+
if @lzma2_debug
|
|
418
|
+
warn "DEBUG: decompress_lzma_chunk - After set_input, checking range_decoder..."
|
|
419
|
+
range_decoder = @lzma_decoder.range_decoder
|
|
420
|
+
if range_decoder
|
|
421
|
+
warn " range_decoder exists: code=0x#{range_decoder.code.to_s(16)}, range=0x#{range_decoder.range.to_s(16)}, init_bytes_remaining=#{range_decoder.init_bytes_remaining}"
|
|
422
|
+
else
|
|
423
|
+
warn " range_decoder is nil"
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
else
|
|
427
|
+
# For control >= 0x80 but < 0xA0: No reset
|
|
428
|
+
# Pass compressed data directly (NO LZMA HEADER)
|
|
429
|
+
input_buffer = StringIO.new(compressed_data)
|
|
430
|
+
input_buffer.set_encoding("ASCII-8BIT")
|
|
431
|
+
|
|
432
|
+
@lzma_decoder.set_input(input_buffer)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
# XZ Utils: Set uncompressed size for each chunk (lzma2_decoder.c:140-141)
|
|
436
|
+
@lzma_decoder.set_uncompressed_size(lzma_uncompressed_size,
|
|
437
|
+
allow_eopm: false)
|
|
438
|
+
|
|
439
|
+
if @lzma2_debug
|
|
440
|
+
warn "DEBUG: decompress_lzma_chunk - Reusing LZMA decoder, set uncompressed_size=#{lzma_uncompressed_size}"
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# For first chunk or when control >= 0xE0 or control == 1, reset dictionary (preserve_dict = false)
|
|
445
|
+
# For other chunks with control < 0xE0 and control != 1, preserve dictionary
|
|
446
|
+
# XZ Utils LZMA2 control byte decoding (lzma2_decoder.c:75-79):
|
|
447
|
+
# - control >= 0xE0: LZMA2 compressed + reset dictionary + properties byte present
|
|
448
|
+
# - control = 0x01: end of chunk marker
|
|
449
|
+
# XZ Utils sets need_dictionary_reset = true ONLY for control >= 0xE0 || control == 1
|
|
450
|
+
# Therefore, dict_reset is ONLY called for control >= 0xE0 || control == 1
|
|
451
|
+
# - control = 0xC0: LZMA2 compressed + state reset + default properties (NO dict reset!)
|
|
452
|
+
# - control < 0x80: LZMA2 uncompressed
|
|
453
|
+
# - 0x80 <= control < 0xC0: LZMA2 compressed + preserve dictionary
|
|
454
|
+
preserve_dictionary = chunk_num.zero? ? false : !(control >= 0xE0 || control == 1)
|
|
455
|
+
|
|
456
|
+
decompressed = @lzma_decoder.decode_stream(nil,
|
|
457
|
+
preserve_dict: preserve_dictionary,
|
|
458
|
+
check_rc_finished: false)
|
|
459
|
+
|
|
460
|
+
@lzma_decoder.compact_buffer
|
|
461
|
+
|
|
462
|
+
if @lzma2_debug
|
|
463
|
+
warn "DEBUG: decompress_lzma_chunk - expected=#{lzma_uncompressed_size}, got=#{decompressed.bytesize}"
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# Verify size matches expected
|
|
467
|
+
if @lzma2_debug
|
|
468
|
+
# puts "DEBUG: Size check - decompressed=#{decompressed.bytesize}, expected=#{lzma_uncompressed_size}"
|
|
469
|
+
end
|
|
470
|
+
if decompressed.bytesize != lzma_uncompressed_size
|
|
471
|
+
raise Omnizip::DecompressionError, "Decompressed size mismatch: expected #{lzma_uncompressed_size}, " \
|
|
472
|
+
"got #{decompressed.bytesize}"
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
decompressed
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
# Build LZMA header for decompression
|
|
479
|
+
#
|
|
480
|
+
# @param uncompressed_size [Integer] Expected size after decompression
|
|
481
|
+
# @param properties [Integer, nil] LZMA properties byte (lc/lp/pb encoding) from LZMA2 chunk
|
|
482
|
+
# @return [String] LZMA header (13 bytes)
|
|
483
|
+
def build_lzma_header(uncompressed_size, properties = nil)
|
|
484
|
+
header = String.new(encoding: "ASCII-8BIT")
|
|
485
|
+
|
|
486
|
+
# The properties byte from LZMA2 encodes lc, lp, pb (not dictionary size!)
|
|
487
|
+
# Decode using XZ Utils formula from lzma_lzma_lclppb_decode:
|
|
488
|
+
# pb = byte / (9 * 5)
|
|
489
|
+
# byte -= pb * 9 * 5
|
|
490
|
+
# lp = byte / 9
|
|
491
|
+
# lc = byte - lp * 9
|
|
492
|
+
if properties && properties >= 0
|
|
493
|
+
prop_byte = properties
|
|
494
|
+
pb = prop_byte / (9 * 5)
|
|
495
|
+
remainder = prop_byte - (pb * 9 * 5)
|
|
496
|
+
lp = remainder / 9
|
|
497
|
+
lc = remainder - (lp * 9)
|
|
498
|
+
|
|
499
|
+
props = lc + (lp * 9) + (pb * 9 * 5)
|
|
500
|
+
|
|
501
|
+
if @lzma2_debug
|
|
502
|
+
warn "DEBUG: build_lzma_header - properties=0x#{prop_byte.to_s(16)} -> lc=#{lc}, lp=#{lp}, pb=#{pb}, props=0x#{props.to_s(16)}"
|
|
503
|
+
end
|
|
504
|
+
else
|
|
505
|
+
# Default values when no properties present
|
|
506
|
+
lc = 0
|
|
507
|
+
lp = 0
|
|
508
|
+
pb = 0
|
|
509
|
+
|
|
510
|
+
if @lzma2_debug
|
|
511
|
+
warn "DEBUG: build_lzma_header - no properties, using defaults lc=0, lp=0, pb=0"
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
# Calculate props encoding (props encoding is calculated the same way for both cases)
|
|
516
|
+
props = lc + (lp * 9) + (pb * 9 * 5)
|
|
517
|
+
|
|
518
|
+
header << [props].pack("C")
|
|
519
|
+
|
|
520
|
+
# Dictionary size from @dict_size (set during initialization from LZMA2 filter properties)
|
|
521
|
+
header << [@dict_size].pack("V")
|
|
522
|
+
|
|
523
|
+
# Uncompressed size (8 bytes, little-endian)
|
|
524
|
+
header << [uncompressed_size].pack("Q<")
|
|
525
|
+
|
|
526
|
+
header
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
# Read size bytes in big-endian order
|
|
530
|
+
#
|
|
531
|
+
# @param num_bytes [Integer] Number of bytes to read
|
|
532
|
+
# @return [Integer] Size value
|
|
533
|
+
def read_size_bytes(num_bytes)
|
|
534
|
+
size = 0
|
|
535
|
+
num_bytes.times do
|
|
536
|
+
byte = @input.getbyte
|
|
537
|
+
raise Omnizip::IOError, "Unexpected end of stream" if byte.nil?
|
|
538
|
+
|
|
539
|
+
size = (size << 8) | byte
|
|
540
|
+
end
|
|
541
|
+
size
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
end
|