omnizip 0.3.1
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 +754 -0
- data/COPYING +502 -0
- data/Gemfile +17 -0
- data/LICENSE +12 -0
- data/README.adoc +1045 -0
- data/Rakefile +12 -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 +91 -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 +271 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +185 -0
- data/docs/getting-started/your-first-archive.adoc +218 -0
- data/docs/guides/advanced-features/encryption.adoc +300 -0
- data/docs/guides/advanced-features/index.adoc +49 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +246 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +320 -0
- data/docs/guides/advanced-features/streaming.adoc +212 -0
- data/docs/guides/archive-formats/gzip-format.adoc +107 -0
- data/docs/guides/archive-formats/index.adoc +130 -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/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 +113 -0
- data/docs/guides/compression-algorithms/deflate.adoc +319 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +398 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +327 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +316 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +361 -0
- data/docs/guides/creating-archives.adoc +354 -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 +218 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +188 -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/troubleshooting/index.adoc +208 -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 +130 -0
- data/lib/omnizip/algorithm_registry.rb +86 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +225 -0
- data/lib/omnizip/algorithms/bzip2/decoder.rb +193 -0
- data/lib/omnizip/algorithms/bzip2/encoder.rb +237 -0
- data/lib/omnizip/algorithms/bzip2/huffman.rb +206 -0
- data/lib/omnizip/algorithms/bzip2/mtf.rb +101 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +151 -0
- data/lib/omnizip/algorithms/bzip2.rb +130 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +38 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +46 -0
- data/lib/omnizip/algorithms/deflate.rb +128 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +153 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +98 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +354 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +142 -0
- data/lib/omnizip/algorithms/deflate64.rb +109 -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 +148 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +69 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +415 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +142 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +260 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +320 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +210 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +341 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +192 -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 +205 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +88 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +130 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +85 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +434 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +325 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +426 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +645 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +227 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +169 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +261 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +331 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +116 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +2055 -0
- data/lib/omnizip/algorithms/lzma.rb +238 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +182 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +41 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +147 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +161 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +127 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +141 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +154 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +126 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +163 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +248 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +116 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +34 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +107 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +138 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +250 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +82 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +138 -0
- data/lib/omnizip/algorithms/sevenzip_lzma2.rb +123 -0
- data/lib/omnizip/algorithms/xz_lzma2.rb +118 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +25 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +46 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +51 -0
- data/lib/omnizip/algorithms/zstandard.rb +138 -0
- data/lib/omnizip/buffer/memory_archive.rb +251 -0
- data/lib/omnizip/buffer/memory_extractor.rb +224 -0
- data/lib/omnizip/buffer.rb +176 -0
- data/lib/omnizip/checksum_registry.rb +114 -0
- data/lib/omnizip/checksums/crc32.rb +100 -0
- data/lib/omnizip/checksums/crc64.rb +101 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/verifier.rb +131 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +120 -0
- data/lib/omnizip/chunked.rb +129 -0
- data/lib/omnizip/cli/output_formatter.rb +104 -0
- data/lib/omnizip/cli.rb +572 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +427 -0
- data/lib/omnizip/commands/archive_extract_command.rb +272 -0
- data/lib/omnizip/commands/archive_list_command.rb +218 -0
- data/lib/omnizip/commands/archive_repair_command.rb +131 -0
- data/lib/omnizip/commands/archive_verify_command.rb +117 -0
- data/lib/omnizip/commands/compress_command.rb +117 -0
- data/lib/omnizip/commands/decompress_command.rb +120 -0
- data/lib/omnizip/commands/list_command.rb +53 -0
- data/lib/omnizip/commands/metadata_command.rb +153 -0
- data/lib/omnizip/commands/parity_create_command.rb +122 -0
- data/lib/omnizip/commands/parity_repair_command.rb +122 -0
- data/lib/omnizip/commands/parity_verify_command.rb +124 -0
- data/lib/omnizip/commands/profile_list_command.rb +56 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/convenience.rb +359 -0
- data/lib/omnizip/converter/conversion_registry.rb +49 -0
- data/lib/omnizip/converter/conversion_strategy.rb +121 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +97 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +112 -0
- data/lib/omnizip/converter.rb +105 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +100 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +101 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/error.rb +106 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +98 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +99 -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 +63 -0
- data/lib/omnizip/extraction/filter_chain.rb +177 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +70 -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 +240 -0
- data/lib/omnizip/extraction.rb +111 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +113 -0
- data/lib/omnizip/filter.rb +139 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +166 -0
- data/lib/omnizip/filters/bcj.rb +279 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +200 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +61 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +93 -0
- data/lib/omnizip/filters/bcj2.rb +99 -0
- data/lib/omnizip/filters/bcj_arm.rb +176 -0
- data/lib/omnizip/filters/bcj_arm64.rb +244 -0
- data/lib/omnizip/filters/bcj_ia64.rb +196 -0
- data/lib/omnizip/filters/bcj_ppc.rb +190 -0
- data/lib/omnizip/filters/bcj_sparc.rb +176 -0
- data/lib/omnizip/filters/bcj_x86.rb +193 -0
- data/lib/omnizip/filters/delta.rb +196 -0
- data/lib/omnizip/filters/filter_base.rb +72 -0
- data/lib/omnizip/filters/registry.rb +123 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/format_detector.rb +162 -0
- data/lib/omnizip/format_registry.rb +59 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +172 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +385 -0
- data/lib/omnizip/formats/cpio/reader.rb +196 -0
- data/lib/omnizip/formats/cpio/writer.rb +234 -0
- data/lib/omnizip/formats/cpio.rb +140 -0
- data/lib/omnizip/formats/format_spec_loader.rb +230 -0
- data/lib/omnizip/formats/gzip.rb +238 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +297 -0
- data/lib/omnizip/formats/iso/directory_record.rb +152 -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 +197 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +320 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +530 -0
- data/lib/omnizip/formats/iso.rb +140 -0
- data/lib/omnizip/formats/lzip.rb +175 -0
- data/lib/omnizip/formats/lzma_alone.rb +171 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +243 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +195 -0
- data/lib/omnizip/formats/rar/block_parser.rb +243 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +217 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +216 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +158 -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/ppmd/context.rb +105 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +219 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +262 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +82 -0
- data/lib/omnizip/formats/rar/decompressor.rb +238 -0
- data/lib/omnizip/formats/rar/external_writer.rb +312 -0
- data/lib/omnizip/formats/rar/header.rb +192 -0
- data/lib/omnizip/formats/rar/license_validator.rb +109 -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/parity_handler.rb +292 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +202 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +578 -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 +97 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +166 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +187 -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 +264 -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 +194 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +109 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +142 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +65 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +466 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +241 -0
- data/lib/omnizip/formats/rar/reader.rb +366 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +168 -0
- data/lib/omnizip/formats/rar/writer.rb +431 -0
- data/lib/omnizip/formats/rar.rb +205 -0
- data/lib/omnizip/formats/rar3/compressor.rb +73 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +66 -0
- data/lib/omnizip/formats/rar3/reader.rb +386 -0
- data/lib/omnizip/formats/rar3/writer.rb +219 -0
- data/lib/omnizip/formats/rar5/compressor.rb +73 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +66 -0
- data/lib/omnizip/formats/rar5/reader.rb +342 -0
- data/lib/omnizip/formats/rar5/writer.rb +214 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +150 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +114 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +142 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +144 -0
- data/lib/omnizip/formats/seven_zip/header.rb +106 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +134 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +466 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +58 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +69 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +660 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +458 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +632 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +315 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +162 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +740 -0
- data/lib/omnizip/formats/seven_zip.rb +93 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +94 -0
- data/lib/omnizip/formats/tar/header.rb +168 -0
- data/lib/omnizip/formats/tar/reader.rb +121 -0
- data/lib/omnizip/formats/tar/writer.rb +216 -0
- data/lib/omnizip/formats/tar.rb +84 -0
- data/lib/omnizip/formats/xz/reader.rb +116 -0
- data/lib/omnizip/formats/xz.rb +237 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +754 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +306 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +186 -0
- data/lib/omnizip/formats/xz_impl/constants.rb +49 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +122 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +468 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +99 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +81 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +117 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +55 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +108 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl/writer.rb +421 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +195 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +133 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +138 -0
- data/lib/omnizip/formats/zip/reader.rb +250 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +375 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +104 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +66 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +114 -0
- data/lib/omnizip/formats/zip.rb +50 -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/seven_zip/lzma/decoder.rb +421 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +465 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +288 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +200 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +141 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +519 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +723 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +750 -0
- data/lib/omnizip/io/buffered_input.rb +146 -0
- data/lib/omnizip/io/buffered_output.rb +105 -0
- data/lib/omnizip/io/stream_manager.rb +115 -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 +124 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +146 -0
- data/lib/omnizip/metadata/metadata_editor.rb +171 -0
- data/lib/omnizip/metadata/metadata_registry.rb +64 -0
- data/lib/omnizip/metadata/metadata_validator.rb +99 -0
- data/lib/omnizip/metadata.rb +57 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +73 -0
- data/lib/omnizip/models/compression_options.rb +71 -0
- data/lib/omnizip/models/conversion_options.rb +87 -0
- data/lib/omnizip/models/conversion_result.rb +135 -0
- data/lib/omnizip/models/eta_result.rb +46 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +144 -0
- data/lib/omnizip/models/filter_config.rb +183 -0
- data/lib/omnizip/models/match_result.rb +124 -0
- data/lib/omnizip/models/optimization_suggestion.rb +91 -0
- data/lib/omnizip/models/parallel_options.rb +104 -0
- data/lib/omnizip/models/performance_result.rb +79 -0
- data/lib/omnizip/models/profile_report.rb +82 -0
- data/lib/omnizip/models/progress_options.rb +38 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +81 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +203 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +347 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +329 -0
- data/lib/omnizip/parallel/worker_pool.rb +223 -0
- data/lib/omnizip/parallel.rb +149 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +196 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +73 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +133 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +123 -0
- data/lib/omnizip/parity/models/main_packet.rb +128 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +109 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +78 -0
- data/lib/omnizip/parity/par2_creator.rb +531 -0
- data/lib/omnizip/parity/par2_repairer.rb +407 -0
- data/lib/omnizip/parity/par2_verifier.rb +364 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +110 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +266 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +111 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +342 -0
- data/lib/omnizip/parity.rb +186 -0
- data/lib/omnizip/password/encryption_registry.rb +65 -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 +192 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +141 -0
- data/lib/omnizip/password.rb +87 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +174 -0
- data/lib/omnizip/pipe.rb +121 -0
- data/lib/omnizip/platform/ntfs_streams.rb +201 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +39 -0
- data/lib/omnizip/profile/balanced_profile.rb +33 -0
- data/lib/omnizip/profile/binary_profile.rb +36 -0
- data/lib/omnizip/profile/compression_profile.rb +158 -0
- data/lib/omnizip/profile/custom_profile.rb +157 -0
- data/lib/omnizip/profile/fast_profile.rb +33 -0
- data/lib/omnizip/profile/maximum_profile.rb +33 -0
- data/lib/omnizip/profile/profile_detector.rb +110 -0
- data/lib/omnizip/profile/profile_registry.rb +161 -0
- data/lib/omnizip/profile/text_profile.rb +36 -0
- data/lib/omnizip/profile.rb +190 -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 +169 -0
- data/lib/omnizip/profiler.rb +204 -0
- data/lib/omnizip/progress/callback_reporter.rb +36 -0
- data/lib/omnizip/progress/console_reporter.rb +62 -0
- data/lib/omnizip/progress/log_reporter.rb +91 -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 +190 -0
- data/lib/omnizip/progress/silent_reporter.rb +24 -0
- data/lib/omnizip/progress.rb +127 -0
- data/lib/omnizip/rubyzip_compat.rb +63 -0
- data/lib/omnizip/temp/safe_extract.rb +168 -0
- data/lib/omnizip/temp/temp_file.rb +124 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +181 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +156 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +273 -0
- data/lib/omnizip/zip/output_stream.rb +324 -0
- data/lib/omnizip.rb +156 -0
- data/readme-docs/advanced-features.adoc +515 -0
- data/readme-docs/api-usage.adoc +444 -0
- data/readme-docs/architecture.adoc +449 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +442 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +325 -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/xz-file-format-1.2.1.txt +1174 -0
- metadata +617 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "constants"
|
|
4
|
+
require_relative "header"
|
|
5
|
+
require_relative "entry"
|
|
6
|
+
|
|
7
|
+
module Omnizip
|
|
8
|
+
module Formats
|
|
9
|
+
module Tar
|
|
10
|
+
# TAR archive writer
|
|
11
|
+
#
|
|
12
|
+
# Creates TAR archives
|
|
13
|
+
class Writer
|
|
14
|
+
include Constants
|
|
15
|
+
|
|
16
|
+
attr_reader :file_path
|
|
17
|
+
|
|
18
|
+
# Initialize TAR writer
|
|
19
|
+
#
|
|
20
|
+
# @param file_path [String] Path to output TAR archive
|
|
21
|
+
def initialize(file_path)
|
|
22
|
+
@file_path = file_path
|
|
23
|
+
@file = nil
|
|
24
|
+
@closed = false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Add a file to the TAR archive
|
|
28
|
+
#
|
|
29
|
+
# @param entry_name [String] Name/path in archive
|
|
30
|
+
# @param source_path [String] Source file path
|
|
31
|
+
# @param options [Hash] Entry options
|
|
32
|
+
def add(entry_name, source_path = nil, options = {})
|
|
33
|
+
source_path ||= entry_name
|
|
34
|
+
|
|
35
|
+
unless File.exist?(source_path)
|
|
36
|
+
raise ArgumentError, "File not found: #{source_path}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
open_file unless @file
|
|
40
|
+
|
|
41
|
+
if File.directory?(source_path)
|
|
42
|
+
add_directory(entry_name, source_path, options)
|
|
43
|
+
elsif File.symlink?(source_path)
|
|
44
|
+
add_symlink(entry_name, source_path, options)
|
|
45
|
+
else
|
|
46
|
+
add_file(entry_name, source_path, options)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Add a file entry
|
|
51
|
+
#
|
|
52
|
+
# @param entry_name [String] Name in archive
|
|
53
|
+
# @param source_path [String] Source file path
|
|
54
|
+
# @param options [Hash] Entry options
|
|
55
|
+
def add_file(entry_name, source_path, options = {})
|
|
56
|
+
open_file unless @file
|
|
57
|
+
|
|
58
|
+
stat = File.stat(source_path)
|
|
59
|
+
data = File.binread(source_path)
|
|
60
|
+
|
|
61
|
+
entry = Entry.new(entry_name, {
|
|
62
|
+
mode: options[:mode] || (stat.mode & 0o777),
|
|
63
|
+
uid: options[:uid] || stat.uid,
|
|
64
|
+
gid: options[:gid] || stat.gid,
|
|
65
|
+
size: data.bytesize,
|
|
66
|
+
mtime: options[:mtime] || stat.mtime,
|
|
67
|
+
typeflag: TYPE_REGULAR,
|
|
68
|
+
uname: options[:uname] || "",
|
|
69
|
+
gname: options[:gname] || "",
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
write_entry(entry, data)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Add a directory entry
|
|
76
|
+
#
|
|
77
|
+
# @param entry_name [String] Directory name in archive
|
|
78
|
+
# @param source_path [String] Source directory path (optional)
|
|
79
|
+
# @param options [Hash] Entry options
|
|
80
|
+
def add_directory(entry_name, source_path = nil, options = {})
|
|
81
|
+
open_file unless @file
|
|
82
|
+
|
|
83
|
+
# Ensure directory name ends with /
|
|
84
|
+
entry_name = "#{entry_name}/" unless entry_name.end_with?("/")
|
|
85
|
+
|
|
86
|
+
if source_path && File.exist?(source_path)
|
|
87
|
+
stat = File.stat(source_path)
|
|
88
|
+
mode = stat.mode & 0o777
|
|
89
|
+
uid = stat.uid
|
|
90
|
+
gid = stat.gid
|
|
91
|
+
mtime = stat.mtime
|
|
92
|
+
else
|
|
93
|
+
mode = 0o755
|
|
94
|
+
uid = 0
|
|
95
|
+
gid = 0
|
|
96
|
+
mtime = Time.now
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
entry = Entry.new(entry_name, {
|
|
100
|
+
mode: options[:mode] || mode,
|
|
101
|
+
uid: options[:uid] || uid,
|
|
102
|
+
gid: options[:gid] || gid,
|
|
103
|
+
size: 0,
|
|
104
|
+
mtime: options[:mtime] || mtime,
|
|
105
|
+
typeflag: TYPE_DIRECTORY,
|
|
106
|
+
uname: options[:uname] || "",
|
|
107
|
+
gname: options[:gname] || "",
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
write_entry(entry, nil)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Add a symbolic link entry
|
|
114
|
+
#
|
|
115
|
+
# @param entry_name [String] Link name in archive
|
|
116
|
+
# @param source_path [String] Source symlink path
|
|
117
|
+
# @param options [Hash] Entry options
|
|
118
|
+
def add_symlink(entry_name, source_path, options = {})
|
|
119
|
+
open_file unless @file
|
|
120
|
+
|
|
121
|
+
linkname = File.readlink(source_path)
|
|
122
|
+
stat = File.lstat(source_path)
|
|
123
|
+
|
|
124
|
+
entry = Entry.new(entry_name, {
|
|
125
|
+
mode: options[:mode] || 0o777,
|
|
126
|
+
uid: options[:uid] || stat.uid,
|
|
127
|
+
gid: options[:gid] || stat.gid,
|
|
128
|
+
size: 0,
|
|
129
|
+
mtime: options[:mtime] || stat.mtime,
|
|
130
|
+
typeflag: TYPE_SYMLINK,
|
|
131
|
+
linkname: linkname,
|
|
132
|
+
uname: options[:uname] || "",
|
|
133
|
+
gname: options[:gname] || "",
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
write_entry(entry, nil)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Add raw entry data
|
|
140
|
+
#
|
|
141
|
+
# @param entry_name [String] Entry name
|
|
142
|
+
# @param data [String] Entry data
|
|
143
|
+
# @param options [Hash] Entry options
|
|
144
|
+
def add_data(entry_name, data, options = {})
|
|
145
|
+
open_file unless @file
|
|
146
|
+
|
|
147
|
+
entry = Entry.new(entry_name, {
|
|
148
|
+
mode: options[:mode] || 0o644,
|
|
149
|
+
uid: options[:uid] || 0,
|
|
150
|
+
gid: options[:gid] || 0,
|
|
151
|
+
size: data.bytesize,
|
|
152
|
+
mtime: options[:mtime] || Time.now,
|
|
153
|
+
typeflag: TYPE_REGULAR,
|
|
154
|
+
uname: options[:uname] || "",
|
|
155
|
+
gname: options[:gname] || "",
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
write_entry(entry, data)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Close the TAR archive
|
|
162
|
+
def close
|
|
163
|
+
return if @closed
|
|
164
|
+
|
|
165
|
+
if @file
|
|
166
|
+
# Write two zero blocks to mark end of archive
|
|
167
|
+
@file.write("\0" * BLOCK_SIZE * 2)
|
|
168
|
+
@file.close
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
@closed = true
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Create TAR archive with block syntax
|
|
175
|
+
#
|
|
176
|
+
# @param file_path [String] Path to output TAR archive
|
|
177
|
+
# @yield [Writer] Writer instance
|
|
178
|
+
def self.create(file_path)
|
|
179
|
+
writer = new(file_path)
|
|
180
|
+
yield writer if block_given?
|
|
181
|
+
writer.close
|
|
182
|
+
writer
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
private
|
|
186
|
+
|
|
187
|
+
# Open output file
|
|
188
|
+
def open_file
|
|
189
|
+
@file = File.open(@file_path, "wb")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Write an entry to the archive
|
|
193
|
+
#
|
|
194
|
+
# @param entry [Entry] Entry to write
|
|
195
|
+
# @param data [String, nil] Entry data
|
|
196
|
+
def write_entry(entry, data)
|
|
197
|
+
# Write header
|
|
198
|
+
header = Header.build(entry)
|
|
199
|
+
@file.write(header)
|
|
200
|
+
|
|
201
|
+
# Write data if present
|
|
202
|
+
if data && !data.empty?
|
|
203
|
+
@file.write(data)
|
|
204
|
+
|
|
205
|
+
# Pad to block boundary
|
|
206
|
+
remainder = data.bytesize % BLOCK_SIZE
|
|
207
|
+
if remainder.positive?
|
|
208
|
+
padding = BLOCK_SIZE - remainder
|
|
209
|
+
@file.write("\0" * padding)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tar/constants"
|
|
4
|
+
require_relative "tar/entry"
|
|
5
|
+
require_relative "tar/header"
|
|
6
|
+
require_relative "tar/reader"
|
|
7
|
+
require_relative "tar/writer"
|
|
8
|
+
|
|
9
|
+
module Omnizip
|
|
10
|
+
module Formats
|
|
11
|
+
# TAR archive format implementation
|
|
12
|
+
#
|
|
13
|
+
# TAR (Tape Archive) is a simple archive format that bundles files
|
|
14
|
+
# without compression. It's commonly used in combination with
|
|
15
|
+
# compression formats like GZIP (.tar.gz) or BZIP2 (.tar.bz2).
|
|
16
|
+
#
|
|
17
|
+
# This implementation supports POSIX ustar format with:
|
|
18
|
+
# - Regular files
|
|
19
|
+
# - Directories
|
|
20
|
+
# - Symbolic links
|
|
21
|
+
# - Hard links
|
|
22
|
+
# - Metadata preservation (permissions, timestamps, ownership)
|
|
23
|
+
module Tar
|
|
24
|
+
class << self
|
|
25
|
+
# Read a TAR archive
|
|
26
|
+
#
|
|
27
|
+
# @param file_path [String] Path to TAR archive
|
|
28
|
+
# @return [Reader] TAR reader instance
|
|
29
|
+
def read(file_path)
|
|
30
|
+
Reader.new(file_path).read
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Open a TAR archive with block syntax
|
|
34
|
+
#
|
|
35
|
+
# @param file_path [String] Path to TAR archive
|
|
36
|
+
# @yield [Reader] TAR reader instance
|
|
37
|
+
# @return [Reader] TAR reader instance
|
|
38
|
+
# rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
|
|
39
|
+
def open(file_path, &block)
|
|
40
|
+
Reader.open(file_path, &block)
|
|
41
|
+
end
|
|
42
|
+
# rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
|
|
43
|
+
|
|
44
|
+
# Create a TAR archive
|
|
45
|
+
#
|
|
46
|
+
# @param file_path [String] Path to output TAR archive
|
|
47
|
+
# @yield [Writer] TAR writer instance
|
|
48
|
+
# @return [Writer] TAR writer instance
|
|
49
|
+
# rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
|
|
50
|
+
def create(file_path, &block)
|
|
51
|
+
Writer.create(file_path, &block)
|
|
52
|
+
end
|
|
53
|
+
# rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
|
|
54
|
+
|
|
55
|
+
# Extract a TAR archive
|
|
56
|
+
#
|
|
57
|
+
# @param file_path [String] Path to TAR archive
|
|
58
|
+
# @param output_dir [String] Output directory
|
|
59
|
+
def extract(file_path, output_dir)
|
|
60
|
+
reader = read(file_path)
|
|
61
|
+
reader.extract_all(output_dir)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# List entries in a TAR archive
|
|
65
|
+
#
|
|
66
|
+
# @param file_path [String] Path to TAR archive
|
|
67
|
+
# @return [Array<Entry>] List of entries
|
|
68
|
+
def list(file_path)
|
|
69
|
+
reader = read(file_path)
|
|
70
|
+
reader.list_entries
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Register TAR format when loaded
|
|
74
|
+
def register!
|
|
75
|
+
require_relative "../format_registry"
|
|
76
|
+
FormatRegistry.register(".tar", Omnizip::Formats::Tar)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Auto-register on load
|
|
84
|
+
Omnizip::Formats::Tar.register!
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025 Ribose Inc.
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
6
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
7
|
+
# to deal in the Software without restriction, including without limitation
|
|
8
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
9
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
10
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
|
+
# DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
require "stringio"
|
|
24
|
+
require_relative "../xz_impl/stream_decoder"
|
|
25
|
+
|
|
26
|
+
module Omnizip
|
|
27
|
+
module Formats
|
|
28
|
+
class Xz
|
|
29
|
+
# XZ format reader
|
|
30
|
+
#
|
|
31
|
+
# Reads and decompresses .xz files compatible with XZ Utils.
|
|
32
|
+
# Provides both low-level stream API and high-level convenience methods.
|
|
33
|
+
class Reader
|
|
34
|
+
# Initialize reader
|
|
35
|
+
#
|
|
36
|
+
# @param input [String, IO] File path or IO object
|
|
37
|
+
def initialize(input)
|
|
38
|
+
@input = if input.is_a?(String)
|
|
39
|
+
File.open(input, "rb")
|
|
40
|
+
elsif input.respond_to?(:read)
|
|
41
|
+
input
|
|
42
|
+
else
|
|
43
|
+
raise ArgumentError,
|
|
44
|
+
"Input must be a file path or IO object"
|
|
45
|
+
end
|
|
46
|
+
@close_on_finish = input.is_a?(String)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Read and decompress XZ data
|
|
50
|
+
#
|
|
51
|
+
# @return [String] Decompressed data
|
|
52
|
+
def read
|
|
53
|
+
XzFormat::StreamDecoder.decode(@input)
|
|
54
|
+
ensure
|
|
55
|
+
close if @close_on_finish
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Close the input stream if we opened it
|
|
59
|
+
def close
|
|
60
|
+
@input.close if @input.respond_to?(:close) && !@input.closed?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Check if reader is open
|
|
64
|
+
#
|
|
65
|
+
# @return [Boolean] True if input is open
|
|
66
|
+
def closed?
|
|
67
|
+
@input.respond_to?(:closed?) ? @input.closed? : false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Read in a streaming fashion (for large files)
|
|
71
|
+
#
|
|
72
|
+
# @yield [String] Chunks of decompressed data
|
|
73
|
+
# @return [String] Full decompressed data
|
|
74
|
+
def each_chunk(chunk_size = 64 * 1024)
|
|
75
|
+
# For now, just read everything and yield chunks
|
|
76
|
+
# TODO: Implement true streaming for memory efficiency
|
|
77
|
+
data = read
|
|
78
|
+
offset = 0
|
|
79
|
+
while offset < data.bytesize
|
|
80
|
+
chunk = data.byteslice(offset, chunk_size)
|
|
81
|
+
yield chunk
|
|
82
|
+
offset += chunk.bytesize
|
|
83
|
+
end
|
|
84
|
+
data
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Entry class for extract API compatibility
|
|
89
|
+
# XZ format is a single stream, so this is a simple wrapper
|
|
90
|
+
class Entry
|
|
91
|
+
attr_reader :data
|
|
92
|
+
|
|
93
|
+
def initialize(data)
|
|
94
|
+
@data = data
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Read the decompressed data
|
|
98
|
+
#
|
|
99
|
+
# @return [String] Decompressed data
|
|
100
|
+
def read
|
|
101
|
+
@data
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Get data size
|
|
105
|
+
#
|
|
106
|
+
# @return [Integer] Size in bytes
|
|
107
|
+
def size
|
|
108
|
+
@data.bytesize
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Alias for compatibility
|
|
112
|
+
alias_method :bytesize, :size
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "xz_impl/constants"
|
|
4
|
+
require_relative "xz_impl/stream_encoder"
|
|
5
|
+
require_relative "xz_impl/writer"
|
|
6
|
+
require_relative "xz/reader"
|
|
7
|
+
require_relative "../algorithms/lzma"
|
|
8
|
+
|
|
9
|
+
module Omnizip
|
|
10
|
+
module Formats
|
|
11
|
+
# XZ compression format
|
|
12
|
+
# Creates .xz files compatible with XZ Utils
|
|
13
|
+
class Xz
|
|
14
|
+
class << self
|
|
15
|
+
# Create a .xz file from input data
|
|
16
|
+
# @param input [String, IO] Input data to compress
|
|
17
|
+
# @param output [String, IO] Output file path or IO object
|
|
18
|
+
# @param options [Hash] Compression options
|
|
19
|
+
# @option options [Integer] :dict_size Dictionary size (default: 8MB to match XZ Utils preset 6)
|
|
20
|
+
# @option options [Integer] :check Check type (default: CRC64)
|
|
21
|
+
def create(input, output = nil, options = {})
|
|
22
|
+
encoder = XzFormat::StreamEncoder.new(
|
|
23
|
+
check_type: options[:check] || XzConst::CHECK_CRC64,
|
|
24
|
+
dict_size: options[:dict_size] || (64 * 1024 * 1024),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
compressed = encoder.encode(input)
|
|
28
|
+
|
|
29
|
+
if output
|
|
30
|
+
if output.respond_to?(:write)
|
|
31
|
+
output.write(compressed)
|
|
32
|
+
else
|
|
33
|
+
File.binwrite(output, compressed)
|
|
34
|
+
end
|
|
35
|
+
else
|
|
36
|
+
compressed
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Convenience method with block syntax
|
|
41
|
+
# @example
|
|
42
|
+
# Xz.create_file('output.xz') do |xz|
|
|
43
|
+
# xz.add_data('Hello, XZ!')
|
|
44
|
+
# end
|
|
45
|
+
def create_file(path, options = {})
|
|
46
|
+
builder = Builder.new(options)
|
|
47
|
+
yield builder if block_given?
|
|
48
|
+
|
|
49
|
+
compressed = create(builder.data, nil, options)
|
|
50
|
+
File.binwrite(path, compressed)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Decode XZ data (alias for decompress with no output)
|
|
54
|
+
# @param input [String, IO] Input XZ data or file path
|
|
55
|
+
# @return [String] Decompressed data
|
|
56
|
+
def decode(input)
|
|
57
|
+
decompress(input)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Decompress XZ, LZIP (.lz), or LZMA_Alone (.lzma) data
|
|
61
|
+
#
|
|
62
|
+
# This method automatically detects the format based on magic bytes and
|
|
63
|
+
# routes to the appropriate decoder:
|
|
64
|
+
# - XZ format (.xz): Container format with stream header/footer/index
|
|
65
|
+
# - LZIP format (.lz): Standalone format with "LZIP" magic and CRC32 footer
|
|
66
|
+
# - LZMA_Alone format (.lzma): Legacy standalone format with properties byte
|
|
67
|
+
#
|
|
68
|
+
# @param input [String, IO] Input data or file path
|
|
69
|
+
# @param output [String, IO, nil] Output file path or IO object
|
|
70
|
+
# @param options [Hash] Options (reserved for future use)
|
|
71
|
+
# @return [String, nil] Decompressed data (if output is nil)
|
|
72
|
+
def decompress(input, output = nil, _options = {})
|
|
73
|
+
# Handle raw data string vs file path
|
|
74
|
+
data = if input.respond_to?(:read)
|
|
75
|
+
# Already an IO object - read content
|
|
76
|
+
if input.respond_to?(:size)
|
|
77
|
+
# Seekable IO (File, etc.) - read without consuming
|
|
78
|
+
original_pos = input.pos
|
|
79
|
+
content = input.read
|
|
80
|
+
input.seek(original_pos)
|
|
81
|
+
else
|
|
82
|
+
# Non-seekable IO - read and consume
|
|
83
|
+
content = input.read
|
|
84
|
+
end
|
|
85
|
+
content
|
|
86
|
+
elsif input.is_a?(String)
|
|
87
|
+
# Could be file path or raw data
|
|
88
|
+
# If string contains null byte, it's definitely data (not a path)
|
|
89
|
+
# Also check if it's a valid file path first
|
|
90
|
+
if !input.include?("\0") && File.exist?(input)
|
|
91
|
+
File.binread(input)
|
|
92
|
+
else
|
|
93
|
+
input.b
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
raise ArgumentError,
|
|
97
|
+
"Input must be a String or IO object"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Detect format and decode
|
|
101
|
+
decompressed = decode_lzma_data(data)
|
|
102
|
+
|
|
103
|
+
if output
|
|
104
|
+
if output.respond_to?(:write)
|
|
105
|
+
output.write(decompressed)
|
|
106
|
+
else
|
|
107
|
+
File.binwrite(output, decompressed)
|
|
108
|
+
end
|
|
109
|
+
nil
|
|
110
|
+
else
|
|
111
|
+
decompressed
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
# Decode LZMA-based data by detecting format
|
|
118
|
+
# @param data [String] Input data
|
|
119
|
+
# @return [String] Decompressed data
|
|
120
|
+
def decode_lzma_data(data)
|
|
121
|
+
format = detect_lzma_format(data)
|
|
122
|
+
|
|
123
|
+
case format
|
|
124
|
+
when :lz
|
|
125
|
+
decode_lzip(data)
|
|
126
|
+
when :lzma_alone
|
|
127
|
+
decode_lzma_alone(data)
|
|
128
|
+
when :xz
|
|
129
|
+
decode_xz_stream(data)
|
|
130
|
+
else
|
|
131
|
+
raise FormatError, "Unknown LZMA format: cannot detect valid format"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Detect LZMA format from magic bytes
|
|
136
|
+
# @param data [String] Input data
|
|
137
|
+
# @return [Symbol] Format type (:xz, :lz, :lzma_alone)
|
|
138
|
+
def detect_lzma_format(data)
|
|
139
|
+
return :unknown if data.nil? || data.bytesize < 4
|
|
140
|
+
|
|
141
|
+
first_bytes = data.byteslice(0, 6).bytes.to_a
|
|
142
|
+
|
|
143
|
+
# Check XZ magic: FD 37 7A 58 5A 00
|
|
144
|
+
# Reference: xz-file-format-1.2.1.txt Section 2.1.1.1
|
|
145
|
+
if first_bytes[0] == 0xFD && first_bytes[1] == 0x37 &&
|
|
146
|
+
first_bytes[2] == 0x7A && first_bytes[3] == 0x58 &&
|
|
147
|
+
first_bytes[4] == 0x5A && first_bytes[5].zero?
|
|
148
|
+
return :xz
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Check LZIP magic: 4C 5A 49 50 ("LZIP")
|
|
152
|
+
# Reference: /Users/mulgogi/src/external/xz/src/liblzma/common/lzip_decoder.c:106
|
|
153
|
+
if first_bytes[0] == 0x4C && first_bytes[1] == 0x5A &&
|
|
154
|
+
first_bytes[2] == 0x49 && first_bytes[3] == 0x50
|
|
155
|
+
return :lz
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Default to LZMA_Alone (legacy format, no magic bytes)
|
|
159
|
+
# The format starts with properties byte, dictionary size, and uncompressed size
|
|
160
|
+
# Reference: /Users/mulgogi/src/external/xz/src/liblzma/common/alone_decoder.c
|
|
161
|
+
:lzma_alone
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Decode LZIP format (.lz files)
|
|
165
|
+
# @param data [String] Input data
|
|
166
|
+
# @return [String] Decompressed data
|
|
167
|
+
def decode_lzip(data)
|
|
168
|
+
input = StringIO.new(data)
|
|
169
|
+
decoder = Omnizip::Algorithms::LZMA::LzipDecoder.new(input)
|
|
170
|
+
decoder.decode_stream
|
|
171
|
+
rescue StandardError => e
|
|
172
|
+
raise FormatError, "Failed to decode LZIP format: #{e.message}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Decode LZMA_Alone format (.lzma files)
|
|
176
|
+
# @param data [String] Input data
|
|
177
|
+
# @return [String] Decompressed data
|
|
178
|
+
def decode_lzma_alone(data)
|
|
179
|
+
input = StringIO.new(data)
|
|
180
|
+
decoder = Omnizip::Algorithms::LZMA::LzmaAloneDecoder.new(input)
|
|
181
|
+
decoder.decode_stream
|
|
182
|
+
rescue StandardError => e
|
|
183
|
+
raise FormatError, "Failed to decode LZMA_Alone format: #{e.message}"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Decode XZ format stream
|
|
187
|
+
# @param data [String] Input data
|
|
188
|
+
# @return [String] Decompressed data
|
|
189
|
+
def decode_xz_stream(data)
|
|
190
|
+
input_io = StringIO.new(data.b)
|
|
191
|
+
reader = Reader.new(input_io)
|
|
192
|
+
reader.read
|
|
193
|
+
rescue StandardError => e
|
|
194
|
+
raise FormatError, "Failed to decode XZ format: #{e.message}"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Alias for compatibility
|
|
198
|
+
alias decode decompress
|
|
199
|
+
alias extract decompress
|
|
200
|
+
|
|
201
|
+
# Entry method for archive-like interface
|
|
202
|
+
# @param input [String, IO] Input XZ data or file path
|
|
203
|
+
# @param options [Hash] Options (reserved)
|
|
204
|
+
# @yield [Entry] Yields entry (XZ has single data stream)
|
|
205
|
+
# @return [String, Entry] Decompressed data or Entry if no block given
|
|
206
|
+
def extract_entry(input, options = {})
|
|
207
|
+
data = decompress(input, nil, options)
|
|
208
|
+
|
|
209
|
+
entry = Entry.new(data)
|
|
210
|
+
if block_given?
|
|
211
|
+
yield entry
|
|
212
|
+
else
|
|
213
|
+
entry
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Builder class for convenient file creation
|
|
219
|
+
class Builder
|
|
220
|
+
attr_reader :data
|
|
221
|
+
|
|
222
|
+
def initialize(_options = {})
|
|
223
|
+
@data = String.new(encoding: Encoding::BINARY)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def add_data(content)
|
|
227
|
+
@data << content.to_s.dup.force_encoding(Encoding::BINARY)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def add_file(path)
|
|
231
|
+
content = File.binread(path)
|
|
232
|
+
add_data(content)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|