omnizip 0.4.7-x86_64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +293 -0
- data/CHANGELOG.md +1647 -0
- data/CONTEXT.md +68 -0
- data/COPYING +502 -0
- data/Gemfile +19 -0
- data/LICENSE +12 -0
- data/README.adoc +1327 -0
- data/Rakefile +15 -0
- data/TODO.refactor/00-overview.md +67 -0
- data/TODO.refactor/01-registry-base-class.md +81 -0
- data/TODO.refactor/02-error-hierarchy.md +57 -0
- data/TODO.refactor/03-autoload-entry-point.md +69 -0
- data/TODO.refactor/04-filter-base-consolidation.md +49 -0
- data/TODO.refactor/05-send-private-methods.md +64 -0
- data/TODO.refactor/06-instance-variable-access.md +69 -0
- data/TODO.refactor/07-respond-to-replacement.md +237 -0
- data/TODO.refactor/08-spec-doubles.md +27 -0
- data/TODO.refactor/09-cli-shared-module.md +35 -0
- data/TODO.refactor/10-format-detector-ocp.md +34 -0
- data/TODO.refactor/11-convenience-decoupling.md +38 -0
- data/TODO.refactor/12-thread-safety.md +8 -0
- data/TODO.refactor/13-lutaml-model-migration.md +158 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -0
- data/benchmark/README.md +260 -0
- data/benchmark/benchmark_suite.rb +125 -0
- data/benchmark/compression_bench.rb +181 -0
- data/benchmark/filter_bench.rb +180 -0
- data/benchmark/models/benchmark_result.rb +59 -0
- data/benchmark/models/comparison_result.rb +69 -0
- data/benchmark/profile_suite.rb +167 -0
- data/benchmark/reporter.rb +150 -0
- data/benchmark/run_benchmarks.rb +66 -0
- data/benchmark/test_data.rb +137 -0
- data/config/formats/rar3_spec.yml +92 -0
- data/config/formats/rar5_spec.yml +102 -0
- data/docs/.github/workflows/docs.yml +142 -0
- data/docs/.gitignore +21 -0
- data/docs/.lychee.toml +67 -0
- data/docs/Gemfile +13 -0
- data/docs/RAR_WRITE_SUPPORT.md +26 -0
- data/docs/README.md +101 -0
- data/docs/_config.yml +112 -0
- data/docs/assets/logo.svg +1 -0
- data/docs/assets/omnizip-logo.pdf +1540 -11
- data/docs/comparison/feature-matrix.adoc +694 -0
- data/docs/comparison/index.adoc +113 -0
- data/docs/comparison/vs-7zip.adoc +309 -0
- data/docs/comparison/vs-peazip.adoc +77 -0
- data/docs/comparison/vs-rubyzip.adoc +342 -0
- data/docs/comparison/vs-winrar.adoc +100 -0
- data/docs/compatibility.adoc +579 -0
- data/docs/concepts/index.adoc +129 -0
- data/docs/developer/architecture.adoc +256 -0
- data/docs/developer/contributing.adoc +158 -0
- data/docs/developer/index.adoc +25 -0
- data/docs/developer/testing.adoc +212 -0
- data/docs/getting-started/basic-usage.adoc +263 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +183 -0
- data/docs/getting-started/your-first-archive.adoc +219 -0
- data/docs/guides/advanced-features/encryption.adoc +277 -0
- data/docs/guides/advanced-features/index.adoc +59 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
- data/docs/guides/advanced-features/streaming.adoc +142 -0
- data/docs/guides/archive-formats/gzip-format.adoc +105 -0
- data/docs/guides/archive-formats/index.adoc +160 -0
- data/docs/guides/archive-formats/ole-format.adoc +151 -0
- data/docs/guides/archive-formats/rar-format.adoc +104 -0
- data/docs/guides/archive-formats/rar5.adoc +521 -0
- data/docs/guides/archive-formats/rpm-format.adoc +108 -0
- data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
- data/docs/guides/archive-formats/tar-format.adoc +106 -0
- data/docs/guides/archive-formats/xz-format.adoc +118 -0
- data/docs/guides/archive-formats/zip-format.adoc +35 -0
- data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
- data/docs/guides/compression-algorithms/deflate.adoc +313 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +394 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
- data/docs/guides/creating-archives.adoc +348 -0
- data/docs/guides/extracting-archives.adoc +53 -0
- data/docs/guides/format-conversion.adoc +64 -0
- data/docs/guides/index.adoc +49 -0
- data/docs/guides/migration-rubyzip.adoc +217 -0
- data/docs/guides/parity-archives.adoc +605 -0
- data/docs/guides/performance-tuning.adoc +88 -0
- data/docs/index.adoc +228 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +187 -0
- data/docs/reference/cli/compress-command.adoc +114 -0
- data/docs/reference/cli/overview.adoc +140 -0
- data/docs/reference/index.adoc +26 -0
- data/docs/resources/faq.adoc +185 -0
- data/docs/resources/quick-reference.adoc +222 -0
- data/docs/rust-backend.md +0 -0
- data/docs/troubleshooting/index.adoc +207 -0
- data/docs/xar_format.md +216 -0
- data/examples/api_comparison.rb +205 -0
- data/examples/deflate64_example.rb +96 -0
- data/examples/par2_demo.rb +121 -0
- data/examples/quick_start_native.rb +150 -0
- data/examples/quick_start_rubyzip.rb +115 -0
- data/examples/rubyzip_compatibility_demo.rb +194 -0
- data/exe/omnizip +27 -0
- data/lib/omnizip/algorithm.rb +176 -0
- data/lib/omnizip/algorithm_registry.rb +65 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
- data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
- data/lib/omnizip/algorithms/bzip2.rb +108 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
- data/lib/omnizip/algorithms/deflate.rb +135 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
- data/lib/omnizip/algorithms/deflate64.rb +118 -0
- data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
- data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
- data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
- data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
- data/lib/omnizip/algorithms/lzma/match.rb +32 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
- data/lib/omnizip/algorithms/lzma.rb +266 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +133 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +146 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +122 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
- data/lib/omnizip/algorithms/registration.rb +28 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
- data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
- data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
- data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
- data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
- data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
- data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
- data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
- data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +210 -0
- data/lib/omnizip/algorithms.rb +35 -0
- data/lib/omnizip/archive/builder.rb +48 -0
- data/lib/omnizip/archive/reader_session.rb +67 -0
- data/lib/omnizip/archive.rb +86 -0
- data/lib/omnizip/archive_handler.rb +82 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
- data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
- data/lib/omnizip/archive_handlers.rb +18 -0
- data/lib/omnizip/backends.rb +160 -0
- data/lib/omnizip/buffer/memory_archive.rb +246 -0
- data/lib/omnizip/buffer/memory_extractor.rb +234 -0
- data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
- data/lib/omnizip/buffer.rb +187 -0
- data/lib/omnizip/checksum_registry.rb +41 -0
- data/lib/omnizip/checksums/crc32.rb +101 -0
- data/lib/omnizip/checksums/crc64.rb +102 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/registration.rb +16 -0
- data/lib/omnizip/checksums/verifier.rb +130 -0
- data/lib/omnizip/checksums.rb +11 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +123 -0
- data/lib/omnizip/chunked.rb +123 -0
- data/lib/omnizip/cli/output_formatter.rb +112 -0
- data/lib/omnizip/cli.rb +604 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +245 -0
- data/lib/omnizip/commands/archive_extract_command.rb +231 -0
- data/lib/omnizip/commands/archive_list_command.rb +204 -0
- data/lib/omnizip/commands/archive_repair_command.rb +129 -0
- data/lib/omnizip/commands/archive_verify_command.rb +115 -0
- data/lib/omnizip/commands/compress_command.rb +115 -0
- data/lib/omnizip/commands/decompress_command.rb +149 -0
- data/lib/omnizip/commands/list_command.rb +51 -0
- data/lib/omnizip/commands/metadata_command.rb +215 -0
- data/lib/omnizip/commands/parity_create_command.rb +114 -0
- data/lib/omnizip/commands/parity_repair_command.rb +120 -0
- data/lib/omnizip/commands/parity_verify_command.rb +122 -0
- data/lib/omnizip/commands/profile_list_command.rb +54 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/commands.rb +21 -0
- data/lib/omnizip/convenience.rb +389 -0
- data/lib/omnizip/converter/conversion_registry.rb +50 -0
- data/lib/omnizip/converter/conversion_strategy.rb +108 -0
- data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
- data/lib/omnizip/converter.rb +124 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/crypto.rb +11 -0
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/error.rb +110 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
- data/lib/omnizip/eta/rate_calculator.rb +104 -0
- data/lib/omnizip/eta/sample_history.rb +143 -0
- data/lib/omnizip/eta/time_estimator.rb +106 -0
- data/lib/omnizip/eta.rb +68 -0
- data/lib/omnizip/extraction/filter_chain.rb +179 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
- data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
- data/lib/omnizip/extraction/regex_pattern.rb +50 -0
- data/lib/omnizip/extraction/selective_extractor.rb +247 -0
- data/lib/omnizip/extraction.rb +115 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +117 -0
- data/lib/omnizip/filter.rb +141 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +113 -0
- data/lib/omnizip/filters/bcj.rb +277 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
- data/lib/omnizip/filters/bcj2.rb +93 -0
- data/lib/omnizip/filters/bcj_arm.rb +174 -0
- data/lib/omnizip/filters/bcj_arm64.rb +242 -0
- data/lib/omnizip/filters/bcj_ia64.rb +194 -0
- data/lib/omnizip/filters/bcj_ppc.rb +188 -0
- data/lib/omnizip/filters/bcj_sparc.rb +174 -0
- data/lib/omnizip/filters/bcj_x86.rb +191 -0
- data/lib/omnizip/filters/delta.rb +195 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/filters.rb +20 -0
- data/lib/omnizip/format_detector.rb +166 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +159 -0
- data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +389 -0
- data/lib/omnizip/formats/cpio/reader.rb +194 -0
- data/lib/omnizip/formats/cpio/writer.rb +232 -0
- data/lib/omnizip/formats/cpio.rb +132 -0
- data/lib/omnizip/formats/format_spec_loader.rb +228 -0
- data/lib/omnizip/formats/gzip.rb +236 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
- data/lib/omnizip/formats/iso/directory_record.rb +162 -0
- data/lib/omnizip/formats/iso/joliet.rb +204 -0
- data/lib/omnizip/formats/iso/path_table.rb +125 -0
- data/lib/omnizip/formats/iso/reader.rb +194 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +543 -0
- data/lib/omnizip/formats/iso.rb +133 -0
- data/lib/omnizip/formats/lzip.rb +161 -0
- data/lib/omnizip/formats/lzma_alone.rb +149 -0
- data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
- data/lib/omnizip/formats/msi/constants.rb +157 -0
- data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
- data/lib/omnizip/formats/msi/entry.rb +134 -0
- data/lib/omnizip/formats/msi/reader.rb +301 -0
- data/lib/omnizip/formats/msi/string_pool.rb +246 -0
- data/lib/omnizip/formats/msi/table_parser.rb +244 -0
- data/lib/omnizip/formats/msi.rb +73 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
- data/lib/omnizip/formats/ole/constants.rb +61 -0
- data/lib/omnizip/formats/ole/dirent.rb +439 -0
- data/lib/omnizip/formats/ole/header.rb +199 -0
- data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
- data/lib/omnizip/formats/ole/storage.rb +482 -0
- data/lib/omnizip/formats/ole/types/variant.rb +338 -0
- data/lib/omnizip/formats/ole.rb +143 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
- data/lib/omnizip/formats/rar/block_parser.rb +282 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
- data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
- data/lib/omnizip/formats/rar/compression.rb +17 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +88 -0
- data/lib/omnizip/formats/rar/decompressor.rb +316 -0
- data/lib/omnizip/formats/rar/external_writer.rb +311 -0
- data/lib/omnizip/formats/rar/header.rb +209 -0
- data/lib/omnizip/formats/rar/license_validator.rb +111 -0
- data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
- data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
- data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
- data/lib/omnizip/formats/rar/models.rb +14 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
- data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
- data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
- data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
- data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
- data/lib/omnizip/formats/rar/reader.rb +377 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
- data/lib/omnizip/formats/rar/writer.rb +437 -0
- data/lib/omnizip/formats/rar.rb +193 -0
- data/lib/omnizip/formats/rar3/compressor.rb +71 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar3/reader.rb +107 -0
- data/lib/omnizip/formats/rar3/writer.rb +220 -0
- data/lib/omnizip/formats/rar3.rb +15 -0
- data/lib/omnizip/formats/rar5/compressor.rb +71 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar5/reader.rb +130 -0
- data/lib/omnizip/formats/rar5/writer.rb +65 -0
- data/lib/omnizip/formats/rar5.rb +15 -0
- data/lib/omnizip/formats/rpm/constants.rb +58 -0
- data/lib/omnizip/formats/rpm/entry.rb +106 -0
- data/lib/omnizip/formats/rpm/header.rb +106 -0
- data/lib/omnizip/formats/rpm/lead.rb +132 -0
- data/lib/omnizip/formats/rpm/tag.rb +228 -0
- data/lib/omnizip/formats/rpm/writer.rb +652 -0
- data/lib/omnizip/formats/rpm.rb +458 -0
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
- data/lib/omnizip/formats/seven_zip/header.rb +102 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/models.rb +20 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
- data/lib/omnizip/formats/seven_zip.rb +179 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +98 -0
- data/lib/omnizip/formats/tar/header.rb +206 -0
- data/lib/omnizip/formats/tar/reader.rb +119 -0
- data/lib/omnizip/formats/tar/writer.rb +212 -0
- data/lib/omnizip/formats/tar.rb +74 -0
- data/lib/omnizip/formats/xar/constants.rb +119 -0
- data/lib/omnizip/formats/xar/entry.rb +268 -0
- data/lib/omnizip/formats/xar/header.rb +223 -0
- data/lib/omnizip/formats/xar/reader.rb +400 -0
- data/lib/omnizip/formats/xar/toc.rb +570 -0
- data/lib/omnizip/formats/xar/writer.rb +461 -0
- data/lib/omnizip/formats/xar.rb +145 -0
- data/lib/omnizip/formats/xz/reader.rb +121 -0
- data/lib/omnizip/formats/xz/writer.rb +416 -0
- data/lib/omnizip/formats/xz.rb +210 -0
- data/lib/omnizip/formats/xz_const.rb +49 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl.rb +52 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
- data/lib/omnizip/formats/zip/reader.rb +376 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +489 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/formats.rb +29 -0
- data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
- data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
- data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
- data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
- data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
- data/lib/omnizip/implementations/base.rb +19 -0
- data/lib/omnizip/implementations/rust/archive.rb +93 -0
- data/lib/omnizip/implementations/rust/library.rb +221 -0
- data/lib/omnizip/implementations/rust.rb +26 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
- data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
- data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
- data/lib/omnizip/implementations/seven_zip.rb +11 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
- data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
- data/lib/omnizip/implementations/xz_utils.rb +10 -0
- data/lib/omnizip/implementations.rb +25 -0
- data/lib/omnizip/io/buffered_input.rb +147 -0
- data/lib/omnizip/io/buffered_output.rb +106 -0
- data/lib/omnizip/io/source.rb +143 -0
- data/lib/omnizip/io/stream_manager.rb +117 -0
- data/lib/omnizip/io.rb +15 -0
- data/lib/omnizip/link_handler/hard_link.rb +79 -0
- data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
- data/lib/omnizip/link_handler.rb +129 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +153 -0
- data/lib/omnizip/metadata/metadata_editor.rb +169 -0
- data/lib/omnizip/metadata/metadata_registry.rb +71 -0
- data/lib/omnizip/metadata/metadata_validator.rb +101 -0
- data/lib/omnizip/metadata.rb +58 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +41 -0
- data/lib/omnizip/models/attribute_apply.rb +40 -0
- data/lib/omnizip/models/compression_options.rb +53 -0
- data/lib/omnizip/models/conversion_options.rb +79 -0
- data/lib/omnizip/models/conversion_result.rb +141 -0
- data/lib/omnizip/models/eta_result.rb +45 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +142 -0
- data/lib/omnizip/models/filter_config.rb +148 -0
- data/lib/omnizip/models/match_result.rb +141 -0
- data/lib/omnizip/models/optimization_suggestion.rb +95 -0
- data/lib/omnizip/models/parallel_options.rb +116 -0
- data/lib/omnizip/models/performance_result.rb +85 -0
- data/lib/omnizip/models/profile_report.rb +116 -0
- data/lib/omnizip/models/progress_options.rb +39 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +45 -0
- data/lib/omnizip/parallel/engine.rb +52 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +225 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
- data/lib/omnizip/parallel/thread_pool.rb +60 -0
- data/lib/omnizip/parallel/worker_pool.rb +227 -0
- data/lib/omnizip/parallel.rb +156 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +71 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
- data/lib/omnizip/parity/models/main_packet.rb +126 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +102 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
- data/lib/omnizip/parity/models.rb +27 -0
- data/lib/omnizip/parity/par2_creator.rb +496 -0
- data/lib/omnizip/parity/par2_repairer.rb +409 -0
- data/lib/omnizip/parity/par2_verifier.rb +373 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
- data/lib/omnizip/parity.rb +207 -0
- data/lib/omnizip/password/encryption_registry.rb +26 -0
- data/lib/omnizip/password/encryption_strategy.rb +96 -0
- data/lib/omnizip/password/password_validator.rb +129 -0
- data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
- data/lib/omnizip/password.rb +88 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
- data/lib/omnizip/pipe.rb +120 -0
- data/lib/omnizip/platform/ntfs_streams.rb +200 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +36 -0
- data/lib/omnizip/profile/balanced_profile.rb +31 -0
- data/lib/omnizip/profile/binary_profile.rb +33 -0
- data/lib/omnizip/profile/compression_profile.rb +157 -0
- data/lib/omnizip/profile/custom_profile.rb +155 -0
- data/lib/omnizip/profile/fast_profile.rb +31 -0
- data/lib/omnizip/profile/maximum_profile.rb +31 -0
- data/lib/omnizip/profile/profile_detector.rb +108 -0
- data/lib/omnizip/profile/profile_registry.rb +160 -0
- data/lib/omnizip/profile/text_profile.rb +33 -0
- data/lib/omnizip/profile.rb +261 -0
- data/lib/omnizip/profiler/memory_profiler.rb +66 -0
- data/lib/omnizip/profiler/method_profiler.rb +49 -0
- data/lib/omnizip/profiler/report_generator.rb +158 -0
- data/lib/omnizip/profiler.rb +192 -0
- data/lib/omnizip/progress/callback_reporter.rb +34 -0
- data/lib/omnizip/progress/console_reporter.rb +59 -0
- data/lib/omnizip/progress/log_reporter.rb +89 -0
- data/lib/omnizip/progress/operation_progress.rb +118 -0
- data/lib/omnizip/progress/progress_bar.rb +156 -0
- data/lib/omnizip/progress/progress_reporter.rb +40 -0
- data/lib/omnizip/progress/progress_tracker.rb +215 -0
- data/lib/omnizip/progress/silent_reporter.rb +22 -0
- data/lib/omnizip/progress.rb +131 -0
- data/lib/omnizip/registry.rb +111 -0
- data/lib/omnizip/rubyzip_compat.rb +61 -0
- data/lib/omnizip/temp/safe_extract.rb +124 -0
- data/lib/omnizip/temp/temp_file.rb +123 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +184 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +160 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +270 -0
- data/lib/omnizip/zip/output_stream.rb +320 -0
- data/lib/omnizip/zip.rb +23 -0
- data/lib/omnizip.rb +157 -0
- data/lib/tasks/msi_test_files.rake +66 -0
- data/lib/tasks/platform_gems.rake +147 -0
- data/lib/tasks/rust_backend.rake +48 -0
- data/readme-docs/advanced-features.adoc +514 -0
- data/readme-docs/api-usage.adoc +445 -0
- data/readme-docs/architecture.adoc +450 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +446 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +316 -0
- data/readme-docs/installation.adoc +228 -0
- data/readme-docs/par2-archives.adoc +608 -0
- data/readme-docs/performance-profiler.adoc +389 -0
- data/readme-docs/preprocessing-filters.adoc +280 -0
- data/vendor/libomnizip_ffi.so +0 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +768 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Parity
|
|
5
|
+
# Chunked block processor for incremental Reed-Solomon recovery
|
|
6
|
+
#
|
|
7
|
+
# Implements correct RS decoding: x = A^-1 * b
|
|
8
|
+
# where b[i] = recovery[i] - sum(present[k] * base[present[k]]^exponent[i])
|
|
9
|
+
#
|
|
10
|
+
# Processes large blocks incrementally in memory-efficient chunks.
|
|
11
|
+
class ChunkedBlockProcessor
|
|
12
|
+
# Default chunk size (1MB)
|
|
13
|
+
DEFAULT_CHUNK_SIZE = 1024 * 1024
|
|
14
|
+
|
|
15
|
+
# @return [ReedSolomonMatrix] RS matrix with precomputed coefficients
|
|
16
|
+
attr_reader :matrix
|
|
17
|
+
|
|
18
|
+
# @return [Hash<Integer, String>] Present input blocks (index => data)
|
|
19
|
+
attr_reader :present_blocks
|
|
20
|
+
|
|
21
|
+
# @return [Hash<Integer, String>] Recovery blocks (exponent => data)
|
|
22
|
+
attr_reader :recovery_blocks
|
|
23
|
+
|
|
24
|
+
# @return [Array<Integer>] Missing block indices to recover
|
|
25
|
+
attr_reader :missing_indices
|
|
26
|
+
|
|
27
|
+
# @return [Integer] Block size in bytes
|
|
28
|
+
attr_reader :block_size
|
|
29
|
+
|
|
30
|
+
# @return [Integer] Chunk size for processing
|
|
31
|
+
attr_reader :chunk_size
|
|
32
|
+
|
|
33
|
+
# Initialize processor
|
|
34
|
+
#
|
|
35
|
+
# @param matrix [ReedSolomonMatrix] Precomputed RS matrix (A^-1)
|
|
36
|
+
# @param present_blocks [Hash<Integer, String>] Present data blocks
|
|
37
|
+
# @param recovery_blocks [Hash<Integer, String>] Recovery blocks (by exponent)
|
|
38
|
+
# @param missing_indices [Array<Integer>] Indices to recover
|
|
39
|
+
# @param block_size [Integer] Block size in bytes
|
|
40
|
+
# @param chunk_size [Integer] Chunk size for processing
|
|
41
|
+
def initialize(matrix, present_blocks, recovery_blocks, missing_indices,
|
|
42
|
+
block_size, chunk_size: DEFAULT_CHUNK_SIZE)
|
|
43
|
+
@matrix = matrix
|
|
44
|
+
@present_blocks = present_blocks
|
|
45
|
+
@recovery_blocks = recovery_blocks
|
|
46
|
+
@missing_indices = missing_indices.sort
|
|
47
|
+
@block_size = block_size
|
|
48
|
+
# Ensure chunk_size is even (we process 16-bit words)
|
|
49
|
+
requested_chunk = [chunk_size, block_size].min
|
|
50
|
+
@chunk_size = requested_chunk - (requested_chunk % 2)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Process all blocks incrementally
|
|
54
|
+
#
|
|
55
|
+
# Implements: x = A^-1 * b
|
|
56
|
+
# where b = recovery - present_contributions
|
|
57
|
+
#
|
|
58
|
+
# @return [Hash<Integer, String>] Recovered blocks
|
|
59
|
+
def process_all
|
|
60
|
+
# Initialize output blocks (all zeros)
|
|
61
|
+
recovered = {}
|
|
62
|
+
missing_indices.each do |idx|
|
|
63
|
+
recovered[idx] = "\x00".b * block_size
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Process block chunk by chunk
|
|
67
|
+
block_offset = 0
|
|
68
|
+
while block_offset < block_size
|
|
69
|
+
current_chunk_size = [chunk_size, block_size - block_offset].min
|
|
70
|
+
process_chunk_at_offset(recovered, block_offset, current_chunk_size)
|
|
71
|
+
block_offset += current_chunk_size
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
recovered
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
# Process one chunk at given offset
|
|
80
|
+
#
|
|
81
|
+
# For each chunk, we:
|
|
82
|
+
# 1. Compute b_vector chunks from recovery blocks
|
|
83
|
+
# 2. Subtract present block contributions to get final b
|
|
84
|
+
# 3. Apply A^-1 matrix to b to get recovered chunks
|
|
85
|
+
#
|
|
86
|
+
# @param recovered [Hash<Integer, String>] Recovered blocks being built
|
|
87
|
+
# @param offset [Integer] Current offset within blocks
|
|
88
|
+
# @param length [Integer] Chunk length
|
|
89
|
+
def process_chunk_at_offset(recovered, offset, length)
|
|
90
|
+
# Step 1: Initialize b vector from recovery blocks
|
|
91
|
+
# b_vector[i] starts as recovery[i] (for each recovery exponent used)
|
|
92
|
+
b_vector = compute_b_vector_chunks(offset, length)
|
|
93
|
+
|
|
94
|
+
# Step 2: Apply A^-1 to b vector to get recovered chunks
|
|
95
|
+
# For each missing block j: recovered[j] = sum(A^-1[j,i] * b[i])
|
|
96
|
+
apply_inverse_matrix(recovered, b_vector, offset, length)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Compute b vector chunks
|
|
100
|
+
#
|
|
101
|
+
# b[i] = recovery[i] - sum(present[k] * base[present[k]]^exponent[i])
|
|
102
|
+
#
|
|
103
|
+
# @param offset [Integer] Offset within blocks
|
|
104
|
+
# @param length [Integer] Chunk length
|
|
105
|
+
# @return [Array<String>] B vector chunks (one per recovery block used)
|
|
106
|
+
def compute_b_vector_chunks(offset, length)
|
|
107
|
+
b_chunks = []
|
|
108
|
+
|
|
109
|
+
# For each recovery block being used (must match matrix computation!)
|
|
110
|
+
matrix.used_recovery_exponents.each_with_index do |exponent, _exp_idx|
|
|
111
|
+
# Start with recovery block chunk
|
|
112
|
+
recovery_data = recovery_blocks[exponent]
|
|
113
|
+
b_chunk = recovery_data[offset, length].dup
|
|
114
|
+
|
|
115
|
+
# Subtract contributions from present blocks
|
|
116
|
+
present_blocks.each do |present_idx, present_data|
|
|
117
|
+
coefficient = matrix.present_contribution_coefficient(present_idx,
|
|
118
|
+
exponent)
|
|
119
|
+
next if coefficient.zero?
|
|
120
|
+
|
|
121
|
+
present_chunk = present_data[offset, length]
|
|
122
|
+
|
|
123
|
+
# Subtract: b -= present * coefficient
|
|
124
|
+
# In GF(2^16), subtraction is XOR, so: b ^= present * coefficient
|
|
125
|
+
subtract_contribution(b_chunk, present_chunk, coefficient, length)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
b_chunks << b_chunk
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
b_chunks
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Subtract present block contribution from b chunk
|
|
135
|
+
#
|
|
136
|
+
# b_chunk ^= present_chunk * coefficient (GF subtraction is XOR)
|
|
137
|
+
#
|
|
138
|
+
# @param b_chunk [String] B vector chunk (modified in place)
|
|
139
|
+
# @param present_chunk [String] Present block chunk
|
|
140
|
+
# @param coefficient [Integer] Galois field coefficient
|
|
141
|
+
# @param length [Integer] Chunk length
|
|
142
|
+
def subtract_contribution(b_chunk, present_chunk, coefficient, length)
|
|
143
|
+
num_words = length / 2
|
|
144
|
+
|
|
145
|
+
num_words.times do |i|
|
|
146
|
+
word_offset = i * 2
|
|
147
|
+
|
|
148
|
+
# Read present word
|
|
149
|
+
present_word = present_chunk.getbyte(word_offset) |
|
|
150
|
+
(present_chunk.getbyte(word_offset + 1) << 8)
|
|
151
|
+
|
|
152
|
+
# Read current b word
|
|
153
|
+
b_word = b_chunk.getbyte(word_offset) |
|
|
154
|
+
(b_chunk.getbyte(word_offset + 1) << 8)
|
|
155
|
+
|
|
156
|
+
# Compute: b ^= present * coefficient
|
|
157
|
+
contribution = Galois16.multiply(present_word, coefficient)
|
|
158
|
+
result = Galois16.add(b_word, contribution) # add is XOR in GF(2^16)
|
|
159
|
+
|
|
160
|
+
# Write back
|
|
161
|
+
b_chunk.setbyte(word_offset, result & 0xFF)
|
|
162
|
+
b_chunk.setbyte(word_offset + 1, (result >> 8) & 0xFF)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Apply inverse matrix to b vector
|
|
167
|
+
#
|
|
168
|
+
# For each missing block j:
|
|
169
|
+
# recovered[j] += sum_i(A^-1[j,i] * b[i])
|
|
170
|
+
#
|
|
171
|
+
# @param recovered [Hash<Integer, String>] Recovered blocks being built
|
|
172
|
+
# @param b_vector [Array<String>] B vector chunks
|
|
173
|
+
# @param offset [Integer] Offset within blocks
|
|
174
|
+
# @param length [Integer] Chunk length
|
|
175
|
+
def apply_inverse_matrix(recovered, b_vector, offset, length)
|
|
176
|
+
# For each output (missing block)
|
|
177
|
+
missing_indices.each_with_index do |missing_idx, output_idx|
|
|
178
|
+
output_block = recovered[missing_idx]
|
|
179
|
+
|
|
180
|
+
# For each b vector element (recovery block)
|
|
181
|
+
b_vector.each_with_index do |b_chunk, recovery_idx|
|
|
182
|
+
# Get coefficient from A^-1
|
|
183
|
+
coefficient = matrix.coefficient(output_idx, recovery_idx)
|
|
184
|
+
next if coefficient.zero?
|
|
185
|
+
|
|
186
|
+
# CRITICAL: Accumulate chunk at the correct offset
|
|
187
|
+
matrix.process_chunk(coefficient, b_chunk, output_block, length,
|
|
188
|
+
output_offset: offset)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Parity
|
|
5
|
+
# Pure implementation of Galois Field GF(2^16) arithmetic
|
|
6
|
+
# Uses generator polynomial 0x1100B (69643) as per PAR2 specification
|
|
7
|
+
#
|
|
8
|
+
# This is pure algorithm code with no I/O dependencies.
|
|
9
|
+
# All operations are exact (no floating point) and work in GF(2^16).
|
|
10
|
+
class Galois16
|
|
11
|
+
BITS = 16
|
|
12
|
+
GENERATOR = 0x1100B # 69643 in decimal
|
|
13
|
+
FIELD_SIZE = 1 << BITS # 65536
|
|
14
|
+
LIMIT = FIELD_SIZE - 1 # 65535
|
|
15
|
+
|
|
16
|
+
# Lookup tables for efficient operations
|
|
17
|
+
@log_table = nil
|
|
18
|
+
@antilog_table = nil
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
# Build log and antilog tables
|
|
22
|
+
# This is called once when the class is loaded
|
|
23
|
+
def build_tables
|
|
24
|
+
return if @log_table && @antilog_table
|
|
25
|
+
|
|
26
|
+
@log_table = Array.new(FIELD_SIZE)
|
|
27
|
+
@antilog_table = Array.new(FIELD_SIZE)
|
|
28
|
+
|
|
29
|
+
b = 1
|
|
30
|
+
LIMIT.times do |l|
|
|
31
|
+
@log_table[b] = l
|
|
32
|
+
@antilog_table[l] = b
|
|
33
|
+
|
|
34
|
+
b <<= 1
|
|
35
|
+
b ^= GENERATOR if b.anybits?(FIELD_SIZE)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Special cases for zero
|
|
39
|
+
@log_table[0] = LIMIT
|
|
40
|
+
@antilog_table[LIMIT] = 0
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Get log value (discrete logarithm)
|
|
44
|
+
def log(value)
|
|
45
|
+
@log_table[value & 0xFFFF]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Get antilog value (inverse of log)
|
|
49
|
+
def antilog(value)
|
|
50
|
+
@antilog_table[value % FIELD_SIZE]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Addition in GF(2^16) - same as subtraction (XOR)
|
|
54
|
+
def add(a, b)
|
|
55
|
+
(a ^ b) & 0xFFFF
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Subtraction in GF(2^16) - same as addition (XOR)
|
|
59
|
+
alias subtract add
|
|
60
|
+
|
|
61
|
+
# Multiplication in GF(2^16)
|
|
62
|
+
def multiply(a, b)
|
|
63
|
+
a &= 0xFFFF
|
|
64
|
+
b &= 0xFFFF
|
|
65
|
+
|
|
66
|
+
return 0 if a.zero? || b.zero?
|
|
67
|
+
|
|
68
|
+
sum = @log_table[a] + @log_table[b]
|
|
69
|
+
sum -= LIMIT if sum >= LIMIT
|
|
70
|
+
@antilog_table[sum]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Division in GF(2^16)
|
|
74
|
+
def divide(a, b)
|
|
75
|
+
a &= 0xFFFF
|
|
76
|
+
b &= 0xFFFF
|
|
77
|
+
|
|
78
|
+
return 0 if a.zero?
|
|
79
|
+
raise ArgumentError, "Division by zero in GF(2^16)" if b.zero?
|
|
80
|
+
|
|
81
|
+
diff = @log_table[a] - @log_table[b]
|
|
82
|
+
diff += LIMIT if diff.negative?
|
|
83
|
+
@antilog_table[diff]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Power in GF(2^16): compute a^n
|
|
87
|
+
def power(a, n)
|
|
88
|
+
a &= 0xFFFF
|
|
89
|
+
|
|
90
|
+
return 1 if n.zero?
|
|
91
|
+
return 0 if a.zero?
|
|
92
|
+
|
|
93
|
+
product = @log_table[a] * n
|
|
94
|
+
|
|
95
|
+
# Reduce modulo LIMIT using the identity:
|
|
96
|
+
# product mod LIMIT = (product >> BITS) + (product & LIMIT)
|
|
97
|
+
product = (product >> BITS) + (product & LIMIT)
|
|
98
|
+
product -= LIMIT if product >= LIMIT
|
|
99
|
+
|
|
100
|
+
@antilog_table[product]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Compute GCD using Euclidean algorithm
|
|
104
|
+
def gcd(a, b)
|
|
105
|
+
while a != 0 && b != 0
|
|
106
|
+
if a > b
|
|
107
|
+
a %= b
|
|
108
|
+
else
|
|
109
|
+
b %= a
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
a + b
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Select base values for Reed-Solomon matrix
|
|
116
|
+
# Par2cmdline uses sequential logbases: base[i] = antilog[i]
|
|
117
|
+
# base[0] = antilog[0] = 1, base[1] = antilog[1] = 2, etc.
|
|
118
|
+
def select_bases(count)
|
|
119
|
+
raise ArgumentError, "Too many bases requested" if count >= LIMIT
|
|
120
|
+
|
|
121
|
+
bases = []
|
|
122
|
+
|
|
123
|
+
count.times do |i|
|
|
124
|
+
# Par2cmdline uses logbase = i (NOT i+1!)
|
|
125
|
+
# This gives: base[0]=1, base[1]=2, base[2]=4, etc.
|
|
126
|
+
logbase = i
|
|
127
|
+
|
|
128
|
+
if logbase >= LIMIT
|
|
129
|
+
raise ArgumentError,
|
|
130
|
+
"Too many input blocks for Reed Solomon matrix"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Convert log to actual value
|
|
134
|
+
bases << @antilog_table[logbase]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
bases
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Build tables when class is loaded
|
|
142
|
+
build_tables
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Parity
|
|
5
|
+
module Models
|
|
6
|
+
# PAR2 Creator packet
|
|
7
|
+
#
|
|
8
|
+
# Contains information about the tool that created the PAR2 file.
|
|
9
|
+
# This packet is optional but recommended for identification.
|
|
10
|
+
#
|
|
11
|
+
# Body structure:
|
|
12
|
+
# - creator_string (variable): Null-terminated string identifying the tool
|
|
13
|
+
class CreatorPacket < Packet
|
|
14
|
+
# Packet type identifier
|
|
15
|
+
PACKET_TYPE = "PAR 2.0\x00Creator\x00"
|
|
16
|
+
|
|
17
|
+
# Creator identification string (without null terminator)
|
|
18
|
+
attribute :creator_string, :string, default: -> { "Omnizip PAR2" }
|
|
19
|
+
|
|
20
|
+
# Initialize creator packet
|
|
21
|
+
#
|
|
22
|
+
# @param attributes [Hash] Packet attributes
|
|
23
|
+
def initialize(**attributes)
|
|
24
|
+
super
|
|
25
|
+
self.type = PACKET_TYPE
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Parse body data into attributes
|
|
29
|
+
#
|
|
30
|
+
# Body format:
|
|
31
|
+
# - creator_string: null-terminated string
|
|
32
|
+
def parse_body
|
|
33
|
+
return if body_data.nil? || body_data.empty?
|
|
34
|
+
|
|
35
|
+
# Read creator string (null-terminated)
|
|
36
|
+
self.creator_string = body_data.unpack1("Z*")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Build body data from attributes
|
|
40
|
+
#
|
|
41
|
+
# Constructs binary body data with null terminator
|
|
42
|
+
#
|
|
43
|
+
# @return [String] Binary body data
|
|
44
|
+
def build_body
|
|
45
|
+
data = +""
|
|
46
|
+
|
|
47
|
+
# Write creator string (null-terminated)
|
|
48
|
+
data << creator_string
|
|
49
|
+
data << "\x00"
|
|
50
|
+
|
|
51
|
+
self.body_data = data
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Get creator tool name
|
|
55
|
+
#
|
|
56
|
+
# @return [String] Creator tool name
|
|
57
|
+
def tool_name
|
|
58
|
+
creator_string.split.first || creator_string
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Get creator version if available
|
|
62
|
+
#
|
|
63
|
+
# @return [String, nil] Version string or nil
|
|
64
|
+
def version
|
|
65
|
+
parts = creator_string.split
|
|
66
|
+
parts.size > 1 ? parts[1..].join(" ") : nil
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Parity
|
|
5
|
+
module Models
|
|
6
|
+
# PAR2 File Description packet
|
|
7
|
+
#
|
|
8
|
+
# Contains metadata about a protected file including hashes and filename.
|
|
9
|
+
#
|
|
10
|
+
# Body structure:
|
|
11
|
+
# - file_id (16 bytes): MD5 hash identifying the file
|
|
12
|
+
# - file_hash (16 bytes): MD5 hash of complete file content
|
|
13
|
+
# - file_hash_16k (16 bytes): MD5 hash of first 16KB
|
|
14
|
+
# - length (8 bytes, Q<): File size in bytes
|
|
15
|
+
# - filename (variable): Null-terminated filename, padded to multiple of 4
|
|
16
|
+
class FileDescriptionPacket < Packet
|
|
17
|
+
# Packet type identifier
|
|
18
|
+
PACKET_TYPE = "PAR 2.0\x00FileDesc"
|
|
19
|
+
|
|
20
|
+
# File identifier (16 bytes MD5)
|
|
21
|
+
attribute :file_id, :string
|
|
22
|
+
|
|
23
|
+
# Full file hash (16 bytes MD5)
|
|
24
|
+
attribute :file_hash, :string
|
|
25
|
+
|
|
26
|
+
# First 16KB hash (16 bytes MD5)
|
|
27
|
+
attribute :file_hash_16k, :string
|
|
28
|
+
|
|
29
|
+
# File length in bytes
|
|
30
|
+
attribute :length, :integer
|
|
31
|
+
|
|
32
|
+
# Filename (without null terminator or padding)
|
|
33
|
+
attribute :filename, :string
|
|
34
|
+
|
|
35
|
+
# Initialize file description packet
|
|
36
|
+
#
|
|
37
|
+
# @param attributes [Hash] Packet attributes
|
|
38
|
+
def initialize(**attributes)
|
|
39
|
+
super
|
|
40
|
+
self.type = PACKET_TYPE
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Parse body data into attributes
|
|
44
|
+
#
|
|
45
|
+
# Body format:
|
|
46
|
+
# - file_id: 16 bytes
|
|
47
|
+
# - file_hash: 16 bytes
|
|
48
|
+
# - file_hash_16k: 16 bytes
|
|
49
|
+
# - length: 8 bytes (Q<)
|
|
50
|
+
# - filename: null-terminated, padded to multiple of 4
|
|
51
|
+
def parse_body
|
|
52
|
+
return if body_data.nil? || body_data.empty?
|
|
53
|
+
|
|
54
|
+
# Validate minimum size (16+16+16+8 = 56 bytes minimum)
|
|
55
|
+
if body_data.bytesize < 56
|
|
56
|
+
warn "FileDescriptionPacket body too short: #{body_data.bytesize} bytes"
|
|
57
|
+
return
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
pos = 0
|
|
61
|
+
|
|
62
|
+
# Read file_id (16 bytes)
|
|
63
|
+
self.file_id = body_data[pos, 16]
|
|
64
|
+
pos += 16
|
|
65
|
+
|
|
66
|
+
# Read file_hash (16 bytes)
|
|
67
|
+
self.file_hash = body_data[pos, 16]
|
|
68
|
+
pos += 16
|
|
69
|
+
|
|
70
|
+
# Read file_hash_16k (16 bytes)
|
|
71
|
+
self.file_hash_16k = body_data[pos, 16]
|
|
72
|
+
pos += 16
|
|
73
|
+
|
|
74
|
+
# Read length (8 bytes, little-endian unsigned 64-bit)
|
|
75
|
+
length_data = body_data[pos, 8]
|
|
76
|
+
return if length_data.nil? || length_data.bytesize < 8
|
|
77
|
+
|
|
78
|
+
self.length = length_data.unpack1("Q<")
|
|
79
|
+
pos += 8
|
|
80
|
+
|
|
81
|
+
# Read filename (null-terminated, remaining bytes)
|
|
82
|
+
filename_data = body_data[pos..]
|
|
83
|
+
self.filename = filename_data&.unpack1("Z*") || ""
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Build body data from attributes
|
|
87
|
+
#
|
|
88
|
+
# Constructs binary body data with proper padding
|
|
89
|
+
#
|
|
90
|
+
# @return [String] Binary body data
|
|
91
|
+
def build_body
|
|
92
|
+
data = +""
|
|
93
|
+
|
|
94
|
+
# Validate file_id, file_hash, file_hash_16k are 16 bytes
|
|
95
|
+
[file_id, file_hash, file_hash_16k].each_with_index do |hash, idx|
|
|
96
|
+
field_name = %w[file_id file_hash file_hash_16k][idx]
|
|
97
|
+
if hash.bytesize != 16
|
|
98
|
+
raise ArgumentError,
|
|
99
|
+
"#{field_name} must be 16 bytes, got #{hash.bytesize}"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Write hashes
|
|
104
|
+
data << file_id
|
|
105
|
+
data << file_hash
|
|
106
|
+
data << file_hash_16k
|
|
107
|
+
|
|
108
|
+
# Write length (8 bytes, little-endian)
|
|
109
|
+
data << [length].pack("Q<")
|
|
110
|
+
|
|
111
|
+
# Write filename (null-terminated, padded to multiple of 4)
|
|
112
|
+
data << filename
|
|
113
|
+
data << "\x00"
|
|
114
|
+
|
|
115
|
+
# Add padding to make total length multiple of 4
|
|
116
|
+
padding = (4 - ((filename.bytesize + 1) % 4)) % 4
|
|
117
|
+
data << ("\x00" * padding) if padding.positive?
|
|
118
|
+
|
|
119
|
+
self.body_data = data
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Get basename of file
|
|
123
|
+
#
|
|
124
|
+
# @return [String] File basename
|
|
125
|
+
def basename
|
|
126
|
+
File.basename(filename)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Parity
|
|
5
|
+
module Models
|
|
6
|
+
# PAR2 IFSC (Input File Slice Checksum) packet
|
|
7
|
+
#
|
|
8
|
+
# Contains checksums for individual data blocks of a file.
|
|
9
|
+
# One IFSC packet contains checksums for ALL blocks of a file.
|
|
10
|
+
#
|
|
11
|
+
# Body structure:
|
|
12
|
+
# - file_id (16 bytes): File identifier
|
|
13
|
+
# - For each block:
|
|
14
|
+
# - block_hash (16 bytes): MD5 hash of block data
|
|
15
|
+
# - block_crc32 (4 bytes, L<): CRC32 of block data
|
|
16
|
+
class IfscPacket < Packet
|
|
17
|
+
# Packet type identifier
|
|
18
|
+
PACKET_TYPE = "PAR 2.0\x00IFSC\x00\x00\x00\x00"
|
|
19
|
+
|
|
20
|
+
# File identifier (16 bytes)
|
|
21
|
+
attribute :file_id, :string
|
|
22
|
+
|
|
23
|
+
# Array of block hashes (16 bytes MD5 each)
|
|
24
|
+
attribute :block_hashes, :string, collection: true, default: -> { [] }
|
|
25
|
+
|
|
26
|
+
# Array of block CRC32s (4 bytes each)
|
|
27
|
+
attribute :block_crc32s, :integer, collection: true, default: -> { [] }
|
|
28
|
+
|
|
29
|
+
# Initialize IFSC packet
|
|
30
|
+
#
|
|
31
|
+
# @param attributes [Hash] Packet attributes
|
|
32
|
+
def initialize(**attributes)
|
|
33
|
+
super
|
|
34
|
+
self.type = PACKET_TYPE
|
|
35
|
+
self.block_hashes = [] if block_hashes.nil?
|
|
36
|
+
self.block_crc32s = [] if block_crc32s.nil?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Parse body data into attributes
|
|
40
|
+
#
|
|
41
|
+
# Body format:
|
|
42
|
+
# - file_id: 16 bytes
|
|
43
|
+
# - For each block:
|
|
44
|
+
# - block_hash: 16 bytes
|
|
45
|
+
# - block_crc32: 4 bytes (L<)
|
|
46
|
+
def parse_body
|
|
47
|
+
return if body_data.nil? || body_data.empty?
|
|
48
|
+
return if body_data.bytesize < 16
|
|
49
|
+
|
|
50
|
+
pos = 0
|
|
51
|
+
|
|
52
|
+
# Read file_id (16 bytes)
|
|
53
|
+
self.file_id = body_data[pos, 16]
|
|
54
|
+
pos += 16
|
|
55
|
+
|
|
56
|
+
# Read all blocks (each is 16 bytes hash + 4 bytes CRC = 20 bytes)
|
|
57
|
+
self.block_hashes = []
|
|
58
|
+
self.block_crc32s = []
|
|
59
|
+
|
|
60
|
+
while pos + 20 <= body_data.bytesize
|
|
61
|
+
# Read block_hash (16 bytes)
|
|
62
|
+
block_hash = body_data[pos, 16]
|
|
63
|
+
pos += 16
|
|
64
|
+
|
|
65
|
+
# Read block_crc32 (4 bytes, little-endian unsigned 32-bit)
|
|
66
|
+
block_crc32 = body_data[pos, 4].unpack1("L<")
|
|
67
|
+
pos += 4
|
|
68
|
+
|
|
69
|
+
block_hashes << block_hash
|
|
70
|
+
block_crc32s << block_crc32
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Build body data from attributes
|
|
75
|
+
#
|
|
76
|
+
# Constructs binary body data
|
|
77
|
+
#
|
|
78
|
+
# @return [String] Binary body data
|
|
79
|
+
def build_body
|
|
80
|
+
data = +""
|
|
81
|
+
|
|
82
|
+
# Validate file_id is 16 bytes
|
|
83
|
+
if file_id.bytesize != 16
|
|
84
|
+
raise ArgumentError,
|
|
85
|
+
"file_id must be 16 bytes, got #{file_id.bytesize}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Write file_id
|
|
89
|
+
data << file_id
|
|
90
|
+
|
|
91
|
+
# Write all blocks
|
|
92
|
+
block_hashes.each_with_index do |block_hash, i|
|
|
93
|
+
# Validate block_hash is 16 bytes
|
|
94
|
+
if block_hash.bytesize != 16
|
|
95
|
+
raise ArgumentError,
|
|
96
|
+
"block_hash must be 16 bytes, got #{block_hash.bytesize}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Write block_hash
|
|
100
|
+
data << block_hash
|
|
101
|
+
|
|
102
|
+
# Write block_crc32 (4 bytes, little-endian)
|
|
103
|
+
data << [block_crc32s[i]].pack("L<")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
self.body_data = data
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|