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,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2025 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
require_relative "operation_progress"
|
|
8
|
+
require_relative "../eta"
|
|
9
|
+
|
|
10
|
+
module Omnizip
|
|
11
|
+
module Progress
|
|
12
|
+
# Central progress tracking coordinator.
|
|
13
|
+
#
|
|
14
|
+
# This class tracks operation progress, calculates rates and ETA,
|
|
15
|
+
# and reports progress to configured reporters. It integrates the
|
|
16
|
+
# OperationProgress model with ETA calculation.
|
|
17
|
+
class ProgressTracker
|
|
18
|
+
attr_reader :operation_progress, :eta_estimator, :reporters,
|
|
19
|
+
:update_interval, :last_report_time
|
|
20
|
+
|
|
21
|
+
# Initialize a new progress tracker
|
|
22
|
+
#
|
|
23
|
+
# @param total_files [Integer] Total number of files to process
|
|
24
|
+
# @param total_bytes [Integer] Total bytes to process
|
|
25
|
+
# @param reporters [Array<ProgressReporter>] Progress reporters
|
|
26
|
+
# @param update_interval [Float] Minimum seconds between reports
|
|
27
|
+
# @param eta_strategy [Symbol] ETA estimation strategy
|
|
28
|
+
def initialize(total_files:, total_bytes:, reporters: [],
|
|
29
|
+
update_interval: 0.5, eta_strategy: :exponential_smoothing)
|
|
30
|
+
@operation_progress = OperationProgress.new(
|
|
31
|
+
total_files: total_files,
|
|
32
|
+
total_bytes: total_bytes,
|
|
33
|
+
)
|
|
34
|
+
@eta_estimator = ETA.create_estimator(eta_strategy)
|
|
35
|
+
@reporters = Array(reporters)
|
|
36
|
+
@update_interval = update_interval
|
|
37
|
+
@last_report_time = Time.now - update_interval # Allow immediate first report
|
|
38
|
+
@mutex = Mutex.new # Thread safety
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Update progress with new values
|
|
42
|
+
#
|
|
43
|
+
# @param files [Integer] Number of files completed
|
|
44
|
+
# @param bytes [Integer] Number of bytes processed
|
|
45
|
+
# @param current_file [String] Name of file currently processing
|
|
46
|
+
def update(files:, bytes:, current_file: nil)
|
|
47
|
+
@mutex.synchronize do
|
|
48
|
+
# Update operation progress
|
|
49
|
+
operation_progress.update(
|
|
50
|
+
files: files,
|
|
51
|
+
bytes: bytes,
|
|
52
|
+
current_file: current_file,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Add sample to ETA estimator
|
|
56
|
+
eta_estimator.add_sample(
|
|
57
|
+
bytes_processed: bytes,
|
|
58
|
+
files_processed: files,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Report if enough time has passed
|
|
62
|
+
report_if_needed
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Get current completion percentage
|
|
67
|
+
#
|
|
68
|
+
# @return [Float] Percentage complete (0.0-100.0)
|
|
69
|
+
def percentage
|
|
70
|
+
operation_progress.percentage
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Get number of files processed
|
|
74
|
+
#
|
|
75
|
+
# @return [Integer] Files processed
|
|
76
|
+
def files_processed
|
|
77
|
+
operation_progress.files_done
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Get number of bytes processed
|
|
81
|
+
#
|
|
82
|
+
# @return [Integer] Bytes processed
|
|
83
|
+
def bytes_processed
|
|
84
|
+
operation_progress.bytes_done
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Get current file being processed
|
|
88
|
+
#
|
|
89
|
+
# @return [String, nil] Current file name
|
|
90
|
+
def current_file
|
|
91
|
+
operation_progress.current_file
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Get processing rate in MB/s
|
|
95
|
+
#
|
|
96
|
+
# @return [Float] Megabytes per second
|
|
97
|
+
def rate_mbps
|
|
98
|
+
eta_estimator.rate_calculator.megabytes_per_second
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Get processing rate in bytes/s
|
|
102
|
+
#
|
|
103
|
+
# @return [Float] Bytes per second
|
|
104
|
+
def rate_bps
|
|
105
|
+
eta_estimator.rate_calculator.bytes_per_second
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Get formatted rate string
|
|
109
|
+
#
|
|
110
|
+
# @return [String] Formatted rate (e.g., "2.5 MB/s")
|
|
111
|
+
def rate_formatted
|
|
112
|
+
eta_estimator.rate_calculator.format_rate
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Get ETA in seconds
|
|
116
|
+
#
|
|
117
|
+
# @return [Float] Estimated seconds remaining
|
|
118
|
+
def eta_seconds
|
|
119
|
+
result = eta_estimator.estimate(operation_progress.remaining_bytes)
|
|
120
|
+
result.seconds_remaining
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Get formatted ETA string
|
|
124
|
+
#
|
|
125
|
+
# @return [String] Formatted ETA (e.g., "2m 30s")
|
|
126
|
+
def eta_formatted
|
|
127
|
+
result = eta_estimator.estimate(operation_progress.remaining_bytes)
|
|
128
|
+
result.formatted
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Get full ETA result with confidence
|
|
132
|
+
#
|
|
133
|
+
# @return [Models::ETAResult] Complete ETA result
|
|
134
|
+
def eta_result
|
|
135
|
+
eta_estimator.estimate(operation_progress.remaining_bytes)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Force a progress report (regardless of interval)
|
|
139
|
+
def report
|
|
140
|
+
@mutex.synchronize do
|
|
141
|
+
reporters.each { |reporter| reporter.report(self) }
|
|
142
|
+
@last_report_time = Time.now
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Add a reporter
|
|
147
|
+
#
|
|
148
|
+
# @param reporter [ProgressReporter] Reporter to add
|
|
149
|
+
def add_reporter(reporter)
|
|
150
|
+
@mutex.synchronize do
|
|
151
|
+
@reporters << reporter
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Remove a reporter
|
|
156
|
+
#
|
|
157
|
+
# @param reporter [ProgressReporter] Reporter to remove
|
|
158
|
+
def remove_reporter(reporter)
|
|
159
|
+
@mutex.synchronize do
|
|
160
|
+
@reporters.delete(reporter)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Check if operation is complete
|
|
165
|
+
#
|
|
166
|
+
# @return [Boolean] true if complete
|
|
167
|
+
def complete?
|
|
168
|
+
operation_progress.complete?
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Get elapsed time
|
|
172
|
+
#
|
|
173
|
+
# @return [Float] Seconds elapsed
|
|
174
|
+
def elapsed_seconds
|
|
175
|
+
operation_progress.elapsed_seconds
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
|
|
180
|
+
# Report progress if enough time has passed since last report
|
|
181
|
+
def report_if_needed
|
|
182
|
+
now = Time.now
|
|
183
|
+
return unless now - last_report_time >= update_interval
|
|
184
|
+
|
|
185
|
+
reporters.each { |reporter| reporter.report(self) }
|
|
186
|
+
@last_report_time = now
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2025 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
require_relative "progress_reporter"
|
|
8
|
+
|
|
9
|
+
module Omnizip
|
|
10
|
+
module Progress
|
|
11
|
+
# Silent progress reporter that produces no output.
|
|
12
|
+
#
|
|
13
|
+
# This reporter is useful when you want to track progress internally
|
|
14
|
+
# but don't want any visible output.
|
|
15
|
+
class SilentReporter < ProgressReporter
|
|
16
|
+
# Report progress (does nothing)
|
|
17
|
+
#
|
|
18
|
+
# @param _progress [ProgressTracker] Progress tracker (ignored)
|
|
19
|
+
def report(_progress)
|
|
20
|
+
# Intentionally does nothing
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2025 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
require_relative "progress/operation_progress"
|
|
8
|
+
require_relative "progress/progress_tracker"
|
|
9
|
+
require_relative "progress/progress_reporter"
|
|
10
|
+
require_relative "progress/silent_reporter"
|
|
11
|
+
require_relative "progress/callback_reporter"
|
|
12
|
+
require_relative "progress/log_reporter"
|
|
13
|
+
require_relative "progress/progress_bar"
|
|
14
|
+
require_relative "progress/console_reporter"
|
|
15
|
+
|
|
16
|
+
module Omnizip
|
|
17
|
+
# Progress tracking module.
|
|
18
|
+
#
|
|
19
|
+
# This module provides real-time progress tracking for long-running
|
|
20
|
+
# operations with multiple reporting strategies (console, callback,
|
|
21
|
+
# log file, etc.) and integrated ETA calculation.
|
|
22
|
+
#
|
|
23
|
+
# @example Basic progress tracking
|
|
24
|
+
# tracker = Omnizip::Progress.track(total_files: 100, total_bytes: 1.gigabyte)
|
|
25
|
+
# # Update progress as work is done
|
|
26
|
+
# tracker.update(files: 10, bytes: 100.megabytes, current_file: "file.txt")
|
|
27
|
+
# puts tracker.percentage # => 10.0
|
|
28
|
+
# puts tracker.eta_formatted # => "2m 30s"
|
|
29
|
+
#
|
|
30
|
+
# @example With console progress bar
|
|
31
|
+
# tracker = Omnizip::Progress.track(
|
|
32
|
+
# total_files: 100,
|
|
33
|
+
# total_bytes: 1.gigabyte,
|
|
34
|
+
# reporter: :console
|
|
35
|
+
# )
|
|
36
|
+
#
|
|
37
|
+
# @example With custom callback
|
|
38
|
+
# tracker = Omnizip::Progress.track(
|
|
39
|
+
# total_files: 100,
|
|
40
|
+
# total_bytes: 1.gigabyte
|
|
41
|
+
# ) do |progress|
|
|
42
|
+
# puts "#{progress.percentage}% complete"
|
|
43
|
+
# end
|
|
44
|
+
module Progress
|
|
45
|
+
# Track an operation's progress
|
|
46
|
+
#
|
|
47
|
+
# @param total_files [Integer] Total number of files to process
|
|
48
|
+
# @param total_bytes [Integer] Total bytes to process
|
|
49
|
+
# @param reporter [Symbol, ProgressReporter, Array] Reporter(s) to use
|
|
50
|
+
# @param update_interval [Float] Minimum seconds between reports
|
|
51
|
+
# @param eta_strategy [Symbol] ETA estimation strategy
|
|
52
|
+
# @yield [progress] Optional callback block for custom reporting
|
|
53
|
+
# @return [ProgressTracker] Configured progress tracker
|
|
54
|
+
def self.track(total_files:, total_bytes:, reporter: :auto,
|
|
55
|
+
update_interval: 0.5, eta_strategy: :exponential_smoothing,
|
|
56
|
+
&block)
|
|
57
|
+
reporters = build_reporters(reporter, block)
|
|
58
|
+
|
|
59
|
+
ProgressTracker.new(
|
|
60
|
+
total_files: total_files,
|
|
61
|
+
total_bytes: total_bytes,
|
|
62
|
+
reporters: reporters,
|
|
63
|
+
update_interval: update_interval,
|
|
64
|
+
eta_strategy: eta_strategy,
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Configure global progress settings
|
|
69
|
+
#
|
|
70
|
+
# @yield [config] Configuration block
|
|
71
|
+
def self.configure
|
|
72
|
+
yield configuration
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Get global configuration
|
|
76
|
+
#
|
|
77
|
+
# @return [Configuration] Configuration object
|
|
78
|
+
def self.configuration
|
|
79
|
+
@configuration ||= Configuration.new
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Build reporters from various input formats
|
|
83
|
+
#
|
|
84
|
+
# @param reporter [Symbol, ProgressReporter, Array] Reporter specification
|
|
85
|
+
# @param block [Proc] Optional callback block
|
|
86
|
+
# @return [Array<ProgressReporter>] Array of reporters
|
|
87
|
+
def self.build_reporters(reporter, block)
|
|
88
|
+
reporters = []
|
|
89
|
+
|
|
90
|
+
# Handle callback block
|
|
91
|
+
reporters << CallbackReporter.new(&block) if block
|
|
92
|
+
|
|
93
|
+
# Handle reporter parameter
|
|
94
|
+
case reporter
|
|
95
|
+
when :auto
|
|
96
|
+
reporters << ConsoleReporter.new if $stdout.tty?
|
|
97
|
+
when :console
|
|
98
|
+
reporters << ConsoleReporter.new
|
|
99
|
+
when :silent
|
|
100
|
+
reporters << SilentReporter.new
|
|
101
|
+
when Array
|
|
102
|
+
reporters.concat(reporter)
|
|
103
|
+
when ProgressReporter
|
|
104
|
+
reporters << reporter
|
|
105
|
+
when Symbol
|
|
106
|
+
raise ArgumentError, "Unknown reporter type: #{reporter}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Default to silent if no reporters
|
|
110
|
+
reporters << SilentReporter.new if reporters.empty?
|
|
111
|
+
|
|
112
|
+
reporters
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Global configuration class
|
|
116
|
+
class Configuration
|
|
117
|
+
attr_accessor :default_reporter, :default_update_interval,
|
|
118
|
+
:default_eta_strategy
|
|
119
|
+
|
|
120
|
+
def initialize
|
|
121
|
+
@default_reporter = :auto
|
|
122
|
+
@default_update_interval = 0.5
|
|
123
|
+
@default_eta_strategy = :exponential_smoothing
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Rubyzip Compatibility Layer
|
|
5
|
+
#
|
|
6
|
+
# This file provides a drop-in replacement for the 'zip' gem (rubyzip).
|
|
7
|
+
# Simply require 'omnizip/rubyzip_compat' instead of 'zip' to use Omnizip
|
|
8
|
+
# with existing rubyzip code.
|
|
9
|
+
#
|
|
10
|
+
# Usage:
|
|
11
|
+
# require 'omnizip/rubyzip_compat'
|
|
12
|
+
#
|
|
13
|
+
# Zip::File.open('archive.zip') do |zip|
|
|
14
|
+
# zip.each { |entry| puts entry.name }
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
require_relative "../omnizip"
|
|
19
|
+
|
|
20
|
+
# Create Zip namespace as alias for Omnizip::Zip
|
|
21
|
+
module Zip
|
|
22
|
+
# Rubyzip-compatible File class
|
|
23
|
+
File = Omnizip::Zip::File
|
|
24
|
+
|
|
25
|
+
# Rubyzip-compatible Entry class
|
|
26
|
+
Entry = Omnizip::Zip::Entry
|
|
27
|
+
|
|
28
|
+
# Rubyzip-compatible OutputStream class
|
|
29
|
+
OutputStream = Omnizip::Zip::OutputStream
|
|
30
|
+
|
|
31
|
+
# Rubyzip-compatible InputStream class
|
|
32
|
+
InputStream = Omnizip::Zip::InputStream
|
|
33
|
+
|
|
34
|
+
# Error classes for compatibility
|
|
35
|
+
Error = Omnizip::Error
|
|
36
|
+
FormatError = Omnizip::FormatError
|
|
37
|
+
CompressionError = Omnizip::CompressionError
|
|
38
|
+
DecompressionError = Omnizip::DecompressionError
|
|
39
|
+
ChecksumError = Omnizip::ChecksumError
|
|
40
|
+
|
|
41
|
+
# Version information
|
|
42
|
+
VERSION = Omnizip::VERSION
|
|
43
|
+
|
|
44
|
+
class << self
|
|
45
|
+
# Legacy compatibility method
|
|
46
|
+
# @deprecated Use Zip::File.open instead
|
|
47
|
+
def open(...)
|
|
48
|
+
File.open(...)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Legacy compatibility method
|
|
52
|
+
# @deprecated Use Zip::File.create instead
|
|
53
|
+
def create(...)
|
|
54
|
+
File.create(...)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Compatibility note
|
|
60
|
+
if $VERBOSE
|
|
61
|
+
warn "Omnizip: Using Omnizip rubyzip compatibility layer. " \
|
|
62
|
+
"API is compatible with rubyzip, but implementation differs."
|
|
63
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Temp
|
|
8
|
+
# Safe extraction with atomic move to destination
|
|
9
|
+
# Provides rollback capability on failure
|
|
10
|
+
class SafeExtract
|
|
11
|
+
# Error raised when extraction verification fails
|
|
12
|
+
class VerificationError < Omnizip::Error; end
|
|
13
|
+
|
|
14
|
+
attr_reader :archive_path, :dest_path
|
|
15
|
+
|
|
16
|
+
# Create new safe extractor
|
|
17
|
+
# @param archive_path [String] Path to archive
|
|
18
|
+
# @param dest_path [String] Destination path
|
|
19
|
+
def initialize(archive_path, dest_path)
|
|
20
|
+
@archive_path = archive_path
|
|
21
|
+
@dest_path = dest_path
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Extract safely with verification
|
|
25
|
+
# @yield [temp_dir] Block for verification (return truthy to proceed)
|
|
26
|
+
# @return [String] Destination path
|
|
27
|
+
def extract
|
|
28
|
+
unless File.exist?(@archive_path)
|
|
29
|
+
raise Errno::ENOENT, "Archive not found: #{@archive_path}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Dir.mktmpdir("omniz_extract_") do |temp_dir|
|
|
33
|
+
# Extract to temp directory
|
|
34
|
+
extract_to_temp(temp_dir)
|
|
35
|
+
|
|
36
|
+
# User verification if block given
|
|
37
|
+
if block_given?
|
|
38
|
+
result = yield(temp_dir)
|
|
39
|
+
unless result
|
|
40
|
+
raise VerificationError, "Extraction verification failed"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Atomic move to destination
|
|
45
|
+
move_to_destination(temp_dir)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@dest_path
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Extract with checksum verification
|
|
52
|
+
# @param expected_checksums [Hash] Map of filename => CRC32
|
|
53
|
+
# @return [String] Destination path
|
|
54
|
+
def extract_verified(expected_checksums)
|
|
55
|
+
extract do |temp_dir|
|
|
56
|
+
verify_checksums(temp_dir, expected_checksums)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Extract with file count verification
|
|
61
|
+
# @param expected_count [Integer] Expected number of files
|
|
62
|
+
# @return [String] Destination path
|
|
63
|
+
def extract_with_count(expected_count)
|
|
64
|
+
extract do |temp_dir|
|
|
65
|
+
actual_count = count_files(temp_dir)
|
|
66
|
+
actual_count == expected_count
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Class method for quick safe extraction
|
|
71
|
+
# @param archive_path [String] Archive to extract
|
|
72
|
+
# @param dest_path [String] Destination
|
|
73
|
+
# @yield [temp_dir] Verification block
|
|
74
|
+
# @return [String] Destination path
|
|
75
|
+
def self.extract_safe(archive_path, dest_path, &block)
|
|
76
|
+
new(archive_path, dest_path).extract(&block)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def extract_to_temp(temp_dir)
|
|
82
|
+
# Detect archive format and extract
|
|
83
|
+
case detect_format
|
|
84
|
+
when :zip
|
|
85
|
+
extract_zip(temp_dir)
|
|
86
|
+
when :seven_zip
|
|
87
|
+
extract_7z(temp_dir)
|
|
88
|
+
else
|
|
89
|
+
raise Omnizip::UnsupportedFormatError,
|
|
90
|
+
"Unknown archive format: #{@archive_path}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def extract_zip(dest)
|
|
95
|
+
require_relative "../zip/file"
|
|
96
|
+
|
|
97
|
+
Omnizip::Zip::File.open(@archive_path) do |zip|
|
|
98
|
+
zip.each do |entry|
|
|
99
|
+
entry_path = File.join(dest, entry.name)
|
|
100
|
+
|
|
101
|
+
if entry.directory?
|
|
102
|
+
FileUtils.mkdir_p(entry_path)
|
|
103
|
+
else
|
|
104
|
+
FileUtils.mkdir_p(File.dirname(entry_path))
|
|
105
|
+
zip.extract(entry, entry_path)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def extract_7z(dest)
|
|
112
|
+
# Placeholder for 7z extraction
|
|
113
|
+
# Would use Omnizip::SevenZip::File when available
|
|
114
|
+
raise NotImplementedError, "7z extraction not yet implemented"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def move_to_destination(temp_dir)
|
|
118
|
+
# Ensure parent directory exists
|
|
119
|
+
FileUtils.mkdir_p(File.dirname(@dest_path))
|
|
120
|
+
|
|
121
|
+
# Remove destination if it exists
|
|
122
|
+
FileUtils.rm_rf(@dest_path)
|
|
123
|
+
|
|
124
|
+
# Copy contents (can't move since Dir.mktmpdir will try to clean up)
|
|
125
|
+
FileUtils.cp_r(temp_dir, @dest_path)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def verify_checksums(dir, expected)
|
|
129
|
+
require_relative "../checksums/crc32"
|
|
130
|
+
|
|
131
|
+
expected.all? do |file, expected_sum|
|
|
132
|
+
file_path = File.join(dir, file)
|
|
133
|
+
next false unless File.exist?(file_path)
|
|
134
|
+
|
|
135
|
+
# Calculate checksum
|
|
136
|
+
crc = Omnizip::Checksums::Crc32.new
|
|
137
|
+
File.open(file_path, "rb") do |f|
|
|
138
|
+
while (chunk = f.read(64 * 1024))
|
|
139
|
+
crc.update(chunk)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
crc.finalize == expected_sum
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def count_files(dir)
|
|
148
|
+
count = 0
|
|
149
|
+
Dir.glob(File.join(dir, "**", "*")) do |path|
|
|
150
|
+
count += 1 unless File.directory?(path)
|
|
151
|
+
end
|
|
152
|
+
count
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def detect_format
|
|
156
|
+
File.open(@archive_path, "rb") do |f|
|
|
157
|
+
magic = f.read(4)
|
|
158
|
+
case magic
|
|
159
|
+
when "PK\x03\x04"
|
|
160
|
+
:zip
|
|
161
|
+
when "7z\xBC\xAF"
|
|
162
|
+
:seven_zip
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tempfile"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Temp
|
|
7
|
+
# RAII-pattern temporary file with automatic cleanup
|
|
8
|
+
class TempFile
|
|
9
|
+
attr_reader :path
|
|
10
|
+
|
|
11
|
+
# Create new temporary file
|
|
12
|
+
# @param prefix [String] Filename prefix
|
|
13
|
+
# @param suffix [String] Filename suffix
|
|
14
|
+
# @param directory [String, nil] Directory (nil = system default)
|
|
15
|
+
def initialize(prefix: "omniz_", suffix: "", directory: nil)
|
|
16
|
+
@prefix = prefix
|
|
17
|
+
@suffix = suffix
|
|
18
|
+
@directory = directory
|
|
19
|
+
@tempfile = nil
|
|
20
|
+
@path = nil
|
|
21
|
+
@kept = false
|
|
22
|
+
@finalized = false
|
|
23
|
+
|
|
24
|
+
create
|
|
25
|
+
setup_finalizer
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Get the underlying Tempfile object
|
|
29
|
+
# @return [Tempfile] The tempfile
|
|
30
|
+
def file
|
|
31
|
+
@tempfile
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Write data to temp file
|
|
35
|
+
# @param data [String] Data to write
|
|
36
|
+
# @return [Integer] Bytes written
|
|
37
|
+
def write(data)
|
|
38
|
+
@tempfile.write(data)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Read data from temp file
|
|
42
|
+
# @param length [Integer, nil] Number of bytes to read
|
|
43
|
+
# @return [String, nil] Data read
|
|
44
|
+
def read(length = nil)
|
|
45
|
+
@tempfile.read(length)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Rewind to beginning of file
|
|
49
|
+
def rewind
|
|
50
|
+
@tempfile.rewind
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Close the temp file
|
|
54
|
+
def close
|
|
55
|
+
@tempfile.close if @tempfile && !@tempfile.closed?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Delete the temp file
|
|
59
|
+
def unlink
|
|
60
|
+
return if @finalized || @kept
|
|
61
|
+
|
|
62
|
+
if @tempfile
|
|
63
|
+
@tempfile.close unless @tempfile.closed?
|
|
64
|
+
@tempfile.unlink
|
|
65
|
+
@finalized = true
|
|
66
|
+
end
|
|
67
|
+
rescue StandardError
|
|
68
|
+
# Ignore errors during cleanup
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Prevent automatic deletion
|
|
73
|
+
def keep!
|
|
74
|
+
@kept = true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Check if file will be kept
|
|
78
|
+
# @return [Boolean] True if file won't be auto-deleted
|
|
79
|
+
def kept?
|
|
80
|
+
@kept
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Check if file has been finalized
|
|
84
|
+
# @return [Boolean] True if finalized
|
|
85
|
+
def finalized?
|
|
86
|
+
@finalized
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def create
|
|
92
|
+
@tempfile = if @directory
|
|
93
|
+
::Tempfile.new(
|
|
94
|
+
[@prefix, @suffix],
|
|
95
|
+
@directory,
|
|
96
|
+
binmode: true,
|
|
97
|
+
)
|
|
98
|
+
else
|
|
99
|
+
::Tempfile.new(
|
|
100
|
+
[@prefix, @suffix],
|
|
101
|
+
binmode: true,
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
@path = @tempfile.path
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def setup_finalizer
|
|
108
|
+
ObjectSpace.define_finalizer(self, self.class.finalizer(@tempfile))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# rubocop:disable Lint/IneffectiveAccessModifier
|
|
112
|
+
def self.finalizer(tempfile)
|
|
113
|
+
proc do
|
|
114
|
+
tempfile.close unless tempfile.closed?
|
|
115
|
+
tempfile.unlink
|
|
116
|
+
rescue StandardError
|
|
117
|
+
# Ignore errors in finalizer
|
|
118
|
+
nil
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
# rubocop:enable Lint/IneffectiveAccessModifier
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|