omnizip 0.4.7-x86_64-linux
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.rubocop_todo.yml +293 -0
- data/CHANGELOG.md +1647 -0
- data/CONTEXT.md +68 -0
- data/COPYING +502 -0
- data/Gemfile +19 -0
- data/LICENSE +12 -0
- data/README.adoc +1327 -0
- data/Rakefile +15 -0
- data/TODO.refactor/00-overview.md +67 -0
- data/TODO.refactor/01-registry-base-class.md +81 -0
- data/TODO.refactor/02-error-hierarchy.md +57 -0
- data/TODO.refactor/03-autoload-entry-point.md +69 -0
- data/TODO.refactor/04-filter-base-consolidation.md +49 -0
- data/TODO.refactor/05-send-private-methods.md +64 -0
- data/TODO.refactor/06-instance-variable-access.md +69 -0
- data/TODO.refactor/07-respond-to-replacement.md +237 -0
- data/TODO.refactor/08-spec-doubles.md +27 -0
- data/TODO.refactor/09-cli-shared-module.md +35 -0
- data/TODO.refactor/10-format-detector-ocp.md +34 -0
- data/TODO.refactor/11-convenience-decoupling.md +38 -0
- data/TODO.refactor/12-thread-safety.md +8 -0
- data/TODO.refactor/13-lutaml-model-migration.md +158 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -0
- data/benchmark/README.md +260 -0
- data/benchmark/benchmark_suite.rb +125 -0
- data/benchmark/compression_bench.rb +181 -0
- data/benchmark/filter_bench.rb +180 -0
- data/benchmark/models/benchmark_result.rb +59 -0
- data/benchmark/models/comparison_result.rb +69 -0
- data/benchmark/profile_suite.rb +167 -0
- data/benchmark/reporter.rb +150 -0
- data/benchmark/run_benchmarks.rb +66 -0
- data/benchmark/test_data.rb +137 -0
- data/config/formats/rar3_spec.yml +92 -0
- data/config/formats/rar5_spec.yml +102 -0
- data/docs/.github/workflows/docs.yml +142 -0
- data/docs/.gitignore +21 -0
- data/docs/.lychee.toml +67 -0
- data/docs/Gemfile +13 -0
- data/docs/RAR_WRITE_SUPPORT.md +26 -0
- data/docs/README.md +101 -0
- data/docs/_config.yml +112 -0
- data/docs/assets/logo.svg +1 -0
- data/docs/assets/omnizip-logo.pdf +1540 -11
- data/docs/comparison/feature-matrix.adoc +694 -0
- data/docs/comparison/index.adoc +113 -0
- data/docs/comparison/vs-7zip.adoc +309 -0
- data/docs/comparison/vs-peazip.adoc +77 -0
- data/docs/comparison/vs-rubyzip.adoc +342 -0
- data/docs/comparison/vs-winrar.adoc +100 -0
- data/docs/compatibility.adoc +579 -0
- data/docs/concepts/index.adoc +129 -0
- data/docs/developer/architecture.adoc +256 -0
- data/docs/developer/contributing.adoc +158 -0
- data/docs/developer/index.adoc +25 -0
- data/docs/developer/testing.adoc +212 -0
- data/docs/getting-started/basic-usage.adoc +263 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +183 -0
- data/docs/getting-started/your-first-archive.adoc +219 -0
- data/docs/guides/advanced-features/encryption.adoc +277 -0
- data/docs/guides/advanced-features/index.adoc +59 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
- data/docs/guides/advanced-features/streaming.adoc +142 -0
- data/docs/guides/archive-formats/gzip-format.adoc +105 -0
- data/docs/guides/archive-formats/index.adoc +160 -0
- data/docs/guides/archive-formats/ole-format.adoc +151 -0
- data/docs/guides/archive-formats/rar-format.adoc +104 -0
- data/docs/guides/archive-formats/rar5.adoc +521 -0
- data/docs/guides/archive-formats/rpm-format.adoc +108 -0
- data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
- data/docs/guides/archive-formats/tar-format.adoc +106 -0
- data/docs/guides/archive-formats/xz-format.adoc +118 -0
- data/docs/guides/archive-formats/zip-format.adoc +35 -0
- data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
- data/docs/guides/compression-algorithms/deflate.adoc +313 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +394 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
- data/docs/guides/creating-archives.adoc +348 -0
- data/docs/guides/extracting-archives.adoc +53 -0
- data/docs/guides/format-conversion.adoc +64 -0
- data/docs/guides/index.adoc +49 -0
- data/docs/guides/migration-rubyzip.adoc +217 -0
- data/docs/guides/parity-archives.adoc +605 -0
- data/docs/guides/performance-tuning.adoc +88 -0
- data/docs/index.adoc +228 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +187 -0
- data/docs/reference/cli/compress-command.adoc +114 -0
- data/docs/reference/cli/overview.adoc +140 -0
- data/docs/reference/index.adoc +26 -0
- data/docs/resources/faq.adoc +185 -0
- data/docs/resources/quick-reference.adoc +222 -0
- data/docs/rust-backend.md +0 -0
- data/docs/troubleshooting/index.adoc +207 -0
- data/docs/xar_format.md +216 -0
- data/examples/api_comparison.rb +205 -0
- data/examples/deflate64_example.rb +96 -0
- data/examples/par2_demo.rb +121 -0
- data/examples/quick_start_native.rb +150 -0
- data/examples/quick_start_rubyzip.rb +115 -0
- data/examples/rubyzip_compatibility_demo.rb +194 -0
- data/exe/omnizip +27 -0
- data/lib/omnizip/algorithm.rb +176 -0
- data/lib/omnizip/algorithm_registry.rb +65 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
- data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
- data/lib/omnizip/algorithms/bzip2.rb +108 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
- data/lib/omnizip/algorithms/deflate.rb +135 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
- data/lib/omnizip/algorithms/deflate64.rb +118 -0
- data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
- data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
- data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
- data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
- data/lib/omnizip/algorithms/lzma/match.rb +32 -0
- data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
- data/lib/omnizip/algorithms/lzma.rb +266 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +133 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +146 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +122 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
- data/lib/omnizip/algorithms/registration.rb +28 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
- data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
- data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
- data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
- data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
- data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
- data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
- data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
- data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +210 -0
- data/lib/omnizip/algorithms.rb +35 -0
- data/lib/omnizip/archive/builder.rb +48 -0
- data/lib/omnizip/archive/reader_session.rb +67 -0
- data/lib/omnizip/archive.rb +86 -0
- data/lib/omnizip/archive_handler.rb +82 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
- data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
- data/lib/omnizip/archive_handlers.rb +18 -0
- data/lib/omnizip/backends.rb +160 -0
- data/lib/omnizip/buffer/memory_archive.rb +246 -0
- data/lib/omnizip/buffer/memory_extractor.rb +234 -0
- data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
- data/lib/omnizip/buffer.rb +187 -0
- data/lib/omnizip/checksum_registry.rb +41 -0
- data/lib/omnizip/checksums/crc32.rb +101 -0
- data/lib/omnizip/checksums/crc64.rb +102 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/registration.rb +16 -0
- data/lib/omnizip/checksums/verifier.rb +130 -0
- data/lib/omnizip/checksums.rb +11 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +123 -0
- data/lib/omnizip/chunked.rb +123 -0
- data/lib/omnizip/cli/output_formatter.rb +112 -0
- data/lib/omnizip/cli.rb +604 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +245 -0
- data/lib/omnizip/commands/archive_extract_command.rb +231 -0
- data/lib/omnizip/commands/archive_list_command.rb +204 -0
- data/lib/omnizip/commands/archive_repair_command.rb +129 -0
- data/lib/omnizip/commands/archive_verify_command.rb +115 -0
- data/lib/omnizip/commands/compress_command.rb +115 -0
- data/lib/omnizip/commands/decompress_command.rb +149 -0
- data/lib/omnizip/commands/list_command.rb +51 -0
- data/lib/omnizip/commands/metadata_command.rb +215 -0
- data/lib/omnizip/commands/parity_create_command.rb +114 -0
- data/lib/omnizip/commands/parity_repair_command.rb +120 -0
- data/lib/omnizip/commands/parity_verify_command.rb +122 -0
- data/lib/omnizip/commands/profile_list_command.rb +54 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/commands.rb +21 -0
- data/lib/omnizip/convenience.rb +389 -0
- data/lib/omnizip/converter/conversion_registry.rb +50 -0
- data/lib/omnizip/converter/conversion_strategy.rb +108 -0
- data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
- data/lib/omnizip/converter.rb +124 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/crypto.rb +11 -0
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/error.rb +110 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
- data/lib/omnizip/eta/rate_calculator.rb +104 -0
- data/lib/omnizip/eta/sample_history.rb +143 -0
- data/lib/omnizip/eta/time_estimator.rb +106 -0
- data/lib/omnizip/eta.rb +68 -0
- data/lib/omnizip/extraction/filter_chain.rb +179 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
- data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
- data/lib/omnizip/extraction/regex_pattern.rb +50 -0
- data/lib/omnizip/extraction/selective_extractor.rb +247 -0
- data/lib/omnizip/extraction.rb +115 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +117 -0
- data/lib/omnizip/filter.rb +141 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +113 -0
- data/lib/omnizip/filters/bcj.rb +277 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
- data/lib/omnizip/filters/bcj2.rb +93 -0
- data/lib/omnizip/filters/bcj_arm.rb +174 -0
- data/lib/omnizip/filters/bcj_arm64.rb +242 -0
- data/lib/omnizip/filters/bcj_ia64.rb +194 -0
- data/lib/omnizip/filters/bcj_ppc.rb +188 -0
- data/lib/omnizip/filters/bcj_sparc.rb +174 -0
- data/lib/omnizip/filters/bcj_x86.rb +191 -0
- data/lib/omnizip/filters/delta.rb +195 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/filters.rb +20 -0
- data/lib/omnizip/format_detector.rb +166 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +159 -0
- data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +389 -0
- data/lib/omnizip/formats/cpio/reader.rb +194 -0
- data/lib/omnizip/formats/cpio/writer.rb +232 -0
- data/lib/omnizip/formats/cpio.rb +132 -0
- data/lib/omnizip/formats/format_spec_loader.rb +228 -0
- data/lib/omnizip/formats/gzip.rb +236 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
- data/lib/omnizip/formats/iso/directory_record.rb +162 -0
- data/lib/omnizip/formats/iso/joliet.rb +204 -0
- data/lib/omnizip/formats/iso/path_table.rb +125 -0
- data/lib/omnizip/formats/iso/reader.rb +194 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +543 -0
- data/lib/omnizip/formats/iso.rb +133 -0
- data/lib/omnizip/formats/lzip.rb +161 -0
- data/lib/omnizip/formats/lzma_alone.rb +149 -0
- data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
- data/lib/omnizip/formats/msi/constants.rb +157 -0
- data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
- data/lib/omnizip/formats/msi/entry.rb +134 -0
- data/lib/omnizip/formats/msi/reader.rb +301 -0
- data/lib/omnizip/formats/msi/string_pool.rb +246 -0
- data/lib/omnizip/formats/msi/table_parser.rb +244 -0
- data/lib/omnizip/formats/msi.rb +73 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
- data/lib/omnizip/formats/ole/constants.rb +61 -0
- data/lib/omnizip/formats/ole/dirent.rb +439 -0
- data/lib/omnizip/formats/ole/header.rb +199 -0
- data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
- data/lib/omnizip/formats/ole/storage.rb +482 -0
- data/lib/omnizip/formats/ole/types/variant.rb +338 -0
- data/lib/omnizip/formats/ole.rb +143 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
- data/lib/omnizip/formats/rar/block_parser.rb +282 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
- data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
- data/lib/omnizip/formats/rar/compression.rb +17 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +88 -0
- data/lib/omnizip/formats/rar/decompressor.rb +316 -0
- data/lib/omnizip/formats/rar/external_writer.rb +311 -0
- data/lib/omnizip/formats/rar/header.rb +209 -0
- data/lib/omnizip/formats/rar/license_validator.rb +111 -0
- data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
- data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
- data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
- data/lib/omnizip/formats/rar/models.rb +14 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
- data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
- data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
- data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
- data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
- data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
- data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
- data/lib/omnizip/formats/rar/reader.rb +377 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
- data/lib/omnizip/formats/rar/writer.rb +437 -0
- data/lib/omnizip/formats/rar.rb +193 -0
- data/lib/omnizip/formats/rar3/compressor.rb +71 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar3/reader.rb +107 -0
- data/lib/omnizip/formats/rar3/writer.rb +220 -0
- data/lib/omnizip/formats/rar3.rb +15 -0
- data/lib/omnizip/formats/rar5/compressor.rb +71 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar5/reader.rb +130 -0
- data/lib/omnizip/formats/rar5/writer.rb +65 -0
- data/lib/omnizip/formats/rar5.rb +15 -0
- data/lib/omnizip/formats/rpm/constants.rb +58 -0
- data/lib/omnizip/formats/rpm/entry.rb +106 -0
- data/lib/omnizip/formats/rpm/header.rb +106 -0
- data/lib/omnizip/formats/rpm/lead.rb +132 -0
- data/lib/omnizip/formats/rpm/tag.rb +228 -0
- data/lib/omnizip/formats/rpm/writer.rb +652 -0
- data/lib/omnizip/formats/rpm.rb +458 -0
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
- data/lib/omnizip/formats/seven_zip/header.rb +102 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/models.rb +20 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
- data/lib/omnizip/formats/seven_zip.rb +179 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +98 -0
- data/lib/omnizip/formats/tar/header.rb +206 -0
- data/lib/omnizip/formats/tar/reader.rb +119 -0
- data/lib/omnizip/formats/tar/writer.rb +212 -0
- data/lib/omnizip/formats/tar.rb +74 -0
- data/lib/omnizip/formats/xar/constants.rb +119 -0
- data/lib/omnizip/formats/xar/entry.rb +268 -0
- data/lib/omnizip/formats/xar/header.rb +223 -0
- data/lib/omnizip/formats/xar/reader.rb +400 -0
- data/lib/omnizip/formats/xar/toc.rb +570 -0
- data/lib/omnizip/formats/xar/writer.rb +461 -0
- data/lib/omnizip/formats/xar.rb +145 -0
- data/lib/omnizip/formats/xz/reader.rb +121 -0
- data/lib/omnizip/formats/xz/writer.rb +416 -0
- data/lib/omnizip/formats/xz.rb +210 -0
- data/lib/omnizip/formats/xz_const.rb +49 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl.rb +52 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
- data/lib/omnizip/formats/zip/reader.rb +376 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +489 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/formats.rb +29 -0
- data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
- data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
- data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
- data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
- data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
- data/lib/omnizip/implementations/base.rb +19 -0
- data/lib/omnizip/implementations/rust/archive.rb +93 -0
- data/lib/omnizip/implementations/rust/library.rb +221 -0
- data/lib/omnizip/implementations/rust.rb +26 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
- data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
- data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
- data/lib/omnizip/implementations/seven_zip.rb +11 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
- data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
- data/lib/omnizip/implementations/xz_utils.rb +10 -0
- data/lib/omnizip/implementations.rb +25 -0
- data/lib/omnizip/io/buffered_input.rb +147 -0
- data/lib/omnizip/io/buffered_output.rb +106 -0
- data/lib/omnizip/io/source.rb +143 -0
- data/lib/omnizip/io/stream_manager.rb +117 -0
- data/lib/omnizip/io.rb +15 -0
- data/lib/omnizip/link_handler/hard_link.rb +79 -0
- data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
- data/lib/omnizip/link_handler.rb +129 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +153 -0
- data/lib/omnizip/metadata/metadata_editor.rb +169 -0
- data/lib/omnizip/metadata/metadata_registry.rb +71 -0
- data/lib/omnizip/metadata/metadata_validator.rb +101 -0
- data/lib/omnizip/metadata.rb +58 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +41 -0
- data/lib/omnizip/models/attribute_apply.rb +40 -0
- data/lib/omnizip/models/compression_options.rb +53 -0
- data/lib/omnizip/models/conversion_options.rb +79 -0
- data/lib/omnizip/models/conversion_result.rb +141 -0
- data/lib/omnizip/models/eta_result.rb +45 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +142 -0
- data/lib/omnizip/models/filter_config.rb +148 -0
- data/lib/omnizip/models/match_result.rb +141 -0
- data/lib/omnizip/models/optimization_suggestion.rb +95 -0
- data/lib/omnizip/models/parallel_options.rb +116 -0
- data/lib/omnizip/models/performance_result.rb +85 -0
- data/lib/omnizip/models/profile_report.rb +116 -0
- data/lib/omnizip/models/progress_options.rb +39 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +45 -0
- data/lib/omnizip/parallel/engine.rb +52 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +225 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
- data/lib/omnizip/parallel/thread_pool.rb +60 -0
- data/lib/omnizip/parallel/worker_pool.rb +227 -0
- data/lib/omnizip/parallel.rb +156 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +71 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
- data/lib/omnizip/parity/models/main_packet.rb +126 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +102 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
- data/lib/omnizip/parity/models.rb +27 -0
- data/lib/omnizip/parity/par2_creator.rb +496 -0
- data/lib/omnizip/parity/par2_repairer.rb +409 -0
- data/lib/omnizip/parity/par2_verifier.rb +373 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
- data/lib/omnizip/parity.rb +207 -0
- data/lib/omnizip/password/encryption_registry.rb +26 -0
- data/lib/omnizip/password/encryption_strategy.rb +96 -0
- data/lib/omnizip/password/password_validator.rb +129 -0
- data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
- data/lib/omnizip/password.rb +88 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
- data/lib/omnizip/pipe.rb +120 -0
- data/lib/omnizip/platform/ntfs_streams.rb +200 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +36 -0
- data/lib/omnizip/profile/balanced_profile.rb +31 -0
- data/lib/omnizip/profile/binary_profile.rb +33 -0
- data/lib/omnizip/profile/compression_profile.rb +157 -0
- data/lib/omnizip/profile/custom_profile.rb +155 -0
- data/lib/omnizip/profile/fast_profile.rb +31 -0
- data/lib/omnizip/profile/maximum_profile.rb +31 -0
- data/lib/omnizip/profile/profile_detector.rb +108 -0
- data/lib/omnizip/profile/profile_registry.rb +160 -0
- data/lib/omnizip/profile/text_profile.rb +33 -0
- data/lib/omnizip/profile.rb +261 -0
- data/lib/omnizip/profiler/memory_profiler.rb +66 -0
- data/lib/omnizip/profiler/method_profiler.rb +49 -0
- data/lib/omnizip/profiler/report_generator.rb +158 -0
- data/lib/omnizip/profiler.rb +192 -0
- data/lib/omnizip/progress/callback_reporter.rb +34 -0
- data/lib/omnizip/progress/console_reporter.rb +59 -0
- data/lib/omnizip/progress/log_reporter.rb +89 -0
- data/lib/omnizip/progress/operation_progress.rb +118 -0
- data/lib/omnizip/progress/progress_bar.rb +156 -0
- data/lib/omnizip/progress/progress_reporter.rb +40 -0
- data/lib/omnizip/progress/progress_tracker.rb +215 -0
- data/lib/omnizip/progress/silent_reporter.rb +22 -0
- data/lib/omnizip/progress.rb +131 -0
- data/lib/omnizip/registry.rb +111 -0
- data/lib/omnizip/rubyzip_compat.rb +61 -0
- data/lib/omnizip/temp/safe_extract.rb +124 -0
- data/lib/omnizip/temp/temp_file.rb +123 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +184 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +160 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +270 -0
- data/lib/omnizip/zip/output_stream.rb +320 -0
- data/lib/omnizip/zip.rb +23 -0
- data/lib/omnizip.rb +157 -0
- data/lib/tasks/msi_test_files.rake +66 -0
- data/lib/tasks/platform_gems.rake +147 -0
- data/lib/tasks/rust_backend.rake +48 -0
- data/readme-docs/advanced-features.adoc +514 -0
- data/readme-docs/api-usage.adoc +445 -0
- data/readme-docs/architecture.adoc +450 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +446 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +316 -0
- data/readme-docs/installation.adoc +228 -0
- data/readme-docs/par2-archives.adoc +608 -0
- data/readme-docs/performance-profiler.adoc +389 -0
- data/readme-docs/preprocessing-filters.adoc +280 -0
- data/vendor/libomnizip_ffi.so +0 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +768 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
# .7z archive format support
|
|
6
|
+
# Provides read and write access to 7-Zip archives
|
|
7
|
+
#
|
|
8
|
+
# This module implements the .7z archive format specification,
|
|
9
|
+
# supporting:
|
|
10
|
+
# - Format signature and header validation
|
|
11
|
+
# - Archive structure parsing
|
|
12
|
+
# - File extraction
|
|
13
|
+
# - Archive creation
|
|
14
|
+
# - Split archives (multi-volume)
|
|
15
|
+
module SevenZip
|
|
16
|
+
# Nested classes - autoloaded
|
|
17
|
+
autoload :Constants, "omnizip/formats/seven_zip/constants"
|
|
18
|
+
autoload :Header, "omnizip/formats/seven_zip/header"
|
|
19
|
+
autoload :Parser, "omnizip/formats/seven_zip/parser"
|
|
20
|
+
autoload :Reader, "omnizip/formats/seven_zip/reader"
|
|
21
|
+
autoload :Writer, "omnizip/formats/seven_zip/writer"
|
|
22
|
+
autoload :CoderChain, "omnizip/formats/seven_zip/coder_chain"
|
|
23
|
+
autoload :StreamDecompressor,
|
|
24
|
+
"omnizip/formats/seven_zip/stream_decompressor"
|
|
25
|
+
autoload :StreamCompressor, "omnizip/formats/seven_zip/stream_compressor"
|
|
26
|
+
autoload :FileCollector, "omnizip/formats/seven_zip/file_collector"
|
|
27
|
+
autoload :HeaderWriter, "omnizip/formats/seven_zip/header_writer"
|
|
28
|
+
autoload :SplitArchiveReader,
|
|
29
|
+
"omnizip/formats/seven_zip/split_archive_reader"
|
|
30
|
+
autoload :SplitArchiveWriter,
|
|
31
|
+
"omnizip/formats/seven_zip/split_archive_writer"
|
|
32
|
+
autoload :HeaderEncryptor, "omnizip/formats/seven_zip/header_encryptor"
|
|
33
|
+
autoload :EncryptedHeader, "omnizip/formats/seven_zip/encrypted_header"
|
|
34
|
+
autoload :EncodedHeader, "omnizip/formats/seven_zip/encoded_header"
|
|
35
|
+
autoload :Bcj2StreamDecompressor,
|
|
36
|
+
"omnizip/formats/seven_zip/bcj2_stream_decompressor"
|
|
37
|
+
module Models
|
|
38
|
+
autoload :StreamInfo, "omnizip/formats/seven_zip/models/stream_info"
|
|
39
|
+
autoload :FileEntry, "omnizip/formats/seven_zip/models/file_entry"
|
|
40
|
+
autoload :Folder, "omnizip/formats/seven_zip/models/folder"
|
|
41
|
+
autoload :CoderInfo, "omnizip/formats/seven_zip/models/coder_info"
|
|
42
|
+
end
|
|
43
|
+
# Add autoload for Models namespace itself
|
|
44
|
+
autoload :Models, "omnizip/formats/seven_zip/models"
|
|
45
|
+
|
|
46
|
+
# Cross-namespace dependencies - autoloaded
|
|
47
|
+
autoload :Crc32, "omnizip/checksums/crc32"
|
|
48
|
+
autoload :LZMA2, "omnizip/algorithms/lzma2"
|
|
49
|
+
autoload :AlgorithmRegistry, "omnizip/algorithm_registry"
|
|
50
|
+
autoload :FilterRegistry, "omnizip/filter_registry"
|
|
51
|
+
autoload :FilterPipeline, "omnizip/filter_pipeline"
|
|
52
|
+
autoload :Bcj2Decoder, "omnizip/filters/bcj2/decoder"
|
|
53
|
+
autoload :Bcj2StreamData, "omnizip/filters/bcj2/stream_data"
|
|
54
|
+
|
|
55
|
+
# Create a new .7z archive
|
|
56
|
+
#
|
|
57
|
+
# @param path [String] Output path
|
|
58
|
+
# @param options [Hash] Compression options
|
|
59
|
+
# @option options [Integer] :volume_size Volume size for split archives
|
|
60
|
+
# @option options [String] :password Password for header encryption
|
|
61
|
+
# @option options [Boolean] :encrypt_headers Encrypt archive headers
|
|
62
|
+
# @yield [writer] Block for adding files
|
|
63
|
+
# @yieldparam writer [Writer] Archive writer
|
|
64
|
+
def self.create(path, options = {})
|
|
65
|
+
writer = Writer.new(path, options)
|
|
66
|
+
yield writer if block_given?
|
|
67
|
+
writer.write
|
|
68
|
+
writer
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Create a split .7z archive
|
|
72
|
+
#
|
|
73
|
+
# @param path [String] Base path (e.g., "backup.7z.001")
|
|
74
|
+
# @param split_options [Models::SplitOptions] Split configuration
|
|
75
|
+
# @param options [Hash] Compression options
|
|
76
|
+
# @yield [writer] Block for adding files
|
|
77
|
+
# @yieldparam writer [SplitArchiveWriter] Archive writer
|
|
78
|
+
def self.create_split(path, split_options, options = {})
|
|
79
|
+
writer = SplitArchiveWriter.new(path, options, split_options)
|
|
80
|
+
yield writer if block_given?
|
|
81
|
+
writer.write
|
|
82
|
+
writer
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Open existing .7z archive
|
|
86
|
+
#
|
|
87
|
+
# @param path [String] Archive path
|
|
88
|
+
# @param options [Hash] Reader options
|
|
89
|
+
# @option options [String] :password Password for encrypted headers
|
|
90
|
+
# @yield [reader] Block for reading archive
|
|
91
|
+
# @yieldparam reader [Reader] Archive reader
|
|
92
|
+
# @return [Reader] Archive reader
|
|
93
|
+
def self.open(path, options = {})
|
|
94
|
+
reader = Reader.new(path, options)
|
|
95
|
+
reader.open
|
|
96
|
+
|
|
97
|
+
if block_given?
|
|
98
|
+
begin
|
|
99
|
+
yield reader
|
|
100
|
+
ensure
|
|
101
|
+
reader.split_reader&.close
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
reader
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Search for embedded .7z archive in self-extracting executable
|
|
109
|
+
#
|
|
110
|
+
# Scans the file for 7z signatures and validates each candidate by
|
|
111
|
+
# checking the Start Header (version bytes, CRC, and header field
|
|
112
|
+
# sanity). Returns the offset of the first valid embedded archive.
|
|
113
|
+
#
|
|
114
|
+
# @param path [String] Path to potential self-extracting archive
|
|
115
|
+
# @return [Integer, nil] Offset of embedded 7z signature, or nil if not found
|
|
116
|
+
def self.search_embedded(path)
|
|
117
|
+
data = File.binread(path)
|
|
118
|
+
file_size = data.bytesize
|
|
119
|
+
signature = Constants::SIGNATURE
|
|
120
|
+
pos = 0
|
|
121
|
+
|
|
122
|
+
while (offset = data.index(signature, pos))
|
|
123
|
+
if valid_7z_start_header?(data, offset, file_size)
|
|
124
|
+
return offset
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
pos = offset + 1
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Validate a candidate 7z Start Header at the given offset.
|
|
134
|
+
#
|
|
135
|
+
# Checks:
|
|
136
|
+
# 1. Enough bytes remain for a full 32-byte Start Header
|
|
137
|
+
# 2. Major version is 0 and minor version is 4 (only supported version)
|
|
138
|
+
# 3. Next Header offset + size points within (or at the end of) the file
|
|
139
|
+
# 4. Start Header CRC matches the header content
|
|
140
|
+
#
|
|
141
|
+
# @param data [String] File data
|
|
142
|
+
# @param offset [Integer] Offset of the 7z signature
|
|
143
|
+
# @param file_size [Integer] Total file size
|
|
144
|
+
# @return [Boolean] true if the header looks valid
|
|
145
|
+
def self.valid_7z_start_header?(data, offset, file_size)
|
|
146
|
+
header_size = Constants::START_HEADER_SIZE # 32
|
|
147
|
+
return false if offset + header_size > file_size
|
|
148
|
+
|
|
149
|
+
header_data = data.byteslice(offset, header_size)
|
|
150
|
+
|
|
151
|
+
# Check version byte (offset 6) - only major version is validated per 7-Zip SDK
|
|
152
|
+
# See: https://github.com/ip7z/7zip/blob/main/CPP/7zip/Archive/7z/7zIn.cpp#L1591-L1598
|
|
153
|
+
major_version = header_data.getbyte(6)
|
|
154
|
+
return false unless major_version == Constants::MAJOR_VERSION
|
|
155
|
+
|
|
156
|
+
# Parse Start Header fields (bytes 12-31)
|
|
157
|
+
next_header_data = header_data.byteslice(12, 20)
|
|
158
|
+
next_header_offset = next_header_data.unpack1("Q<")
|
|
159
|
+
next_header_size = next_header_data.byteslice(8, 8).unpack1("Q<")
|
|
160
|
+
|
|
161
|
+
# next_header_offset is relative to end of Start Header
|
|
162
|
+
header_end = offset + header_size + next_header_offset + next_header_size
|
|
163
|
+
return false if header_end > file_size
|
|
164
|
+
return false if next_header_size.zero? || next_header_size > file_size
|
|
165
|
+
|
|
166
|
+
# Validate Start Header CRC (bytes 8-11) over next_header_data (bytes 12-31)
|
|
167
|
+
stored_crc = header_data.byteslice(8, 4).unpack1("V")
|
|
168
|
+
computed_crc = Omnizip::Checksums::Crc32.new.tap do |c|
|
|
169
|
+
c.update(next_header_data)
|
|
170
|
+
end.finalize
|
|
171
|
+
return false unless stored_crc == computed_crc
|
|
172
|
+
|
|
173
|
+
true
|
|
174
|
+
rescue StandardError
|
|
175
|
+
false
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Tar
|
|
6
|
+
# TAR format constants
|
|
7
|
+
module Constants
|
|
8
|
+
# TAR header size (POSIX ustar format)
|
|
9
|
+
HEADER_SIZE = 512
|
|
10
|
+
|
|
11
|
+
# Block size for TAR archives
|
|
12
|
+
BLOCK_SIZE = 512
|
|
13
|
+
|
|
14
|
+
# Type flags for TAR entries
|
|
15
|
+
TYPE_REGULAR = "0" # Regular file
|
|
16
|
+
TYPE_HARD_LINK = "1" # Hard link
|
|
17
|
+
TYPE_SYMLINK = "2" # Symbolic link
|
|
18
|
+
TYPE_CHAR_DEVICE = "3" # Character device
|
|
19
|
+
TYPE_BLOCK_DEVICE = "4" # Block device
|
|
20
|
+
TYPE_DIRECTORY = "5" # Directory
|
|
21
|
+
TYPE_FIFO = "6" # FIFO
|
|
22
|
+
TYPE_CONTIGUOUS = "7" # Contiguous file
|
|
23
|
+
TYPE_EXTENDED = "x" # Extended header
|
|
24
|
+
TYPE_GLOBAL_EXTENDED = "g" # Global extended header
|
|
25
|
+
TYPE_GNU_LONGNAME = "L" # GNU long name
|
|
26
|
+
TYPE_GNU_LONGLINK = "K" # GNU long link
|
|
27
|
+
|
|
28
|
+
# POSIX ustar magic value
|
|
29
|
+
USTAR_MAGIC = "ustar"
|
|
30
|
+
|
|
31
|
+
# POSIX ustar version
|
|
32
|
+
USTAR_VERSION = "00"
|
|
33
|
+
|
|
34
|
+
# Maximum file size (8GB - 1 for base-8 12-byte field)
|
|
35
|
+
MAX_FILE_SIZE = (8**12) - 1
|
|
36
|
+
|
|
37
|
+
# Field positions in TAR header
|
|
38
|
+
NAME_OFFSET = 0
|
|
39
|
+
NAME_SIZE = 100
|
|
40
|
+
MODE_OFFSET = 100
|
|
41
|
+
MODE_SIZE = 8
|
|
42
|
+
UID_OFFSET = 108
|
|
43
|
+
UID_SIZE = 8
|
|
44
|
+
GID_OFFSET = 116
|
|
45
|
+
GID_SIZE = 8
|
|
46
|
+
SIZE_OFFSET = 124
|
|
47
|
+
SIZE_SIZE = 12
|
|
48
|
+
MTIME_OFFSET = 136
|
|
49
|
+
MTIME_SIZE = 12
|
|
50
|
+
CHECKSUM_OFFSET = 148
|
|
51
|
+
CHECKSUM_SIZE = 8
|
|
52
|
+
TYPEFLAG_OFFSET = 156
|
|
53
|
+
TYPEFLAG_SIZE = 1
|
|
54
|
+
LINKNAME_OFFSET = 157
|
|
55
|
+
LINKNAME_SIZE = 100
|
|
56
|
+
MAGIC_OFFSET = 257
|
|
57
|
+
MAGIC_SIZE = 6
|
|
58
|
+
VERSION_OFFSET = 263
|
|
59
|
+
VERSION_SIZE = 2
|
|
60
|
+
UNAME_OFFSET = 265
|
|
61
|
+
UNAME_SIZE = 32
|
|
62
|
+
GNAME_OFFSET = 297
|
|
63
|
+
GNAME_SIZE = 32
|
|
64
|
+
DEVMAJOR_OFFSET = 329
|
|
65
|
+
DEVMAJOR_SIZE = 8
|
|
66
|
+
DEVMINOR_OFFSET = 337
|
|
67
|
+
DEVMINOR_SIZE = 8
|
|
68
|
+
PREFIX_OFFSET = 345
|
|
69
|
+
PREFIX_SIZE = 155
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Tar
|
|
6
|
+
# TAR entry model
|
|
7
|
+
#
|
|
8
|
+
# Represents a single entry (file, directory, link) in a TAR archive
|
|
9
|
+
class Entry
|
|
10
|
+
include Omnizip::Entry
|
|
11
|
+
include Omnizip::Formats::Tar::Constants
|
|
12
|
+
|
|
13
|
+
attr_accessor :name, :mode, :uid, :gid, :size, :mtime, :typeflag,
|
|
14
|
+
:linkname, :uname, :gname, :devmajor, :devminor, :prefix
|
|
15
|
+
attr_reader :data
|
|
16
|
+
|
|
17
|
+
def entry_name = name
|
|
18
|
+
def entry_directory? = directory?
|
|
19
|
+
def entry_size = size
|
|
20
|
+
def entry_mtime = mtime
|
|
21
|
+
|
|
22
|
+
# Initialize a new TAR entry
|
|
23
|
+
#
|
|
24
|
+
# @param name [String] Entry name/path
|
|
25
|
+
# @param options [Hash] Entry options
|
|
26
|
+
def initialize(name, options = {})
|
|
27
|
+
@name = name
|
|
28
|
+
@mode = options[:mode] || 0o644
|
|
29
|
+
@uid = options[:uid] || 0
|
|
30
|
+
@gid = options[:gid] || 0
|
|
31
|
+
@size = options[:size] || 0
|
|
32
|
+
@mtime = options[:mtime] || Time.now
|
|
33
|
+
@typeflag = options[:typeflag] || TYPE_REGULAR
|
|
34
|
+
@linkname = options[:linkname] || ""
|
|
35
|
+
@uname = options[:uname] || ""
|
|
36
|
+
@gname = options[:gname] || ""
|
|
37
|
+
@devmajor = options[:devmajor] || 0
|
|
38
|
+
@devminor = options[:devminor] || 0
|
|
39
|
+
@prefix = options[:prefix] || ""
|
|
40
|
+
@data = nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Set entry data
|
|
44
|
+
#
|
|
45
|
+
# @param data [String] Entry data
|
|
46
|
+
def data=(data)
|
|
47
|
+
@data = data
|
|
48
|
+
@size = data.bytesize if data
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Check if entry is a directory
|
|
52
|
+
#
|
|
53
|
+
# @return [Boolean] true if directory
|
|
54
|
+
def directory?
|
|
55
|
+
@typeflag == TYPE_DIRECTORY
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Check if entry is a file
|
|
59
|
+
#
|
|
60
|
+
# @return [Boolean] true if regular file
|
|
61
|
+
def file?
|
|
62
|
+
@typeflag == TYPE_REGULAR || @typeflag.nil? || @typeflag.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Check if entry is a symbolic link
|
|
66
|
+
#
|
|
67
|
+
# @return [Boolean] true if symbolic link
|
|
68
|
+
def symlink?
|
|
69
|
+
@typeflag == TYPE_SYMLINK
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Get full entry name (prefix + name)
|
|
73
|
+
#
|
|
74
|
+
# @return [String] Full entry name
|
|
75
|
+
def full_name
|
|
76
|
+
if @prefix && !@prefix.empty?
|
|
77
|
+
File.join(@prefix, @name)
|
|
78
|
+
else
|
|
79
|
+
@name
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Calculate checksum for TAR header
|
|
84
|
+
#
|
|
85
|
+
# @param header [String] TAR header bytes
|
|
86
|
+
# @return [Integer] Checksum value
|
|
87
|
+
def self.calculate_checksum(header)
|
|
88
|
+
# Replace checksum field with spaces for calculation
|
|
89
|
+
checksum_header = header.dup
|
|
90
|
+
checksum_header[CHECKSUM_OFFSET, CHECKSUM_SIZE] = " " * CHECKSUM_SIZE
|
|
91
|
+
|
|
92
|
+
# Sum all bytes
|
|
93
|
+
checksum_header.bytes.sum
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Tar
|
|
6
|
+
# TAR header parser (POSIX ustar format)
|
|
7
|
+
#
|
|
8
|
+
# Handles reading and writing 512-byte TAR headers
|
|
9
|
+
class Header
|
|
10
|
+
include Omnizip::Formats::Tar::Constants
|
|
11
|
+
|
|
12
|
+
# Parse a TAR header from binary data
|
|
13
|
+
#
|
|
14
|
+
# @param header_data [String] 512 bytes of header data
|
|
15
|
+
# @return [Entry, nil] Parsed entry or nil if end of archive
|
|
16
|
+
def self.parse(header_data)
|
|
17
|
+
return nil if header_data.nil? || header_data.bytesize < HEADER_SIZE
|
|
18
|
+
return nil if all_zeros?(header_data)
|
|
19
|
+
|
|
20
|
+
entry = Entry.new("")
|
|
21
|
+
|
|
22
|
+
# Extract fields from header
|
|
23
|
+
entry.name = extract_string(header_data, NAME_OFFSET, NAME_SIZE)
|
|
24
|
+
entry.mode = extract_octal(header_data, MODE_OFFSET, MODE_SIZE)
|
|
25
|
+
entry.uid = extract_octal(header_data, UID_OFFSET, UID_SIZE)
|
|
26
|
+
entry.gid = extract_octal(header_data, GID_OFFSET, GID_SIZE)
|
|
27
|
+
entry.size = extract_octal(header_data, SIZE_OFFSET, SIZE_SIZE)
|
|
28
|
+
entry.mtime = Time.at(
|
|
29
|
+
extract_octal(header_data, MTIME_OFFSET, MTIME_SIZE),
|
|
30
|
+
)
|
|
31
|
+
entry.typeflag = header_data[TYPEFLAG_OFFSET]
|
|
32
|
+
entry.linkname = extract_string(
|
|
33
|
+
header_data, LINKNAME_OFFSET, LINKNAME_SIZE
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Check for ustar format
|
|
37
|
+
magic = extract_string(header_data, MAGIC_OFFSET, MAGIC_SIZE)
|
|
38
|
+
if magic == USTAR_MAGIC
|
|
39
|
+
entry.uname = extract_string(header_data, UNAME_OFFSET, UNAME_SIZE)
|
|
40
|
+
entry.gname = extract_string(header_data, GNAME_OFFSET, GNAME_SIZE)
|
|
41
|
+
entry.devmajor = extract_octal(
|
|
42
|
+
header_data, DEVMAJOR_OFFSET, DEVMAJOR_SIZE
|
|
43
|
+
)
|
|
44
|
+
entry.devminor = extract_octal(
|
|
45
|
+
header_data, DEVMINOR_OFFSET, DEVMINOR_SIZE
|
|
46
|
+
)
|
|
47
|
+
entry.prefix = extract_string(
|
|
48
|
+
header_data, PREFIX_OFFSET, PREFIX_SIZE
|
|
49
|
+
)
|
|
50
|
+
# ustar stores long paths split across prefix + name;
|
|
51
|
+
# consumers see the joined path
|
|
52
|
+
unless entry.prefix.empty?
|
|
53
|
+
entry.name = "#{entry.prefix}/#{entry.name}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Verify checksum
|
|
58
|
+
checksum = extract_octal(
|
|
59
|
+
header_data, CHECKSUM_OFFSET, CHECKSUM_SIZE
|
|
60
|
+
)
|
|
61
|
+
calculated = Entry.calculate_checksum(header_data)
|
|
62
|
+
unless checksum == calculated
|
|
63
|
+
raise Error, "TAR header checksum mismatch"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
entry
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Build a TAR header from an entry
|
|
70
|
+
#
|
|
71
|
+
# @param entry [Entry] Entry to build header for
|
|
72
|
+
# @return [String] 512 bytes of header data
|
|
73
|
+
def self.build(entry)
|
|
74
|
+
header = "\0" * HEADER_SIZE
|
|
75
|
+
|
|
76
|
+
# Write fields to header
|
|
77
|
+
name, prefix = split_long_name(entry.name, entry.prefix)
|
|
78
|
+
write_string(header, name, NAME_OFFSET, NAME_SIZE)
|
|
79
|
+
write_octal(header, entry.mode, MODE_OFFSET, MODE_SIZE)
|
|
80
|
+
write_octal(header, entry.uid, UID_OFFSET, UID_SIZE)
|
|
81
|
+
write_octal(header, entry.gid, GID_OFFSET, GID_SIZE)
|
|
82
|
+
write_octal(header, entry.size, SIZE_OFFSET, SIZE_SIZE)
|
|
83
|
+
write_octal(
|
|
84
|
+
header, entry.mtime.to_i, MTIME_OFFSET, MTIME_SIZE
|
|
85
|
+
)
|
|
86
|
+
header[TYPEFLAG_OFFSET] = entry.typeflag || TYPE_REGULAR
|
|
87
|
+
write_string(header, entry.linkname, LINKNAME_OFFSET, LINKNAME_SIZE)
|
|
88
|
+
|
|
89
|
+
# Write ustar magic and version
|
|
90
|
+
write_string(header, USTAR_MAGIC, MAGIC_OFFSET, MAGIC_SIZE)
|
|
91
|
+
write_string(header, USTAR_VERSION, VERSION_OFFSET, VERSION_SIZE)
|
|
92
|
+
write_string(header, entry.uname, UNAME_OFFSET, UNAME_SIZE)
|
|
93
|
+
write_string(header, entry.gname, GNAME_OFFSET, GNAME_SIZE)
|
|
94
|
+
write_octal(header, entry.devmajor, DEVMAJOR_OFFSET, DEVMAJOR_SIZE)
|
|
95
|
+
write_octal(header, entry.devminor, DEVMINOR_OFFSET, DEVMINOR_SIZE)
|
|
96
|
+
write_string(header, prefix, PREFIX_OFFSET, PREFIX_SIZE)
|
|
97
|
+
|
|
98
|
+
# Calculate and write checksum
|
|
99
|
+
checksum = Entry.calculate_checksum(header)
|
|
100
|
+
write_octal(header, checksum, CHECKSUM_OFFSET, CHECKSUM_SIZE)
|
|
101
|
+
|
|
102
|
+
header
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Check if header data is all zeros (end of archive marker)
|
|
106
|
+
#
|
|
107
|
+
# @param data [String] Header data
|
|
108
|
+
# @return [Boolean] true if all zeros
|
|
109
|
+
def self.all_zeros?(data)
|
|
110
|
+
data.bytes.all?(&:zero?)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Extract a null-terminated string from header
|
|
114
|
+
#
|
|
115
|
+
# @param header [String] Header data
|
|
116
|
+
# @param offset [Integer] Field offset
|
|
117
|
+
# @param size [Integer] Field size
|
|
118
|
+
# @return [String] Extracted string
|
|
119
|
+
def self.extract_string(header, offset, size)
|
|
120
|
+
field = header[offset, size]
|
|
121
|
+
return "" if field.nil?
|
|
122
|
+
|
|
123
|
+
# Find null terminator
|
|
124
|
+
null_pos = field.index("\0")
|
|
125
|
+
null_pos ? field[0...null_pos] : field
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Extract an octal number from header
|
|
129
|
+
#
|
|
130
|
+
# @param header [String] Header data
|
|
131
|
+
# @param offset [Integer] Field offset
|
|
132
|
+
# @param size [Integer] Field size
|
|
133
|
+
# @return [Integer] Extracted number
|
|
134
|
+
def self.extract_octal(header, offset, size)
|
|
135
|
+
field = extract_string(header, offset, size)
|
|
136
|
+
field.strip.to_i(8)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Split a path for the ustar name (100) + prefix (155)
|
|
140
|
+
# fields. Paths under 100 bytes pass through; longer paths
|
|
141
|
+
# split at a "/" boundary, preferring the longest prefix
|
|
142
|
+
# that keeps both halves in bounds. Raises when no ustar
|
|
143
|
+
# representation exists — silent truncation corrupts
|
|
144
|
+
# archives.
|
|
145
|
+
#
|
|
146
|
+
# @param path [String] Full entry path
|
|
147
|
+
# @param prefix [String] Explicit prefix (wins when given)
|
|
148
|
+
# @return [Array<String>] [name, prefix] pair
|
|
149
|
+
def self.split_long_name(path, prefix = nil)
|
|
150
|
+
path = path.to_s
|
|
151
|
+
prefix = prefix.to_s
|
|
152
|
+
return [path, prefix] if !prefix.empty? || path.bytesize < NAME_SIZE
|
|
153
|
+
|
|
154
|
+
best = nil
|
|
155
|
+
offset = -1
|
|
156
|
+
while (slash = path.index("/", offset + 1))
|
|
157
|
+
candidate_prefix = path[0...slash]
|
|
158
|
+
candidate_name = path[(slash + 1)..]
|
|
159
|
+
offset = slash
|
|
160
|
+
|
|
161
|
+
next if candidate_prefix.bytesize >= PREFIX_SIZE
|
|
162
|
+
next if candidate_name.bytesize >= NAME_SIZE
|
|
163
|
+
|
|
164
|
+
best = [candidate_name, candidate_prefix]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
return best if best
|
|
168
|
+
|
|
169
|
+
raise Omnizip::FormatError,
|
|
170
|
+
"Path too long for the ustar name+prefix fields " \
|
|
171
|
+
"(no PAX/GNU long-name support): #{path}"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Write a string to header
|
|
175
|
+
#
|
|
176
|
+
# @param header [String] Header data
|
|
177
|
+
# @param value [String] Value to write
|
|
178
|
+
# @param offset [Integer] Field offset
|
|
179
|
+
# @param size [Integer] Field size
|
|
180
|
+
def self.write_string(header, value, offset, size)
|
|
181
|
+
value = value.to_s
|
|
182
|
+
# Truncate if too long
|
|
183
|
+
value = value[0, size - 1] if value.bytesize >= size
|
|
184
|
+
header[offset, value.bytesize] = value
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Write an octal number to header
|
|
188
|
+
#
|
|
189
|
+
# @param header [String] Header data
|
|
190
|
+
# @param value [Integer] Value to write
|
|
191
|
+
# @param offset [Integer] Field offset
|
|
192
|
+
# @param size [Integer] Field size
|
|
193
|
+
def self.write_octal(header, value, offset, size)
|
|
194
|
+
# Format as octal with leading zeros
|
|
195
|
+
octal_str = format("%0#{size - 1}o", value.to_i)
|
|
196
|
+
# Truncate if too long
|
|
197
|
+
octal_str = octal_str[(-size + 1)..] if octal_str.bytesize >= size
|
|
198
|
+
header[offset, octal_str.bytesize] = octal_str
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
private_class_method :extract_string, :extract_octal
|
|
202
|
+
private_class_method :write_string, :write_octal, :all_zeros?
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Formats
|
|
7
|
+
module Tar
|
|
8
|
+
# TAR archive reader
|
|
9
|
+
#
|
|
10
|
+
# Reads and extracts TAR archives
|
|
11
|
+
class Reader
|
|
12
|
+
include Omnizip::Formats::Tar::Constants
|
|
13
|
+
|
|
14
|
+
attr_reader :file_path, :entries
|
|
15
|
+
|
|
16
|
+
# Initialize TAR reader
|
|
17
|
+
#
|
|
18
|
+
# @param file_path [String] Path to TAR archive
|
|
19
|
+
def initialize(file_path)
|
|
20
|
+
@file_path = file_path
|
|
21
|
+
@entries = []
|
|
22
|
+
@file = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Read TAR archive and parse all entries
|
|
26
|
+
#
|
|
27
|
+
# @return [self] Returns self for method chaining
|
|
28
|
+
def read
|
|
29
|
+
File.open(@file_path, "rb") do |file|
|
|
30
|
+
@file = file
|
|
31
|
+
parse_entries
|
|
32
|
+
end
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Extract all entries to a directory
|
|
37
|
+
#
|
|
38
|
+
# @param output_dir [String] Output directory path
|
|
39
|
+
def extract_all(output_dir)
|
|
40
|
+
read unless @entries.any?
|
|
41
|
+
|
|
42
|
+
FileUtils.mkdir_p(output_dir)
|
|
43
|
+
|
|
44
|
+
@entries.each do |entry|
|
|
45
|
+
extract_entry(entry, output_dir)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Extract a specific entry
|
|
50
|
+
#
|
|
51
|
+
# @param entry [Entry] Entry to extract
|
|
52
|
+
# @param output_dir [String] Output directory
|
|
53
|
+
def extract_entry(entry, output_dir)
|
|
54
|
+
full_path = File.join(output_dir, entry.full_name)
|
|
55
|
+
|
|
56
|
+
if entry.directory?
|
|
57
|
+
FileUtils.mkdir_p(full_path)
|
|
58
|
+
elsif entry.file?
|
|
59
|
+
FileUtils.mkdir_p(File.dirname(full_path))
|
|
60
|
+
File.binwrite(full_path, entry.data)
|
|
61
|
+
File.chmod(entry.mode, full_path) if entry.mode
|
|
62
|
+
File.utime(entry.mtime, entry.mtime, full_path) if entry.mtime
|
|
63
|
+
elsif entry.symlink?
|
|
64
|
+
FileUtils.mkdir_p(File.dirname(full_path))
|
|
65
|
+
File.symlink(entry.linkname, full_path)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# List all entries
|
|
70
|
+
#
|
|
71
|
+
# @return [Array<Entry>] List of entries
|
|
72
|
+
def list_entries
|
|
73
|
+
read unless @entries.any?
|
|
74
|
+
@entries
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Open TAR archive and yield reader
|
|
78
|
+
#
|
|
79
|
+
# @param file_path [String] Path to TAR archive
|
|
80
|
+
# @yield [Reader] Reader instance
|
|
81
|
+
def self.open(file_path)
|
|
82
|
+
reader = new(file_path)
|
|
83
|
+
reader.read
|
|
84
|
+
yield reader if block_given?
|
|
85
|
+
reader
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
# Parse all entries from TAR archive
|
|
91
|
+
def parse_entries
|
|
92
|
+
@entries = []
|
|
93
|
+
|
|
94
|
+
loop do
|
|
95
|
+
header_data = @file.read(HEADER_SIZE)
|
|
96
|
+
break if header_data.nil? || header_data.bytesize < HEADER_SIZE
|
|
97
|
+
|
|
98
|
+
entry = Header.parse(header_data)
|
|
99
|
+
break if entry.nil?
|
|
100
|
+
|
|
101
|
+
# Read entry data
|
|
102
|
+
if entry.size.positive?
|
|
103
|
+
entry.data = @file.read(entry.size)
|
|
104
|
+
|
|
105
|
+
# Skip to next block boundary
|
|
106
|
+
remainder = entry.size % BLOCK_SIZE
|
|
107
|
+
if remainder.positive?
|
|
108
|
+
padding = BLOCK_SIZE - remainder
|
|
109
|
+
@file.read(padding)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
@entries << entry
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|