omnizip 0.4.7-aarch64-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,142 @@
|
|
|
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 Algorithms
|
|
27
|
+
# Base class for PPMd (Prediction by Partial Matching) algorithms
|
|
28
|
+
#
|
|
29
|
+
# This abstract base class provides common functionality for PPMd
|
|
30
|
+
# variants (PPMd7, PPMd8, etc.) while allowing each variant to
|
|
31
|
+
# implement its specific features.
|
|
32
|
+
#
|
|
33
|
+
# The design follows the Template Method pattern, where common
|
|
34
|
+
# operations are defined here and variant-specific operations
|
|
35
|
+
# are delegated to subclasses.
|
|
36
|
+
class PPMdBase < Algorithm
|
|
37
|
+
# Common constants for all PPMd variants
|
|
38
|
+
module BaseConstants
|
|
39
|
+
# Context order limits
|
|
40
|
+
MIN_ORDER = 2
|
|
41
|
+
MAX_ORDER = 16
|
|
42
|
+
DEFAULT_ORDER = 6
|
|
43
|
+
|
|
44
|
+
# Memory allocation
|
|
45
|
+
MIN_MEM_SIZE = 1 << 20 # 1 MB
|
|
46
|
+
MAX_MEM_SIZE = 1 << 30 # 1 GB
|
|
47
|
+
DEFAULT_MEM_SIZE = 1 << 24 # 16 MB
|
|
48
|
+
|
|
49
|
+
# Alphabet
|
|
50
|
+
ALPHABET_SIZE = 256
|
|
51
|
+
|
|
52
|
+
# Range coder constants
|
|
53
|
+
TOP_VALUE = 1 << 24
|
|
54
|
+
BOT_VALUE = 1 << 15
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
include BaseConstants
|
|
58
|
+
|
|
59
|
+
# Compress data using PPMd variant
|
|
60
|
+
#
|
|
61
|
+
# @param input [IO, String] Input data to compress
|
|
62
|
+
# @param output [IO, String] Output for compressed data
|
|
63
|
+
# @param options [Hash] Compression options
|
|
64
|
+
# @return [void]
|
|
65
|
+
def compress(input, output, options = {})
|
|
66
|
+
input = prepare_input(input)
|
|
67
|
+
output = prepare_output(output)
|
|
68
|
+
|
|
69
|
+
encoder = create_encoder(output, options)
|
|
70
|
+
encoder.encode_stream(input)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Decompress data using PPMd variant
|
|
74
|
+
#
|
|
75
|
+
# @param input [IO, String] Compressed input data
|
|
76
|
+
# @param output [IO, String] Output for decompressed data
|
|
77
|
+
# @param options [Hash] Decompression options
|
|
78
|
+
# @return [void]
|
|
79
|
+
def decompress(input, output, options = {})
|
|
80
|
+
input = prepare_input(input)
|
|
81
|
+
output = prepare_output(output)
|
|
82
|
+
|
|
83
|
+
decoder = create_decoder(input, options)
|
|
84
|
+
result = decoder.decode_stream
|
|
85
|
+
|
|
86
|
+
output.write(result)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
protected
|
|
90
|
+
|
|
91
|
+
# Template method for creating encoder
|
|
92
|
+
# Subclasses must implement this
|
|
93
|
+
#
|
|
94
|
+
# @param output [IO] Output stream
|
|
95
|
+
# @param options [Hash] Encoding options
|
|
96
|
+
# @return [Object] Encoder instance
|
|
97
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
98
|
+
def create_encoder(output, options)
|
|
99
|
+
raise NotImplementedError,
|
|
100
|
+
"#{self.class} must implement #create_encoder"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Template method for creating decoder
|
|
104
|
+
# Subclasses must implement this
|
|
105
|
+
#
|
|
106
|
+
# @param input [IO] Input stream
|
|
107
|
+
# @param options [Hash] Decoding options
|
|
108
|
+
# @return [Object] Decoder instance
|
|
109
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
110
|
+
def create_decoder(input, options)
|
|
111
|
+
raise NotImplementedError,
|
|
112
|
+
"#{self.class} must implement #create_decoder"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
# Prepare input for processing
|
|
118
|
+
#
|
|
119
|
+
# @param input [IO, String] Input data
|
|
120
|
+
# @return [IO] IO object ready for reading
|
|
121
|
+
def prepare_input(input)
|
|
122
|
+
# StringIO is not an ::IO, and its #to_s is Kernel's (the
|
|
123
|
+
# INSPECT string) — pass anything readable straight through.
|
|
124
|
+
return input if input.respond_to?(:read) # allowed: IO-duck detection — StringIO must pass through (its #to_s is the INSPECT string)
|
|
125
|
+
|
|
126
|
+
StringIO.new(input.to_s)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Prepare output for processing
|
|
130
|
+
#
|
|
131
|
+
# @param output [IO, String, nil] Output destination
|
|
132
|
+
# @return [IO] IO object ready for writing
|
|
133
|
+
def prepare_output(output)
|
|
134
|
+
# StringIO is not an ::IO subclass — the old check discarded
|
|
135
|
+
# it for a fresh buffer, silently dropping the output.
|
|
136
|
+
return output if output.is_a?(IO) || output.is_a?(StringIO)
|
|
137
|
+
|
|
138
|
+
StringIO.new(String.new(encoding: Encoding::BINARY))
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Algorithm registration - triggers autoload and registers all algorithms
|
|
4
|
+
# This file should be required after algorithms.rb which sets up autoloads
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Algorithms
|
|
8
|
+
# Touch constants to trigger autoload, then register
|
|
9
|
+
LZMA
|
|
10
|
+
LZMA2
|
|
11
|
+
PPMd7
|
|
12
|
+
PPMd8
|
|
13
|
+
BZip2
|
|
14
|
+
Deflate
|
|
15
|
+
Deflate64
|
|
16
|
+
Zstandard
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Now register all algorithms
|
|
21
|
+
Omnizip::AlgorithmRegistry.register(:lzma, Omnizip::Algorithms::LZMA)
|
|
22
|
+
Omnizip::Algorithms::LZMA2.register_algorithm
|
|
23
|
+
Omnizip::AlgorithmRegistry.register(:ppmd7, Omnizip::Algorithms::PPMd7)
|
|
24
|
+
Omnizip::AlgorithmRegistry.register(:ppmd8, Omnizip::Algorithms::PPMd8)
|
|
25
|
+
Omnizip::AlgorithmRegistry.register(:bzip2, Omnizip::Algorithms::BZip2)
|
|
26
|
+
Omnizip::AlgorithmRegistry.register(:deflate, Omnizip::Algorithms::Deflate)
|
|
27
|
+
Omnizip::AlgorithmRegistry.register(:deflate64, Omnizip::Algorithms::Deflate64)
|
|
28
|
+
Omnizip::AlgorithmRegistry.register(:zstandard, Omnizip::Algorithms::Zstandard)
|
|
@@ -0,0 +1,158 @@
|
|
|
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
|
+
module Omnizip
|
|
24
|
+
module Algorithms
|
|
25
|
+
class Zstandard
|
|
26
|
+
# Constants from RFC 8878 (Zstandard Compression)
|
|
27
|
+
#
|
|
28
|
+
# @see https://datatracker.ietf.org/doc/html/rfc8878
|
|
29
|
+
module Constants
|
|
30
|
+
# Frame Constants
|
|
31
|
+
MAGIC_NUMBER = 0xFD2FB528
|
|
32
|
+
MAGIC_BYTES = [0x28, 0xB5, 0x2F, 0xFD].freeze
|
|
33
|
+
SKIPPABLE_MAGIC_BASE = 0x184D2A50
|
|
34
|
+
SKIPPABLE_MAGIC_MASK = 0xFFFFFFF0
|
|
35
|
+
|
|
36
|
+
# Block Types (RFC 8878 Section 3.1.1.2)
|
|
37
|
+
BLOCK_TYPE_RAW = 0
|
|
38
|
+
BLOCK_TYPE_RLE = 1
|
|
39
|
+
BLOCK_TYPE_COMPRESSED = 2
|
|
40
|
+
BLOCK_TYPE_RESERVED = 3
|
|
41
|
+
BLOCK_HEADER_SIZE = 3
|
|
42
|
+
BLOCK_MAX_SIZE = 128 * 1024
|
|
43
|
+
|
|
44
|
+
# Literals Block Types (RFC 8878 Section 3.1.1.3.1)
|
|
45
|
+
LITERALS_BLOCK_RAW = 0
|
|
46
|
+
LITERALS_BLOCK_RLE = 1
|
|
47
|
+
LITERALS_BLOCK_COMPRESSED = 2
|
|
48
|
+
LITERALS_BLOCK_TREELESS = 3
|
|
49
|
+
HUFFMAN_MAX_BITS = 11
|
|
50
|
+
|
|
51
|
+
# Sequence Compression Modes (RFC 8878 Section 3.1.1.3.2)
|
|
52
|
+
MODE_PREDEFINED = 0
|
|
53
|
+
MODE_RLE = 1
|
|
54
|
+
MODE_FSE = 2
|
|
55
|
+
MODE_REPEAT = 3
|
|
56
|
+
|
|
57
|
+
# FSE Accuracy Logs (RFC 8878 Section 4)
|
|
58
|
+
LITERALS_LENGTH_ACCURACY_LOG = 6
|
|
59
|
+
MATCH_LENGTH_ACCURACY_LOG = 6
|
|
60
|
+
OFFSET_ACCURACY_LOG = 5
|
|
61
|
+
|
|
62
|
+
# Repeat Offsets (RFC 8878 Section 3.1.2.2.3)
|
|
63
|
+
REPEAT_OFFSET_1 = 1
|
|
64
|
+
REPEAT_OFFSET_2 = 2
|
|
65
|
+
REPEAT_OFFSET_3 = 3
|
|
66
|
+
DEFAULT_REPEAT_OFFSETS = [1, 4, 8].freeze
|
|
67
|
+
|
|
68
|
+
# Window Constants (RFC 8878 Section 3.1.1.1.2)
|
|
69
|
+
WINDOW_LOG_MIN = 10
|
|
70
|
+
WINDOW_LOG_MAX = 41
|
|
71
|
+
|
|
72
|
+
# Huffman Constants (RFC 8878 Section 4.2.1)
|
|
73
|
+
HUFFMAN_MAX_LOG = 11
|
|
74
|
+
HUFFMAN_MAX_CODE_LENGTH = 11
|
|
75
|
+
HUFFMAN_STANDARD_TABLE_SIZE = 256
|
|
76
|
+
HUF_SYMBOLVALUE_MAX = 255
|
|
77
|
+
|
|
78
|
+
# FSE Table Limits (RFC 8878 Section 4.1)
|
|
79
|
+
FSE_MAX_ACCURACY_LOG = 9
|
|
80
|
+
FSE_MIN_ACCURACY_LOG = 5
|
|
81
|
+
FSE_DEFAULT_TABLELOG = 6
|
|
82
|
+
|
|
83
|
+
# Compression levels
|
|
84
|
+
MIN_LEVEL = 1
|
|
85
|
+
MAX_LEVEL = 22
|
|
86
|
+
DEFAULT_LEVEL = 3
|
|
87
|
+
|
|
88
|
+
# Long-distance matching kicks in at this level for inputs
|
|
89
|
+
# larger than one block (Btultra2 in the C strategy table).
|
|
90
|
+
LDM_MIN_LEVEL = 19
|
|
91
|
+
|
|
92
|
+
# Buffer size for streaming operations
|
|
93
|
+
BUFFER_SIZE = 128 * 1024 # 128KB
|
|
94
|
+
|
|
95
|
+
# Literal length codes (RFC 8878 Table: literals length codes)
|
|
96
|
+
# Each entry: [baseline, extra_bits]
|
|
97
|
+
LITERAL_LENGTH_TABLE = [
|
|
98
|
+
[0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0],
|
|
99
|
+
[8, 0], [9, 0], [10, 0], [11, 0], [12, 0], [13, 0], [14, 0], [15, 0],
|
|
100
|
+
[16, 1], [18, 1], [20, 1], [22, 1], [24, 2], [28, 2], [32, 3], [40, 3],
|
|
101
|
+
[48, 4], [64, 6], [128, 7], [256, 8], [512, 9], [1024, 10], [2048, 11],
|
|
102
|
+
[4096, 12], [8192, 13], [16384, 14], [32768, 15], [65536, 16]
|
|
103
|
+
].freeze
|
|
104
|
+
|
|
105
|
+
# Match length codes (RFC 8878 Table: match length codes, 53 entries)
|
|
106
|
+
# Each entry: [baseline, extra_bits]
|
|
107
|
+
MATCH_LENGTH_TABLE = [
|
|
108
|
+
[3, 0], [4, 0], [5, 0], [6, 0], [7, 0], [8, 0], [9, 0], [10, 0],
|
|
109
|
+
[11, 0], [12, 0], [13, 0], [14, 0], [15, 0], [16, 0], [17, 0], [18, 0],
|
|
110
|
+
[19, 0], [20, 0], [21, 0], [22, 0], [23, 0], [24, 0], [25, 0], [26, 0],
|
|
111
|
+
[27, 0], [28, 0], [29, 0], [30, 0], [31, 0], [32, 0], [33, 0], [34, 0],
|
|
112
|
+
[35, 1], [37, 1], [39, 1], [41, 1], [43, 2], [47, 2], [51, 3], [59, 3],
|
|
113
|
+
[67, 4], [83, 4], [99, 5], [131, 7], [259, 8], [515, 9], [1027, 10],
|
|
114
|
+
[2051, 11], [4099, 12], [8195, 13], [16387, 14], [32771, 15], [65539, 16]
|
|
115
|
+
].freeze
|
|
116
|
+
|
|
117
|
+
# Offset codes (RFC 8878 Section 3.1.2.2.3.2)
|
|
118
|
+
# OF_BASE[c] + read(c bits) = match distance for c >= 2; codes 0 and
|
|
119
|
+
# 1 are the repeat-offset specials handled by the executor.
|
|
120
|
+
OF_BASE = [
|
|
121
|
+
0, 1, 1, 5, 13, 29, 61, 125, 253, 509, 1021, 2045, 4093, 8189,
|
|
122
|
+
16381, 32765, 65533, 131069, 262141, 524285, 1048573, 2097149,
|
|
123
|
+
4194301, 8388605, 16777213, 33554429, 67108861, 134217725,
|
|
124
|
+
268435453, 536870909, 1073741821, 2147483645
|
|
125
|
+
].freeze
|
|
126
|
+
OF_BITS = (0..31).to_a.freeze
|
|
127
|
+
|
|
128
|
+
# Predefined FSE distributions (RFC 8878 Section 4.1.3, matching
|
|
129
|
+
# the zstd C reference). -1 marks a "less than 1" probability that
|
|
130
|
+
# occupies a single cell at the top of the table.
|
|
131
|
+
PREDEFINED_LL_DISTRIBUTION = [
|
|
132
|
+
4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
|
|
133
|
+
2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
|
|
134
|
+
-1, -1, -1, -1
|
|
135
|
+
].freeze
|
|
136
|
+
|
|
137
|
+
# Sum: 4+3+2*11+1*3 + 2*8+3+2*2+1*5 = 32 + 32 = 64 = 2^6
|
|
138
|
+
PREDEFINED_ML_DISTRIBUTION = [
|
|
139
|
+
1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
|
|
140
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
141
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
|
|
142
|
+
-1, -1, -1, -1, -1
|
|
143
|
+
].freeze
|
|
144
|
+
|
|
145
|
+
# Sum: 27 positive + 5 low-probability = 32 = 2^5
|
|
146
|
+
PREDEFINED_OFFSET_DISTRIBUTION = [
|
|
147
|
+
1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
|
|
148
|
+
1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 0, 0, 0
|
|
149
|
+
].freeze
|
|
150
|
+
|
|
151
|
+
# floor(log2(x)); 0 for x == 0 (C ZSTD_highbit32 defensive value)
|
|
152
|
+
def self.highbit32(value)
|
|
153
|
+
value.zero? ? 0 : value.bit_length - 1
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,249 @@
|
|
|
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
|
+
module Omnizip
|
|
24
|
+
module Algorithms
|
|
25
|
+
class Zstandard
|
|
26
|
+
# Pure Ruby Zstandard decoder (RFC 8878).
|
|
27
|
+
#
|
|
28
|
+
# Pipeline:
|
|
29
|
+
#
|
|
30
|
+
# 1. For each frame: parse the frame header and reset per-frame
|
|
31
|
+
# state (repeat offsets, previous Huffman table, previous FSE
|
|
32
|
+
# tables).
|
|
33
|
+
# 2. For each block: parse the 3-byte block header and dispatch on
|
|
34
|
+
# the block type (raw copy, RLE expansion, or compressed =
|
|
35
|
+
# literals + sequences).
|
|
36
|
+
# 3. Verify the optional content checksum: the low 32 bits of
|
|
37
|
+
# XXHash64 over the decoded frame content.
|
|
38
|
+
class Decoder
|
|
39
|
+
include Constants
|
|
40
|
+
|
|
41
|
+
# @return [IO] input stream
|
|
42
|
+
attr_reader :input_stream
|
|
43
|
+
|
|
44
|
+
def initialize(input_stream)
|
|
45
|
+
@input_stream = input_stream
|
|
46
|
+
@executor = SequenceExecutor.new
|
|
47
|
+
@previous_huffman_table = nil
|
|
48
|
+
@previous_fse_tables = {}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Decode a complete stream (one or more concatenated frames).
|
|
52
|
+
#
|
|
53
|
+
# @return [String] decompressed data (binary)
|
|
54
|
+
def decode_stream
|
|
55
|
+
data = read_all
|
|
56
|
+
output = String.new(encoding: Encoding::BINARY)
|
|
57
|
+
pos = 0
|
|
58
|
+
|
|
59
|
+
loop do
|
|
60
|
+
remaining = data.bytesize - pos
|
|
61
|
+
break if remaining.zero?
|
|
62
|
+
raise Omnizip::DecompressionError, "trailing bytes are not a frame" if remaining < 4
|
|
63
|
+
|
|
64
|
+
magic = data.byteslice(pos, 4).unpack1("V")
|
|
65
|
+
|
|
66
|
+
if (magic & SKIPPABLE_MAGIC_MASK) == SKIPPABLE_MAGIC_BASE
|
|
67
|
+
pos = skip_skippable_frame(data, pos)
|
|
68
|
+
next
|
|
69
|
+
end
|
|
70
|
+
unless magic == MAGIC_NUMBER
|
|
71
|
+
raise Omnizip::DecompressionError,
|
|
72
|
+
"invalid Zstandard magic: 0x#{magic.to_s(16)}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
frame_output, pos = decode_frame(data, pos + 4)
|
|
76
|
+
output << frame_output
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
output
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Decode a stream produced by a dictionary-primed encoder: the
|
|
83
|
+
# dictionary's content primes the reconstruction window of
|
|
84
|
+
# frames carrying its ID (verified; mismatch raises).
|
|
85
|
+
#
|
|
86
|
+
# @param dict [Dictionary]
|
|
87
|
+
# @return [String] decompressed data (binary)
|
|
88
|
+
def decode_stream_with_dict(dict)
|
|
89
|
+
data = read_all
|
|
90
|
+
output = String.new(encoding: Encoding::BINARY)
|
|
91
|
+
pos = 0
|
|
92
|
+
|
|
93
|
+
loop do
|
|
94
|
+
remaining = data.bytesize - pos
|
|
95
|
+
break if remaining.zero?
|
|
96
|
+
raise Omnizip::DecompressionError, "trailing bytes are not a frame" if remaining < 4
|
|
97
|
+
|
|
98
|
+
magic = data.byteslice(pos, 4).unpack1("V")
|
|
99
|
+
unless magic == MAGIC_NUMBER
|
|
100
|
+
raise Omnizip::DecompressionError,
|
|
101
|
+
"invalid Zstandard magic: 0x#{magic.to_s(16)}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
frame_output, pos = decode_frame(data, pos + 4, dict)
|
|
105
|
+
output << frame_output
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
output
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def read_all
|
|
114
|
+
data = @input_stream.read
|
|
115
|
+
data ||= ""
|
|
116
|
+
data.dup.force_encoding(Encoding::BINARY)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def skip_skippable_frame(data, pos)
|
|
120
|
+
raise Omnizip::DecompressionError, "truncated skippable frame" if data.bytesize < pos + 8
|
|
121
|
+
|
|
122
|
+
size = data.byteslice(pos + 4, 4).unpack1("V")
|
|
123
|
+
end_pos = pos + 8 + size
|
|
124
|
+
if data.bytesize < end_pos
|
|
125
|
+
raise Omnizip::DecompressionError, "truncated skippable frame body"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
end_pos
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Decode one frame (input positioned after the magic).
|
|
132
|
+
# Returns [frame_output, pos_after_frame].
|
|
133
|
+
#
|
|
134
|
+
# With a dictionary prefix, the reconstruction window is
|
|
135
|
+
# primed with the dictionary content so sequences can
|
|
136
|
+
# back-reference it; the prefix is verified (checksum) and
|
|
137
|
+
# stripped from the returned output.
|
|
138
|
+
def decode_frame(data, pos, dict = nil)
|
|
139
|
+
header, pos = Frame::Header.parse_from(data, pos)
|
|
140
|
+
verify_dictionary_id(header, dict)
|
|
141
|
+
prefix = dict&.content
|
|
142
|
+
|
|
143
|
+
# Reset per-frame state: repeat offsets, previous Huffman
|
|
144
|
+
# table, previous FSE tables.
|
|
145
|
+
@executor = SequenceExecutor.new
|
|
146
|
+
@previous_huffman_table = nil
|
|
147
|
+
@previous_fse_tables = {}
|
|
148
|
+
|
|
149
|
+
output = String.new(encoding: Encoding::BINARY)
|
|
150
|
+
output << prefix if prefix
|
|
151
|
+
loop do
|
|
152
|
+
block, pos = Frame::Block.parse_from(data, pos)
|
|
153
|
+
if block.reserved?
|
|
154
|
+
raise Omnizip::DecompressionError,
|
|
155
|
+
"reserved block type in frame"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
pos = decode_block(block, data, pos, output)
|
|
159
|
+
break if block.last_block
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
if header.content_checksum?
|
|
163
|
+
if data.bytesize < pos + 4
|
|
164
|
+
raise Omnizip::DecompressionError, "truncated frame checksum"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
expected = data.byteslice(pos, 4).unpack1("V")
|
|
168
|
+
actual = XXHash64.frame_checksum(
|
|
169
|
+
prefix ? output.byteslice(prefix.bytesize..) : output,
|
|
170
|
+
)
|
|
171
|
+
if expected != actual
|
|
172
|
+
raise Omnizip::DecompressionError,
|
|
173
|
+
"frame checksum mismatch: stored 0x#{expected.to_s(16)}, " \
|
|
174
|
+
"computed 0x#{actual.to_s(16)}"
|
|
175
|
+
end
|
|
176
|
+
pos += 4
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
frame_output = prefix ? output.byteslice(prefix.bytesize..) : output
|
|
180
|
+
[frame_output, pos]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# A frame that carries a Dictionary_ID must be decoded with a
|
|
184
|
+
# dictionary of the same ID; a mismatched or missing
|
|
185
|
+
# dictionary would silently garble every back-reference.
|
|
186
|
+
def verify_dictionary_id(header, dict)
|
|
187
|
+
return unless header.dictionary_id?
|
|
188
|
+
|
|
189
|
+
frame_id = header.dictionary_id
|
|
190
|
+
if dict.nil?
|
|
191
|
+
raise Omnizip::DecompressionError,
|
|
192
|
+
"frame requires dictionary #{frame_id}, none supplied"
|
|
193
|
+
end
|
|
194
|
+
return if dict.id == frame_id
|
|
195
|
+
|
|
196
|
+
raise Omnizip::DecompressionError,
|
|
197
|
+
"frame requires dictionary #{frame_id}, got #{dict.id}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Decode one block into `output`. Returns the position after
|
|
201
|
+
# the block's payload.
|
|
202
|
+
def decode_block(block, data, pos, output)
|
|
203
|
+
case block.block_type
|
|
204
|
+
when BLOCK_TYPE_RAW
|
|
205
|
+
if data.bytesize < pos + block.block_size
|
|
206
|
+
raise Omnizip::DecompressionError, "truncated raw block"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
output << data.byteslice(pos, block.block_size)
|
|
210
|
+
pos + block.block_size
|
|
211
|
+
when BLOCK_TYPE_RLE
|
|
212
|
+
raise Omnizip::DecompressionError, "truncated RLE block" if data.bytesize < pos + 1
|
|
213
|
+
|
|
214
|
+
output << (data.getbyte(pos).chr * block.block_size)
|
|
215
|
+
pos + 1
|
|
216
|
+
when BLOCK_TYPE_COMPRESSED
|
|
217
|
+
block_end = pos + block.block_size
|
|
218
|
+
if data.bytesize < block_end
|
|
219
|
+
raise Omnizip::DecompressionError, "truncated compressed block"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
decode_compressed_block(data.byteslice(pos...block_end), output)
|
|
223
|
+
block_end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def decode_compressed_block(block_input, output)
|
|
228
|
+
literals_decoder = LiteralsDecoder.decode(block_input,
|
|
229
|
+
@previous_huffman_table)
|
|
230
|
+
@previous_huffman_table = literals_decoder.huffman_table ||
|
|
231
|
+
@previous_huffman_table
|
|
232
|
+
|
|
233
|
+
sequences_decoder = SequencesDecoder.decode(
|
|
234
|
+
block_input.byteslice(literals_decoder.consumed..),
|
|
235
|
+
@previous_fse_tables,
|
|
236
|
+
@executor,
|
|
237
|
+
)
|
|
238
|
+
# Merge: Repeat-mode tables are not re-emitted, so the entries
|
|
239
|
+
# carried from earlier blocks must survive.
|
|
240
|
+
@previous_fse_tables =
|
|
241
|
+
@previous_fse_tables.merge(sequences_decoder.fse_tables)
|
|
242
|
+
|
|
243
|
+
@executor.execute(literals_decoder.literals,
|
|
244
|
+
sequences_decoder.sequences, output)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
module Omnizip
|
|
24
|
+
module Algorithms
|
|
25
|
+
class Zstandard
|
|
26
|
+
# Zstandard dictionary (port of the omnizip-rs dict.rs).
|
|
27
|
+
#
|
|
28
|
+
# A dictionary lets the encoder preload a reference-content
|
|
29
|
+
# window so small inputs compress dramatically better: the
|
|
30
|
+
# dictionary content is used as a match-finder prefix, and the
|
|
31
|
+
# frame header carries the dictionary's ID.
|
|
32
|
+
#
|
|
33
|
+
# Wire format (simplified form, as in the Rust reference):
|
|
34
|
+
# magic (4) + dictionary ID (4, LE) + raw content.
|
|
35
|
+
class Dictionary
|
|
36
|
+
DICT_MAGIC = 0xEC30A437
|
|
37
|
+
|
|
38
|
+
attr_reader :id, :content
|
|
39
|
+
|
|
40
|
+
# @param id [Integer] dictionary ID carried in frame headers
|
|
41
|
+
# @param content [String] corpus bytes used as the prefix
|
|
42
|
+
def initialize(id, content)
|
|
43
|
+
@id = id
|
|
44
|
+
@content = content.dup.force_encoding(Encoding::BINARY)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.from_raw(id, content)
|
|
48
|
+
new(id, content)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.deserialize(data)
|
|
52
|
+
if data.bytesize < 8
|
|
53
|
+
raise Omnizip::DecompressionError,
|
|
54
|
+
"dictionary too short for magic + id"
|
|
55
|
+
end
|
|
56
|
+
if data.byteslice(0, 4).unpack1("V") != DICT_MAGIC
|
|
57
|
+
raise Omnizip::DecompressionError, "bad dictionary magic"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
new(data.byteslice(4, 4).unpack1("V"), data.byteslice(8..))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def serialize
|
|
64
|
+
[DICT_MAGIC].pack("V") + [@id].pack("V") + @content
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def ==(other)
|
|
68
|
+
other.is_a?(Dictionary) && id == other.id && content == other.content
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|