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,230 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yaml"
|
|
4
|
+
begin
|
|
5
|
+
require "lutaml/model"
|
|
6
|
+
rescue LoadError, ArgumentError
|
|
7
|
+
# lutaml-model not available, using simple classes
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require_relative "../error"
|
|
11
|
+
|
|
12
|
+
module Omnizip
|
|
13
|
+
module Formats
|
|
14
|
+
# Loads and manages format specifications from YAML configuration files
|
|
15
|
+
#
|
|
16
|
+
# This class provides a configuration-driven architecture for archive formats,
|
|
17
|
+
# allowing format specifications to be externalized in YAML files rather than
|
|
18
|
+
# hardcoded in the application.
|
|
19
|
+
#
|
|
20
|
+
# @example Loading a format specification
|
|
21
|
+
# spec = FormatSpecLoader.load("rar5")
|
|
22
|
+
# spec.format.name # => "RAR5"
|
|
23
|
+
# spec.format.magic_bytes # => [0x52, 0x61, 0x72, ...]
|
|
24
|
+
#
|
|
25
|
+
# @example Getting all loaded specifications
|
|
26
|
+
# specs = FormatSpecLoader.all_specs
|
|
27
|
+
# specs.keys # => ["rar3", "rar5", "zip", ...]
|
|
28
|
+
class FormatSpecLoader
|
|
29
|
+
class << self
|
|
30
|
+
# Load a format specification from a YAML file
|
|
31
|
+
#
|
|
32
|
+
# @param format_name [String] The name of the format (e.g., "rar5")
|
|
33
|
+
# @param config_dir [String] The directory containing format specs
|
|
34
|
+
# @return [FormatSpecification] The loaded format specification
|
|
35
|
+
# @raise [FormatError] If the specification file is not found
|
|
36
|
+
# or invalid
|
|
37
|
+
def load(format_name, config_dir: default_config_dir)
|
|
38
|
+
spec_file = File.join(config_dir, "#{format_name}_spec.yml")
|
|
39
|
+
|
|
40
|
+
unless File.exist?(spec_file)
|
|
41
|
+
raise FormatError,
|
|
42
|
+
"Format specification not found: #{spec_file}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
yaml_content = File.read(spec_file)
|
|
46
|
+
parsed_yaml = YAML.safe_load(
|
|
47
|
+
yaml_content,
|
|
48
|
+
permitted_classes: [Symbol],
|
|
49
|
+
symbolize_names: true,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
validate_spec(parsed_yaml, format_name)
|
|
53
|
+
|
|
54
|
+
spec = FormatSpecification.new(parsed_yaml)
|
|
55
|
+
register_spec(format_name, spec)
|
|
56
|
+
spec
|
|
57
|
+
rescue Psych::SyntaxError => e
|
|
58
|
+
raise FormatError,
|
|
59
|
+
"Invalid YAML in #{spec_file}: #{e.message}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Get all loaded format specifications
|
|
63
|
+
#
|
|
64
|
+
# @return [Hash<String, FormatSpecification>] All loaded specs
|
|
65
|
+
def all_specs
|
|
66
|
+
@all_specs ||= {}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Clear all loaded specifications (primarily for testing)
|
|
70
|
+
#
|
|
71
|
+
# @return [void]
|
|
72
|
+
def clear_specs
|
|
73
|
+
@all_specs = {}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Check if a format specification is loaded
|
|
77
|
+
#
|
|
78
|
+
# @param format_name [String] The format name
|
|
79
|
+
# @return [Boolean] True if loaded, false otherwise
|
|
80
|
+
def loaded?(format_name)
|
|
81
|
+
all_specs.key?(format_name)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Get a loaded specification
|
|
85
|
+
#
|
|
86
|
+
# @param format_name [String] The format name
|
|
87
|
+
# @return [FormatSpecification, nil] The spec or nil if not loaded
|
|
88
|
+
def get(format_name)
|
|
89
|
+
all_specs[format_name]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Load all format specifications from a directory
|
|
93
|
+
#
|
|
94
|
+
# @param config_dir [String] The directory containing format specs
|
|
95
|
+
# @return [Hash<String, FormatSpecification>] All loaded specs
|
|
96
|
+
def load_all(config_dir: default_config_dir)
|
|
97
|
+
return all_specs unless Dir.exist?(config_dir)
|
|
98
|
+
|
|
99
|
+
Dir.glob(File.join(config_dir, "*_spec.yml")).each do |spec_file|
|
|
100
|
+
format_name = File.basename(spec_file, "_spec.yml")
|
|
101
|
+
unless loaded?(format_name)
|
|
102
|
+
load(format_name,
|
|
103
|
+
config_dir: config_dir)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
all_specs
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
# Default configuration directory for format specifications
|
|
113
|
+
#
|
|
114
|
+
# @return [String] The default config directory path
|
|
115
|
+
def default_config_dir
|
|
116
|
+
File.join(__dir__, "../../../config/formats")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Register a loaded specification
|
|
120
|
+
#
|
|
121
|
+
# @param format_name [String] The format name
|
|
122
|
+
# @param spec [FormatSpecification] The specification to register
|
|
123
|
+
# @return [void]
|
|
124
|
+
def register_spec(format_name, spec)
|
|
125
|
+
all_specs[format_name] = spec
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Validate a parsed YAML specification
|
|
129
|
+
#
|
|
130
|
+
# @param parsed_yaml [Hash] The parsed YAML content
|
|
131
|
+
# @param format_name [String] The format name
|
|
132
|
+
# @return [void]
|
|
133
|
+
# @raise [FormatError] If the spec is invalid
|
|
134
|
+
def validate_spec(parsed_yaml, format_name)
|
|
135
|
+
unless parsed_yaml.is_a?(Hash) && parsed_yaml[:format]
|
|
136
|
+
raise FormatError,
|
|
137
|
+
"Invalid format specification for #{format_name}: " \
|
|
138
|
+
"missing 'format' key"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
format_data = parsed_yaml[:format]
|
|
142
|
+
required_keys = %i[name version magic_bytes]
|
|
143
|
+
|
|
144
|
+
required_keys.each do |key|
|
|
145
|
+
next if format_data[key]
|
|
146
|
+
|
|
147
|
+
raise FormatError,
|
|
148
|
+
"Invalid format specification for #{format_name}: " \
|
|
149
|
+
"missing required key '#{key}'"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Model class for encryption data
|
|
156
|
+
class EncryptionData < Lutaml::Model::Serializable
|
|
157
|
+
attribute :supported, :boolean
|
|
158
|
+
attribute :algorithms, :string, collection: true
|
|
159
|
+
attribute :key_derivation, :string
|
|
160
|
+
attribute :kdf_iterations, :integer
|
|
161
|
+
attribute :salt_size, :integer
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Model class for checksum data
|
|
165
|
+
class ChecksumData < Lutaml::Model::Serializable
|
|
166
|
+
attribute :algorithm, :string
|
|
167
|
+
attribute :size, :integer
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Model class for format data
|
|
171
|
+
class FormatData < Lutaml::Model::Serializable
|
|
172
|
+
attribute :name, :string
|
|
173
|
+
attribute :version, :string
|
|
174
|
+
attribute :extension, :string
|
|
175
|
+
attribute :magic_bytes, :integer, collection: true
|
|
176
|
+
attribute :block_types, :hash
|
|
177
|
+
attribute :archive_flags, :hash
|
|
178
|
+
attribute :main_header_flags, :hash
|
|
179
|
+
attribute :file_header_flags, :hash
|
|
180
|
+
attribute :file_flags, :hash
|
|
181
|
+
attribute :encryption_flags, :hash
|
|
182
|
+
attribute :compression_methods, :hash
|
|
183
|
+
attribute :host_os, :hash
|
|
184
|
+
attribute :dictionary_sizes, :hash
|
|
185
|
+
attribute :encryption, EncryptionData
|
|
186
|
+
attribute :checksum, ChecksumData
|
|
187
|
+
attribute :features, :hash
|
|
188
|
+
attribute :compression_features, :hash
|
|
189
|
+
attribute :advanced_features, :hash
|
|
190
|
+
attribute :extra_records, :hash
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Model class representing a format specification
|
|
194
|
+
#
|
|
195
|
+
# This class uses Lutaml::Model to provide a structured representation
|
|
196
|
+
# of format specifications loaded from YAML files.
|
|
197
|
+
class FormatSpecification < Lutaml::Model::Serializable
|
|
198
|
+
attribute :format, FormatData
|
|
199
|
+
|
|
200
|
+
# Get a value from the format specification
|
|
201
|
+
#
|
|
202
|
+
# @param key [Symbol, String] The key to retrieve
|
|
203
|
+
# @return [Object] The value for the key
|
|
204
|
+
def [](key)
|
|
205
|
+
format.send(key)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Get magic bytes as an array of integers
|
|
209
|
+
#
|
|
210
|
+
# @return [Array<Integer>] The magic bytes
|
|
211
|
+
def magic_bytes
|
|
212
|
+
format.magic_bytes
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Get the format name
|
|
216
|
+
#
|
|
217
|
+
# @return [String] The format name
|
|
218
|
+
def name
|
|
219
|
+
format.name
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Get the format version
|
|
223
|
+
#
|
|
224
|
+
# @return [String] The format version
|
|
225
|
+
def version
|
|
226
|
+
format.version
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zlib"
|
|
4
|
+
require "stringio"
|
|
5
|
+
require_relative "../algorithm_registry"
|
|
6
|
+
|
|
7
|
+
module Omnizip
|
|
8
|
+
module Formats
|
|
9
|
+
# GZIP compression format
|
|
10
|
+
#
|
|
11
|
+
# GZIP is a file compression format that wraps Deflate compression
|
|
12
|
+
# with a 10-byte header and 8-byte footer containing CRC32 and
|
|
13
|
+
# uncompressed size.
|
|
14
|
+
#
|
|
15
|
+
# Format structure:
|
|
16
|
+
# - Header (10 bytes minimum):
|
|
17
|
+
# - Magic bytes: 0x1F 0x8B
|
|
18
|
+
# - Compression method: 0x08 (Deflate)
|
|
19
|
+
# - Flags
|
|
20
|
+
# - Modification time (4 bytes)
|
|
21
|
+
# - Extra flags
|
|
22
|
+
# - OS type
|
|
23
|
+
# - Compressed data (Deflate)
|
|
24
|
+
# - Footer (8 bytes):
|
|
25
|
+
# - CRC32 (4 bytes)
|
|
26
|
+
# - Uncompressed size (4 bytes, modulo 2^32)
|
|
27
|
+
module Gzip
|
|
28
|
+
# GZIP magic bytes
|
|
29
|
+
GZIP_MAGIC = [0x1F, 0x8B].pack("C*")
|
|
30
|
+
|
|
31
|
+
# Compression method (Deflate)
|
|
32
|
+
CM_DEFLATE = 8
|
|
33
|
+
|
|
34
|
+
# Flag bits
|
|
35
|
+
FTEXT = 0x01 # File is text
|
|
36
|
+
FHCRC = 0x02 # Header CRC present
|
|
37
|
+
FEXTRA = 0x04 # Extra fields present
|
|
38
|
+
FNAME = 0x08 # Original filename present
|
|
39
|
+
FCOMMENT = 0x10 # Comment present
|
|
40
|
+
|
|
41
|
+
# OS types
|
|
42
|
+
OS_FAT = 0 # FAT filesystem
|
|
43
|
+
OS_UNIX = 3 # Unix
|
|
44
|
+
OS_UNKNOWN = 255 # Unknown
|
|
45
|
+
|
|
46
|
+
class << self
|
|
47
|
+
# Compress a file with GZIP
|
|
48
|
+
#
|
|
49
|
+
# @param input_path [String] Input file path
|
|
50
|
+
# @param output_path [String] Output GZIP file path
|
|
51
|
+
# @param options [Hash] Compression options
|
|
52
|
+
# @option options [Integer] :level Compression level (0-9)
|
|
53
|
+
# @option options [String] :original_name Original filename
|
|
54
|
+
# @option options [Time] :mtime Modification time
|
|
55
|
+
def compress(input_path, output_path, options = {})
|
|
56
|
+
input_data = File.binread(input_path)
|
|
57
|
+
|
|
58
|
+
File.open(output_path, "wb") do |output|
|
|
59
|
+
original_name = options[:original_name] ||
|
|
60
|
+
File.basename(input_path)
|
|
61
|
+
compress_stream(
|
|
62
|
+
StringIO.new(input_data),
|
|
63
|
+
output,
|
|
64
|
+
options.merge(original_name: original_name),
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Decompress a GZIP file
|
|
70
|
+
#
|
|
71
|
+
# @param input_path [String] Input GZIP file path
|
|
72
|
+
# @param output_path [String] Output file path
|
|
73
|
+
def decompress(input_path, output_path)
|
|
74
|
+
File.open(input_path, "rb") do |input|
|
|
75
|
+
File.open(output_path, "wb") do |output|
|
|
76
|
+
decompress_stream(input, output)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Compress data stream with GZIP
|
|
82
|
+
#
|
|
83
|
+
# @param input_io [IO] Input stream
|
|
84
|
+
# @param output_io [IO] Output stream
|
|
85
|
+
# @param options [Hash] Compression options
|
|
86
|
+
def compress_stream(input_io, output_io, options = {})
|
|
87
|
+
input_data = input_io.read
|
|
88
|
+
level = options[:level] || Zlib::DEFAULT_COMPRESSION
|
|
89
|
+
mtime = options[:mtime] || Time.now
|
|
90
|
+
original_name = options[:original_name]
|
|
91
|
+
|
|
92
|
+
# Write GZIP header
|
|
93
|
+
write_header(output_io, mtime, original_name)
|
|
94
|
+
|
|
95
|
+
# Compress data with Deflate
|
|
96
|
+
deflate = Zlib::Deflate.new(
|
|
97
|
+
level,
|
|
98
|
+
Zlib::MAX_WBITS + 16, # Use GZIP wrapper
|
|
99
|
+
)
|
|
100
|
+
compressed = deflate.deflate(input_data, Zlib::FINISH)
|
|
101
|
+
deflate.close
|
|
102
|
+
|
|
103
|
+
# Extract just the compressed data (remove zlib's GZIP wrapper)
|
|
104
|
+
# We'll write our own footer
|
|
105
|
+
output_io.write(compressed[0...-8]) if compressed.bytesize > 8
|
|
106
|
+
|
|
107
|
+
# Write GZIP footer
|
|
108
|
+
write_footer(output_io, input_data)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Decompress GZIP stream
|
|
112
|
+
#
|
|
113
|
+
# @param input_io [IO] Input stream
|
|
114
|
+
# @param output_io [IO] Output stream
|
|
115
|
+
# @return [Hash] Metadata (original_name, mtime)
|
|
116
|
+
def decompress_stream(input_io, output_io)
|
|
117
|
+
# Read and parse header
|
|
118
|
+
metadata = read_header(input_io)
|
|
119
|
+
|
|
120
|
+
# Decompress with Deflate
|
|
121
|
+
inflate = Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
|
|
122
|
+
decompressed = inflate.inflate(input_io.read)
|
|
123
|
+
inflate.close
|
|
124
|
+
|
|
125
|
+
# Write decompressed data
|
|
126
|
+
output_io.write(decompressed)
|
|
127
|
+
|
|
128
|
+
metadata
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Register GZIP format when loaded
|
|
132
|
+
def register!
|
|
133
|
+
require_relative "../format_registry"
|
|
134
|
+
FormatRegistry.register(".gz", Omnizip::Formats::Gzip)
|
|
135
|
+
FormatRegistry.register(".gzip", Omnizip::Formats::Gzip)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
# Write GZIP header
|
|
141
|
+
#
|
|
142
|
+
# @param output [IO] Output stream
|
|
143
|
+
# @param mtime [Time] Modification time
|
|
144
|
+
# @param original_name [String, nil] Original filename
|
|
145
|
+
def write_header(output, mtime, original_name = nil)
|
|
146
|
+
flags = 0
|
|
147
|
+
flags |= FNAME if original_name
|
|
148
|
+
|
|
149
|
+
header = [
|
|
150
|
+
0x1F, 0x8B, # Magic
|
|
151
|
+
CM_DEFLATE, # Compression method
|
|
152
|
+
flags, # Flags
|
|
153
|
+
mtime.to_i, # Modification time
|
|
154
|
+
0, # Extra flags
|
|
155
|
+
OS_UNIX # OS type
|
|
156
|
+
].pack("C C C C V C C")
|
|
157
|
+
|
|
158
|
+
output.write(header)
|
|
159
|
+
|
|
160
|
+
# Write original filename if present
|
|
161
|
+
return unless original_name
|
|
162
|
+
|
|
163
|
+
output.write(original_name)
|
|
164
|
+
output.write("\0")
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Read GZIP header
|
|
168
|
+
#
|
|
169
|
+
# @param input [IO] Input stream
|
|
170
|
+
# @return [Hash] Header metadata
|
|
171
|
+
def read_header(input)
|
|
172
|
+
magic = input.read(2)
|
|
173
|
+
unless magic == GZIP_MAGIC
|
|
174
|
+
raise Error, "Not a GZIP file (invalid magic bytes)"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
cm = input.read(1).unpack1("C")
|
|
178
|
+
unless cm == CM_DEFLATE
|
|
179
|
+
raise Error, "Unsupported GZIP compression method: #{cm}"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
flags = input.read(1).unpack1("C")
|
|
183
|
+
mtime = Time.at(input.read(4).unpack1("V"))
|
|
184
|
+
_xfl = input.read(1)
|
|
185
|
+
_os = input.read(1)
|
|
186
|
+
|
|
187
|
+
metadata = { mtime: mtime }
|
|
188
|
+
|
|
189
|
+
# Read extra fields if present
|
|
190
|
+
if flags.anybits?(FEXTRA)
|
|
191
|
+
xlen = input.read(2).unpack1("v")
|
|
192
|
+
input.read(xlen) # Skip extra data
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Read original filename if present
|
|
196
|
+
if flags.anybits?(FNAME)
|
|
197
|
+
name = +""
|
|
198
|
+
loop do
|
|
199
|
+
byte = input.read(1)
|
|
200
|
+
break if byte == "\0"
|
|
201
|
+
|
|
202
|
+
name << byte
|
|
203
|
+
end
|
|
204
|
+
metadata[:original_name] = name
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Read comment if present
|
|
208
|
+
if flags.anybits?(FCOMMENT)
|
|
209
|
+
loop do
|
|
210
|
+
byte = input.read(1)
|
|
211
|
+
break if byte == "\0"
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Read header CRC if present
|
|
216
|
+
input.read(2) if flags.anybits?(FHCRC)
|
|
217
|
+
|
|
218
|
+
metadata
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Write GZIP footer
|
|
222
|
+
#
|
|
223
|
+
# @param output [IO] Output stream
|
|
224
|
+
# @param uncompressed_data [String] Original uncompressed data
|
|
225
|
+
def write_footer(output, uncompressed_data)
|
|
226
|
+
crc32 = Zlib.crc32(uncompressed_data)
|
|
227
|
+
size = uncompressed_data.bytesize & 0xFFFFFFFF
|
|
228
|
+
|
|
229
|
+
footer = [crc32, size].pack("VV")
|
|
230
|
+
output.write(footer)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Auto-register on load
|
|
238
|
+
Omnizip::Formats::Gzip.register!
|