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,263 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
# This file is part of Omnizip.
|
|
7
|
+
#
|
|
8
|
+
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
+
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# See the COPYING file for the complete text of the license.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
module Omnizip
|
|
20
|
+
module Filters
|
|
21
|
+
# BCJ2 decoder - reconstructs original data from 4 streams.
|
|
22
|
+
#
|
|
23
|
+
# Matches the modern 7-Zip SDK Bcj2.c decode loop (v18.06+):
|
|
24
|
+
# - Pre-allocated output buffer (no dynamic growth)
|
|
25
|
+
# - Handles E8 (CALL), E9 (JMP), and JCC (0x0F 0x80-0x8F) opcodes
|
|
26
|
+
# - Probability model: index 0=JCC, 1=E9, 2+prev_byte=E8
|
|
27
|
+
# - Inline range decoder with cached locals
|
|
28
|
+
class Bcj2Decoder
|
|
29
|
+
include Bcj2Constants
|
|
30
|
+
|
|
31
|
+
attr_reader :ip
|
|
32
|
+
|
|
33
|
+
# Initialize decoder.
|
|
34
|
+
#
|
|
35
|
+
# @param streams [Bcj2StreamData] The 4 input streams
|
|
36
|
+
# @param position [Integer] Starting instruction pointer
|
|
37
|
+
def initialize(streams, position = 0)
|
|
38
|
+
@streams = streams
|
|
39
|
+
@ip = position
|
|
40
|
+
@range = 0
|
|
41
|
+
@code = 0
|
|
42
|
+
@probs = Array.new(NUM_PROBS, INITIAL_PROB)
|
|
43
|
+
|
|
44
|
+
# Stream positions
|
|
45
|
+
@main_pos = 0
|
|
46
|
+
@call_pos = 0
|
|
47
|
+
@jump_pos = 0
|
|
48
|
+
@rc_pos = 0
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Decode 4 streams back to original data.
|
|
52
|
+
#
|
|
53
|
+
# Matches modern 7-Zip SDK Bcj2Dec_Decode pattern:
|
|
54
|
+
# - Pre-allocated output buffer sized to expected output
|
|
55
|
+
# - Single C-optimized regex scan for E8/E9/JCC opcodes
|
|
56
|
+
# - Direct setbyte writes (no intermediate String allocations)
|
|
57
|
+
# - Opcode written to output before range-coded decision (matches SDK)
|
|
58
|
+
#
|
|
59
|
+
# @param expected_size [Integer, nil] Expected output size for pre-allocation
|
|
60
|
+
# @return [String] Decoded binary data
|
|
61
|
+
# @raise [Omnizip::DecompressionError] If output exceeds buffer capacity when expected_size is nil
|
|
62
|
+
def decode(expected_size = nil)
|
|
63
|
+
main_data = @streams.main
|
|
64
|
+
main_size = main_data.bytesize
|
|
65
|
+
|
|
66
|
+
# Pre-allocate output buffer to expected size (C++ SDK: dic is pre-allocated)
|
|
67
|
+
# When expected_size is unknown, use a conservative upper bound
|
|
68
|
+
# Each byte can produce at most 5 bytes (opcode + 4-byte address), but
|
|
69
|
+
# in practice BCJ2 never expands more than 2x due to rarity of convertible opcodes
|
|
70
|
+
out_capacity = expected_size || (main_size * 2)
|
|
71
|
+
result = ("\0" * out_capacity).b
|
|
72
|
+
result_pos = 0
|
|
73
|
+
|
|
74
|
+
# Helper to grow buffer if needed (only when expected_size is nil)
|
|
75
|
+
grow_buffer = lambda do |required|
|
|
76
|
+
return if result_pos + required <= result.bytesize
|
|
77
|
+
|
|
78
|
+
if expected_size
|
|
79
|
+
raise Omnizip::DecompressionError,
|
|
80
|
+
"BCJ2 output size (#{result_pos + required}) exceeds expected size (#{expected_size})"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Dynamic growth when expected_size is unknown
|
|
84
|
+
new_capacity = [result.bytesize * 2, result_pos + required].max
|
|
85
|
+
new_buf = ("\0" * new_capacity).b
|
|
86
|
+
new_buf[0, result_pos] = result.byteslice(0, result_pos)
|
|
87
|
+
result = new_buf
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Cache stream references as locals (avoids repeated ivar lookups in hot loop)
|
|
91
|
+
call_data = @streams.call
|
|
92
|
+
jump_data = @streams.jump
|
|
93
|
+
rc_data = @streams.rc
|
|
94
|
+
call_size = call_data.bytesize
|
|
95
|
+
jump_size = jump_data.bytesize
|
|
96
|
+
rc_size = rc_data.bytesize
|
|
97
|
+
call_pos = @call_pos
|
|
98
|
+
jump_pos = @jump_pos
|
|
99
|
+
rc_pos = @rc_pos
|
|
100
|
+
probs = @probs
|
|
101
|
+
ip = @ip
|
|
102
|
+
|
|
103
|
+
# Initialize range decoder (read first 5 bytes from RC stream)
|
|
104
|
+
range = 0xFFFFFFFF
|
|
105
|
+
code = 0
|
|
106
|
+
5.times do
|
|
107
|
+
break if rc_pos >= rc_size
|
|
108
|
+
|
|
109
|
+
code = ((code << 8) | rc_data.getbyte(rc_pos)) & 0xFFFFFFFF
|
|
110
|
+
rc_pos += 1
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Regex to find E8, E9, or JCC (0x0F followed by 0x80-0x8F)
|
|
114
|
+
opcode_re = /[\xe8\xe9]|\x0f[\x80-\x8f]/n
|
|
115
|
+
main_pos = @main_pos
|
|
116
|
+
prev_byte = 0
|
|
117
|
+
|
|
118
|
+
while main_pos < main_size
|
|
119
|
+
# C-optimized scan for E8, E9, and JCC opcodes
|
|
120
|
+
next_pos = main_data.index(opcode_re, main_pos)
|
|
121
|
+
|
|
122
|
+
unless next_pos
|
|
123
|
+
# No more opcodes — bulk copy remaining bytes
|
|
124
|
+
chunk_len = main_size - main_pos
|
|
125
|
+
grow_buffer.call(chunk_len)
|
|
126
|
+
result[result_pos, chunk_len] =
|
|
127
|
+
main_data.byteslice(main_pos, chunk_len)
|
|
128
|
+
result_pos += chunk_len
|
|
129
|
+
ip += chunk_len
|
|
130
|
+
main_pos = main_size
|
|
131
|
+
break
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Bulk copy bytes before opcode
|
|
135
|
+
if next_pos > main_pos
|
|
136
|
+
chunk_len = next_pos - main_pos
|
|
137
|
+
grow_buffer.call(chunk_len)
|
|
138
|
+
result[result_pos, chunk_len] =
|
|
139
|
+
main_data.byteslice(main_pos, chunk_len)
|
|
140
|
+
result_pos += chunk_len
|
|
141
|
+
ip += chunk_len
|
|
142
|
+
main_pos = next_pos
|
|
143
|
+
# Track prev_byte from bulk copy (last byte before opcode in output)
|
|
144
|
+
prev_byte = main_data.getbyte(next_pos - 1)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
byte = main_data.getbyte(main_pos)
|
|
148
|
+
|
|
149
|
+
if byte == 0x0F
|
|
150
|
+
# JCC: 0x0F followed by 0x80-0x8F conditional jump
|
|
151
|
+
# Ensure buffer has room for 2 opcode bytes + potential 4 address bytes
|
|
152
|
+
grow_buffer.call(6)
|
|
153
|
+
# Write 0x0F to output (SDK writes opcode bytes before range decision)
|
|
154
|
+
result.setbyte(result_pos, 0x0F)
|
|
155
|
+
result_pos += 1
|
|
156
|
+
ip += 1
|
|
157
|
+
main_pos += 1
|
|
158
|
+
|
|
159
|
+
# Read and write the 0x8x second opcode byte
|
|
160
|
+
byte = main_data.getbyte(main_pos)
|
|
161
|
+
result.setbyte(result_pos, byte)
|
|
162
|
+
result_pos += 1
|
|
163
|
+
ip += 1
|
|
164
|
+
main_pos += 1
|
|
165
|
+
|
|
166
|
+
prob_idx = 0 # JCC uses probability index 0
|
|
167
|
+
is_call = false
|
|
168
|
+
else
|
|
169
|
+
# E8 (CALL) or E9 (JMP) — write opcode before range decision
|
|
170
|
+
# Ensure buffer has room for 1 opcode byte + potential 4 address bytes
|
|
171
|
+
grow_buffer.call(5)
|
|
172
|
+
result.setbyte(result_pos, byte)
|
|
173
|
+
result_pos += 1
|
|
174
|
+
ip += 1
|
|
175
|
+
main_pos += 1
|
|
176
|
+
|
|
177
|
+
if byte == 0xE8
|
|
178
|
+
prob_idx = 2 + prev_byte # E8 uses prev_byte context (256 models)
|
|
179
|
+
is_call = true
|
|
180
|
+
else
|
|
181
|
+
prob_idx = 1 # E9 uses fixed index 1
|
|
182
|
+
is_call = false
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Inline range decoder normalization
|
|
187
|
+
if range < TOP_VALUE
|
|
188
|
+
range = (range << 8) & 0xFFFFFFFF
|
|
189
|
+
rc_byte = rc_pos < rc_size ? rc_data.getbyte(rc_pos) : 0
|
|
190
|
+
code = ((code << 8) | rc_byte) & 0xFFFFFFFF
|
|
191
|
+
rc_pos += 1 if rc_pos < rc_size
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
prob = probs[prob_idx]
|
|
195
|
+
bound = (range >> BIT_MODEL_TOTAL_BITS) * prob
|
|
196
|
+
|
|
197
|
+
if code < bound
|
|
198
|
+
# Bit = 0: not convertible (opcode already written to output)
|
|
199
|
+
range = bound
|
|
200
|
+
probs[prob_idx] = prob + ((BIT_MODEL_TOTAL - prob) >> MOVE_BITS)
|
|
201
|
+
prev_byte = byte
|
|
202
|
+
else
|
|
203
|
+
# Bit = 1: convertible — read 4-byte address from call/jump stream
|
|
204
|
+
range -= bound
|
|
205
|
+
code -= bound
|
|
206
|
+
probs[prob_idx] = prob - (prob >> MOVE_BITS)
|
|
207
|
+
|
|
208
|
+
# Read 4 bytes big-endian from call stream (E8) or jump stream (E9/JCC)
|
|
209
|
+
if is_call
|
|
210
|
+
if call_pos + 4 <= call_size
|
|
211
|
+
addr = call_data.byteslice(call_pos, 4).unpack1("N")
|
|
212
|
+
call_pos += 4
|
|
213
|
+
else
|
|
214
|
+
addr = 0
|
|
215
|
+
4.times do |i|
|
|
216
|
+
break if call_pos >= call_size
|
|
217
|
+
|
|
218
|
+
addr |= call_data.getbyte(call_pos) << (24 - (i * 8))
|
|
219
|
+
call_pos += 1
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
elsif jump_pos + 4 <= jump_size
|
|
223
|
+
addr = jump_data.byteslice(jump_pos, 4).unpack1("N")
|
|
224
|
+
jump_pos += 4
|
|
225
|
+
else
|
|
226
|
+
addr = 0
|
|
227
|
+
4.times do |i|
|
|
228
|
+
break if jump_pos >= jump_size
|
|
229
|
+
|
|
230
|
+
addr |= jump_data.getbyte(jump_pos) << (24 - (i * 8))
|
|
231
|
+
jump_pos += 1
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Convert absolute address to relative (ip already past opcode bytes)
|
|
236
|
+
addr = (addr - (ip + 4)) & 0xFFFFFFFF
|
|
237
|
+
|
|
238
|
+
# Write 4-byte little-endian address directly (no pack/Array alloc)
|
|
239
|
+
result.setbyte(result_pos, addr & 0xFF)
|
|
240
|
+
result.setbyte(result_pos + 1, (addr >> 8) & 0xFF)
|
|
241
|
+
result.setbyte(result_pos + 2, (addr >> 16) & 0xFF)
|
|
242
|
+
result.setbyte(result_pos + 3, (addr >> 24) & 0xFF)
|
|
243
|
+
result_pos += 4
|
|
244
|
+
ip += 4
|
|
245
|
+
prev_byte = (addr >> 24) & 0xFF
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Store final positions back
|
|
250
|
+
@main_pos = main_pos
|
|
251
|
+
@call_pos = call_pos
|
|
252
|
+
@jump_pos = jump_pos
|
|
253
|
+
@rc_pos = rc_pos
|
|
254
|
+
@range = range
|
|
255
|
+
@code = code
|
|
256
|
+
@ip = ip
|
|
257
|
+
|
|
258
|
+
# Return exact output (trim if pre-allocated too large)
|
|
259
|
+
result_pos < result.bytesize ? result.byteslice(0, result_pos) : result
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
# This file is part of Omnizip.
|
|
7
|
+
#
|
|
8
|
+
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
+
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# See the COPYING file for the complete text of the license.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
module Omnizip
|
|
20
|
+
module Filters
|
|
21
|
+
# BCJ2 encoder - splits data into 4 streams.
|
|
22
|
+
#
|
|
23
|
+
# NOTE: BCJ2 encoding is extremely complex and is not yet
|
|
24
|
+
# implemented. This is primarily needed for compression,
|
|
25
|
+
# while decoding (decompression) is the more common use case.
|
|
26
|
+
#
|
|
27
|
+
# BCJ2 encoding requires:
|
|
28
|
+
# - Range encoder implementation
|
|
29
|
+
# - Proper probability model management
|
|
30
|
+
# - Stream splitting logic
|
|
31
|
+
# - Address conversion to absolute
|
|
32
|
+
#
|
|
33
|
+
# This will be implemented in a future version.
|
|
34
|
+
class Bcj2Encoder
|
|
35
|
+
include Bcj2Constants
|
|
36
|
+
|
|
37
|
+
# Initialize encoder.
|
|
38
|
+
#
|
|
39
|
+
# @param data [String] Binary data to encode
|
|
40
|
+
# @param position [Integer] Starting instruction pointer
|
|
41
|
+
def initialize(data, position = 0)
|
|
42
|
+
@data = data
|
|
43
|
+
@position = position
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Encode data into 4 streams.
|
|
47
|
+
#
|
|
48
|
+
# @raise [NotImplementedError] BCJ2 encoding not yet impl
|
|
49
|
+
# @return [Bcj2StreamData] The 4 output streams
|
|
50
|
+
def encode
|
|
51
|
+
raise NotImplementedError,
|
|
52
|
+
"BCJ2 encoding is not yet implemented. " \
|
|
53
|
+
"BCJ2 is primarily used for decompression. " \
|
|
54
|
+
"For compression, use the simpler BCJ-x86 filter."
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
# This file is part of Omnizip.
|
|
7
|
+
#
|
|
8
|
+
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
+
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# See the COPYING file for the complete text of the license.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
module Omnizip
|
|
20
|
+
module Filters
|
|
21
|
+
# Model class representing the 4 BCJ2 streams.
|
|
22
|
+
#
|
|
23
|
+
# BCJ2 splits data into:
|
|
24
|
+
# - Main stream: Non-convertible bytes
|
|
25
|
+
# - Call stream: CALL (E8) instruction addresses
|
|
26
|
+
# - Jump stream: JUMP (E9) instruction addresses
|
|
27
|
+
# - RC stream: Range coder probability data
|
|
28
|
+
class Bcj2StreamData
|
|
29
|
+
include Bcj2Constants
|
|
30
|
+
|
|
31
|
+
attr_accessor :main, :call, :jump, :rc
|
|
32
|
+
|
|
33
|
+
# Initialize empty streams.
|
|
34
|
+
#
|
|
35
|
+
# @return [Bcj2StreamData] New stream data instance
|
|
36
|
+
def initialize
|
|
37
|
+
@main = String.new(encoding: Encoding::BINARY)
|
|
38
|
+
@call = String.new(encoding: Encoding::BINARY)
|
|
39
|
+
@jump = String.new(encoding: Encoding::BINARY)
|
|
40
|
+
@rc = String.new(encoding: Encoding::BINARY)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Get stream by index.
|
|
44
|
+
#
|
|
45
|
+
# @param index [Integer] Stream index (0-3)
|
|
46
|
+
# @return [String] Stream data
|
|
47
|
+
# @raise [ArgumentError] If index is invalid
|
|
48
|
+
def [](index)
|
|
49
|
+
case index
|
|
50
|
+
when STREAM_MAIN then @main
|
|
51
|
+
when STREAM_CALL then @call
|
|
52
|
+
when STREAM_JUMP then @jump
|
|
53
|
+
when STREAM_RC then @rc
|
|
54
|
+
else
|
|
55
|
+
raise ArgumentError, "Invalid stream index: #{index}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Set stream by index.
|
|
60
|
+
#
|
|
61
|
+
# @param index [Integer] Stream index (0-3)
|
|
62
|
+
# @param data [String] Stream data
|
|
63
|
+
# @return [String] The data that was set
|
|
64
|
+
# @raise [ArgumentError] If index is invalid
|
|
65
|
+
def []=(index, data)
|
|
66
|
+
case index
|
|
67
|
+
when STREAM_MAIN then @main = data
|
|
68
|
+
when STREAM_CALL then @call = data
|
|
69
|
+
when STREAM_JUMP then @jump = data
|
|
70
|
+
when STREAM_RC then @rc = data
|
|
71
|
+
else
|
|
72
|
+
raise ArgumentError, "Invalid stream index: #{index}"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Get all streams as an array.
|
|
77
|
+
#
|
|
78
|
+
# @return [Array<String>] Array of 4 streams
|
|
79
|
+
def to_a
|
|
80
|
+
[@main, @call, @jump, @rc]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Check if all streams are empty.
|
|
84
|
+
#
|
|
85
|
+
# @return [Boolean] True if all streams are empty
|
|
86
|
+
def empty?
|
|
87
|
+
@main.empty? && @call.empty? && @jump.empty? && @rc.empty?
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
# This file is part of Omnizip.
|
|
7
|
+
#
|
|
8
|
+
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
+
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# See the COPYING file for the complete text of the license.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
module Omnizip
|
|
20
|
+
module Filters
|
|
21
|
+
# BCJ2 filter for x86/x64 executables (4-stream variant).
|
|
22
|
+
#
|
|
23
|
+
# BCJ2 is an advanced version of BCJ that splits x86 executable code
|
|
24
|
+
# into 4 separate streams for maximum compression:
|
|
25
|
+
# - Main stream: Non-convertible bytes
|
|
26
|
+
# - Call stream: CALL (0xE8) instruction addresses
|
|
27
|
+
# - Jump stream: JUMP (0xE9) instruction addresses
|
|
28
|
+
# - RC stream: Range coder probability data
|
|
29
|
+
#
|
|
30
|
+
# This provides better compression than simple BCJ at the cost of
|
|
31
|
+
# increased complexity. BCJ2 requires special handling in archive
|
|
32
|
+
# formats - the 4 streams must be stored and retrieved separately.
|
|
33
|
+
#
|
|
34
|
+
# NOTE: Currently only decoding (decompression) is implemented.
|
|
35
|
+
# Encoding is extremely complex and will be added in a future version.
|
|
36
|
+
# For compression use cases, the simpler BCJ-x86 filter is recommended.
|
|
37
|
+
class Bcj2 < Omnizip::Filter
|
|
38
|
+
# Encode is not currently supported for BCJ2.
|
|
39
|
+
#
|
|
40
|
+
# @param _data [String] Binary data to encode
|
|
41
|
+
# @param _position [Integer] Current stream position
|
|
42
|
+
# @raise [NotImplementedError] BCJ2 encoding not yet implemented
|
|
43
|
+
# @return [String] Encoded binary data
|
|
44
|
+
def encode(_data, _position = 0)
|
|
45
|
+
raise NotImplementedError,
|
|
46
|
+
"BCJ2 encoding is not yet implemented. " \
|
|
47
|
+
"Use the simpler BCJ-x86 filter for compression, " \
|
|
48
|
+
"or wait for a future version with BCJ2 encoding support."
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Decode (postprocess) BCJ2 data after decompression.
|
|
52
|
+
#
|
|
53
|
+
# This method expects the 4 BCJ2 streams to be provided in a
|
|
54
|
+
# Bcj2StreamData object. In practice, this is called by the archive
|
|
55
|
+
# format reader (e.g., 7z reader) which handles splitting the
|
|
56
|
+
# compressed data into the 4 streams.
|
|
57
|
+
#
|
|
58
|
+
# @param data [Bcj2StreamData, String] The 4 BCJ2 streams or error
|
|
59
|
+
# @param position [Integer] Current stream position
|
|
60
|
+
# @raise [ArgumentError] If data is not a Bcj2StreamData object
|
|
61
|
+
# @return [String] Decoded binary data
|
|
62
|
+
def decode(data, position = 0)
|
|
63
|
+
unless data.is_a?(Bcj2StreamData)
|
|
64
|
+
raise ArgumentError,
|
|
65
|
+
"BCJ2 decode requires a Bcj2StreamData object with " \
|
|
66
|
+
"4 streams. This is typically handled by the archive " \
|
|
67
|
+
"format reader."
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
decoder = Bcj2Decoder.new(data, position)
|
|
71
|
+
decoder.decode
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class << self
|
|
75
|
+
# Get metadata about this filter.
|
|
76
|
+
#
|
|
77
|
+
# @return [Hash] Filter metadata
|
|
78
|
+
def metadata
|
|
79
|
+
{
|
|
80
|
+
name: "BCJ2",
|
|
81
|
+
description: "Advanced 4-stream Branch/Call/Jump converter " \
|
|
82
|
+
"for x86/x64 executables",
|
|
83
|
+
architecture: "x86/x64",
|
|
84
|
+
streams: 4,
|
|
85
|
+
complexity: "high",
|
|
86
|
+
compression_quality: "maximum",
|
|
87
|
+
limitations: "Encoding not yet implemented",
|
|
88
|
+
}
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
# This file is part of Omnizip.
|
|
7
|
+
#
|
|
8
|
+
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
+
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# See the COPYING file for the complete text of the license.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
module Omnizip
|
|
20
|
+
module Filters
|
|
21
|
+
# BCJ filter for 32-bit ARM executables.
|
|
22
|
+
#
|
|
23
|
+
# This filter preprocesses ARM machine code by converting relative
|
|
24
|
+
# addresses in BL (Branch and Link - 0xEB) instructions to absolute
|
|
25
|
+
# addresses. ARM uses 4-byte aligned instructions with little-endian
|
|
26
|
+
# encoding.
|
|
27
|
+
#
|
|
28
|
+
# The filter improves compression by making branch targets
|
|
29
|
+
# position-independent. The offset in ARM BL instructions is stored
|
|
30
|
+
# as word offset (divided by 4), and is relative to PC+8.
|
|
31
|
+
class BcjArm < Omnizip::Filter
|
|
32
|
+
# ARM BL (Branch and Link) opcode
|
|
33
|
+
OPCODE_BL = 0xEB
|
|
34
|
+
|
|
35
|
+
# Size of ARM instruction (4 bytes, little-endian)
|
|
36
|
+
INSTRUCTION_SIZE = 4
|
|
37
|
+
|
|
38
|
+
# Offset mask (24-bit offset in BL instruction)
|
|
39
|
+
OFFSET_MASK = 0x00FFFFFF
|
|
40
|
+
|
|
41
|
+
# Encode (preprocess) ARM executable data for compression.
|
|
42
|
+
#
|
|
43
|
+
# Scans for BL (0xEB) opcodes and converts relative word offsets
|
|
44
|
+
# to absolute word offsets. ARM branch offset is relative to PC+8.
|
|
45
|
+
#
|
|
46
|
+
# @param data [String] Binary executable data
|
|
47
|
+
# @param position [Integer] Current stream position
|
|
48
|
+
# @return [String] Encoded binary data
|
|
49
|
+
def encode(data, position = 0)
|
|
50
|
+
return data.dup if data.bytesize < INSTRUCTION_SIZE
|
|
51
|
+
|
|
52
|
+
result = data.b
|
|
53
|
+
size = data.bytesize & ~(INSTRUCTION_SIZE - 1)
|
|
54
|
+
i = 0
|
|
55
|
+
# PC starts at position + 4 (as per C implementation)
|
|
56
|
+
pc = position + 4
|
|
57
|
+
|
|
58
|
+
while i < size
|
|
59
|
+
# Advance PC to current instruction position
|
|
60
|
+
current_pc = pc + i
|
|
61
|
+
|
|
62
|
+
# Check if last byte is 0xEB (BL instruction)
|
|
63
|
+
if result.getbyte(i + 3) == OPCODE_BL
|
|
64
|
+
# Extract full 32-bit instruction value
|
|
65
|
+
instruction = extract_uint32_le(result, i)
|
|
66
|
+
|
|
67
|
+
# Calculate word offset from PC
|
|
68
|
+
word_offset = current_pc >> 2
|
|
69
|
+
|
|
70
|
+
# Add word offset to instruction value
|
|
71
|
+
instruction += word_offset
|
|
72
|
+
|
|
73
|
+
# Mask to 24-bit and combine with opcode
|
|
74
|
+
instruction = (instruction & OFFSET_MASK) | 0xEB000000
|
|
75
|
+
|
|
76
|
+
write_uint32_le(result, i, instruction)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
i += INSTRUCTION_SIZE
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
result
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Decode (postprocess) ARM executable data after decompression.
|
|
86
|
+
#
|
|
87
|
+
# Reverses the encoding by converting absolute word offsets back to
|
|
88
|
+
# relative word offsets.
|
|
89
|
+
#
|
|
90
|
+
# @param data [String] Binary executable data
|
|
91
|
+
# @param position [Integer] Current stream position
|
|
92
|
+
# @return [String] Decoded binary data
|
|
93
|
+
def decode(data, position = 0)
|
|
94
|
+
return data.dup if data.bytesize < INSTRUCTION_SIZE
|
|
95
|
+
|
|
96
|
+
result = data.b
|
|
97
|
+
size = data.bytesize & ~(INSTRUCTION_SIZE - 1)
|
|
98
|
+
i = 0
|
|
99
|
+
# PC starts at position + 4 (as per C implementation)
|
|
100
|
+
pc = position + 4
|
|
101
|
+
|
|
102
|
+
while i < size
|
|
103
|
+
# Advance PC to current instruction position
|
|
104
|
+
current_pc = pc + i
|
|
105
|
+
|
|
106
|
+
# Check if last byte is 0xEB (BL instruction)
|
|
107
|
+
if result.getbyte(i + 3) == OPCODE_BL
|
|
108
|
+
# Extract full 32-bit instruction value
|
|
109
|
+
instruction = extract_uint32_le(result, i)
|
|
110
|
+
|
|
111
|
+
# Calculate word offset from PC
|
|
112
|
+
word_offset = current_pc >> 2
|
|
113
|
+
|
|
114
|
+
# Subtract word offset from instruction value
|
|
115
|
+
instruction -= word_offset
|
|
116
|
+
|
|
117
|
+
# Mask to 24-bit and combine with opcode
|
|
118
|
+
instruction = (instruction & OFFSET_MASK) | 0xEB000000
|
|
119
|
+
|
|
120
|
+
write_uint32_le(result, i, instruction)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
i += INSTRUCTION_SIZE
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
result
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
class << self
|
|
130
|
+
# Get metadata about this filter.
|
|
131
|
+
#
|
|
132
|
+
# @return [Hash] Filter metadata
|
|
133
|
+
def metadata
|
|
134
|
+
{
|
|
135
|
+
name: "BCJ-ARM",
|
|
136
|
+
description: "Branch converter for 32-bit ARM executables",
|
|
137
|
+
architecture: "ARM (32-bit)",
|
|
138
|
+
alignment: 4,
|
|
139
|
+
endian: "little",
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
private
|
|
145
|
+
|
|
146
|
+
# Extract an unsigned 32-bit little-endian integer from data.
|
|
147
|
+
#
|
|
148
|
+
# @param data [String] Binary data
|
|
149
|
+
# @param offset [Integer] Starting position
|
|
150
|
+
# @return [Integer] Unsigned 32-bit integer
|
|
151
|
+
def extract_uint32_le(data, offset)
|
|
152
|
+
bytes = data.byteslice(offset, INSTRUCTION_SIZE).bytes
|
|
153
|
+
bytes[0] |
|
|
154
|
+
(bytes[1] << 8) |
|
|
155
|
+
(bytes[2] << 16) |
|
|
156
|
+
(bytes[3] << 24)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Write an unsigned 32-bit little-endian integer to data.
|
|
160
|
+
#
|
|
161
|
+
# @param data [String] Binary data (modified in place)
|
|
162
|
+
# @param offset [Integer] Starting position
|
|
163
|
+
# @param value [Integer] 32-bit integer to write
|
|
164
|
+
# @return [void]
|
|
165
|
+
def write_uint32_le(data, offset, value)
|
|
166
|
+
value &= 0xFFFFFFFF
|
|
167
|
+
data.setbyte(offset, value & 0xFF)
|
|
168
|
+
data.setbyte(offset + 1, (value >> 8) & 0xFF)
|
|
169
|
+
data.setbyte(offset + 2, (value >> 16) & 0xFF)
|
|
170
|
+
data.setbyte(offset + 3, (value >> 24) & 0xFF)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|