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,350 @@
|
|
|
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
|
+
# Sequences section decoder (RFC 8878 §3.1.1.3.2) and the LZ77
|
|
27
|
+
# executor (§3.1.2).
|
|
28
|
+
#
|
|
29
|
+
# Decoding follows the C reference ZSTD_decodeSequence:
|
|
30
|
+
#
|
|
31
|
+
# - State initialization order: LL, OF, ML.
|
|
32
|
+
# - Per sequence: resolve the offset first (reading its extra
|
|
33
|
+
# bits and updating the repeat-offset slots), then read the ML
|
|
34
|
+
# extra bits, then the LL extra bits.
|
|
35
|
+
# - State updates (non-last sequences) in order LL, ML, OF.
|
|
36
|
+
class SequencesDecoder
|
|
37
|
+
include Constants
|
|
38
|
+
|
|
39
|
+
Sequence = Struct.new(:literal_length, :match_length, :offset)
|
|
40
|
+
|
|
41
|
+
# @return [Array<Sequence>]
|
|
42
|
+
attr_reader :sequences
|
|
43
|
+
|
|
44
|
+
# @return [Hash] FSE tables for the next block's Repeat mode
|
|
45
|
+
attr_reader :fse_tables
|
|
46
|
+
|
|
47
|
+
# Decode the sequences section at the head of `input`.
|
|
48
|
+
#
|
|
49
|
+
# @param input [String]
|
|
50
|
+
# @param previous_tables [Hash] tables carried from the previous
|
|
51
|
+
# compressed block (:ll, :ml, :of entries)
|
|
52
|
+
# @param executor [SequenceExecutor] repeat-offset state,
|
|
53
|
+
# updated in place while decoding
|
|
54
|
+
# @return [SequencesDecoder]
|
|
55
|
+
def self.decode(input, previous_tables = {}, executor = nil)
|
|
56
|
+
new(input, previous_tables, executor || SequenceExecutor.new).decode_section
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def initialize(input, previous_tables, executor)
|
|
60
|
+
@input = input
|
|
61
|
+
@previous_tables = previous_tables
|
|
62
|
+
@executor = executor
|
|
63
|
+
@sequences = []
|
|
64
|
+
@fse_tables = {}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# rubocop:disable Metrics/MethodLength
|
|
68
|
+
# rubocop:disable Metrics/AbcSize
|
|
69
|
+
def decode_section
|
|
70
|
+
num_sequences, offset = read_sequence_count
|
|
71
|
+
return self if num_sequences.zero?
|
|
72
|
+
|
|
73
|
+
if @input.bytesize <= offset
|
|
74
|
+
raise Omnizip::DecompressionError,
|
|
75
|
+
"truncated sequences section: missing modes byte"
|
|
76
|
+
end
|
|
77
|
+
# rubocop:enable Metrics/AbcSize
|
|
78
|
+
|
|
79
|
+
modes = @input.getbyte(offset)
|
|
80
|
+
ll_mode = (modes >> 6) & 0x03
|
|
81
|
+
of_mode = (modes >> 4) & 0x03
|
|
82
|
+
ml_mode = (modes >> 2) & 0x03
|
|
83
|
+
|
|
84
|
+
cursor = offset + 1
|
|
85
|
+
@ll_table, cursor = build_table(ll_mode, :ll,
|
|
86
|
+
PREDEFINED_LL_DISTRIBUTION,
|
|
87
|
+
LITERALS_LENGTH_ACCURACY_LOG, cursor)
|
|
88
|
+
@of_table, cursor = build_table(of_mode, :of,
|
|
89
|
+
PREDEFINED_OFFSET_DISTRIBUTION,
|
|
90
|
+
OFFSET_ACCURACY_LOG, cursor)
|
|
91
|
+
@ml_table, cursor = build_table(ml_mode, :ml,
|
|
92
|
+
PREDEFINED_ML_DISTRIBUTION,
|
|
93
|
+
MATCH_LENGTH_ACCURACY_LOG, cursor)
|
|
94
|
+
|
|
95
|
+
decode_sequences(num_sequences, @input.byteslice(cursor..))
|
|
96
|
+
self
|
|
97
|
+
end
|
|
98
|
+
# rubocop:enable Metrics/AbcSize
|
|
99
|
+
# rubocop:enable Metrics/MethodLength
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
# Sequence count: 1-3 bytes (RFC 8878 §3.1.1.3.2.1).
|
|
104
|
+
# rubocop:disable Metrics/AbcSize
|
|
105
|
+
def read_sequence_count
|
|
106
|
+
b0 = @input.getbyte(0)
|
|
107
|
+
if b0 < 0x80
|
|
108
|
+
[b0, 1]
|
|
109
|
+
elsif b0 == 0xFF
|
|
110
|
+
if @input.bytesize < 3
|
|
111
|
+
raise Omnizip::DecompressionError,
|
|
112
|
+
"truncated 3-byte sequence count"
|
|
113
|
+
end
|
|
114
|
+
# rubocop:enable Metrics/AbcSize
|
|
115
|
+
|
|
116
|
+
[@input.byteslice(1, 2).unpack1("v") + 0x7F00, 3]
|
|
117
|
+
else
|
|
118
|
+
if @input.bytesize < 2
|
|
119
|
+
raise Omnizip::DecompressionError,
|
|
120
|
+
"truncated 2-byte sequence count"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
[((b0 - 0x80) << 8) + @input.getbyte(1), 2]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Build the table for one symbol type. Returns [table, new_cursor].
|
|
128
|
+
# rubocop:disable Metrics/AbcSize
|
|
129
|
+
def build_table(mode, type, predef_distribution, predef_log, cursor)
|
|
130
|
+
table = case mode
|
|
131
|
+
when MODE_PREDEFINED
|
|
132
|
+
FSE::Table.build_predefined(predef_distribution.to_a,
|
|
133
|
+
predef_log)
|
|
134
|
+
when MODE_RLE
|
|
135
|
+
if cursor >= @input.bytesize
|
|
136
|
+
raise Omnizip::DecompressionError,
|
|
137
|
+
"RLE mode: missing symbol byte"
|
|
138
|
+
end
|
|
139
|
+
# rubocop:enable Metrics/AbcSize
|
|
140
|
+
|
|
141
|
+
symbol = @input.getbyte(cursor)
|
|
142
|
+
limit = { ll: LITERAL_LENGTH_TABLE.length,
|
|
143
|
+
ml: MATCH_LENGTH_TABLE.length,
|
|
144
|
+
of: OF_BASE.length }[type]
|
|
145
|
+
if symbol >= limit
|
|
146
|
+
raise Omnizip::DecompressionError,
|
|
147
|
+
"RLE symbol #{symbol} out of range for #{type}"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
FSE::Table.build_rle(symbol, 0)
|
|
151
|
+
when MODE_FSE
|
|
152
|
+
tbl, consumed = FSE.read_table(@input.byteslice(cursor..))
|
|
153
|
+
attach_code_values(tbl, type)
|
|
154
|
+
@fse_tables[type] = tbl
|
|
155
|
+
return [tbl, cursor + consumed]
|
|
156
|
+
when MODE_REPEAT
|
|
157
|
+
prev = @previous_tables[type]
|
|
158
|
+
if prev.nil?
|
|
159
|
+
raise Omnizip::DecompressionError,
|
|
160
|
+
"repeat mode for #{type} without a previous table"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
return [prev, cursor]
|
|
164
|
+
else
|
|
165
|
+
raise Omnizip::DecompressionError,
|
|
166
|
+
"invalid sequence mode #{mode}"
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
attach_code_values(table, type)
|
|
170
|
+
@fse_tables[type] = table
|
|
171
|
+
cursor2 = mode == MODE_RLE ? cursor + 1 : cursor
|
|
172
|
+
[table, cursor2]
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Annotate each FSE state with the (base, extra_bits) of the LL /
|
|
176
|
+
# ML / OF code its symbol maps to, following the C reference's
|
|
177
|
+
# precomputed seqSymbol layout.
|
|
178
|
+
# rubocop:disable Metrics/AbcSize
|
|
179
|
+
def attach_code_values(table, type)
|
|
180
|
+
case type
|
|
181
|
+
when :ll
|
|
182
|
+
table.states.each do |st|
|
|
183
|
+
base, bits = LITERAL_LENGTH_TABLE[st.symbol] || [0, 0]
|
|
184
|
+
st.base_val = base
|
|
185
|
+
st.nb_add_bits = bits
|
|
186
|
+
end
|
|
187
|
+
# rubocop:enable Metrics/AbcSize
|
|
188
|
+
when :ml
|
|
189
|
+
table.states.each do |st|
|
|
190
|
+
base, bits = MATCH_LENGTH_TABLE[st.symbol] || [0, 0]
|
|
191
|
+
st.base_val = base
|
|
192
|
+
st.nb_add_bits = bits
|
|
193
|
+
end
|
|
194
|
+
when :of
|
|
195
|
+
table.states.each do |st|
|
|
196
|
+
st.base_val = OF_BASE[st.symbol] || 0
|
|
197
|
+
st.nb_add_bits = OF_BITS[st.symbol] || 0
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# rubocop:disable Metrics/MethodLength
|
|
203
|
+
# rubocop:disable Metrics/AbcSize
|
|
204
|
+
def decode_sequences(count, bitstream_bytes)
|
|
205
|
+
bs = FSE::BitStream.new(bitstream_bytes)
|
|
206
|
+
|
|
207
|
+
ll_tbl = @ll_table
|
|
208
|
+
of_tbl = @of_table
|
|
209
|
+
ml_tbl = @ml_table
|
|
210
|
+
ll_state = bs.read_bits(ll_tbl.accuracy_log)
|
|
211
|
+
bs.reload
|
|
212
|
+
of_state = bs.read_bits(of_tbl.accuracy_log)
|
|
213
|
+
bs.reload
|
|
214
|
+
ml_state = bs.read_bits(ml_tbl.accuracy_log)
|
|
215
|
+
bs.reload
|
|
216
|
+
|
|
217
|
+
count.times do |seq_idx|
|
|
218
|
+
is_last = seq_idx == count - 1
|
|
219
|
+
|
|
220
|
+
ll_e = ll_tbl[ll_state]
|
|
221
|
+
of_e = of_tbl[of_state]
|
|
222
|
+
ml_e = ml_tbl[ml_state]
|
|
223
|
+
|
|
224
|
+
ll0 = ll_e.base_val.zero?
|
|
225
|
+
offset = @executor.resolve_offset(of_e, ll0, bs)
|
|
226
|
+
match_length = ml_e.base_val + bs.read_bits(ml_e.nb_add_bits)
|
|
227
|
+
literal_length = ll_e.base_val + bs.read_bits(ll_e.nb_add_bits)
|
|
228
|
+
|
|
229
|
+
unless is_last
|
|
230
|
+
ll_state = ll_e.baseline + bs.read_bits(ll_e.num_bits)
|
|
231
|
+
ml_state = ml_e.baseline + bs.read_bits(ml_e.num_bits)
|
|
232
|
+
of_state = of_e.baseline + bs.read_bits(of_e.num_bits)
|
|
233
|
+
bs.reload
|
|
234
|
+
end
|
|
235
|
+
# rubocop:enable Metrics/AbcSize
|
|
236
|
+
|
|
237
|
+
@sequences << Sequence.new(literal_length, match_length, offset)
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
# rubocop:enable Metrics/MethodLength
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Stateful LZ77 sequence executor (RFC 8878 §3.1.2). Tracks the
|
|
244
|
+
# three repeat-offset slots across the frame; the slots are
|
|
245
|
+
# updated while decoding each sequence's offset.
|
|
246
|
+
class SequenceExecutor
|
|
247
|
+
include Constants
|
|
248
|
+
|
|
249
|
+
# @return [Array<Integer>] repeat offsets, most recent first
|
|
250
|
+
attr_reader :repeat_offsets
|
|
251
|
+
|
|
252
|
+
def initialize
|
|
253
|
+
@repeat_offsets = DEFAULT_REPEAT_OFFSETS.dup
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Reset to the frame defaults [1, 4, 8].
|
|
257
|
+
def reset
|
|
258
|
+
@repeat_offsets = DEFAULT_REPEAT_OFFSETS.dup
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Resolve a sequence offset (C reference semantics).
|
|
262
|
+
#
|
|
263
|
+
# Offset codes 0 and 1 address the repeat slots; the exact
|
|
264
|
+
# behaviour depends on ll0 (whether the sequence emits no
|
|
265
|
+
# literals). Codes >= 2 carry a real distance:
|
|
266
|
+
# distance = OF_BASE[code] + read(code bits).
|
|
267
|
+
#
|
|
268
|
+
# @param of_e [FSE::State] offset table entry for this sequence
|
|
269
|
+
# @param ll0 [Boolean] literal length is zero
|
|
270
|
+
# @param bs [FSE::BitStream]
|
|
271
|
+
# @return [Integer] resolved byte distance
|
|
272
|
+
# rubocop:disable Metrics/AbcSize
|
|
273
|
+
def resolve_offset(of_e, ll0, bs)
|
|
274
|
+
of_bits = of_e.nb_add_bits
|
|
275
|
+
prev = @repeat_offsets
|
|
276
|
+
|
|
277
|
+
if of_bits > 1
|
|
278
|
+
offset = of_e.base_val + bs.read_bits(of_bits)
|
|
279
|
+
prev[2] = prev[1]
|
|
280
|
+
prev[1] = prev[0]
|
|
281
|
+
prev[0] = offset
|
|
282
|
+
offset
|
|
283
|
+
elsif of_bits.zero?
|
|
284
|
+
offset = prev[ll0 ? 1 : 0]
|
|
285
|
+
if ll0
|
|
286
|
+
prev[1] = prev[0]
|
|
287
|
+
prev[0] = offset
|
|
288
|
+
end
|
|
289
|
+
# rubocop:enable Metrics/AbcSize
|
|
290
|
+
offset
|
|
291
|
+
else
|
|
292
|
+
# of_bits == 1: the "rep3-1" special family.
|
|
293
|
+
selector = of_e.base_val + (ll0 ? 1 : 0) + bs.read_bits(1)
|
|
294
|
+
temp = case selector
|
|
295
|
+
when 1 then prev[1]
|
|
296
|
+
when 3 then prev[0] - 1
|
|
297
|
+
else prev[2]
|
|
298
|
+
end
|
|
299
|
+
if temp.zero?
|
|
300
|
+
raise Omnizip::DecompressionError,
|
|
301
|
+
"repeat offset 1 - 1 evaluated to 0 (corrupt stream)"
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
prev[2] = prev[1] unless selector == 1
|
|
305
|
+
prev[1] = prev[0]
|
|
306
|
+
prev[0] = temp
|
|
307
|
+
temp
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Execute decoded sequences against the literal buffer,
|
|
312
|
+
# appending to output and returning the produced bytes.
|
|
313
|
+
#
|
|
314
|
+
# @param literals [String]
|
|
315
|
+
# @param sequences [Array<SequencesDecoder::Sequence>]
|
|
316
|
+
# @param output [String] accumulator (frame output so far)
|
|
317
|
+
# @return [String] the block's output
|
|
318
|
+
# rubocop:disable Metrics/AbcSize
|
|
319
|
+
def execute(literals, sequences, output)
|
|
320
|
+
lit_pos = 0
|
|
321
|
+
block_start = output.bytesize
|
|
322
|
+
|
|
323
|
+
sequences.each do |seq|
|
|
324
|
+
ll = seq.literal_length
|
|
325
|
+
if ll.positive?
|
|
326
|
+
take = [ll, literals.bytesize - lit_pos].min
|
|
327
|
+
output << literals.byteslice(lit_pos, take)
|
|
328
|
+
lit_pos += take
|
|
329
|
+
end
|
|
330
|
+
# rubocop:enable Metrics/AbcSize
|
|
331
|
+
|
|
332
|
+
distance = seq.offset
|
|
333
|
+
if distance.zero? || distance > output.bytesize
|
|
334
|
+
raise Omnizip::DecompressionError,
|
|
335
|
+
"match distance #{distance} exceeds decoded output " \
|
|
336
|
+
"length #{output.bytesize}"
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
ml = seq.match_length
|
|
340
|
+
src_start = output.bytesize - distance
|
|
341
|
+
ml.times { |i| output << output.getbyte(src_start + (i % distance)) }
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
output << literals.byteslice(lit_pos..) if lit_pos < literals.bytesize
|
|
345
|
+
output.byteslice(block_start..)
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
@@ -0,0 +1,333 @@
|
|
|
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
|
+
# Sequences section encoder (RFC 8878 §3.1.1.3.2; port of the
|
|
27
|
+
# omnizip-rs encoder/sequences.rs, from zstd_compress_sequences.c).
|
|
28
|
+
#
|
|
29
|
+
# Encodes the match finder's sequences with three FSE states
|
|
30
|
+
# (LL, OF, ML) into the reverse bitstream, choosing Predefined or
|
|
31
|
+
# FSE_Compressed tables per symbol type. Repeat offsets use the
|
|
32
|
+
# offBase 0/1/2 short codes exactly as the decoder resolves
|
|
33
|
+
# them.
|
|
34
|
+
module SequencesEncoder
|
|
35
|
+
include Constants
|
|
36
|
+
|
|
37
|
+
MODE_PREDEFINED = 0
|
|
38
|
+
MODE_FSE = 2
|
|
39
|
+
|
|
40
|
+
# Slack favoring Predefined tables (the payload estimate is
|
|
41
|
+
# entropy-approximate; marginal FSE wins on small streams are
|
|
42
|
+
# noise and lose in practice).
|
|
43
|
+
FSE_SLACK_BITS = 24
|
|
44
|
+
|
|
45
|
+
module_function
|
|
46
|
+
|
|
47
|
+
# Encode the sequences section for `seq_store`.
|
|
48
|
+
#
|
|
49
|
+
# @param seq_store [MatchFinder::SeqStore]
|
|
50
|
+
# @param initial_reps [Array<Integer>] wire repeat offsets the
|
|
51
|
+
# decoder holds before this block
|
|
52
|
+
# @return [Array(String, Array<Integer>)] the section bytes and
|
|
53
|
+
# the wire rep state after this block
|
|
54
|
+
# rubocop:disable Metrics/MethodLength
|
|
55
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
56
|
+
def encode_section(seq_store, initial_reps)
|
|
57
|
+
nb_seq = seq_store.sequences.length
|
|
58
|
+
out = write_sequence_count(nb_seq)
|
|
59
|
+
return [out, initial_reps] if nb_seq.zero?
|
|
60
|
+
|
|
61
|
+
ll_codes, ml_codes, of_codes, ll_extras, ml_extras, off_bases,
|
|
62
|
+
wire_reps = compute_codes(seq_store, initial_reps)
|
|
63
|
+
|
|
64
|
+
ll_count = Array.new(LITERAL_LENGTH_TABLE.length, 0)
|
|
65
|
+
ml_count = Array.new(MATCH_LENGTH_TABLE.length, 0)
|
|
66
|
+
of_count = Array.new(32, 0)
|
|
67
|
+
ll_max = count_symbols(ll_codes, ll_count)
|
|
68
|
+
ml_max = count_symbols(ml_codes, ml_count)
|
|
69
|
+
of_max = count_symbols(of_codes, of_count)
|
|
70
|
+
|
|
71
|
+
ll_choice = choose_table_mode(ll_count, ll_max,
|
|
72
|
+
PREDEFINED_LL_DISTRIBUTION, 6, 35, 9,
|
|
73
|
+
nb_seq)
|
|
74
|
+
of_choice = choose_table_mode(of_count, of_max,
|
|
75
|
+
PREDEFINED_OFFSET_DISTRIBUTION, 5, 28,
|
|
76
|
+
8, nb_seq)
|
|
77
|
+
ml_choice = choose_table_mode(ml_count, ml_max,
|
|
78
|
+
PREDEFINED_ML_DISTRIBUTION, 6, 52, 9,
|
|
79
|
+
nb_seq)
|
|
80
|
+
|
|
81
|
+
modes = (ll_choice[:mode] << 6) | (of_choice[:mode] << 4) |
|
|
82
|
+
(ml_choice[:mode] << 2)
|
|
83
|
+
out << modes.chr
|
|
84
|
+
|
|
85
|
+
if ll_choice[:mode] == MODE_FSE
|
|
86
|
+
out << FSE::Encoder.new(ll_choice[:norm], ll_choice[:table_log],
|
|
87
|
+
ll_max).write_ncount
|
|
88
|
+
end
|
|
89
|
+
if of_choice[:mode] == MODE_FSE
|
|
90
|
+
out << FSE::Encoder.new(of_choice[:norm], of_choice[:table_log],
|
|
91
|
+
of_max).write_ncount
|
|
92
|
+
end
|
|
93
|
+
if ml_choice[:mode] == MODE_FSE
|
|
94
|
+
out << FSE::Encoder.new(ml_choice[:norm], ml_choice[:table_log],
|
|
95
|
+
ml_max).write_ncount
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
ll_ctable = table_for(ll_choice)
|
|
99
|
+
of_ctable = table_for(of_choice)
|
|
100
|
+
ml_ctable = table_for(ml_choice)
|
|
101
|
+
|
|
102
|
+
out << encode_sequences_bitstream(
|
|
103
|
+
ll_codes, ml_codes, of_codes, ll_extras, ml_extras, off_bases,
|
|
104
|
+
ll_ctable, ml_ctable, of_ctable
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
[out, wire_reps]
|
|
108
|
+
end
|
|
109
|
+
# rubocop:enable Metrics/MethodLength
|
|
110
|
+
|
|
111
|
+
# Compute per-sequence codes and extras, tracking the WIRE rep
|
|
112
|
+
# state exactly as the decoder's resolve_offset does (this is
|
|
113
|
+
# the state the next block must carry, not the match finder's).
|
|
114
|
+
#
|
|
115
|
+
# rubocop:disable Metrics/MethodLength
|
|
116
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
117
|
+
def compute_codes(seq_store, initial_reps)
|
|
118
|
+
ll_codes = []
|
|
119
|
+
ml_codes = []
|
|
120
|
+
of_codes = []
|
|
121
|
+
ll_extras = []
|
|
122
|
+
ml_extras = []
|
|
123
|
+
off_bases = []
|
|
124
|
+
reps = initial_reps.dup
|
|
125
|
+
|
|
126
|
+
seq_store.sequences.each do |seq|
|
|
127
|
+
ll_c, ll_e = ll_code(seq.literal_length)
|
|
128
|
+
ml_c, ml_e = ml_code(seq.match_length)
|
|
129
|
+
ll0 = seq.literal_length.zero?
|
|
130
|
+
|
|
131
|
+
ob = if !ll0 && seq.offset == reps[0]
|
|
132
|
+
1 # rep1: decoder uses prev[0], no rotation
|
|
133
|
+
elsif ll0 && seq.offset == reps[1]
|
|
134
|
+
used = reps[1] # decoder swaps prev[0]/prev[1]
|
|
135
|
+
reps[1] = reps[0]
|
|
136
|
+
reps[0] = used
|
|
137
|
+
1
|
|
138
|
+
elsif seq.offset == reps[2] && seq.offset > 3
|
|
139
|
+
used = reps[2] # rep3: decoder shifts prev[2] to front
|
|
140
|
+
reps[2] = reps[1]
|
|
141
|
+
reps[1] = reps[0]
|
|
142
|
+
reps[0] = used
|
|
143
|
+
ll0 ? 2 : 3
|
|
144
|
+
else
|
|
145
|
+
reps[2] = reps[1]
|
|
146
|
+
reps[1] = reps[0]
|
|
147
|
+
reps[0] = seq.offset
|
|
148
|
+
seq.offset + 3
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
ll_codes << ll_c
|
|
152
|
+
ml_codes << ml_c
|
|
153
|
+
of_codes << [ob.bit_length - 1, 31].min
|
|
154
|
+
ll_extras << ll_e
|
|
155
|
+
ml_extras << ml_e
|
|
156
|
+
off_bases << ob
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
[ll_codes, ml_codes, of_codes, ll_extras, ml_extras, off_bases,
|
|
160
|
+
reps]
|
|
161
|
+
end
|
|
162
|
+
# rubocop:enable Metrics/MethodLength
|
|
163
|
+
|
|
164
|
+
# LL code for a literal length: (code, extra value).
|
|
165
|
+
def ll_code(lit_len)
|
|
166
|
+
code = LITERAL_LENGTH_TABLE.length - 1
|
|
167
|
+
while code.positive? && LITERAL_LENGTH_TABLE[code][0] > lit_len
|
|
168
|
+
code -= 1
|
|
169
|
+
end
|
|
170
|
+
[code, lit_len - LITERAL_LENGTH_TABLE[code][0]]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# ML code for a match length: (code, extra value).
|
|
174
|
+
def ml_code(match_len)
|
|
175
|
+
code = MATCH_LENGTH_TABLE.length - 1
|
|
176
|
+
while code.positive? && MATCH_LENGTH_TABLE[code][0] > match_len
|
|
177
|
+
code -= 1
|
|
178
|
+
end
|
|
179
|
+
[code, match_len - MATCH_LENGTH_TABLE[code][0]]
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def count_symbols(codes, count)
|
|
183
|
+
max_sym = 0
|
|
184
|
+
codes.each do |c|
|
|
185
|
+
count[c] += 1
|
|
186
|
+
max_sym = c if c > max_sym
|
|
187
|
+
end
|
|
188
|
+
max_sym
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Choose Predefined vs FSE_Compressed for one symbol type.
|
|
192
|
+
#
|
|
193
|
+
# rubocop:disable Metrics/MethodLength
|
|
194
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
195
|
+
def choose_table_mode(count, max_sym, default_norm, default_log,
|
|
196
|
+
default_max_sym, accuracy_cap, total)
|
|
197
|
+
predefined_viable = (0..max_sym).all? do |s|
|
|
198
|
+
count[s].zero? ||
|
|
199
|
+
(s < default_norm.length && default_norm[s] != 0)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
opt_log = FSE::Encoder.optimal_table_log(accuracy_cap, total,
|
|
203
|
+
max_sym)
|
|
204
|
+
custom_norm = FSE::Encoder.normalize_count(
|
|
205
|
+
opt_log, count, total, max_sym, use_low_prob: false
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
fse_norm = if custom_norm.empty?
|
|
209
|
+
single = Array.new(max_sym + 1, 0)
|
|
210
|
+
single[max_sym] = 1 << opt_log
|
|
211
|
+
single
|
|
212
|
+
else
|
|
213
|
+
custom_norm
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
unless predefined_viable
|
|
217
|
+
return { mode: MODE_FSE, norm: fse_norm, table_log: opt_log,
|
|
218
|
+
max_sym: max_sym }
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
predef_bits = estimate_cost(count, default_norm, default_log,
|
|
222
|
+
max_sym)
|
|
223
|
+
fse_bits = estimate_cost(count, fse_norm, opt_log, max_sym) +
|
|
224
|
+
(8 * ncount_size(fse_norm, max_sym, opt_log))
|
|
225
|
+
|
|
226
|
+
if fse_bits + FSE_SLACK_BITS < predef_bits
|
|
227
|
+
{ mode: MODE_FSE, norm: fse_norm, table_log: opt_log,
|
|
228
|
+
max_sym: max_sym }
|
|
229
|
+
else
|
|
230
|
+
{ mode: MODE_PREDEFINED, norm: default_norm.to_a,
|
|
231
|
+
table_log: default_log, max_sym: default_max_sym }
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
# rubocop:enable Metrics/MethodLength
|
|
235
|
+
|
|
236
|
+
# Estimated payload cost in bits for a distribution.
|
|
237
|
+
def estimate_cost(count, norm, table_log, max_sym)
|
|
238
|
+
table_size = 1 << table_log
|
|
239
|
+
total_bits = 0
|
|
240
|
+
(0..max_sym).each do |s|
|
|
241
|
+
next if count[s].zero?
|
|
242
|
+
|
|
243
|
+
n = s < norm.length ? norm[s] : 0
|
|
244
|
+
prob = if n.positive?
|
|
245
|
+
n
|
|
246
|
+
elsif n == -1
|
|
247
|
+
1
|
|
248
|
+
else
|
|
249
|
+
table_size
|
|
250
|
+
end
|
|
251
|
+
total_bits += (count[s] * Math.log(table_size.to_f / prob, 2))
|
|
252
|
+
.round
|
|
253
|
+
end
|
|
254
|
+
total_bits
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def table_for(choice)
|
|
258
|
+
FSE::Encoder.new(choice[:norm], choice[:table_log], choice[:max_sym])
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# Exact size of the NCount header a distribution would write.
|
|
262
|
+
def ncount_size(norm, max_sym, table_log)
|
|
263
|
+
FSE::Encoder.new(norm, table_log, max_sym).write_ncount.bytesize
|
|
264
|
+
rescue Omnizip::CompressionError
|
|
265
|
+
Float::INFINITY
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Sequence count, 1-3 bytes (RFC 8878 §3.1.1.3.2.1).
|
|
269
|
+
def write_sequence_count(nb_seq)
|
|
270
|
+
if nb_seq < 128
|
|
271
|
+
[nb_seq].pack("C")
|
|
272
|
+
elsif nb_seq < 0x7F00
|
|
273
|
+
[128 + (nb_seq >> 8), nb_seq & 0xFF].pack("CC")
|
|
274
|
+
else
|
|
275
|
+
v = nb_seq - 0x7F00
|
|
276
|
+
[0xFF, v & 0xFF, (v >> 8) & 0xFF].pack("C*")
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# The reverse-order three-state FSE bitstream (port of the
|
|
281
|
+
# Rust encode_sequences_bitstream). The decoder reads states
|
|
282
|
+
# LL, OF, ML first and consumes extras OF, ML, LL per
|
|
283
|
+
# sequence, so the encoder initializes from the LAST sequence
|
|
284
|
+
# and walks backwards.
|
|
285
|
+
#
|
|
286
|
+
# rubocop:disable Metrics/MethodLength
|
|
287
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
288
|
+
def encode_sequences_bitstream(ll_codes, ml_codes, of_codes,
|
|
289
|
+
ll_extras, ml_extras, off_bases,
|
|
290
|
+
ll_ctable, ml_ctable, of_ctable)
|
|
291
|
+
nb_seq = ll_codes.length
|
|
292
|
+
bitc = FSE::Encoder::BitCStream.new
|
|
293
|
+
|
|
294
|
+
state_ml = FSE::Encoder::CState.init2(ml_ctable, ml_codes[nb_seq - 1])
|
|
295
|
+
state_of = FSE::Encoder::CState.init2(of_ctable, of_codes[nb_seq - 1])
|
|
296
|
+
state_ll = FSE::Encoder::CState.init2(ll_ctable, ll_codes[nb_seq - 1])
|
|
297
|
+
|
|
298
|
+
last = nb_seq - 1
|
|
299
|
+
bitc.add_bits(ll_extras[last],
|
|
300
|
+
LITERAL_LENGTH_TABLE[ll_codes[last]][1])
|
|
301
|
+
bitc.flush
|
|
302
|
+
bitc.add_bits(ml_extras[last],
|
|
303
|
+
MATCH_LENGTH_TABLE[ml_codes[last]][1])
|
|
304
|
+
bitc.flush
|
|
305
|
+
bitc.add_bits(off_bases[last], of_codes[last])
|
|
306
|
+
bitc.flush
|
|
307
|
+
|
|
308
|
+
(nb_seq - 2).downto(0) do |n|
|
|
309
|
+
state_of.encode(bitc, of_ctable, of_codes[n])
|
|
310
|
+
state_ml.encode(bitc, ml_ctable, ml_codes[n])
|
|
311
|
+
bitc.flush
|
|
312
|
+
state_ll.encode(bitc, ll_ctable, ll_codes[n])
|
|
313
|
+
bitc.flush
|
|
314
|
+
|
|
315
|
+
bitc.add_bits(ll_extras[n],
|
|
316
|
+
LITERAL_LENGTH_TABLE[ll_codes[n]][1])
|
|
317
|
+
bitc.add_bits(ml_extras[n],
|
|
318
|
+
MATCH_LENGTH_TABLE[ml_codes[n]][1])
|
|
319
|
+
bitc.flush
|
|
320
|
+
bitc.add_bits(off_bases[n], of_codes[n])
|
|
321
|
+
bitc.flush
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
state_ml.flush(bitc)
|
|
325
|
+
state_of.flush(bitc)
|
|
326
|
+
state_ll.flush(bitc)
|
|
327
|
+
bitc.close
|
|
328
|
+
end
|
|
329
|
+
# rubocop:enable Metrics/MethodLength
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|