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,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Profile
|
|
5
|
+
# Thread-safe registry for compression profiles
|
|
6
|
+
#
|
|
7
|
+
# This class manages both built-in and custom compression profiles,
|
|
8
|
+
# providing a central location for profile registration, lookup, and
|
|
9
|
+
# management.
|
|
10
|
+
class ProfileRegistry
|
|
11
|
+
# Initialize a new profile registry
|
|
12
|
+
def initialize
|
|
13
|
+
@profiles = {}
|
|
14
|
+
@mutex = Mutex.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Register a profile
|
|
18
|
+
#
|
|
19
|
+
# @param profile [CompressionProfile] Profile to register
|
|
20
|
+
# @raise [ArgumentError] if profile with same name already exists
|
|
21
|
+
# @return [CompressionProfile] The registered profile
|
|
22
|
+
def register(profile)
|
|
23
|
+
unless profile.is_a?(CompressionProfile)
|
|
24
|
+
raise ArgumentError,
|
|
25
|
+
"Profile must be a CompressionProfile instance"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@mutex.synchronize do
|
|
29
|
+
if @profiles.key?(profile.name)
|
|
30
|
+
raise ArgumentError,
|
|
31
|
+
"Profile '#{profile.name}' is already registered"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
@profiles[profile.name] = profile
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
profile
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Register a profile, replacing if it exists
|
|
41
|
+
#
|
|
42
|
+
# @param profile [CompressionProfile] Profile to register
|
|
43
|
+
# @return [CompressionProfile] The registered profile
|
|
44
|
+
def register!(profile)
|
|
45
|
+
unless profile.is_a?(CompressionProfile)
|
|
46
|
+
raise ArgumentError,
|
|
47
|
+
"Profile must be a CompressionProfile instance"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
@mutex.synchronize do
|
|
51
|
+
@profiles[profile.name] = profile
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
profile
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Unregister a profile by name
|
|
58
|
+
#
|
|
59
|
+
# @param name [Symbol] Profile name
|
|
60
|
+
# @return [CompressionProfile, nil] The unregistered profile or nil
|
|
61
|
+
def unregister(name)
|
|
62
|
+
@mutex.synchronize do
|
|
63
|
+
@profiles.delete(name)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Get a profile by name
|
|
68
|
+
#
|
|
69
|
+
# @param name [Symbol] Profile name
|
|
70
|
+
# @return [CompressionProfile, nil] Profile or nil if not found
|
|
71
|
+
def get(name)
|
|
72
|
+
@mutex.synchronize do
|
|
73
|
+
@profiles[name]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Check if a profile is registered
|
|
78
|
+
#
|
|
79
|
+
# @param name [Symbol] Profile name
|
|
80
|
+
# @return [Boolean] true if profile exists
|
|
81
|
+
def registered?(name)
|
|
82
|
+
@mutex.synchronize do
|
|
83
|
+
@profiles.key?(name)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Get all registered profile names
|
|
88
|
+
#
|
|
89
|
+
# @return [Array<Symbol>] List of profile names
|
|
90
|
+
def names
|
|
91
|
+
@mutex.synchronize do
|
|
92
|
+
@profiles.keys
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Get all registered profiles
|
|
97
|
+
#
|
|
98
|
+
# @return [Array<CompressionProfile>] List of profiles
|
|
99
|
+
def all
|
|
100
|
+
@mutex.synchronize do
|
|
101
|
+
@profiles.values
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Find profiles suitable for a MIME type
|
|
106
|
+
#
|
|
107
|
+
# @param mime_type [String] MIME type string
|
|
108
|
+
# @return [Array<CompressionProfile>] Suitable profiles
|
|
109
|
+
def suitable_for(mime_type)
|
|
110
|
+
all.select { |profile| profile.suitable_for?(mime_type) }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Clear all registered profiles
|
|
114
|
+
#
|
|
115
|
+
# @return [void]
|
|
116
|
+
def clear
|
|
117
|
+
@mutex.synchronize do
|
|
118
|
+
@profiles.clear
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Get the number of registered profiles
|
|
123
|
+
#
|
|
124
|
+
# @return [Integer] Profile count
|
|
125
|
+
def count
|
|
126
|
+
@mutex.synchronize do
|
|
127
|
+
@profiles.size
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Iterate over all profiles
|
|
132
|
+
#
|
|
133
|
+
# @yield [profile] Yields each profile
|
|
134
|
+
# @yieldparam profile [CompressionProfile] A registered profile
|
|
135
|
+
# @return [void]
|
|
136
|
+
# rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
|
|
137
|
+
def each(&block)
|
|
138
|
+
all.each(&block)
|
|
139
|
+
end
|
|
140
|
+
# rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
|
|
141
|
+
|
|
142
|
+
# Get profile information as hash
|
|
143
|
+
#
|
|
144
|
+
# @return [Hash{Symbol => Hash}] Profiles indexed by name
|
|
145
|
+
def to_h
|
|
146
|
+
@mutex.synchronize do
|
|
147
|
+
@profiles.transform_values(&:to_h)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# String representation
|
|
152
|
+
#
|
|
153
|
+
# @return [String]
|
|
154
|
+
def inspect
|
|
155
|
+
@mutex.synchronize do
|
|
156
|
+
"#<#{self.class.name} profiles=#{@profiles.keys.join(', ')}>"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "compression_profile"
|
|
4
|
+
require_relative "../file_type/mime_classifier"
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Profile
|
|
8
|
+
# Text compression profile
|
|
9
|
+
#
|
|
10
|
+
# Optimized for compressing text files.
|
|
11
|
+
# Uses PPMd7 which excels at text compression through context modeling.
|
|
12
|
+
class TextProfile < CompressionProfile
|
|
13
|
+
# Initialize text profile
|
|
14
|
+
def initialize
|
|
15
|
+
super(
|
|
16
|
+
name: :text,
|
|
17
|
+
algorithm: :ppmd7,
|
|
18
|
+
level: 6,
|
|
19
|
+
filter: nil,
|
|
20
|
+
solid: false,
|
|
21
|
+
description: "Optimized for text files"
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Check if this profile is suitable for a MIME type
|
|
26
|
+
#
|
|
27
|
+
# @param mime_type [String] MIME type string
|
|
28
|
+
# @return [Boolean] true if MIME type is text-based
|
|
29
|
+
def suitable_for?(mime_type)
|
|
30
|
+
return true unless mime_type
|
|
31
|
+
|
|
32
|
+
FileType::MimeClassifier.text?(mime_type)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "profile/compression_profile"
|
|
4
|
+
require_relative "profile/profile_registry"
|
|
5
|
+
require_relative "profile/profile_detector"
|
|
6
|
+
require_relative "profile/custom_profile"
|
|
7
|
+
require_relative "profile/fast_profile"
|
|
8
|
+
require_relative "profile/balanced_profile"
|
|
9
|
+
require_relative "profile/maximum_profile"
|
|
10
|
+
require_relative "profile/text_profile"
|
|
11
|
+
require_relative "profile/binary_profile"
|
|
12
|
+
require_relative "profile/archive_profile"
|
|
13
|
+
|
|
14
|
+
module Omnizip
|
|
15
|
+
# Compression profile management
|
|
16
|
+
#
|
|
17
|
+
# This module provides a high-level API for working with compression
|
|
18
|
+
# profiles. Profiles encapsulate compression settings and allow users
|
|
19
|
+
# to easily select optimal compression strategies for different file types.
|
|
20
|
+
module Profile
|
|
21
|
+
class << self
|
|
22
|
+
# Get the global profile registry
|
|
23
|
+
#
|
|
24
|
+
# @return [ProfileRegistry] The global registry
|
|
25
|
+
def registry
|
|
26
|
+
@registry ||= ProfileRegistry.new.tap do |reg|
|
|
27
|
+
register_built_in_profiles(reg)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Get a profile by name
|
|
32
|
+
#
|
|
33
|
+
# @param name [Symbol] Profile name
|
|
34
|
+
# @return [CompressionProfile, nil] The profile or nil
|
|
35
|
+
def get(name)
|
|
36
|
+
registry.get(name)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Define a custom profile
|
|
40
|
+
#
|
|
41
|
+
# @param name [Symbol] Profile name
|
|
42
|
+
# @param base [Symbol, nil] Base profile to extend
|
|
43
|
+
# @yield [builder] Yields a builder for profile configuration
|
|
44
|
+
# @yieldparam builder [CustomProfile::Builder] The profile builder
|
|
45
|
+
# @return [CustomProfile] The created profile
|
|
46
|
+
#
|
|
47
|
+
# @example Define a custom profile
|
|
48
|
+
# Omnizip::Profile.define(:my_profile) do |p|
|
|
49
|
+
# p.algorithm = :lzma2
|
|
50
|
+
# p.level = 7
|
|
51
|
+
# p.filter = :bcj_x86
|
|
52
|
+
# p.solid = true
|
|
53
|
+
# p.description = "My custom profile"
|
|
54
|
+
# end
|
|
55
|
+
#
|
|
56
|
+
# @example Extend an existing profile
|
|
57
|
+
# Omnizip::Profile.define(:my_fast, base: :fast) do |p|
|
|
58
|
+
# p.level = 2
|
|
59
|
+
# p.description = "Slightly better than fast"
|
|
60
|
+
# end
|
|
61
|
+
def define(name, base: nil)
|
|
62
|
+
base_profile = base ? registry.get(base) : nil
|
|
63
|
+
builder = CustomProfile::Builder.new(name, base_profile)
|
|
64
|
+
|
|
65
|
+
yield builder if block_given?
|
|
66
|
+
|
|
67
|
+
builder.valid?
|
|
68
|
+
profile = builder.build
|
|
69
|
+
|
|
70
|
+
registry.register!(profile)
|
|
71
|
+
profile
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# List all available profile names
|
|
75
|
+
#
|
|
76
|
+
# @return [Array<Symbol>] List of profile names
|
|
77
|
+
def list
|
|
78
|
+
registry.names
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Get recommended profile for a file type
|
|
82
|
+
#
|
|
83
|
+
# @param file_type [String, Symbol] MIME type string or category symbol
|
|
84
|
+
# @return [CompressionProfile, nil] Recommended profile
|
|
85
|
+
def for_file_type(file_type)
|
|
86
|
+
# If file_type is a symbol (category), find first suitable profile
|
|
87
|
+
return find_profile_for_category(file_type) if file_type.is_a?(Symbol)
|
|
88
|
+
|
|
89
|
+
# If file_type is a MIME string, find suitable profiles
|
|
90
|
+
if file_type.is_a?(String)
|
|
91
|
+
suitable = registry.suitable_for(file_type)
|
|
92
|
+
return registry.get(:balanced) if suitable.empty?
|
|
93
|
+
|
|
94
|
+
return select_best_profile_for_mime(suitable, file_type)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Default to balanced
|
|
98
|
+
registry.get(:balanced)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Auto-detect optimal profile for a file
|
|
102
|
+
#
|
|
103
|
+
# @param file_path [String] Path to the file
|
|
104
|
+
# @param options [Hash] Detection options
|
|
105
|
+
# @return [CompressionProfile] Detected profile
|
|
106
|
+
def detect(file_path, options = {})
|
|
107
|
+
detector.detect(file_path, options)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Get the profile detector
|
|
111
|
+
#
|
|
112
|
+
# @return [ProfileDetector] The detector instance
|
|
113
|
+
def detector
|
|
114
|
+
@detector ||= ProfileDetector.new(registry)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Reset the global registry (mainly for testing)
|
|
118
|
+
#
|
|
119
|
+
# @return [void]
|
|
120
|
+
def reset!
|
|
121
|
+
@registry = nil
|
|
122
|
+
@detector = nil
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
# Register all built-in profiles
|
|
128
|
+
#
|
|
129
|
+
# @param registry [ProfileRegistry] Registry to populate
|
|
130
|
+
# @return [void]
|
|
131
|
+
def register_built_in_profiles(registry)
|
|
132
|
+
registry.register(FastProfile.new)
|
|
133
|
+
registry.register(BalancedProfile.new)
|
|
134
|
+
registry.register(MaximumProfile.new)
|
|
135
|
+
registry.register(TextProfile.new)
|
|
136
|
+
registry.register(BinaryProfile.new)
|
|
137
|
+
registry.register(ArchiveProfile.new)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Find profile for a category symbol
|
|
141
|
+
#
|
|
142
|
+
# @param category [Symbol] File category
|
|
143
|
+
# @return [CompressionProfile, nil] Recommended profile
|
|
144
|
+
def find_profile_for_category(category)
|
|
145
|
+
case category
|
|
146
|
+
when :text, :document, :code
|
|
147
|
+
registry.get(:text)
|
|
148
|
+
when :executable
|
|
149
|
+
registry.get(:binary)
|
|
150
|
+
when :archive, :compressed
|
|
151
|
+
registry.get(:archive)
|
|
152
|
+
else
|
|
153
|
+
registry.get(:balanced)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Select best profile from suitable candidates based on MIME type
|
|
158
|
+
#
|
|
159
|
+
# @param profiles [Array<CompressionProfile>] Suitable profiles
|
|
160
|
+
# @param mime_type [String] MIME type string
|
|
161
|
+
# @return [CompressionProfile] Best profile
|
|
162
|
+
def select_best_profile_for_mime(profiles, mime_type)
|
|
163
|
+
require_relative "file_type/mime_classifier"
|
|
164
|
+
|
|
165
|
+
# Determine category from MIME type
|
|
166
|
+
category = FileType::MimeClassifier.profile_category(mime_type)
|
|
167
|
+
|
|
168
|
+
priority = case category
|
|
169
|
+
when :archive
|
|
170
|
+
%i[archive fast balanced]
|
|
171
|
+
when :text
|
|
172
|
+
%i[text balanced]
|
|
173
|
+
when :binary
|
|
174
|
+
%i[binary maximum balanced]
|
|
175
|
+
else
|
|
176
|
+
[:balanced]
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Find first profile matching priority
|
|
180
|
+
priority.each do |name|
|
|
181
|
+
profile = profiles.find { |p| p.name == name }
|
|
182
|
+
return profile if profile
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Return first suitable profile if none matched priority
|
|
186
|
+
profiles.first
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
class Profiler
|
|
5
|
+
# Profiles memory allocation and retention
|
|
6
|
+
class MemoryProfiler
|
|
7
|
+
def initialize
|
|
8
|
+
@call_counts = Hash.new(0)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def profile(operation_name)
|
|
12
|
+
GC.start
|
|
13
|
+
GC.disable
|
|
14
|
+
|
|
15
|
+
gc_stat_before = GC.stat
|
|
16
|
+
objspace_before = ObjectSpace.count_objects
|
|
17
|
+
|
|
18
|
+
yield
|
|
19
|
+
|
|
20
|
+
objspace_after = ObjectSpace.count_objects
|
|
21
|
+
gc_stat_after = GC.stat
|
|
22
|
+
|
|
23
|
+
GC.enable
|
|
24
|
+
|
|
25
|
+
@call_counts[operation_name] += 1
|
|
26
|
+
|
|
27
|
+
# Calculate memory metrics
|
|
28
|
+
total_allocated = gc_stat_after[:total_allocated_objects] -
|
|
29
|
+
gc_stat_before[:total_allocated_objects]
|
|
30
|
+
total_freed = gc_stat_after[:total_freed_objects] -
|
|
31
|
+
gc_stat_before[:total_freed_objects]
|
|
32
|
+
|
|
33
|
+
# Object allocation delta
|
|
34
|
+
objspace_after[:TOTAL]
|
|
35
|
+
objspace_before[:TOTAL]
|
|
36
|
+
|
|
37
|
+
# Estimate memory based on object allocations
|
|
38
|
+
# Average Ruby object is ~40 bytes
|
|
39
|
+
estimated_memory = total_allocated * 40
|
|
40
|
+
|
|
41
|
+
Models::PerformanceResult.new(
|
|
42
|
+
operation_name: operation_name,
|
|
43
|
+
memory_allocated: estimated_memory,
|
|
44
|
+
memory_retained: (total_allocated - total_freed) * 40,
|
|
45
|
+
object_allocations: total_allocated,
|
|
46
|
+
gc_runs: 0,
|
|
47
|
+
call_count: @call_counts[operation_name],
|
|
48
|
+
)
|
|
49
|
+
ensure
|
|
50
|
+
GC.enable
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def reset!
|
|
54
|
+
@call_counts.clear
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def call_count(operation_name)
|
|
58
|
+
@call_counts[operation_name]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def total_calls
|
|
62
|
+
@call_counts.values.sum
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
class Profiler
|
|
7
|
+
# Profiles method execution time and call counts
|
|
8
|
+
class MethodProfiler
|
|
9
|
+
def initialize
|
|
10
|
+
@call_counts = Hash.new(0)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def profile(operation_name)
|
|
14
|
+
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
15
|
+
gc_stat_before = GC.stat
|
|
16
|
+
|
|
17
|
+
yield
|
|
18
|
+
|
|
19
|
+
end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
20
|
+
gc_stat_after = GC.stat
|
|
21
|
+
|
|
22
|
+
@call_counts[operation_name] += 1
|
|
23
|
+
|
|
24
|
+
wall_time = end_time - start_time
|
|
25
|
+
gc_runs = gc_stat_after[:count] - gc_stat_before[:count]
|
|
26
|
+
|
|
27
|
+
Models::PerformanceResult.new(
|
|
28
|
+
operation_name: operation_name,
|
|
29
|
+
total_time: wall_time,
|
|
30
|
+
wall_time: wall_time,
|
|
31
|
+
gc_runs: gc_runs,
|
|
32
|
+
call_count: @call_counts[operation_name],
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def reset!
|
|
37
|
+
@call_counts.clear
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call_count(operation_name)
|
|
41
|
+
@call_counts[operation_name]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def total_calls
|
|
45
|
+
@call_counts.values.sum
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
class Profiler
|
|
8
|
+
# Generates formatted profiling reports with optimization recommendations
|
|
9
|
+
class ReportGenerator
|
|
10
|
+
attr_reader :report
|
|
11
|
+
|
|
12
|
+
def initialize(report)
|
|
13
|
+
@report = report
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Generate a human-readable text report
|
|
17
|
+
def generate_text_report
|
|
18
|
+
lines = []
|
|
19
|
+
lines << ("=" * 80)
|
|
20
|
+
lines << "PERFORMANCE PROFILING REPORT"
|
|
21
|
+
lines << ("=" * 80)
|
|
22
|
+
lines << "Profile: #{report.profile_name}"
|
|
23
|
+
lines << "Timestamp: #{report.timestamp}"
|
|
24
|
+
lines << ""
|
|
25
|
+
|
|
26
|
+
lines += generate_summary_section
|
|
27
|
+
lines += generate_results_section
|
|
28
|
+
lines += generate_hot_paths_section
|
|
29
|
+
lines += generate_bottlenecks_section
|
|
30
|
+
|
|
31
|
+
lines.join("\n")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Generate a JSON report
|
|
35
|
+
def generate_json_report
|
|
36
|
+
JSON.pretty_generate(report.to_h)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Save report to file
|
|
40
|
+
def save_to_file(filename, format: :text)
|
|
41
|
+
content = case format
|
|
42
|
+
when :text then generate_text_report
|
|
43
|
+
when :json then generate_json_report
|
|
44
|
+
else raise ArgumentError, "Unknown format: #{format}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Create parent directories if they don't exist
|
|
48
|
+
dir = File.dirname(filename)
|
|
49
|
+
FileUtils.mkdir_p(dir)
|
|
50
|
+
|
|
51
|
+
File.write(filename, content)
|
|
52
|
+
puts "Report saved to #{filename}"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Print report to console
|
|
56
|
+
def print_report
|
|
57
|
+
puts generate_text_report
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def generate_summary_section
|
|
63
|
+
lines = []
|
|
64
|
+
lines << ("-" * 80)
|
|
65
|
+
lines << "SUMMARY"
|
|
66
|
+
lines << ("-" * 80)
|
|
67
|
+
lines << format("Total Execution Time: %.3fs",
|
|
68
|
+
report.total_execution_time)
|
|
69
|
+
lines << format("Total Memory Allocated: %s",
|
|
70
|
+
format_bytes(report.total_memory_allocated))
|
|
71
|
+
lines << format("Total GC Runs: %d", report.total_gc_runs)
|
|
72
|
+
lines << format("Operations Profiled: %d", report.results.size)
|
|
73
|
+
lines << ""
|
|
74
|
+
lines
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def generate_results_section
|
|
78
|
+
return [] if report.results.empty?
|
|
79
|
+
|
|
80
|
+
lines = []
|
|
81
|
+
lines << ("-" * 80)
|
|
82
|
+
lines << "DETAILED RESULTS"
|
|
83
|
+
lines << ("-" * 80)
|
|
84
|
+
lines << "Operation Time (s) Memory Calls"
|
|
85
|
+
lines << ("-" * 80)
|
|
86
|
+
|
|
87
|
+
report.results.sort_by(&:total_time).reverse.each do |result|
|
|
88
|
+
lines << format("%-40s %12.3f %15s %10d",
|
|
89
|
+
truncate(result.operation_name, 40),
|
|
90
|
+
result.total_time || 0.0,
|
|
91
|
+
format_bytes(result.memory_allocated || 0),
|
|
92
|
+
result.call_count || 0)
|
|
93
|
+
end
|
|
94
|
+
lines << ""
|
|
95
|
+
lines
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def generate_hot_paths_section
|
|
99
|
+
return [] if report.hot_paths.empty?
|
|
100
|
+
|
|
101
|
+
lines = []
|
|
102
|
+
lines << ("-" * 80)
|
|
103
|
+
lines << "HOT PATHS (>10% execution time)"
|
|
104
|
+
lines << ("-" * 80)
|
|
105
|
+
|
|
106
|
+
report.hot_paths.each do |hot_path|
|
|
107
|
+
lines << format(" %s: %.3fs (%.1f%%)",
|
|
108
|
+
hot_path[:operation],
|
|
109
|
+
hot_path[:time],
|
|
110
|
+
hot_path[:percentage])
|
|
111
|
+
end
|
|
112
|
+
lines << ""
|
|
113
|
+
lines
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def generate_bottlenecks_section
|
|
117
|
+
return [] if report.bottlenecks.empty?
|
|
118
|
+
|
|
119
|
+
lines = []
|
|
120
|
+
lines << ("-" * 80)
|
|
121
|
+
lines << "PERFORMANCE BOTTLENECKS"
|
|
122
|
+
lines << ("-" * 80)
|
|
123
|
+
|
|
124
|
+
report.bottlenecks.group_by { |b| b[:type] }.each do |type, bottlenecks|
|
|
125
|
+
lines << "\n#{type.to_s.upcase} Bottlenecks:"
|
|
126
|
+
bottlenecks.each do |bottleneck|
|
|
127
|
+
lines << format(" [%s] %s",
|
|
128
|
+
bottleneck[:severity].to_s.upcase,
|
|
129
|
+
bottleneck[:operation])
|
|
130
|
+
|
|
131
|
+
case type
|
|
132
|
+
when :memory
|
|
133
|
+
lines << format(" Memory: %s",
|
|
134
|
+
format_bytes(bottleneck[:allocated]))
|
|
135
|
+
when :cpu
|
|
136
|
+
lines << format(" Time: %.3fs", bottleneck[:time])
|
|
137
|
+
when :gc
|
|
138
|
+
lines << format(" GC Pressure: %.2f runs/s",
|
|
139
|
+
bottleneck[:gc_pressure])
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
lines << ""
|
|
144
|
+
lines
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def format_bytes(bytes)
|
|
148
|
+
return "0 B" if bytes.nil? || bytes.zero?
|
|
149
|
+
|
|
150
|
+
units = %w[B KB MB GB]
|
|
151
|
+
size = bytes.to_f
|
|
152
|
+
unit_index = 0
|
|
153
|
+
|
|
154
|
+
while size >= 1024.0 && unit_index < units.size - 1
|
|
155
|
+
size /= 1024.0
|
|
156
|
+
unit_index += 1
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
format("%.2f %s", size, units[unit_index])
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def truncate(string, max_length)
|
|
163
|
+
return string if string.length <= max_length
|
|
164
|
+
|
|
165
|
+
"#{string[0...(max_length - 3)]}..."
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|