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,540 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Rar
|
|
6
|
+
module Rar5
|
|
7
|
+
# RAR5 format writer
|
|
8
|
+
#
|
|
9
|
+
# This class creates RAR5 archives with STORE or LZMA compression.
|
|
10
|
+
# Supports single-file archives, multi-volume archives, solid compression,
|
|
11
|
+
# AES-256-CBC encryption, and PAR2 recovery records.
|
|
12
|
+
#
|
|
13
|
+
# @example Create single archive with STORE compression
|
|
14
|
+
# writer = Writer.new('archive.rar')
|
|
15
|
+
# writer.add_file('test.txt')
|
|
16
|
+
# writer.write
|
|
17
|
+
#
|
|
18
|
+
# @example Create archive with LZMA compression
|
|
19
|
+
# writer = Writer.new('archive.rar', compression: :lzma, level: 5)
|
|
20
|
+
# writer.add_file('test.txt')
|
|
21
|
+
# writer.write
|
|
22
|
+
#
|
|
23
|
+
# @example Create solid archive
|
|
24
|
+
# writer = Writer.new('archive.rar', compression: :lzma, level: 5, solid: true)
|
|
25
|
+
# writer.add_directory('project/')
|
|
26
|
+
# writer.write
|
|
27
|
+
#
|
|
28
|
+
# @example Create encrypted archive
|
|
29
|
+
# writer = Writer.new('archive.rar',
|
|
30
|
+
# compression: :lzma,
|
|
31
|
+
# password: 'SecurePass123!',
|
|
32
|
+
# kdf_iterations: 262_144
|
|
33
|
+
# )
|
|
34
|
+
# writer.add_file('confidential.pdf')
|
|
35
|
+
# writer.write
|
|
36
|
+
#
|
|
37
|
+
# @example Create multi-volume archive
|
|
38
|
+
# writer = Writer.new('archive.rar',
|
|
39
|
+
# multi_volume: true,
|
|
40
|
+
# volume_size: '10M',
|
|
41
|
+
# compression: :lzma
|
|
42
|
+
# )
|
|
43
|
+
# writer.add_file('largefile.dat')
|
|
44
|
+
# writer.write # Returns: ['archive.part1.rar', 'archive.part2.rar', ...]
|
|
45
|
+
class Writer
|
|
46
|
+
# RAR5 signature: "Rar!\x1A\x07\x01\x00"
|
|
47
|
+
RAR5_SIGNATURE = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01,
|
|
48
|
+
0x00].pack("C*")
|
|
49
|
+
|
|
50
|
+
# Threshold for automatic compression selection (1 KB)
|
|
51
|
+
AUTO_COMPRESS_THRESHOLD = 1024
|
|
52
|
+
|
|
53
|
+
# @return [String] Output archive path
|
|
54
|
+
attr_reader :path
|
|
55
|
+
|
|
56
|
+
# @return [Hash] Archive options
|
|
57
|
+
attr_reader :options
|
|
58
|
+
|
|
59
|
+
# Initialize RAR5 writer
|
|
60
|
+
#
|
|
61
|
+
# @param path [String] Output RAR file path
|
|
62
|
+
# @param options [Hash] Archive options
|
|
63
|
+
# @option options [Symbol] :compression Compression method (:store, :lzma, :auto)
|
|
64
|
+
# @option options [Integer] :level LZMA compression level (1-5, default: 3)
|
|
65
|
+
# @option options [Boolean] :include_mtime Include modification time in file headers (default: false)
|
|
66
|
+
# @option options [Boolean] :include_crc32 Include CRC32 checksum in file headers (default: false)
|
|
67
|
+
# @option options [Boolean] :solid Enable solid compression (default: false)
|
|
68
|
+
# @option options [String] :password Password for encryption (default: nil)
|
|
69
|
+
# @option options [Integer] :kdf_iterations PBKDF2 iterations for encryption (default: 262,144)
|
|
70
|
+
# @option options [Boolean] :recovery Enable PAR2 recovery records (default: false)
|
|
71
|
+
# @option options [Integer] :recovery_percent Redundancy percentage for PAR2 (default: 5)
|
|
72
|
+
# @option options [Boolean] :multi_volume Enable multi-volume archive (default: false)
|
|
73
|
+
# @option options [Integer, String] :volume_size Maximum volume size (e.g., "10M", 10485760)
|
|
74
|
+
# @option options [String] :volume_naming Volume naming pattern ("part", "volume", "numeric")
|
|
75
|
+
def initialize(path, options = {})
|
|
76
|
+
@path = path
|
|
77
|
+
@options = {
|
|
78
|
+
compression: :store,
|
|
79
|
+
level: 3,
|
|
80
|
+
include_mtime: false,
|
|
81
|
+
include_crc32: false,
|
|
82
|
+
solid: false,
|
|
83
|
+
password: nil,
|
|
84
|
+
kdf_iterations: 262_144,
|
|
85
|
+
recovery: false,
|
|
86
|
+
recovery_percent: 5,
|
|
87
|
+
multi_volume: false,
|
|
88
|
+
volume_size: nil,
|
|
89
|
+
volume_naming: "part",
|
|
90
|
+
}.merge(options)
|
|
91
|
+
@files = []
|
|
92
|
+
|
|
93
|
+
# Initialize encryption manager if password provided (and not empty)
|
|
94
|
+
@encryption_manager = if @options[:password] && !@options[:password].empty?
|
|
95
|
+
Encryption::EncryptionManager.new(
|
|
96
|
+
@options[:password],
|
|
97
|
+
kdf_iterations: @options[:kdf_iterations],
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Add file to archive
|
|
103
|
+
#
|
|
104
|
+
# @param input_path [String] Path to file on disk
|
|
105
|
+
# @param archive_path [String, nil] Path within archive (defaults to basename)
|
|
106
|
+
# @raise [ArgumentError] if file does not exist
|
|
107
|
+
def add_file(input_path, archive_path = nil)
|
|
108
|
+
unless File.exist?(input_path)
|
|
109
|
+
raise ArgumentError,
|
|
110
|
+
"File not found: #{input_path}"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
archive_path ||= File.basename(input_path)
|
|
114
|
+
|
|
115
|
+
# Store file with metadata
|
|
116
|
+
@files << {
|
|
117
|
+
input: input_path,
|
|
118
|
+
archive: archive_path,
|
|
119
|
+
mtime: File.mtime(input_path),
|
|
120
|
+
stat: File.stat(input_path),
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Add a name-only directory entry (empty trees survive
|
|
125
|
+
# archive creation instead of vanishing)
|
|
126
|
+
#
|
|
127
|
+
# @param archive_path [String] Directory path inside the
|
|
128
|
+
# archive (trailing slash optional)
|
|
129
|
+
# @return [self]
|
|
130
|
+
def add_directory_entry(archive_path)
|
|
131
|
+
@files << {
|
|
132
|
+
input: nil,
|
|
133
|
+
archive: archive_path.chomp("/"),
|
|
134
|
+
mtime: Time.now,
|
|
135
|
+
directory: true,
|
|
136
|
+
}
|
|
137
|
+
self
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Add directory recursively
|
|
141
|
+
#
|
|
142
|
+
# @param dir_path [String] Directory path
|
|
143
|
+
# @param base_path [String, nil] Base path for relative names
|
|
144
|
+
# @return [void]
|
|
145
|
+
def add_directory(dir_path, base_path = nil)
|
|
146
|
+
unless File.directory?(dir_path)
|
|
147
|
+
raise ArgumentError,
|
|
148
|
+
"Directory not found: #{dir_path}"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
base_path ||= dir_path
|
|
152
|
+
|
|
153
|
+
Dir.glob(File.join(dir_path, "**", "*")).each do |path|
|
|
154
|
+
next unless File.file?(path)
|
|
155
|
+
|
|
156
|
+
relative_path = path.sub(
|
|
157
|
+
/^#{Regexp.escape(base_path)}#{File::SEPARATOR}?/, ""
|
|
158
|
+
)
|
|
159
|
+
add_file(path, relative_path)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Write archive to disk
|
|
164
|
+
#
|
|
165
|
+
# For single archives, returns the archive path or array of paths (with PAR2).
|
|
166
|
+
# For multi-volume archives, returns an array of volume paths.
|
|
167
|
+
#
|
|
168
|
+
# @return [String, Array<String>] Path(s) to created archive(s) and PAR2 files
|
|
169
|
+
def write
|
|
170
|
+
archive_paths = if @options[:multi_volume]
|
|
171
|
+
write_multi_volume
|
|
172
|
+
else
|
|
173
|
+
write_single_archive
|
|
174
|
+
[@path]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Generate PAR2 recovery files if requested
|
|
178
|
+
if @options[:recovery]
|
|
179
|
+
par2_paths = generate_recovery_files(archive_paths)
|
|
180
|
+
return archive_paths + par2_paths
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
@options[:multi_volume] ? archive_paths : archive_paths.first
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
private
|
|
187
|
+
|
|
188
|
+
# Write single-file archive
|
|
189
|
+
#
|
|
190
|
+
# @return [void]
|
|
191
|
+
def write_single_archive
|
|
192
|
+
File.open(@path, "wb") do |f|
|
|
193
|
+
write_signature(f)
|
|
194
|
+
write_main_header(f)
|
|
195
|
+
|
|
196
|
+
# Solid mode needs a RAR-compatible LZSS encoder; until
|
|
197
|
+
# one lands, fall back to independent STORE entries so
|
|
198
|
+
# the archive is actually extractable by unrar.
|
|
199
|
+
if @options[:solid] && Compression::Lzss.available?
|
|
200
|
+
write_solid_block(f, @files)
|
|
201
|
+
else
|
|
202
|
+
if @options[:solid]
|
|
203
|
+
warn "omnizip: solid: true requested but the " \
|
|
204
|
+
"RAR-compatible LZSS encoder is not available " \
|
|
205
|
+
"— writing independent STORE entries instead"
|
|
206
|
+
end
|
|
207
|
+
@files.each do |file|
|
|
208
|
+
write_file_entry(f, file)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
write_end_header(f)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Write multi-volume archive (new behavior)
|
|
217
|
+
#
|
|
218
|
+
# @return [Array<String>] Paths to created volume files
|
|
219
|
+
def write_multi_volume
|
|
220
|
+
# Parse volume size if string
|
|
221
|
+
volume_size = if @options[:volume_size].is_a?(String)
|
|
222
|
+
Models::VolumeOptions.parse_size(@options[:volume_size])
|
|
223
|
+
else
|
|
224
|
+
@options[:volume_size] || 104_857_600 # 100 MB default
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Create volume manager
|
|
228
|
+
manager = MultiVolume::VolumeManager.new(@path,
|
|
229
|
+
max_volume_size: volume_size,
|
|
230
|
+
volume_naming: @options[:volume_naming],
|
|
231
|
+
compression: @options[:compression],
|
|
232
|
+
level: @options[:level],
|
|
233
|
+
include_mtime: @options[:include_mtime],
|
|
234
|
+
include_crc32: @options[:include_crc32])
|
|
235
|
+
|
|
236
|
+
# Add all files to manager
|
|
237
|
+
@files.each do |file|
|
|
238
|
+
manager.add_file(file[:input], file[:archive])
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# Create volumes
|
|
242
|
+
manager.create_volumes
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Write solid block containing multiple files
|
|
246
|
+
#
|
|
247
|
+
# @param io [IO] Output stream
|
|
248
|
+
# @param files [Array<Hash>] Files to compress in solid mode
|
|
249
|
+
# @return [void]
|
|
250
|
+
def write_solid_block(io, files)
|
|
251
|
+
# Directory entries carry no data; write their headers
|
|
252
|
+
# separately so the solid stream indexes stay aligned
|
|
253
|
+
files.each do |file|
|
|
254
|
+
write_directory_file_entry(io, file) if file[:directory]
|
|
255
|
+
end
|
|
256
|
+
solid_files = files.reject { |f| f[:directory] }
|
|
257
|
+
|
|
258
|
+
# Create solid manager
|
|
259
|
+
manager = Solid::SolidManager.new(level: @options[:level])
|
|
260
|
+
|
|
261
|
+
# Add all files to solid stream
|
|
262
|
+
solid_files.each do |file|
|
|
263
|
+
data = File.binread(file[:input])
|
|
264
|
+
manager.add_file(file[:archive], data, mtime: file[:mtime],
|
|
265
|
+
stat: file[:stat])
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Compress entire solid block
|
|
269
|
+
result = manager.compress_all
|
|
270
|
+
|
|
271
|
+
# Write each file header with references to the solid block
|
|
272
|
+
# In RAR5, all files share the same compressed data
|
|
273
|
+
solid_files.each_with_index do |file, idx|
|
|
274
|
+
file_info = result[:files][idx]
|
|
275
|
+
|
|
276
|
+
# Calculate CRC32 if needed (note: only for STORE in non-solid)
|
|
277
|
+
# Solid compression always uses LZMA, so CRC32 is not included
|
|
278
|
+
compression_method = Compression::Lzma.method_id(@options[:level])
|
|
279
|
+
|
|
280
|
+
header = FileHeader.new(
|
|
281
|
+
filename: file[:archive],
|
|
282
|
+
file_size: file_info[:size],
|
|
283
|
+
compressed_size: (idx.zero? ? result[:compressed_size] : 0), # Only first file has compressed size
|
|
284
|
+
compression_method: compression_method,
|
|
285
|
+
dict_size: dictionary_size_for(compression_method),
|
|
286
|
+
mtime: @options[:include_mtime] ? file[:mtime] : nil,
|
|
287
|
+
crc32: nil, # No CRC32 for solid/LZMA
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
io.write(header.encode)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
# Write the compressed data once after all headers
|
|
294
|
+
io.write(result[:compressed_data])
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Write RAR5 signature (8 bytes)
|
|
298
|
+
#
|
|
299
|
+
# @param io [IO] Output stream
|
|
300
|
+
def write_signature(io)
|
|
301
|
+
io.write(RAR5_SIGNATURE)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Write Main header
|
|
305
|
+
#
|
|
306
|
+
# @param io [IO] Output stream
|
|
307
|
+
def write_main_header(io)
|
|
308
|
+
header = MainHeader.new
|
|
309
|
+
io.write(header.encode)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Write file entry (header + data)
|
|
313
|
+
#
|
|
314
|
+
# @param io [IO] Output stream
|
|
315
|
+
# @param file [Hash] File information
|
|
316
|
+
def write_file_entry(io, file)
|
|
317
|
+
return write_directory_file_entry(io, file) if file[:directory]
|
|
318
|
+
|
|
319
|
+
# Read file data
|
|
320
|
+
data = File.binread(file[:input])
|
|
321
|
+
|
|
322
|
+
# Select compression method
|
|
323
|
+
compression_method = select_compression_method(data)
|
|
324
|
+
|
|
325
|
+
# Compress data (may return hash with properties for LZMA)
|
|
326
|
+
compression_result = compress_data(data, compression_method)
|
|
327
|
+
|
|
328
|
+
# Extract compressed data and optional properties
|
|
329
|
+
if compression_result.is_a?(Hash)
|
|
330
|
+
compressed_data = compression_result[:data]
|
|
331
|
+
compression_properties = compression_result[:properties]
|
|
332
|
+
else
|
|
333
|
+
compressed_data = compression_result
|
|
334
|
+
compression_properties = nil
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Build extra area if compression properties are present
|
|
338
|
+
extra_area = build_compression_extra_area(compression_properties)
|
|
339
|
+
|
|
340
|
+
# Encrypt if password provided (encryption happens AFTER compression)
|
|
341
|
+
if @encryption_manager
|
|
342
|
+
encryption_result = @encryption_manager.encrypt_file_data(compressed_data)
|
|
343
|
+
final_data = encryption_result[:encrypted_data]
|
|
344
|
+
# Persist the salt/IV as the RAR5 file encryption extra
|
|
345
|
+
# record (spec type 0x01) — without it the archive
|
|
346
|
+
# cannot be decrypted by anything.
|
|
347
|
+
enc_record = build_encryption_extra_record(
|
|
348
|
+
encryption_result[:header],
|
|
349
|
+
)
|
|
350
|
+
extra_area = extra_area ? extra_area + enc_record : enc_record
|
|
351
|
+
else
|
|
352
|
+
final_data = compressed_data
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# Calculate CRC32 if needed
|
|
356
|
+
# NOTE: RAR5's optional CRC32 is only compatible with STORE compression.
|
|
357
|
+
# When LZMA or other compression is used, disable CRC32 even if requested.
|
|
358
|
+
# When encryption is used, CRC32 is also not included.
|
|
359
|
+
use_crc32 = @options[:include_crc32] &&
|
|
360
|
+
compression_method == Compression::Store::METHOD &&
|
|
361
|
+
!@encryption_manager
|
|
362
|
+
file_crc32 = use_crc32 ? CRC32.calculate(data) : nil
|
|
363
|
+
|
|
364
|
+
# Create file header
|
|
365
|
+
header = FileHeader.new(
|
|
366
|
+
filename: file[:archive],
|
|
367
|
+
file_size: data.bytesize,
|
|
368
|
+
compressed_size: final_data.bytesize,
|
|
369
|
+
compression_method: compression_method,
|
|
370
|
+
dict_size: dictionary_size_for(compression_method),
|
|
371
|
+
mtime: @options[:include_mtime] ? file[:mtime] : nil,
|
|
372
|
+
crc32: file_crc32,
|
|
373
|
+
extra_area: extra_area,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
# Write header
|
|
377
|
+
io.write(header.encode)
|
|
378
|
+
|
|
379
|
+
# Write data (compressed and encrypted if applicable)
|
|
380
|
+
io.write(final_data)
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# Write a directory entry: FileFlags directory bit, zero
|
|
384
|
+
# sizes, no data area
|
|
385
|
+
#
|
|
386
|
+
# @param io [IO] Output stream
|
|
387
|
+
# @param file [Hash] Entry with :archive name and :mtime
|
|
388
|
+
def write_directory_file_entry(io, file)
|
|
389
|
+
header = FileHeader.new(
|
|
390
|
+
filename: file[:archive],
|
|
391
|
+
file_size: 0,
|
|
392
|
+
compressed_size: 0,
|
|
393
|
+
compression_method: Compression::Store::METHOD,
|
|
394
|
+
dict_size: 0,
|
|
395
|
+
mtime: @options[:include_mtime] ? file[:mtime] : nil,
|
|
396
|
+
directory: true,
|
|
397
|
+
)
|
|
398
|
+
io.write(header.encode)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# Write End header
|
|
402
|
+
#
|
|
403
|
+
# @param io [IO] Output stream
|
|
404
|
+
def write_end_header(io)
|
|
405
|
+
header = EndHeader.new
|
|
406
|
+
io.write(header.encode)
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Select compression method based on options and data
|
|
410
|
+
#
|
|
411
|
+
# @param data [String] File data
|
|
412
|
+
# @return [Integer] Compression method ID
|
|
413
|
+
# Dictionary size matching the compression modules' level
|
|
414
|
+
# table (128 KB << N), for the file header's dictionary
|
|
415
|
+
# bits. STORE needs no dictionary.
|
|
416
|
+
def dictionary_size_for(method)
|
|
417
|
+
return 0 if method == Compression::Store::METHOD
|
|
418
|
+
|
|
419
|
+
1 << case method
|
|
420
|
+
when 1 then 18 # 256 KB
|
|
421
|
+
when 2 then 20 # 1 MB
|
|
422
|
+
when 3 then 22 # 4 MB
|
|
423
|
+
when 4 then 23 # 8 MB
|
|
424
|
+
when 5 then 24 # 16 MB
|
|
425
|
+
else 22
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def select_compression_method(data)
|
|
430
|
+
case @options[:compression]
|
|
431
|
+
when :store
|
|
432
|
+
Compression::Store::METHOD
|
|
433
|
+
when :lzss, :lzma
|
|
434
|
+
# RAR5 uses LZSS compression (methods 1-5)
|
|
435
|
+
# Note: :lzma is deprecated, use :lzss for clarity
|
|
436
|
+
level = @options[:level] || 3
|
|
437
|
+
if Compression::Lzss.available?
|
|
438
|
+
Compression::Lzss.method_id(level)
|
|
439
|
+
else
|
|
440
|
+
warn "omnizip: RAR5 #{@options[:compression] == :lzma ? 'lzma' : 'lzss'} " \
|
|
441
|
+
"compression is not interoperable yet; storing data " \
|
|
442
|
+
"uncompressed instead"
|
|
443
|
+
Compression::Store::METHOD
|
|
444
|
+
end
|
|
445
|
+
when :auto
|
|
446
|
+
# Auto-select based on file size
|
|
447
|
+
if data.bytesize < AUTO_COMPRESS_THRESHOLD
|
|
448
|
+
Compression::Store::METHOD
|
|
449
|
+
else
|
|
450
|
+
level = @options[:level] || 3
|
|
451
|
+
if Compression::Lzss.available?
|
|
452
|
+
Compression::Lzss.method_id(level)
|
|
453
|
+
else
|
|
454
|
+
# LZSS not implemented, fall back to STORE
|
|
455
|
+
Compression::Store::METHOD
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
else
|
|
459
|
+
Compression::Store::METHOD
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# Compress data using selected method
|
|
464
|
+
#
|
|
465
|
+
# @param data [String] Data to compress
|
|
466
|
+
# @param method [Integer] Compression method ID
|
|
467
|
+
# @return [String, Hash] Compressed data or hash with :data and :properties
|
|
468
|
+
def compress_data(data, method)
|
|
469
|
+
if method == Compression::Store::METHOD
|
|
470
|
+
Compression::Store.compress(data)
|
|
471
|
+
else
|
|
472
|
+
# Methods 1-5 are RAR5 LZSS with different levels
|
|
473
|
+
level = method.clamp(1, 5)
|
|
474
|
+
if Compression::Lzss.available?
|
|
475
|
+
Compression::Lzss.compress(data, level: level)
|
|
476
|
+
else
|
|
477
|
+
# LZSS not implemented, fall back to STORE
|
|
478
|
+
Compression::Store.compress(data)
|
|
479
|
+
end
|
|
480
|
+
end
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Build extra area for compression parameters
|
|
484
|
+
#
|
|
485
|
+
# RAR5 stores compression parameters in an extra area with type 0x03.
|
|
486
|
+
# The format depends on the compression method used.
|
|
487
|
+
#
|
|
488
|
+
# @param properties [String, nil] Compression properties
|
|
489
|
+
# @return [String, nil] Encoded extra area or nil if no properties
|
|
490
|
+
def build_compression_extra_area(properties)
|
|
491
|
+
return nil if properties.nil?
|
|
492
|
+
|
|
493
|
+
# Extra record format per the RAR 5.0 spec: Size(vint),
|
|
494
|
+
# Type(vint), Data. Type 0x03 carries the compression
|
|
495
|
+
# parameters.
|
|
496
|
+
record = VINT.encode(0x03) + properties.bytes
|
|
497
|
+
VINT.encode(record.length) + record
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
# File encryption extra record (spec type 0x01): AES-256
|
|
501
|
+
# parameters the reader needs to derive the key and IV.
|
|
502
|
+
def build_encryption_extra_record(header)
|
|
503
|
+
require "base64"
|
|
504
|
+
|
|
505
|
+
kdf_count = Math.log2(header.kdf_iterations).round
|
|
506
|
+
record = [].concat(VINT.encode(0x01)) # record type
|
|
507
|
+
.concat(VINT.encode(header.version)) # 0 = AES-256
|
|
508
|
+
.concat(VINT.encode(0)) # flags: no check data
|
|
509
|
+
record << kdf_count # 1 byte, log2
|
|
510
|
+
record.concat(Base64.strict_decode64(header.salt).bytes)
|
|
511
|
+
record.concat(Base64.strict_decode64(header.iv).bytes)
|
|
512
|
+
|
|
513
|
+
(VINT.encode(record.length) + record).pack("C*")
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# Generate PAR2 recovery files for archives
|
|
517
|
+
#
|
|
518
|
+
# @param archive_paths [Array<String>] Paths to archive files
|
|
519
|
+
# @return [Array<String>] Paths to created PAR2 files
|
|
520
|
+
def generate_recovery_files(archive_paths)
|
|
521
|
+
base_name = @path.sub(/\.rar$/, "")
|
|
522
|
+
|
|
523
|
+
creator = Parity::Par2Creator.new(
|
|
524
|
+
redundancy: @options[:recovery_percent] || 5,
|
|
525
|
+
block_size: 16_384,
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
# Add all archive files
|
|
529
|
+
archive_paths.each do |path|
|
|
530
|
+
creator.add_file(path)
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
# Create PAR2 files
|
|
534
|
+
creator.create(base_name)
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
end
|