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,146 @@
|
|
|
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 BZip2 < Algorithm
|
|
26
|
+
# Run-Length Encoding (RLE) for BZip2
|
|
27
|
+
#
|
|
28
|
+
# This is a BZip2-specific RLE variant that encodes runs of
|
|
29
|
+
# identical bytes. After MTF, the data often contains long runs
|
|
30
|
+
# of zeros, which RLE compresses efficiently.
|
|
31
|
+
#
|
|
32
|
+
# BZip2 RLE encoding scheme:
|
|
33
|
+
# - Runs of 4-259 identical bytes are encoded as:
|
|
34
|
+
# [byte, byte, byte, byte, count-4]
|
|
35
|
+
# - Where count is 0-255 representing 4-259 repetitions
|
|
36
|
+
# - Runs < 4 are left unencoded
|
|
37
|
+
# - This scheme avoids ambiguity in decoding
|
|
38
|
+
class Rle
|
|
39
|
+
# Maximum run length (4 + 255)
|
|
40
|
+
MAX_RUN_LENGTH = 259
|
|
41
|
+
|
|
42
|
+
# Minimum run length for encoding
|
|
43
|
+
MIN_RUN_LENGTH = 4
|
|
44
|
+
|
|
45
|
+
# Encode data using BZip2 RLE
|
|
46
|
+
#
|
|
47
|
+
# @param data [String] Input data to encode
|
|
48
|
+
# @return [String] RLE-encoded data
|
|
49
|
+
def encode(data)
|
|
50
|
+
return "".b if data.empty?
|
|
51
|
+
|
|
52
|
+
result = []
|
|
53
|
+
i = 0
|
|
54
|
+
|
|
55
|
+
while i < data.length
|
|
56
|
+
byte = data.getbyte(i)
|
|
57
|
+
run_length = count_run(data, i)
|
|
58
|
+
|
|
59
|
+
if run_length >= MIN_RUN_LENGTH
|
|
60
|
+
# Encode run: emit 4 copies + extra count
|
|
61
|
+
extra = [run_length - MIN_RUN_LENGTH, 255].min
|
|
62
|
+
4.times { result << byte }
|
|
63
|
+
result << extra
|
|
64
|
+
i += MIN_RUN_LENGTH + extra
|
|
65
|
+
else
|
|
66
|
+
# No run, emit single byte
|
|
67
|
+
result << byte
|
|
68
|
+
i += 1
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
result.pack("C*")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Decode RLE-encoded data
|
|
76
|
+
#
|
|
77
|
+
# @param data [String] RLE-encoded data
|
|
78
|
+
# @return [String] Decoded data
|
|
79
|
+
def decode(data)
|
|
80
|
+
return "".b if data.empty?
|
|
81
|
+
|
|
82
|
+
# Single linear pass over the INPUT: a run marker is four
|
|
83
|
+
# identical bytes followed by an extra-count byte (the old
|
|
84
|
+
# decoder rescanned the growing output per byte, which made
|
|
85
|
+
# decode quadratic).
|
|
86
|
+
result = []
|
|
87
|
+
i = 0
|
|
88
|
+
n = data.bytesize
|
|
89
|
+
|
|
90
|
+
while i < n
|
|
91
|
+
byte = data.getbyte(i)
|
|
92
|
+
if byte == data.getbyte(i + 1) &&
|
|
93
|
+
byte == data.getbyte(i + 2) &&
|
|
94
|
+
byte == data.getbyte(i + 3)
|
|
95
|
+
count = data.getbyte(i + 4) || 0
|
|
96
|
+
result << byte
|
|
97
|
+
result << byte
|
|
98
|
+
result << byte
|
|
99
|
+
result << byte
|
|
100
|
+
count.times { result << byte }
|
|
101
|
+
i += 5
|
|
102
|
+
else
|
|
103
|
+
result << byte
|
|
104
|
+
i += 1
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
result.pack("C*")
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
# Count run length starting at given position
|
|
114
|
+
#
|
|
115
|
+
# @param data [String] Input data
|
|
116
|
+
# @param start [Integer] Starting position
|
|
117
|
+
# @return [Integer] Run length
|
|
118
|
+
def count_run(data, start)
|
|
119
|
+
byte = data.getbyte(start)
|
|
120
|
+
count = 1
|
|
121
|
+
|
|
122
|
+
(start + 1).upto([start + MAX_RUN_LENGTH - 1,
|
|
123
|
+
data.length - 1].min) do |i|
|
|
124
|
+
break if data.getbyte(i) != byte
|
|
125
|
+
|
|
126
|
+
count += 1
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
count
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Check if last n bytes in array match the given byte
|
|
133
|
+
#
|
|
134
|
+
# @param array [Array<Integer>] Byte array
|
|
135
|
+
# @param byte [Integer] Byte to match
|
|
136
|
+
# @param count [Integer] Number of bytes to check
|
|
137
|
+
# @return [Boolean] True if last n bytes match
|
|
138
|
+
def consecutive_match?(array, byte, count)
|
|
139
|
+
return false if array.length < count
|
|
140
|
+
|
|
141
|
+
array[-count..].all?(byte)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
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
|
+
# BZip2 block-sorting compression algorithm
|
|
26
|
+
#
|
|
27
|
+
# BZip2 combines several compression techniques in a pipeline:
|
|
28
|
+
# 1. Burrows-Wheeler Transform (BWT) - block-sorting transformation
|
|
29
|
+
# 2. Move-to-Front Transform (MTF) - exploits locality
|
|
30
|
+
# 3. Run-Length Encoding (RLE) - compresses repeated bytes
|
|
31
|
+
# 4. Huffman Coding - variable-length entropy encoding
|
|
32
|
+
#
|
|
33
|
+
# This algorithm is particularly effective for:
|
|
34
|
+
# - Text files with repetitive patterns
|
|
35
|
+
# - Data with high local similarity
|
|
36
|
+
# - Files where block-sorting improves compressibility
|
|
37
|
+
#
|
|
38
|
+
# Block size affects both compression ratio and memory usage.
|
|
39
|
+
# Larger blocks (up to 900KB) generally provide better compression
|
|
40
|
+
# but require more memory.
|
|
41
|
+
class BZip2 < Algorithm
|
|
42
|
+
# Nested classes - autoloaded
|
|
43
|
+
autoload :Bwt, "omnizip/algorithms/bzip2/bwt"
|
|
44
|
+
autoload :Rle, "omnizip/algorithms/bzip2/rle"
|
|
45
|
+
autoload :Bz2, "omnizip/algorithms/bzip2/bz2"
|
|
46
|
+
|
|
47
|
+
# Cross-namespace dependencies - autoloaded
|
|
48
|
+
autoload :Crc32, "omnizip/checksums/crc32"
|
|
49
|
+
|
|
50
|
+
# Get algorithm metadata
|
|
51
|
+
#
|
|
52
|
+
# @return [AlgorithmMetadata] Algorithm information
|
|
53
|
+
def self.metadata
|
|
54
|
+
Models::AlgorithmMetadata.new.tap do |meta|
|
|
55
|
+
meta.name = "bzip2"
|
|
56
|
+
meta.description = "BZip2 block-sorting compression using " \
|
|
57
|
+
"BWT, MTF, RLE, and Huffman coding"
|
|
58
|
+
meta.version = "1.0.0"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Compress data using BZip2 algorithm
|
|
63
|
+
#
|
|
64
|
+
# @param input_stream [IO] Input stream to compress
|
|
65
|
+
# @param output_stream [IO] Output stream for compressed data
|
|
66
|
+
# @param options [Models::CompressionOptions] Compression options
|
|
67
|
+
# @return [void]
|
|
68
|
+
def compress(input_stream, output_stream, options = nil)
|
|
69
|
+
level = level_from(options)
|
|
70
|
+
data = input_stream.read
|
|
71
|
+
output_stream.write(
|
|
72
|
+
Backends.compress("bzip2", data, level) { Bz2.compress(data, level) },
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Decompress BZip2-compressed data
|
|
77
|
+
#
|
|
78
|
+
# @param input_stream [IO] Input stream of compressed data
|
|
79
|
+
# @param output_stream [IO] Output stream for decompressed data
|
|
80
|
+
# @param options [Models::CompressionOptions] Decompression options
|
|
81
|
+
# @return [void]
|
|
82
|
+
def decompress(input_stream, output_stream, _options = nil)
|
|
83
|
+
output_stream.set_encoding(Encoding::BINARY)
|
|
84
|
+
compressed = input_stream.read
|
|
85
|
+
plain = Backends.decompress("bzip2", compressed, Backends::UNKNOWN_LENGTH) do
|
|
86
|
+
Bz2.decompress(compressed)
|
|
87
|
+
end
|
|
88
|
+
output_stream.write(plain)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# Compression level (1-9) from options; bzip2's levels map
|
|
94
|
+
# directly to 100 KB..900 KB block sizes.
|
|
95
|
+
def level_from(options)
|
|
96
|
+
return 9 if options.nil?
|
|
97
|
+
return (options[:level] || 9).clamp(1, 9) if options.is_a?(Hash)
|
|
98
|
+
|
|
99
|
+
# allowed: options is a public parameter; any object with #level is honored
|
|
100
|
+
level = options.respond_to?(:level) ? options.level : nil
|
|
101
|
+
(level || 9).clamp(1, 9)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Register the BZip2 algorithm
|
|
108
|
+
Omnizip::AlgorithmRegistry.register(:bzip2, Omnizip::Algorithms::BZip2)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zlib"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Algorithms
|
|
7
|
+
class Deflate
|
|
8
|
+
# Constants for Deflate algorithm
|
|
9
|
+
module Constants
|
|
10
|
+
# Compression levels
|
|
11
|
+
NO_COMPRESSION = Zlib::NO_COMPRESSION
|
|
12
|
+
BEST_SPEED = Zlib::BEST_SPEED
|
|
13
|
+
BEST_COMPRESSION = Zlib::BEST_COMPRESSION
|
|
14
|
+
DEFAULT_COMPRESSION = Zlib::DEFAULT_COMPRESSION
|
|
15
|
+
|
|
16
|
+
# Compression strategies
|
|
17
|
+
FILTERED = Zlib::FILTERED
|
|
18
|
+
HUFFMAN_ONLY = Zlib::HUFFMAN_ONLY
|
|
19
|
+
RLE = Zlib::RLE
|
|
20
|
+
FIXED = Zlib::FIXED
|
|
21
|
+
DEFAULT_STRATEGY = Zlib::DEFAULT_STRATEGY
|
|
22
|
+
|
|
23
|
+
# Buffer size for streaming operations
|
|
24
|
+
BUFFER_SIZE = 32 * 1024 # 32KB
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zlib"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Algorithms
|
|
7
|
+
class Deflate
|
|
8
|
+
# Deflate decoder using Zlib
|
|
9
|
+
#
|
|
10
|
+
# This class wraps Ruby's Zlib::Inflate to provide Deflate
|
|
11
|
+
# decompression following the established Omnizip architecture.
|
|
12
|
+
class Decoder
|
|
13
|
+
include Constants
|
|
14
|
+
|
|
15
|
+
attr_reader :input_stream
|
|
16
|
+
|
|
17
|
+
# Initialize decoder
|
|
18
|
+
#
|
|
19
|
+
# @param input_stream [IO] Input stream of compressed data
|
|
20
|
+
def initialize(input_stream)
|
|
21
|
+
@input_stream = input_stream
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Decode compressed data stream
|
|
25
|
+
#
|
|
26
|
+
# @return [String] Decompressed data
|
|
27
|
+
def decode_stream
|
|
28
|
+
compressed = @input_stream.read
|
|
29
|
+
inflater = Zlib::Inflate.new
|
|
30
|
+
decompressed = inflater.inflate(compressed)
|
|
31
|
+
inflater.close
|
|
32
|
+
decompressed
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zlib"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Algorithms
|
|
7
|
+
class Deflate
|
|
8
|
+
# Deflate encoder using Zlib
|
|
9
|
+
#
|
|
10
|
+
# This class wraps Ruby's Zlib::Deflate to provide Deflate
|
|
11
|
+
# compression following the established Omnizip architecture.
|
|
12
|
+
class Encoder
|
|
13
|
+
include Constants
|
|
14
|
+
|
|
15
|
+
attr_reader :output_stream, :options
|
|
16
|
+
|
|
17
|
+
# Initialize encoder
|
|
18
|
+
#
|
|
19
|
+
# @param output_stream [IO] Output stream for compressed data
|
|
20
|
+
# @param options [Hash] Encoder options
|
|
21
|
+
# @option options [Integer] :level Compression level (0-9)
|
|
22
|
+
# @option options [Integer] :strategy Compression strategy
|
|
23
|
+
# @option options [Integer] :window_bits Window size (8-15)
|
|
24
|
+
def initialize(output_stream, options = {})
|
|
25
|
+
@output_stream = output_stream
|
|
26
|
+
@options = options
|
|
27
|
+
@level = options[:level] || DEFAULT_COMPRESSION
|
|
28
|
+
@strategy = options[:strategy] || DEFAULT_STRATEGY
|
|
29
|
+
@window_bits = options[:window_bits] || 15
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Encode data stream
|
|
33
|
+
#
|
|
34
|
+
# @param data [String] Data to compress
|
|
35
|
+
# @return [void]
|
|
36
|
+
def encode_stream(data)
|
|
37
|
+
deflater = Zlib::Deflate.new(@level, @window_bits, 9, @strategy)
|
|
38
|
+
compressed = deflater.deflate(data, Zlib::FINISH)
|
|
39
|
+
deflater.close
|
|
40
|
+
@output_stream.write(compressed)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
|
|
5
|
+
# Copyright (C) 2025 Ribose Inc.
|
|
6
|
+
#
|
|
7
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
8
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
9
|
+
# to deal in the Software without restriction, including without limitation
|
|
10
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
11
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
12
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be included in
|
|
15
|
+
# all copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
22
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
23
|
+
# DEALINGS IN THE SOFTWARE.
|
|
24
|
+
|
|
25
|
+
module Omnizip
|
|
26
|
+
module Algorithms
|
|
27
|
+
# Deflate compression algorithm (RFC 1951)
|
|
28
|
+
#
|
|
29
|
+
# Deflate is a widely-used lossless data compression algorithm that
|
|
30
|
+
# combines LZ77 compression with Huffman coding. It is the foundation
|
|
31
|
+
# of many popular formats including ZIP, gzip, and PNG.
|
|
32
|
+
#
|
|
33
|
+
# The algorithm works in two phases:
|
|
34
|
+
# 1. LZ77 compression - Identifies repeated byte sequences
|
|
35
|
+
# 2. Huffman coding - Encodes the result using variable-length codes
|
|
36
|
+
#
|
|
37
|
+
# This implementation uses Ruby's Zlib library which provides a
|
|
38
|
+
# well-tested, efficient implementation of the Deflate algorithm.
|
|
39
|
+
#
|
|
40
|
+
# Deflate is particularly effective for:
|
|
41
|
+
# - Text files and source code
|
|
42
|
+
# - HTML, XML, and JSON documents
|
|
43
|
+
# - Files with repeated patterns
|
|
44
|
+
# - General-purpose compression needs
|
|
45
|
+
class Deflate < Algorithm
|
|
46
|
+
# Nested classes - autoloaded
|
|
47
|
+
autoload :Constants, "omnizip/algorithms/deflate/constants"
|
|
48
|
+
autoload :Encoder, "omnizip/algorithms/deflate/encoder"
|
|
49
|
+
autoload :Decoder, "omnizip/algorithms/deflate/decoder"
|
|
50
|
+
|
|
51
|
+
# Get algorithm metadata
|
|
52
|
+
#
|
|
53
|
+
# @return [AlgorithmMetadata] Algorithm information
|
|
54
|
+
def self.metadata
|
|
55
|
+
Models::AlgorithmMetadata.new.tap do |meta|
|
|
56
|
+
meta.name = "deflate"
|
|
57
|
+
meta.description = "Deflate compression using LZ77 and " \
|
|
58
|
+
"Huffman coding (RFC 1951)"
|
|
59
|
+
meta.version = "1.0.0"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Compress data using Deflate algorithm
|
|
64
|
+
#
|
|
65
|
+
# @param input_stream [IO] Input stream to compress
|
|
66
|
+
# @param output_stream [IO] Output stream for compressed data
|
|
67
|
+
# @param options [Models::CompressionOptions] Compression options
|
|
68
|
+
# @return [void]
|
|
69
|
+
def compress(input_stream, output_stream, options = nil)
|
|
70
|
+
input_data = input_stream.read
|
|
71
|
+
level = build_encoder_options(options)[:level] || 6
|
|
72
|
+
output_stream.write(
|
|
73
|
+
Backends.compress("zlib", input_data, level) do
|
|
74
|
+
encoder = Encoder.new(output_stream, build_encoder_options(options))
|
|
75
|
+
encoder.encode_stream(input_data)
|
|
76
|
+
end,
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Decompress Deflate-compressed data
|
|
81
|
+
#
|
|
82
|
+
# @param input_stream [IO] Input stream of compressed data
|
|
83
|
+
# @param output_stream [IO] Output stream for decompressed data
|
|
84
|
+
# @param options [Models::CompressionOptions] Decompression options
|
|
85
|
+
# @return [void]
|
|
86
|
+
def decompress(input_stream, output_stream, _options = nil)
|
|
87
|
+
output_stream.set_encoding(Encoding::BINARY)
|
|
88
|
+
compressed = input_stream.read
|
|
89
|
+
# The encoder's streams carry the zlib wrapper (RFC 1950) —
|
|
90
|
+
# the Rust "zlib" name speaks exactly that framing.
|
|
91
|
+
decompressed = Backends.decompress("zlib", compressed, Backends::UNKNOWN_LENGTH) do
|
|
92
|
+
Decoder.new(StringIO.new(compressed)).decode_stream
|
|
93
|
+
end
|
|
94
|
+
output_stream.write(decompressed)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
# Build encoder options from compression options
|
|
100
|
+
#
|
|
101
|
+
# @param options [Models::CompressionOptions, nil] Compression opts
|
|
102
|
+
# @return [Hash] Encoder options
|
|
103
|
+
def build_encoder_options(options)
|
|
104
|
+
return {} if options.nil?
|
|
105
|
+
|
|
106
|
+
opts = {}
|
|
107
|
+
|
|
108
|
+
# allowed: options is a public parameter; any object with #level is honored
|
|
109
|
+
if options.respond_to?(:level)
|
|
110
|
+
opts[:level] = map_compression_level(options.level)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
opts
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Map generic compression level (0-9) to Zlib level
|
|
117
|
+
#
|
|
118
|
+
# @param level [Integer] Compression level (0-9)
|
|
119
|
+
# @return [Integer] Zlib compression level
|
|
120
|
+
def map_compression_level(level)
|
|
121
|
+
return Zlib::DEFAULT_COMPRESSION if level.nil?
|
|
122
|
+
|
|
123
|
+
case level
|
|
124
|
+
when 0 then Zlib::NO_COMPRESSION
|
|
125
|
+
when 1 then Zlib::BEST_SPEED
|
|
126
|
+
when 9 then Zlib::BEST_COMPRESSION
|
|
127
|
+
else level
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Register the Deflate algorithm
|
|
135
|
+
Omnizip::AlgorithmRegistry.register(:deflate, Omnizip::Algorithms::Deflate)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Algorithms
|
|
5
|
+
class Deflate64
|
|
6
|
+
# Constants for Deflate64 (Enhanced Deflate) algorithm
|
|
7
|
+
module Constants
|
|
8
|
+
# Dictionary/window size - 64KB vs 32KB in standard Deflate
|
|
9
|
+
DICTIONARY_SIZE = 65_536
|
|
10
|
+
|
|
11
|
+
# Match length constraints
|
|
12
|
+
MAX_MATCH_LENGTH = 258
|
|
13
|
+
MIN_MATCH_LENGTH = 3
|
|
14
|
+
MAX_DISTANCE = DICTIONARY_SIZE - 1
|
|
15
|
+
|
|
16
|
+
# Huffman coding constants
|
|
17
|
+
LITERAL_CODES = 286
|
|
18
|
+
DISTANCE_CODES = 30
|
|
19
|
+
LENGTH_CODES = 19
|
|
20
|
+
|
|
21
|
+
# Block types
|
|
22
|
+
BLOCK_TYPE_STORED = 0
|
|
23
|
+
BLOCK_TYPE_FIXED = 1
|
|
24
|
+
BLOCK_TYPE_DYNAMIC = 2
|
|
25
|
+
|
|
26
|
+
# End of block marker
|
|
27
|
+
END_OF_BLOCK = 256
|
|
28
|
+
|
|
29
|
+
# Maximum code lengths
|
|
30
|
+
MAX_LITERAL_CODE_LENGTH = 15
|
|
31
|
+
MAX_DISTANCE_CODE_LENGTH = 15
|
|
32
|
+
|
|
33
|
+
# Hash table size for LZ77
|
|
34
|
+
HASH_SIZE = 65_536
|
|
35
|
+
HASH_SHIFT = 5
|
|
36
|
+
|
|
37
|
+
# Search limits
|
|
38
|
+
MAX_CHAIN_LENGTH = 4096
|
|
39
|
+
GOOD_MATCH = 32
|
|
40
|
+
NICE_MATCH = 258
|
|
41
|
+
MAX_LAZY_MATCH = 258
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Algorithms
|
|
7
|
+
class Deflate64
|
|
8
|
+
# Deflate64 decoder
|
|
9
|
+
class Decoder
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :window_size
|
|
13
|
+
|
|
14
|
+
def initialize(input_stream)
|
|
15
|
+
@input_stream = input_stream
|
|
16
|
+
@window_size = DICTIONARY_SIZE
|
|
17
|
+
@window = []
|
|
18
|
+
@huffman = HuffmanCoder.new
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Decompress input stream to output stream
|
|
22
|
+
#
|
|
23
|
+
# @param output_stream [IO] Output data stream
|
|
24
|
+
def decompress(output_stream)
|
|
25
|
+
compressed_data = @input_stream.read
|
|
26
|
+
|
|
27
|
+
# Deserialize trees and compressed data
|
|
28
|
+
literal_tree, distance_tree, data = deserialize_with_trees(compressed_data)
|
|
29
|
+
|
|
30
|
+
# Decode Huffman-encoded data
|
|
31
|
+
tokens = @huffman.decode(data, literal_tree, distance_tree)
|
|
32
|
+
|
|
33
|
+
# Reconstruct data from LZ77 tokens
|
|
34
|
+
decompressed = reconstruct_from_tokens(tokens)
|
|
35
|
+
|
|
36
|
+
output_stream.write(decompressed)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Deserialize compressed data with Huffman trees
|
|
40
|
+
#
|
|
41
|
+
# @param data [String] Serialized compressed data
|
|
42
|
+
# @return [Array] Literal tree, distance tree, compressed data
|
|
43
|
+
def deserialize_with_trees(data)
|
|
44
|
+
# Extract sizes (4 bytes each)
|
|
45
|
+
literal_size, distance_size = data.unpack("NN")
|
|
46
|
+
offset = 8
|
|
47
|
+
|
|
48
|
+
# Extract literal tree JSON
|
|
49
|
+
literal_json = data[offset, literal_size]
|
|
50
|
+
offset += literal_size
|
|
51
|
+
|
|
52
|
+
# Extract distance tree JSON
|
|
53
|
+
distance_json = data[offset, distance_size]
|
|
54
|
+
offset += distance_size
|
|
55
|
+
|
|
56
|
+
# Extract compressed data
|
|
57
|
+
compressed = data[offset..]
|
|
58
|
+
|
|
59
|
+
# Parse trees from JSON with symbol keys as integers
|
|
60
|
+
literal_tree = parse_tree_from_json(literal_json)
|
|
61
|
+
distance_tree = parse_tree_from_json(distance_json)
|
|
62
|
+
|
|
63
|
+
[literal_tree, distance_tree, compressed]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Parse Huffman tree from JSON with integer keys
|
|
67
|
+
#
|
|
68
|
+
# @param json [String] JSON string
|
|
69
|
+
# @return [Hash] Huffman tree with integer keys
|
|
70
|
+
def parse_tree_from_json(json)
|
|
71
|
+
parsed = JSON.parse(json)
|
|
72
|
+
# Convert string keys back to integers
|
|
73
|
+
parsed.transform_keys(&:to_i)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Reconstruct data from LZ77 tokens
|
|
77
|
+
#
|
|
78
|
+
# @param tokens [Array<Hash>] LZ77 tokens
|
|
79
|
+
# @return [String] Decompressed data
|
|
80
|
+
def reconstruct_from_tokens(tokens)
|
|
81
|
+
output = []
|
|
82
|
+
|
|
83
|
+
tokens.each do |token|
|
|
84
|
+
if token[:type] == :literal
|
|
85
|
+
byte_char = token[:value].chr(Encoding::BINARY)
|
|
86
|
+
output << byte_char
|
|
87
|
+
@window << token[:value]
|
|
88
|
+
elsif token[:type] == :match
|
|
89
|
+
copy_from_window(
|
|
90
|
+
output,
|
|
91
|
+
token[:distance],
|
|
92
|
+
token[:length],
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Maintain 64KB window
|
|
97
|
+
while @window.size > @window_size
|
|
98
|
+
@window.shift
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
output.join.force_encoding(Encoding::BINARY)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Decode single block
|
|
106
|
+
#
|
|
107
|
+
# @param data [String] Compressed block
|
|
108
|
+
# @return [String] Decompressed data
|
|
109
|
+
def decode_block(data)
|
|
110
|
+
tokens = @huffman.decode(data, {}, {})
|
|
111
|
+
reconstruct_from_tokens(tokens)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
# Copy data from sliding window
|
|
117
|
+
#
|
|
118
|
+
# @param output [Array] Output buffer
|
|
119
|
+
# @param distance [Integer] Distance back in window
|
|
120
|
+
# @param length [Integer] Number of bytes to copy
|
|
121
|
+
def copy_from_window(output, distance, length)
|
|
122
|
+
start_pos = @window.size - distance
|
|
123
|
+
|
|
124
|
+
# Check if we're trying to copy from beyond the window
|
|
125
|
+
if start_pos.negative?
|
|
126
|
+
raise Omnizip::DecompressionError,
|
|
127
|
+
"Invalid distance: #{distance} exceeds window size #{@window.size}"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
length.times do |i|
|
|
131
|
+
# Handle RLE case where we copy bytes we just wrote
|
|
132
|
+
idx = (start_pos + i) % @window.size
|
|
133
|
+
byte = @window[idx]
|
|
134
|
+
|
|
135
|
+
if byte.nil?
|
|
136
|
+
raise Omnizip::DecompressionError,
|
|
137
|
+
"Window access failed at index #{idx} (start: #{start_pos}, i: #{i})"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
byte_char = byte.chr(Encoding::BINARY)
|
|
141
|
+
output << byte_char
|
|
142
|
+
@window << byte
|
|
143
|
+
|
|
144
|
+
# Maintain window size during copy
|
|
145
|
+
@window.shift if @window.size > @window_size
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|