omnizip 0.4.7-arm-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,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Formats
|
|
7
|
+
module Rar
|
|
8
|
+
module Rar5
|
|
9
|
+
module Encryption
|
|
10
|
+
# AES-256-CBC cipher for RAR5 encryption
|
|
11
|
+
#
|
|
12
|
+
# Wrapper around the existing Crypto::Aes256::Cipher that provides
|
|
13
|
+
# RAR5-specific encryption/decryption with proper key and IV handling.
|
|
14
|
+
#
|
|
15
|
+
# RAR5 uses:
|
|
16
|
+
# - AES-256 in CBC mode
|
|
17
|
+
# - PKCS#7 padding
|
|
18
|
+
# - Per-file IV generation
|
|
19
|
+
# - PBKDF2-HMAC-SHA256 key derivation
|
|
20
|
+
#
|
|
21
|
+
# @example Encrypt file data
|
|
22
|
+
# cipher = Aes256Cbc.new(key, iv)
|
|
23
|
+
# encrypted = cipher.encrypt(data)
|
|
24
|
+
class Aes256Cbc
|
|
25
|
+
# IV size (16 bytes = AES block size)
|
|
26
|
+
IV_SIZE = 16
|
|
27
|
+
|
|
28
|
+
# Key size (32 bytes for AES-256)
|
|
29
|
+
KEY_SIZE = 32
|
|
30
|
+
|
|
31
|
+
# @return [String] AES-256 key (32 bytes)
|
|
32
|
+
attr_reader :key
|
|
33
|
+
|
|
34
|
+
# @return [String] Initialization vector (16 bytes)
|
|
35
|
+
attr_reader :iv
|
|
36
|
+
|
|
37
|
+
# Initialize cipher with key and IV
|
|
38
|
+
#
|
|
39
|
+
# @param key [String] 32-byte AES-256 key
|
|
40
|
+
# @param iv [String] 16-byte initialization vector
|
|
41
|
+
# @raise [ArgumentError] If key or IV wrong size
|
|
42
|
+
def initialize(key, iv)
|
|
43
|
+
validate_key_iv(key, iv)
|
|
44
|
+
@key = key
|
|
45
|
+
@iv = iv
|
|
46
|
+
@cipher = Crypto::Aes256::Cipher.new(key, iv)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Encrypt data
|
|
50
|
+
#
|
|
51
|
+
# @param plaintext [String] Data to encrypt
|
|
52
|
+
# @return [String] Encrypted data (with PKCS#7 padding)
|
|
53
|
+
def encrypt(plaintext)
|
|
54
|
+
@cipher.encrypt(plaintext)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Decrypt data
|
|
58
|
+
#
|
|
59
|
+
# @param ciphertext [String] Encrypted data
|
|
60
|
+
# @return [String] Decrypted data (padding removed)
|
|
61
|
+
def decrypt(ciphertext)
|
|
62
|
+
@cipher.decrypt(ciphertext)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Generate random IV
|
|
66
|
+
#
|
|
67
|
+
# @return [String] 16-byte random IV
|
|
68
|
+
def self.generate_iv
|
|
69
|
+
SecureRandom.random_bytes(IV_SIZE)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# Validate key and IV sizes
|
|
75
|
+
#
|
|
76
|
+
# @param key [String] Key to validate
|
|
77
|
+
# @param iv [String] IV to validate
|
|
78
|
+
# @return [void]
|
|
79
|
+
# @raise [ArgumentError] If key or IV wrong size
|
|
80
|
+
def validate_key_iv(key, iv)
|
|
81
|
+
if key.bytesize != KEY_SIZE
|
|
82
|
+
raise ArgumentError,
|
|
83
|
+
"Key must be #{KEY_SIZE} bytes, got #{key.bytesize}"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
return unless iv.bytesize != IV_SIZE
|
|
87
|
+
|
|
88
|
+
raise ArgumentError,
|
|
89
|
+
"IV must be #{IV_SIZE} bytes, got #{iv.bytesize}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require "lutaml/model"
|
|
5
|
+
rescue LoadError, ArgumentError
|
|
6
|
+
# lutaml-model not available, using simple classes
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
require "base64"
|
|
10
|
+
|
|
11
|
+
module Omnizip
|
|
12
|
+
module Formats
|
|
13
|
+
module Rar
|
|
14
|
+
module Rar5
|
|
15
|
+
module Encryption
|
|
16
|
+
# RAR5 encryption header
|
|
17
|
+
#
|
|
18
|
+
# This model stores encryption parameters needed for password verification
|
|
19
|
+
# and decryption. The header is written at the beginning of encrypted
|
|
20
|
+
# archive sections.
|
|
21
|
+
#
|
|
22
|
+
# RAR5 encryption header contains:
|
|
23
|
+
# - Version (always 0 for AES-256)
|
|
24
|
+
# - KDF iteration count
|
|
25
|
+
# - Salt for key derivation
|
|
26
|
+
# - IV for AES-CBC
|
|
27
|
+
# - Check value for password verification
|
|
28
|
+
#
|
|
29
|
+
# @example Create encryption header
|
|
30
|
+
# header = EncryptionHeader.new(
|
|
31
|
+
# version: 0,
|
|
32
|
+
# kdf_iterations: 262_144,
|
|
33
|
+
# salt: salt,
|
|
34
|
+
# iv: iv,
|
|
35
|
+
# check_value: check
|
|
36
|
+
# )
|
|
37
|
+
class EncryptionHeader < Lutaml::Model::Serializable
|
|
38
|
+
# Encryption version (0 for AES-256)
|
|
39
|
+
attribute :version, :integer, default: 0
|
|
40
|
+
|
|
41
|
+
# PBKDF2 iteration count
|
|
42
|
+
attribute :kdf_iterations, :integer, default: 262_144
|
|
43
|
+
|
|
44
|
+
# Salt for key derivation (16 bytes, base64 encoded for serialization)
|
|
45
|
+
attribute :salt, :string
|
|
46
|
+
|
|
47
|
+
# Initialization vector (16 bytes, base64 encoded for serialization)
|
|
48
|
+
attribute :iv, :string
|
|
49
|
+
|
|
50
|
+
# Password check value (first 8 bytes of encrypted data)
|
|
51
|
+
# Used to verify password before full decryption
|
|
52
|
+
attribute :check_value, :string
|
|
53
|
+
|
|
54
|
+
# Validate header
|
|
55
|
+
#
|
|
56
|
+
# @raise [ArgumentError] If validation fails
|
|
57
|
+
def validate!
|
|
58
|
+
if version != 0
|
|
59
|
+
raise ArgumentError, "Only AES-256 (version 0) is supported"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if kdf_iterations < 65_536 || kdf_iterations > 1_048_576
|
|
63
|
+
raise ArgumentError,
|
|
64
|
+
"KDF iterations must be between 65,536 and 1,048,576"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Validate salt (base64 decoded should be 16 bytes)
|
|
68
|
+
decoded_salt = Base64.strict_decode64(salt)
|
|
69
|
+
if decoded_salt.bytesize != 16
|
|
70
|
+
raise ArgumentError, "Salt must be 16 bytes"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Validate IV (base64 decoded should be 16 bytes)
|
|
74
|
+
decoded_iv = Base64.strict_decode64(iv)
|
|
75
|
+
if decoded_iv.bytesize != 16
|
|
76
|
+
raise ArgumentError, "IV must be 16 bytes"
|
|
77
|
+
end
|
|
78
|
+
rescue ArgumentError => e
|
|
79
|
+
raise ArgumentError, "Invalid encryption header: #{e.message}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Get salt as binary
|
|
83
|
+
#
|
|
84
|
+
# @return [String] 16-byte binary salt
|
|
85
|
+
def salt_binary
|
|
86
|
+
Base64.strict_decode64(salt)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Get IV as binary
|
|
90
|
+
#
|
|
91
|
+
# @return [String] 16-byte binary IV
|
|
92
|
+
def iv_binary
|
|
93
|
+
Base64.strict_decode64(iv)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Set salt from binary
|
|
97
|
+
#
|
|
98
|
+
# @param binary_salt [String] 16-byte binary salt
|
|
99
|
+
def salt_binary=(binary_salt)
|
|
100
|
+
self.salt = Base64.strict_encode64(binary_salt)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Set IV from binary
|
|
104
|
+
#
|
|
105
|
+
# @param binary_iv [String] 16-byte binary IV
|
|
106
|
+
def iv_binary=(binary_iv)
|
|
107
|
+
self.iv = Base64.strict_encode64(binary_iv)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Rar
|
|
6
|
+
module Rar5
|
|
7
|
+
module Encryption
|
|
8
|
+
# Encryption manager for RAR5 archives
|
|
9
|
+
#
|
|
10
|
+
# This manager coordinates the encryption process:
|
|
11
|
+
# 1. Generate salt and IV
|
|
12
|
+
# 2. Derive key from password using PBKDF2
|
|
13
|
+
# 3. Encrypt file data with AES-256-CBC
|
|
14
|
+
# 4. Create encryption header with metadata
|
|
15
|
+
#
|
|
16
|
+
# @example Encrypt file data
|
|
17
|
+
# manager = EncryptionManager.new("SecurePassword", kdf_iterations: 262_144)
|
|
18
|
+
# result = manager.encrypt_file_data(file_data)
|
|
19
|
+
# # result[:encrypted_data] = encrypted bytes
|
|
20
|
+
# # result[:header] = EncryptionHeader with salt, IV, etc.
|
|
21
|
+
class EncryptionManager
|
|
22
|
+
# @return [String] Password for encryption
|
|
23
|
+
attr_reader :password
|
|
24
|
+
|
|
25
|
+
# @return [Integer] PBKDF2 iteration count
|
|
26
|
+
attr_reader :kdf_iterations
|
|
27
|
+
|
|
28
|
+
# @return [String, nil] Optional pre-generated salt
|
|
29
|
+
attr_reader :salt
|
|
30
|
+
|
|
31
|
+
# @return [String, nil] Optional pre-generated IV
|
|
32
|
+
attr_reader :iv
|
|
33
|
+
|
|
34
|
+
# Initialize encryption manager
|
|
35
|
+
#
|
|
36
|
+
# @param password [String] Encryption password
|
|
37
|
+
# @param options [Hash] Options
|
|
38
|
+
# @option options [Integer] :kdf_iterations PBKDF2 iterations (default: 262,144)
|
|
39
|
+
# @option options [String] :salt Pre-generated salt (16 bytes, optional)
|
|
40
|
+
# @option options [String] :iv Pre-generated IV (16 bytes, optional)
|
|
41
|
+
def initialize(password, options = {})
|
|
42
|
+
@password = password
|
|
43
|
+
@kdf_iterations = options[:kdf_iterations] || KeyDerivation::DEFAULT_ITERATIONS
|
|
44
|
+
@salt = options[:salt]
|
|
45
|
+
@iv = options[:iv]
|
|
46
|
+
|
|
47
|
+
validate_password!
|
|
48
|
+
validate_iterations!
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Encrypt file data
|
|
52
|
+
#
|
|
53
|
+
# @param plaintext [String] File data to encrypt
|
|
54
|
+
# @return [Hash] Encryption result
|
|
55
|
+
# @option result [String] :encrypted_data Encrypted bytes
|
|
56
|
+
# @option result [EncryptionHeader] :header Encryption metadata
|
|
57
|
+
# @option result [String] :key Derived encryption key (for debugging)
|
|
58
|
+
def encrypt_file_data(plaintext)
|
|
59
|
+
# Generate or use provided salt and IV
|
|
60
|
+
salt = @salt || KeyDerivation.generate_salt
|
|
61
|
+
iv = @iv || Aes256Cbc.generate_iv
|
|
62
|
+
|
|
63
|
+
# Derive key from password
|
|
64
|
+
key = KeyDerivation.derive_key(@password, salt, @kdf_iterations)
|
|
65
|
+
|
|
66
|
+
# Encrypt data
|
|
67
|
+
cipher = Aes256Cbc.new(key, iv)
|
|
68
|
+
encrypted = cipher.encrypt(plaintext)
|
|
69
|
+
|
|
70
|
+
# Create encryption header
|
|
71
|
+
header = create_encryption_header(salt, iv)
|
|
72
|
+
|
|
73
|
+
{
|
|
74
|
+
encrypted_data: encrypted,
|
|
75
|
+
header: header,
|
|
76
|
+
key: key, # Include for verification if needed
|
|
77
|
+
}
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Decrypt file data
|
|
81
|
+
#
|
|
82
|
+
# @param ciphertext [String] Encrypted data
|
|
83
|
+
# @param header [EncryptionHeader] Encryption metadata
|
|
84
|
+
# @return [String] Decrypted data
|
|
85
|
+
# @raise [ArgumentError] If password incorrect
|
|
86
|
+
def decrypt_file_data(ciphertext, header)
|
|
87
|
+
# Extract salt and IV
|
|
88
|
+
salt = header.salt_binary
|
|
89
|
+
iv = header.iv_binary
|
|
90
|
+
|
|
91
|
+
# Derive key from password
|
|
92
|
+
key = KeyDerivation.derive_key(@password, salt,
|
|
93
|
+
header.kdf_iterations)
|
|
94
|
+
|
|
95
|
+
# Decrypt data
|
|
96
|
+
cipher = Aes256Cbc.new(key, iv)
|
|
97
|
+
cipher.decrypt(ciphertext)
|
|
98
|
+
rescue OpenSSL::Cipher::CipherError => e
|
|
99
|
+
raise ArgumentError,
|
|
100
|
+
"Decryption failed (wrong password?): #{e.message}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Verify password without full decryption
|
|
104
|
+
#
|
|
105
|
+
# This checks if the derived key can decrypt the check value.
|
|
106
|
+
# Faster than decrypting entire file.
|
|
107
|
+
#
|
|
108
|
+
# @param header [EncryptionHeader] Encryption metadata
|
|
109
|
+
# @return [Boolean] true if password correct
|
|
110
|
+
def verify_password(_header)
|
|
111
|
+
# For now, we'll need a small encrypted sample to verify
|
|
112
|
+
# This is a simplified check - full implementation would use
|
|
113
|
+
# the check_value field properly
|
|
114
|
+
true # Placeholder
|
|
115
|
+
rescue StandardError
|
|
116
|
+
false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
# Create encryption header
|
|
122
|
+
#
|
|
123
|
+
# @param salt [String] 16-byte salt
|
|
124
|
+
# @param iv [String] 16-byte IV
|
|
125
|
+
# @return [EncryptionHeader] Header object
|
|
126
|
+
def create_encryption_header(salt, iv)
|
|
127
|
+
header = EncryptionHeader.new
|
|
128
|
+
header.version = 0 # AES-256
|
|
129
|
+
header.kdf_iterations = @kdf_iterations
|
|
130
|
+
header.salt_binary = salt
|
|
131
|
+
header.iv_binary = iv
|
|
132
|
+
header.check_value = "" # Placeholder for password check
|
|
133
|
+
header
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Validate password
|
|
137
|
+
#
|
|
138
|
+
# @raise [ArgumentError] If password invalid
|
|
139
|
+
def validate_password!
|
|
140
|
+
if @password.nil? || @password.empty?
|
|
141
|
+
raise ArgumentError, "Password cannot be empty"
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Validate iteration count
|
|
146
|
+
#
|
|
147
|
+
# @raise [ArgumentError] If iterations invalid
|
|
148
|
+
def validate_iterations!
|
|
149
|
+
min = KeyDerivation::MIN_ITERATIONS
|
|
150
|
+
max = KeyDerivation::MAX_ITERATIONS
|
|
151
|
+
|
|
152
|
+
return if @kdf_iterations.between?(min, max)
|
|
153
|
+
|
|
154
|
+
raise ArgumentError,
|
|
155
|
+
"KDF iterations must be between #{min} and #{max}"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "openssl"
|
|
4
|
+
require "securerandom"
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Formats
|
|
8
|
+
module Rar
|
|
9
|
+
module Rar5
|
|
10
|
+
module Encryption
|
|
11
|
+
# RAR5 password-based key derivation
|
|
12
|
+
#
|
|
13
|
+
# RAR5 uses PBKDF2-HMAC-SHA256 for key derivation, which is more
|
|
14
|
+
# secure than 7-Zip's iterative SHA-256 approach.
|
|
15
|
+
#
|
|
16
|
+
# The process:
|
|
17
|
+
# 1. Generate random salt (16 bytes)
|
|
18
|
+
# 2. Apply PBKDF2-HMAC-SHA256 with configurable iterations
|
|
19
|
+
# 3. Derive 32-byte AES-256 key
|
|
20
|
+
#
|
|
21
|
+
# @example Derive key from password
|
|
22
|
+
# salt = SecureRandom.random_bytes(16)
|
|
23
|
+
# key = KeyDerivation.derive_key("password", salt, 262_144)
|
|
24
|
+
class KeyDerivation
|
|
25
|
+
# Default PBKDF2 iterations (262,144 = 2^18)
|
|
26
|
+
# This provides good security while maintaining reasonable performance
|
|
27
|
+
DEFAULT_ITERATIONS = 262_144
|
|
28
|
+
|
|
29
|
+
# Minimum iterations (2^16 = 65,536)
|
|
30
|
+
MIN_ITERATIONS = 65_536
|
|
31
|
+
|
|
32
|
+
# Maximum iterations (2^20 = 1,048,576)
|
|
33
|
+
MAX_ITERATIONS = 1_048_576
|
|
34
|
+
|
|
35
|
+
# Salt size (16 bytes)
|
|
36
|
+
SALT_SIZE = 16
|
|
37
|
+
|
|
38
|
+
# Key size (32 bytes for AES-256)
|
|
39
|
+
KEY_SIZE = 32
|
|
40
|
+
|
|
41
|
+
# Derive AES-256 key from password using PBKDF2-HMAC-SHA256
|
|
42
|
+
#
|
|
43
|
+
# @param password [String] User password
|
|
44
|
+
# @param salt [String] Random salt (16 bytes)
|
|
45
|
+
# @param iterations [Integer] Number of PBKDF2 iterations
|
|
46
|
+
# @return [String] 32-byte AES-256 key
|
|
47
|
+
# @raise [ArgumentError] If password empty or salt wrong size
|
|
48
|
+
def self.derive_key(password, salt, iterations = DEFAULT_ITERATIONS)
|
|
49
|
+
validate_inputs(password, salt, iterations)
|
|
50
|
+
|
|
51
|
+
# PBKDF2-HMAC-SHA256
|
|
52
|
+
OpenSSL::PKCS5.pbkdf2_hmac(
|
|
53
|
+
password,
|
|
54
|
+
salt,
|
|
55
|
+
iterations,
|
|
56
|
+
KEY_SIZE,
|
|
57
|
+
OpenSSL::Digest.new("SHA256"),
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Generate random salt
|
|
62
|
+
#
|
|
63
|
+
# @return [String] 16-byte random salt
|
|
64
|
+
def self.generate_salt
|
|
65
|
+
SecureRandom.random_bytes(SALT_SIZE)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Validate key derivation inputs
|
|
69
|
+
#
|
|
70
|
+
# @param password [String] Password to validate
|
|
71
|
+
# @param salt [String] Salt to validate
|
|
72
|
+
# @param iterations [Integer] Iteration count to validate
|
|
73
|
+
# @return [void]
|
|
74
|
+
# @raise [ArgumentError] If inputs are invalid
|
|
75
|
+
def self.validate_inputs(password, salt, iterations)
|
|
76
|
+
if password.nil? || password.empty?
|
|
77
|
+
raise ArgumentError, "Password cannot be empty"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if salt.bytesize != SALT_SIZE
|
|
81
|
+
raise ArgumentError,
|
|
82
|
+
"Salt must be #{SALT_SIZE} bytes, got #{salt.bytesize}"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
return if iterations.between?(MIN_ITERATIONS, MAX_ITERATIONS)
|
|
86
|
+
|
|
87
|
+
raise ArgumentError,
|
|
88
|
+
"Iterations must be between #{MIN_ITERATIONS} and #{MAX_ITERATIONS}"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private_class_method :validate_inputs
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Rar
|
|
6
|
+
module Rar5
|
|
7
|
+
# Header types
|
|
8
|
+
HEADER_TYPE_MAIN = 1
|
|
9
|
+
HEADER_TYPE_FILE = 2
|
|
10
|
+
HEADER_TYPE_SERVICE = 3
|
|
11
|
+
HEADER_TYPE_ENCRYPTION = 4
|
|
12
|
+
HEADER_TYPE_END = 5
|
|
13
|
+
|
|
14
|
+
# Header flags (common)
|
|
15
|
+
FLAG_EXTRA_AREA = 0x0001
|
|
16
|
+
FLAG_DATA_AREA = 0x0002
|
|
17
|
+
|
|
18
|
+
# Base class for RAR5 headers
|
|
19
|
+
class Header
|
|
20
|
+
attr_reader :type, :flags, :extra_area, :data_area_size, :header_data
|
|
21
|
+
|
|
22
|
+
def initialize(type, flags: 0, extra_area: nil, data_area_size: nil,
|
|
23
|
+
header_data: "")
|
|
24
|
+
@type = type
|
|
25
|
+
@flags = flags
|
|
26
|
+
@flags |= FLAG_EXTRA_AREA if extra_area
|
|
27
|
+
@flags |= FLAG_DATA_AREA if data_area_size
|
|
28
|
+
@extra_area = extra_area
|
|
29
|
+
@data_area_size = data_area_size
|
|
30
|
+
@header_data = header_data
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def encode
|
|
34
|
+
# Build header without CRC
|
|
35
|
+
header_bytes = build_header_bytes
|
|
36
|
+
|
|
37
|
+
# Calculate CRC32
|
|
38
|
+
crc = CRC32.calculate(header_bytes.pack("C*"))
|
|
39
|
+
|
|
40
|
+
# Prepend CRC (little-endian)
|
|
41
|
+
[crc].pack("V") + header_bytes.pack("C*")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def build_header_bytes
|
|
47
|
+
bytes = []
|
|
48
|
+
|
|
49
|
+
# Header size (placeholder - will calculate)
|
|
50
|
+
size_bytes = []
|
|
51
|
+
|
|
52
|
+
# Type
|
|
53
|
+
type_bytes = VINT.encode(@type)
|
|
54
|
+
size_bytes.concat(type_bytes)
|
|
55
|
+
|
|
56
|
+
# Flags
|
|
57
|
+
flags_bytes = VINT.encode(@flags)
|
|
58
|
+
size_bytes.concat(flags_bytes)
|
|
59
|
+
|
|
60
|
+
# Extra area size (if present)
|
|
61
|
+
if @flags.anybits?(FLAG_EXTRA_AREA)
|
|
62
|
+
extra_size_bytes = VINT.encode(@extra_area.bytesize)
|
|
63
|
+
size_bytes.concat(extra_size_bytes)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Data area size (if present)
|
|
67
|
+
if @flags.anybits?(FLAG_DATA_AREA)
|
|
68
|
+
data_size_bytes = VINT.encode(@data_area_size)
|
|
69
|
+
size_bytes.concat(data_size_bytes)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Header data
|
|
73
|
+
size_bytes.concat(@header_data.bytes)
|
|
74
|
+
|
|
75
|
+
# Extra area
|
|
76
|
+
size_bytes.concat(@extra_area.bytes) if @extra_area
|
|
77
|
+
|
|
78
|
+
# Calculate total header size (excluding CRC)
|
|
79
|
+
header_size = size_bytes.size
|
|
80
|
+
header_size_vint = VINT.encode(header_size)
|
|
81
|
+
|
|
82
|
+
# Build final header
|
|
83
|
+
bytes.concat(header_size_vint)
|
|
84
|
+
bytes.concat(size_bytes)
|
|
85
|
+
|
|
86
|
+
bytes
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Main archive header
|
|
91
|
+
class MainHeader < Header
|
|
92
|
+
# Archive flags: 0x0001 volume, 0x0002 volume number
|
|
93
|
+
# present, 0x0004 solid, 0x0008 recovery, 0x0010 locked
|
|
94
|
+
ARCHIVE_FLAG_VOLUME = 0x0001
|
|
95
|
+
ARCHIVE_FLAG_VOLUME_NUMBER = 0x0002
|
|
96
|
+
|
|
97
|
+
def initialize(archive_flags: 0, volume_number: nil)
|
|
98
|
+
data = VINT.encode(archive_flags)
|
|
99
|
+
if archive_flags.anybits?(ARCHIVE_FLAG_VOLUME_NUMBER)
|
|
100
|
+
data.concat(VINT.encode(volume_number.to_i))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
super(HEADER_TYPE_MAIN, header_data: data.pack("C*"))
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# File header
|
|
108
|
+
class FileHeader < Header
|
|
109
|
+
# File header flags. Per the RAR 5.0 spec, 0x0001 marks a
|
|
110
|
+
# directory entry (what this codebase once mislabeled as
|
|
111
|
+
# "has attributes" — attributes are an always-present field)
|
|
112
|
+
FILE_IS_DIRECTORY = 0x0001
|
|
113
|
+
FILE_HAS_MTIME = 0x0002
|
|
114
|
+
FILE_HAS_CRC32 = 0x0004
|
|
115
|
+
|
|
116
|
+
# Compression information field layout (RAR 5.0 spec):
|
|
117
|
+
# bits 0-5 algorithm version (0), bit 7 solid,
|
|
118
|
+
# bits 8-10 method (0=store, 1-5=LZMA), bits 11-15
|
|
119
|
+
# dictionary size (128 KB * 2^N).
|
|
120
|
+
DICT_BASE = 128 * 1024
|
|
121
|
+
|
|
122
|
+
def initialize(filename:, file_size:, compressed_size:,
|
|
123
|
+
compression_method: 0, dict_size: 0,
|
|
124
|
+
flags: 0, mtime: nil, crc32: nil,
|
|
125
|
+
directory: false, extra_area: nil)
|
|
126
|
+
# Build file flags based on what's provided
|
|
127
|
+
file_flags = 0
|
|
128
|
+
file_flags |= FILE_IS_DIRECTORY if directory
|
|
129
|
+
file_flags |= FILE_HAS_MTIME if mtime
|
|
130
|
+
file_flags |= FILE_HAS_CRC32 if crc32
|
|
131
|
+
|
|
132
|
+
# Build header data with file information
|
|
133
|
+
data = build_file_data(filename, file_size,
|
|
134
|
+
compression_method, dict_size,
|
|
135
|
+
file_flags, mtime, crc32,
|
|
136
|
+
directory: directory)
|
|
137
|
+
super(HEADER_TYPE_FILE, flags: flags, data_area_size: compressed_size, header_data: data, extra_area: extra_area)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
def build_file_data(filename, file_size, compression_method,
|
|
143
|
+
dict_size, file_flags, mtime, crc32,
|
|
144
|
+
directory: false)
|
|
145
|
+
data = []
|
|
146
|
+
|
|
147
|
+
# File flags (VINT)
|
|
148
|
+
data.concat(VINT.encode(file_flags))
|
|
149
|
+
|
|
150
|
+
# Unpacked size (VINT)
|
|
151
|
+
data.concat(VINT.encode(file_size))
|
|
152
|
+
|
|
153
|
+
# Attributes (VINT) - ALWAYS present in RAR5.
|
|
154
|
+
# Unix host: directory mode for directory entries,
|
|
155
|
+
# regular-file 0o100644 otherwise.
|
|
156
|
+
data.concat(VINT.encode(directory ? 0o040755 : 0o100644))
|
|
157
|
+
|
|
158
|
+
# mtime (optional) - only if FILE_HAS_MTIME flag is set
|
|
159
|
+
# RAR5 stores mtime as Unix timestamp (seconds since epoch)
|
|
160
|
+
# Format: 4 bytes little-endian (NOT a VINT)
|
|
161
|
+
if file_flags.anybits?(FILE_HAS_MTIME) && mtime
|
|
162
|
+
data.concat([mtime.to_i].pack("V").bytes)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Data CRC32 (optional) - only if FILE_HAS_CRC32 flag is set
|
|
166
|
+
# Format: 4 bytes little-endian (NOT a VINT)
|
|
167
|
+
if file_flags.anybits?(FILE_HAS_CRC32) && crc32
|
|
168
|
+
data.concat([crc32].pack("V").bytes)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Compression information (VINT): version 0 in bits 0-5,
|
|
172
|
+
# method in bits 8-10, dictionary size in bits 11-15
|
|
173
|
+
# (128 KB * 2^N).
|
|
174
|
+
dict_bits = if dict_size.positive?
|
|
175
|
+
Math.log2(dict_size / DICT_BASE).round.clamp(0, 15)
|
|
176
|
+
else
|
|
177
|
+
0
|
|
178
|
+
end
|
|
179
|
+
compression_info = (compression_method << 8) | (dict_bits << 11)
|
|
180
|
+
data.concat(VINT.encode(compression_info))
|
|
181
|
+
|
|
182
|
+
# Host OS (VINT) - 1 = Unix
|
|
183
|
+
data.concat(VINT.encode(1))
|
|
184
|
+
|
|
185
|
+
# Name length (VINT) and name
|
|
186
|
+
name_bytes = filename.encode("UTF-8").bytes
|
|
187
|
+
data.concat(VINT.encode(name_bytes.size))
|
|
188
|
+
data.concat(name_bytes)
|
|
189
|
+
|
|
190
|
+
data.pack("C*")
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# End of archive header
|
|
195
|
+
class EndHeader < Header
|
|
196
|
+
# End of archive flags: 0x0001 volume and not the last
|
|
197
|
+
# volume in the set
|
|
198
|
+
END_FLAG_VOLUME_NEXT = 0x0001
|
|
199
|
+
|
|
200
|
+
def initialize(end_flags: 0)
|
|
201
|
+
super(HEADER_TYPE_END,
|
|
202
|
+
header_data: VINT.encode(end_flags).pack("C*"))
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|