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,205 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# API Comparison Demo
|
|
6
|
+
# Shows both Rubyzip compatibility and native Omnizip APIs side-by-side
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
puts "=== Omnizip: Dual API Demonstration ==="
|
|
10
|
+
puts "Showing both rubyzip-compatible and native APIs"
|
|
11
|
+
puts
|
|
12
|
+
|
|
13
|
+
require "tmpdir"
|
|
14
|
+
tmpdir = Dir.mktmpdir("omnizip_comparison")
|
|
15
|
+
|
|
16
|
+
# =============================================================================
|
|
17
|
+
# Example 1: Creating an archive
|
|
18
|
+
# =============================================================================
|
|
19
|
+
puts "1. Creating a ZIP archive"
|
|
20
|
+
puts " #{'=' * 70}"
|
|
21
|
+
|
|
22
|
+
zip1_path = File.join(tmpdir, "compat.zip")
|
|
23
|
+
zip2_path = File.join(tmpdir, "native.zip")
|
|
24
|
+
|
|
25
|
+
# Rubyzip-compatible approach
|
|
26
|
+
puts "\n A) Rubyzip-compatible API:"
|
|
27
|
+
puts " #{'-' * 70}"
|
|
28
|
+
puts <<~CODE
|
|
29
|
+
require 'omnizip/rubyzip_compat'
|
|
30
|
+
|
|
31
|
+
Zip::File.open('archive.zip', create: true) do |zip|
|
|
32
|
+
zip.add('file.txt') { 'Content' }
|
|
33
|
+
end
|
|
34
|
+
CODE
|
|
35
|
+
|
|
36
|
+
require "omnizip/rubyzip_compat"
|
|
37
|
+
Zip::File.open(zip1_path, create: true) do |zip|
|
|
38
|
+
zip.add("file.txt") { "Content from rubyzip API" }
|
|
39
|
+
end
|
|
40
|
+
puts " ✓ Created: #{zip1_path}"
|
|
41
|
+
|
|
42
|
+
# Native Omnizip approach
|
|
43
|
+
puts "\n B) Native Omnizip API:"
|
|
44
|
+
puts " #{'-' * 70}"
|
|
45
|
+
puts <<~CODE
|
|
46
|
+
require 'omnizip'
|
|
47
|
+
|
|
48
|
+
Omnizip::Zip::File.create('archive.zip') do |zip|
|
|
49
|
+
zip.add('file.txt') { 'Content' }
|
|
50
|
+
end
|
|
51
|
+
CODE
|
|
52
|
+
|
|
53
|
+
require "omnizip"
|
|
54
|
+
Omnizip::Zip::File.create(zip2_path) do |zip|
|
|
55
|
+
zip.add("file.txt") { "Content from native API" }
|
|
56
|
+
end
|
|
57
|
+
puts " ✓ Created: #{zip2_path}"
|
|
58
|
+
|
|
59
|
+
# =============================================================================
|
|
60
|
+
# Example 2: Reading an archive
|
|
61
|
+
# =============================================================================
|
|
62
|
+
puts "\n\n2. Reading archive contents"
|
|
63
|
+
puts " #{'=' * 70}"
|
|
64
|
+
|
|
65
|
+
# Rubyzip-compatible approach
|
|
66
|
+
puts "\n A) Rubyzip-compatible API:"
|
|
67
|
+
puts " #{'-' * 70}"
|
|
68
|
+
puts <<~CODE
|
|
69
|
+
Zip::File.open('archive.zip') do |zip|
|
|
70
|
+
content = zip.read('file.txt')
|
|
71
|
+
puts content
|
|
72
|
+
end
|
|
73
|
+
CODE
|
|
74
|
+
|
|
75
|
+
content1 = Zip::File.open(zip1_path) { |zip| zip.read("file.txt") }
|
|
76
|
+
puts " ✓ Read: #{content1}"
|
|
77
|
+
|
|
78
|
+
# Native Omnizip approach
|
|
79
|
+
puts "\n B) Native Omnizip API (convenience method):"
|
|
80
|
+
puts " #{'-' * 70}"
|
|
81
|
+
puts <<~CODE
|
|
82
|
+
content = Omnizip.read_from_archive('archive.zip', 'file.txt')
|
|
83
|
+
puts content
|
|
84
|
+
CODE
|
|
85
|
+
|
|
86
|
+
content2 = Omnizip.read_from_archive(zip2_path, "file.txt")
|
|
87
|
+
puts " ✓ Read: #{content2}"
|
|
88
|
+
|
|
89
|
+
# =============================================================================
|
|
90
|
+
# Example 3: Working with directories
|
|
91
|
+
# =============================================================================
|
|
92
|
+
puts "\n\n3. Compressing a directory"
|
|
93
|
+
puts " #{'=' * 70}"
|
|
94
|
+
|
|
95
|
+
# Create sample directory
|
|
96
|
+
sample_dir = File.join(tmpdir, "sample")
|
|
97
|
+
FileUtils.mkdir_p(File.join(sample_dir, "subdir"))
|
|
98
|
+
File.write(File.join(sample_dir, "file1.txt"), "File 1")
|
|
99
|
+
File.write(File.join(sample_dir, "file2.txt"), "File 2")
|
|
100
|
+
File.write(File.join(sample_dir, "subdir", "file3.txt"), "File 3")
|
|
101
|
+
|
|
102
|
+
zip3_path = File.join(tmpdir, "dir_compat.zip")
|
|
103
|
+
zip4_path = File.join(tmpdir, "dir_native.zip")
|
|
104
|
+
|
|
105
|
+
# Rubyzip-compatible approach
|
|
106
|
+
puts "\n A) Rubyzip-compatible API (manual iteration):"
|
|
107
|
+
puts " #{'-' * 70}"
|
|
108
|
+
puts <<~CODE
|
|
109
|
+
Zip::File.open('backup.zip', create: true) do |zip|
|
|
110
|
+
Dir.glob('dir/**/*').each do |file|
|
|
111
|
+
next if File.directory?(file)
|
|
112
|
+
zip.add(file.sub('dir/', ''), file)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
CODE
|
|
116
|
+
|
|
117
|
+
Zip::File.open(zip3_path, create: true) do |zip|
|
|
118
|
+
Dir.glob(File.join(sample_dir, "**/*")).each do |file|
|
|
119
|
+
rel_path = file.sub("#{sample_dir}/", "")
|
|
120
|
+
if File.directory?(file)
|
|
121
|
+
zip.add("#{rel_path}/")
|
|
122
|
+
else
|
|
123
|
+
zip.add(rel_path, file)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
puts " ✓ Created with #{Zip::File.open(zip3_path) do |z|
|
|
128
|
+
z.entries.size
|
|
129
|
+
end} entries"
|
|
130
|
+
|
|
131
|
+
# Native Omnizip approach
|
|
132
|
+
puts "\n B) Native Omnizip API (one-liner):"
|
|
133
|
+
puts " #{'-' * 70}"
|
|
134
|
+
puts <<~CODE
|
|
135
|
+
Omnizip.compress_directory('dir/', 'backup.zip')
|
|
136
|
+
CODE
|
|
137
|
+
|
|
138
|
+
Omnizip.compress_directory(sample_dir, zip4_path)
|
|
139
|
+
puts " ✓ Created with #{Omnizip.list_archive(zip4_path).size} entries"
|
|
140
|
+
|
|
141
|
+
# =============================================================================
|
|
142
|
+
# Example 4: Both APIs work on same archive
|
|
143
|
+
# =============================================================================
|
|
144
|
+
puts "\n\n4. Both APIs can work on the same archive"
|
|
145
|
+
puts " #{'=' * 70}"
|
|
146
|
+
|
|
147
|
+
shared_zip = File.join(tmpdir, "shared.zip")
|
|
148
|
+
|
|
149
|
+
# Create with rubyzip API
|
|
150
|
+
puts "\n Creating with Rubyzip API..."
|
|
151
|
+
Zip::File.create(shared_zip) do |zip|
|
|
152
|
+
zip.add("from_rubyzip.txt") { "Created with Zip::" }
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Modify with native API
|
|
156
|
+
puts " Modifying with Native API..."
|
|
157
|
+
source = File.join(tmpdir, "from_native.txt")
|
|
158
|
+
File.write(source, "Added with Omnizip")
|
|
159
|
+
Omnizip.add_to_archive(shared_zip, "from_native.txt", source)
|
|
160
|
+
|
|
161
|
+
# Read with both APIs
|
|
162
|
+
puts "\n Reading with both APIs:"
|
|
163
|
+
Zip::File.open(shared_zip) do |zip|
|
|
164
|
+
puts " - Rubyzip sees: #{zip.names.join(', ')}"
|
|
165
|
+
end
|
|
166
|
+
puts " - Native sees: #{Omnizip.list_archive(shared_zip).join(', ')}"
|
|
167
|
+
|
|
168
|
+
# =============================================================================
|
|
169
|
+
# Summary
|
|
170
|
+
# =============================================================================
|
|
171
|
+
puts "\n\n#{'=' * 76}"
|
|
172
|
+
puts "SUMMARY: Which API should you use?"
|
|
173
|
+
puts "=" * 76
|
|
174
|
+
puts <<~SUMMARY
|
|
175
|
+
|
|
176
|
+
┌─ Rubyzip Compatibility API ────────────────────────────────────────┐
|
|
177
|
+
│ │
|
|
178
|
+
│ Use when: │
|
|
179
|
+
│ • Migrating from rubyzip │
|
|
180
|
+
│ • Maintaining existing code │
|
|
181
|
+
│ • Need drop-in compatibility │
|
|
182
|
+
│ │
|
|
183
|
+
│ require 'omnizip/rubyzip_compat' │
|
|
184
|
+
│ Zip::File.open('archive.zip') { ... } │
|
|
185
|
+
│ │
|
|
186
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
187
|
+
|
|
188
|
+
┌─ Native Omnizip API ───────────────────────────────────────────────┐
|
|
189
|
+
│ │
|
|
190
|
+
│ Use when: │
|
|
191
|
+
│ • Starting new projects │
|
|
192
|
+
│ • Want convenience methods │
|
|
193
|
+
│ • Need cleaner, more Ruby-idiomatic code │
|
|
194
|
+
│ │
|
|
195
|
+
│ require 'omnizip' │
|
|
196
|
+
│ Omnizip.compress_file('file.txt', 'archive.zip') │
|
|
197
|
+
│ │
|
|
198
|
+
└─────────────────────────────────────────────────────────────────────┘
|
|
199
|
+
|
|
200
|
+
💡 Both APIs work seamlessly together - choose based on your needs!
|
|
201
|
+
|
|
202
|
+
SUMMARY
|
|
203
|
+
|
|
204
|
+
puts "All demo files created in: #{tmpdir}"
|
|
205
|
+
puts
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "omnizip"
|
|
6
|
+
|
|
7
|
+
# Example: Using Deflate64 compression algorithm
|
|
8
|
+
#
|
|
9
|
+
# Deflate64 (Enhanced Deflate) extends standard Deflate with:
|
|
10
|
+
# - 64KB sliding window (vs 32KB)
|
|
11
|
+
# - Better compression for large files
|
|
12
|
+
# - ZIP compression method 9
|
|
13
|
+
|
|
14
|
+
puts "=" * 60
|
|
15
|
+
puts "Deflate64 Algorithm Example"
|
|
16
|
+
puts "=" * 60
|
|
17
|
+
puts
|
|
18
|
+
|
|
19
|
+
# Example 1: Basic Deflate64 compression
|
|
20
|
+
puts "1. Basic Deflate64 compression"
|
|
21
|
+
puts "-" * 60
|
|
22
|
+
|
|
23
|
+
original_data = "Hello, World! " * 1000
|
|
24
|
+
puts "Original size: #{original_data.bytesize} bytes"
|
|
25
|
+
|
|
26
|
+
# Compress using Deflate64
|
|
27
|
+
compressed = StringIO.new
|
|
28
|
+
algorithm = Omnizip::Algorithms::Deflate64.new
|
|
29
|
+
algorithm.compress(StringIO.new(original_data), compressed)
|
|
30
|
+
|
|
31
|
+
puts "Compressed size: #{compressed.string.bytesize} bytes"
|
|
32
|
+
puts "Compression ratio: #{(compressed.string.bytesize.to_f / original_data.bytesize * 100).round(2)}%"
|
|
33
|
+
|
|
34
|
+
# Decompress
|
|
35
|
+
decompressed = StringIO.new
|
|
36
|
+
algorithm.decompress(StringIO.new(compressed.string), decompressed)
|
|
37
|
+
|
|
38
|
+
puts "Decompressed size: #{decompressed.string.bytesize} bytes"
|
|
39
|
+
puts "Data integrity: #{decompressed.string == original_data ? '✓ OK' : '✗ FAILED'}"
|
|
40
|
+
puts
|
|
41
|
+
|
|
42
|
+
# Example 2: Deflate64 with large data (benefits from 64KB window)
|
|
43
|
+
puts "2. Deflate64 with large repetitive data"
|
|
44
|
+
puts "-" * 60
|
|
45
|
+
|
|
46
|
+
large_data = ("Pattern#{rand(1000)} " * 100) * 500
|
|
47
|
+
puts "Original size: #{large_data.bytesize} bytes"
|
|
48
|
+
|
|
49
|
+
compressed_large = StringIO.new
|
|
50
|
+
algorithm.compress(StringIO.new(large_data), compressed_large)
|
|
51
|
+
|
|
52
|
+
puts "Compressed size: #{compressed_large.string.bytesize} bytes"
|
|
53
|
+
puts "Compression ratio: #{(compressed_large.string.bytesize.to_f / large_data.bytesize * 100).round(2)}%"
|
|
54
|
+
puts
|
|
55
|
+
|
|
56
|
+
# Example 3: Creating a ZIP archive with Deflate64
|
|
57
|
+
puts "3. Creating ZIP archive with Deflate64"
|
|
58
|
+
puts "-" * 60
|
|
59
|
+
|
|
60
|
+
# Note: This requires ZIP format integration
|
|
61
|
+
# Once integrated, usage would be:
|
|
62
|
+
#
|
|
63
|
+
# Omnizip::Archive.create("test.zip") do |archive|
|
|
64
|
+
# archive.compression_method = :deflate64
|
|
65
|
+
# archive.add_file("example.txt", "Large file content...")
|
|
66
|
+
# end
|
|
67
|
+
|
|
68
|
+
puts "ZIP integration: Coming in v2.0"
|
|
69
|
+
puts "Deflate64 will be available as compression method 9"
|
|
70
|
+
puts
|
|
71
|
+
|
|
72
|
+
# Example 4: Algorithm metadata
|
|
73
|
+
puts "4. Deflate64 algorithm metadata"
|
|
74
|
+
puts "-" * 60
|
|
75
|
+
|
|
76
|
+
metadata = Omnizip::Algorithms::Deflate64.metadata
|
|
77
|
+
puts "Name: #{metadata[:name]}"
|
|
78
|
+
puts "Type: #{metadata[:type]}"
|
|
79
|
+
puts "Dictionary size: #{metadata[:dictionary_size]} bytes (#{metadata[:dictionary_size] / 1024}KB)"
|
|
80
|
+
puts "ZIP method ID: #{metadata[:compression_method]}"
|
|
81
|
+
puts "Streaming: #{metadata[:streaming_supported] ? 'Yes' : 'No'}"
|
|
82
|
+
puts
|
|
83
|
+
|
|
84
|
+
# Example 5: Comparison with standard Deflate
|
|
85
|
+
puts "5. Deflate64 advantages"
|
|
86
|
+
puts "-" * 60
|
|
87
|
+
puts "✓ 64KB dictionary (2x larger than standard Deflate)"
|
|
88
|
+
puts "✓ Better compression for files > 32KB"
|
|
89
|
+
puts "✓ Fully compatible with 7-Zip and PKZip"
|
|
90
|
+
puts "✓ Streaming support for large files"
|
|
91
|
+
puts "✓ Same Huffman coding as standard Deflate"
|
|
92
|
+
puts
|
|
93
|
+
|
|
94
|
+
puts "=" * 60
|
|
95
|
+
puts "Example complete!"
|
|
96
|
+
puts "=" * 60
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# PAR2 Parity Archive Demo
|
|
5
|
+
# Demonstrates creating, verifying, and repairing files with PAR2 error correction
|
|
6
|
+
|
|
7
|
+
require "bundler/setup"
|
|
8
|
+
require "omnizip/parity"
|
|
9
|
+
require "tempfile"
|
|
10
|
+
require "fileutils"
|
|
11
|
+
|
|
12
|
+
def demo_par2_workflow
|
|
13
|
+
puts "=== PAR2 Parity Archive Demo ==="
|
|
14
|
+
puts
|
|
15
|
+
|
|
16
|
+
# Create temporary directory for demo
|
|
17
|
+
temp_dir = Dir.mktmpdir("par2_demo")
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
# Step 1: Create test files
|
|
21
|
+
puts "Step 1: Creating test files..."
|
|
22
|
+
file1 = File.join(temp_dir, "important_data.txt")
|
|
23
|
+
file2 = File.join(temp_dir, "documents.txt")
|
|
24
|
+
|
|
25
|
+
File.write(file1, "This is important data! " * 100)
|
|
26
|
+
File.write(file2, "These are valuable documents. " * 100)
|
|
27
|
+
puts " ✓ Created test files (#{File.size(file1) + File.size(file2)} bytes total)"
|
|
28
|
+
puts
|
|
29
|
+
|
|
30
|
+
# Step 2: Create PAR2 protection
|
|
31
|
+
puts "Step 2: Creating PAR2 recovery files with 10% redundancy..."
|
|
32
|
+
creator = Omnizip::Parity::Par2Creator.new(
|
|
33
|
+
redundancy: 10,
|
|
34
|
+
block_size: 1024,
|
|
35
|
+
progress: ->(pct, msg) { puts " [#{pct}%] #{msg}" },
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
creator.add_file(file1)
|
|
39
|
+
creator.add_file(file2)
|
|
40
|
+
|
|
41
|
+
par2_files = creator.create(File.join(temp_dir, "backup"))
|
|
42
|
+
puts " ✓ Created #{par2_files.size} PAR2 files"
|
|
43
|
+
par2_files.each { |f| puts " - #{File.basename(f)}" }
|
|
44
|
+
puts
|
|
45
|
+
|
|
46
|
+
# Step 3: Verify intact files
|
|
47
|
+
puts "Step 3: Verifying file integrity..."
|
|
48
|
+
verifier = Omnizip::Parity::Par2Verifier.new(par2_files.first)
|
|
49
|
+
result = verifier.verify
|
|
50
|
+
|
|
51
|
+
if result.all_ok?
|
|
52
|
+
puts " ✓ All files intact!"
|
|
53
|
+
puts " Total blocks: #{result.total_blocks}"
|
|
54
|
+
puts " Recovery blocks: #{result.recovery_blocks}"
|
|
55
|
+
else
|
|
56
|
+
puts " ✗ Verification failed (unexpected!)"
|
|
57
|
+
end
|
|
58
|
+
puts
|
|
59
|
+
|
|
60
|
+
# Step 4: Simulate corruption
|
|
61
|
+
puts "Step 4: Simulating file corruption..."
|
|
62
|
+
corrupted_content = "CORRUPTED DATA! " * 100
|
|
63
|
+
File.write(file1, corrupted_content)
|
|
64
|
+
puts " ✓ Corrupted #{File.basename(file1)}"
|
|
65
|
+
puts
|
|
66
|
+
|
|
67
|
+
# Step 5: Verify corrupted file
|
|
68
|
+
puts "Step 5: Verifying corrupted files..."
|
|
69
|
+
result2 = verifier.verify
|
|
70
|
+
|
|
71
|
+
if result2.all_ok?
|
|
72
|
+
puts " ✗ No corruption detected (unexpected!)"
|
|
73
|
+
else
|
|
74
|
+
puts " ✓ Detected corruption:"
|
|
75
|
+
puts " Damaged files: #{result2.damaged_files.join(', ')}"
|
|
76
|
+
puts " Damaged blocks: #{result2.damaged_blocks.size}"
|
|
77
|
+
puts " Repairable: #{result2.repairable?}"
|
|
78
|
+
end
|
|
79
|
+
puts
|
|
80
|
+
|
|
81
|
+
# Step 6: Repair damaged file
|
|
82
|
+
if result2.repairable?
|
|
83
|
+
puts "Step 6: Repairing corrupted files..."
|
|
84
|
+
repairer = Omnizip::Parity::Par2Repairer.new(
|
|
85
|
+
par2_files.first,
|
|
86
|
+
progress: ->(pct, msg) { puts " [#{pct}%] #{msg}" },
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
repair_result = repairer.repair
|
|
90
|
+
|
|
91
|
+
if repair_result.success?
|
|
92
|
+
puts " ✓ Repair successful!"
|
|
93
|
+
puts " Recovered files: #{repair_result.recovered_files.join(', ')}"
|
|
94
|
+
puts " Recovered blocks: #{repair_result.recovered_blocks}"
|
|
95
|
+
|
|
96
|
+
# Verify repair worked
|
|
97
|
+
result3 = verifier.verify
|
|
98
|
+
if result3.all_ok?
|
|
99
|
+
puts " ✓ Verification after repair: All files intact!"
|
|
100
|
+
else
|
|
101
|
+
puts " ✗ Verification after repair failed"
|
|
102
|
+
end
|
|
103
|
+
else
|
|
104
|
+
puts " ✗ Repair failed: #{repair_result.error_message}"
|
|
105
|
+
end
|
|
106
|
+
else
|
|
107
|
+
puts "Step 6: Cannot repair - insufficient recovery blocks"
|
|
108
|
+
end
|
|
109
|
+
ensure
|
|
110
|
+
# Cleanup
|
|
111
|
+
puts
|
|
112
|
+
puts "Cleaning up temporary files..."
|
|
113
|
+
FileUtils.rm_rf(temp_dir)
|
|
114
|
+
puts "Demo complete!"
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Run the demo
|
|
119
|
+
if __FILE__ == $PROGRAM_NAME
|
|
120
|
+
demo_par2_workflow
|
|
121
|
+
end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Native Omnizip API Demo
|
|
6
|
+
# Shows how to use Omnizip's native convenience methods
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require "omnizip"
|
|
10
|
+
|
|
11
|
+
puts "=== Native Omnizip API Demo ==="
|
|
12
|
+
puts "Using Omnizip's native convenience methods"
|
|
13
|
+
puts
|
|
14
|
+
|
|
15
|
+
# Create a temporary directory for examples
|
|
16
|
+
require "tmpdir"
|
|
17
|
+
tmpdir = Dir.mktmpdir("omnizip_native_demo")
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
# Example 1: Compress a single file
|
|
21
|
+
puts "1. Compressing a single file..."
|
|
22
|
+
source_file = File.join(tmpdir, "document.txt")
|
|
23
|
+
File.write(source_file, "This is a sample document with some content.")
|
|
24
|
+
|
|
25
|
+
zip_file = File.join(tmpdir, "document.zip")
|
|
26
|
+
Omnizip.compress_file(source_file, zip_file)
|
|
27
|
+
|
|
28
|
+
puts " Compressed: #{source_file} -> #{zip_file}"
|
|
29
|
+
puts " Original size: #{File.size(source_file)} bytes"
|
|
30
|
+
puts " Compressed size: #{File.size(zip_file)} bytes"
|
|
31
|
+
puts
|
|
32
|
+
|
|
33
|
+
# Example 2: Compress a directory
|
|
34
|
+
puts "2. Compressing a directory..."
|
|
35
|
+
source_dir = File.join(tmpdir, "project")
|
|
36
|
+
FileUtils.mkdir_p(File.join(source_dir, "src"))
|
|
37
|
+
FileUtils.mkdir_p(File.join(source_dir, "docs"))
|
|
38
|
+
File.write(File.join(source_dir, "README.md"), "# Project README")
|
|
39
|
+
File.write(File.join(source_dir, "src", "main.rb"), "puts 'Hello, World!'")
|
|
40
|
+
File.write(File.join(source_dir, "docs", "guide.txt"), "User Guide")
|
|
41
|
+
|
|
42
|
+
backup_zip = File.join(tmpdir, "project_backup.zip")
|
|
43
|
+
Omnizip.compress_directory(source_dir, backup_zip)
|
|
44
|
+
|
|
45
|
+
puts " Compressed directory: #{source_dir}"
|
|
46
|
+
puts " Archive created: #{backup_zip}"
|
|
47
|
+
puts
|
|
48
|
+
|
|
49
|
+
# Example 3: List archive contents
|
|
50
|
+
puts "3. Listing archive contents..."
|
|
51
|
+
names = Omnizip.list_archive(backup_zip)
|
|
52
|
+
puts " Archive contains #{names.size} entries:"
|
|
53
|
+
names.each { |name| puts " - #{name}" }
|
|
54
|
+
puts
|
|
55
|
+
|
|
56
|
+
# Example 4: List with details
|
|
57
|
+
puts "4. Listing with detailed information..."
|
|
58
|
+
details = Omnizip.list_archive(backup_zip, details: true)
|
|
59
|
+
details.each do |entry|
|
|
60
|
+
type = entry[:directory] ? "[DIR]" : "[FILE]"
|
|
61
|
+
ratio = entry[:size].positive? ? (100 * entry[:compressed_size].to_f / entry[:size]).round(1) : 0
|
|
62
|
+
puts " #{type} #{entry[:name]}"
|
|
63
|
+
puts " Size: #{entry[:size]} bytes, Compressed: #{entry[:compressed_size]} bytes (#{ratio}%)"
|
|
64
|
+
end
|
|
65
|
+
puts
|
|
66
|
+
|
|
67
|
+
# Example 5: Read a file from archive
|
|
68
|
+
puts "5. Reading file from archive..."
|
|
69
|
+
content = Omnizip.read_from_archive(backup_zip, "README.md")
|
|
70
|
+
puts " README.md content:"
|
|
71
|
+
puts " #{content}"
|
|
72
|
+
puts
|
|
73
|
+
|
|
74
|
+
# Example 6: Extract archive
|
|
75
|
+
puts "6. Extracting archive..."
|
|
76
|
+
extract_dir = File.join(tmpdir, "extracted")
|
|
77
|
+
extracted_files = Omnizip.extract_archive(backup_zip, extract_dir)
|
|
78
|
+
|
|
79
|
+
puts " Extracted #{extracted_files.size} entries to: #{extract_dir}"
|
|
80
|
+
extracted_files.each { |f| puts " - #{f}" }
|
|
81
|
+
puts
|
|
82
|
+
|
|
83
|
+
# Example 7: Add file to existing archive
|
|
84
|
+
puts "7. Adding file to existing archive..."
|
|
85
|
+
new_file = File.join(tmpdir, "changelog.txt")
|
|
86
|
+
File.write(new_file, "v1.0.0 - Initial release")
|
|
87
|
+
|
|
88
|
+
Omnizip.add_to_archive(backup_zip, "CHANGELOG.txt", new_file)
|
|
89
|
+
|
|
90
|
+
updated_names = Omnizip.list_archive(backup_zip)
|
|
91
|
+
puts " Added CHANGELOG.txt to archive"
|
|
92
|
+
puts " Archive now has #{updated_names.size} entries"
|
|
93
|
+
puts
|
|
94
|
+
|
|
95
|
+
# Example 8: Remove file from archive
|
|
96
|
+
puts "8. Removing file from archive..."
|
|
97
|
+
Omnizip.remove_from_archive(backup_zip, "docs/guide.txt")
|
|
98
|
+
|
|
99
|
+
final_names = Omnizip.list_archive(backup_zip)
|
|
100
|
+
puts " Removed docs/guide.txt"
|
|
101
|
+
puts " Archive now has #{final_names.size} entries"
|
|
102
|
+
puts
|
|
103
|
+
|
|
104
|
+
# Example 9: Using low-level API for advanced features
|
|
105
|
+
puts "9. Using low-level API for advanced control..."
|
|
106
|
+
advanced_zip = File.join(tmpdir, "advanced.zip")
|
|
107
|
+
|
|
108
|
+
Omnizip::Zip::File.create(advanced_zip) do |zip|
|
|
109
|
+
zip.add("data.txt") { "Some data" }
|
|
110
|
+
zip.add("more_data.txt") { "More data" }
|
|
111
|
+
|
|
112
|
+
# Set archive comment
|
|
113
|
+
zip.comment = "Created with Omnizip native API"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
Omnizip::Zip::File.open(advanced_zip) do |zip|
|
|
117
|
+
puts " Archive comment: #{zip.comment}"
|
|
118
|
+
puts " Contains #{zip.size} entries"
|
|
119
|
+
end
|
|
120
|
+
puts
|
|
121
|
+
|
|
122
|
+
# Example 10: Streaming API
|
|
123
|
+
puts "10. Using streaming API..."
|
|
124
|
+
stream_zip = File.join(tmpdir, "streamed.zip")
|
|
125
|
+
|
|
126
|
+
Omnizip::Zip::OutputStream.open(stream_zip) do |zos|
|
|
127
|
+
zos.put_next_entry("log.txt")
|
|
128
|
+
zos.puts("Log entry 1")
|
|
129
|
+
zos.puts("Log entry 2")
|
|
130
|
+
zos.puts("Log entry 3")
|
|
131
|
+
|
|
132
|
+
zos.put_next_entry("data.bin")
|
|
133
|
+
zos.write([1, 2, 3, 4, 5].pack("C*"))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
puts " Created streaming archive: #{stream_zip}"
|
|
137
|
+
puts
|
|
138
|
+
|
|
139
|
+
puts "=== Demo Complete ==="
|
|
140
|
+
puts "All files created in: #{tmpdir}"
|
|
141
|
+
puts
|
|
142
|
+
puts "Key advantages of native API:"
|
|
143
|
+
puts " - Simple convenience methods for common operations"
|
|
144
|
+
puts " - Automatic resource management"
|
|
145
|
+
puts " - Clear, readable code"
|
|
146
|
+
puts " - Full control when needed via low-level API"
|
|
147
|
+
|
|
148
|
+
# Cleanup (optional - tmpdir usually handles this)
|
|
149
|
+
# FileUtils.rm_rf(tmpdir)
|
|
150
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# Rubyzip Compatibility Demo
|
|
6
|
+
# Shows how to use Omnizip as a drop-in replacement for rubyzip
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require "omnizip/rubyzip_compat"
|
|
10
|
+
|
|
11
|
+
puts "=== Rubyzip Compatibility Demo ==="
|
|
12
|
+
puts "Using Omnizip with rubyzip-compatible API"
|
|
13
|
+
puts
|
|
14
|
+
|
|
15
|
+
# Create a temporary directory for examples
|
|
16
|
+
require "tmpdir"
|
|
17
|
+
tmpdir = Dir.mktmpdir("omnizip_rubyzip_demo")
|
|
18
|
+
|
|
19
|
+
begin
|
|
20
|
+
# Example 1: Create a ZIP archive using Zip::File
|
|
21
|
+
puts "1. Creating ZIP archive with Zip::File..."
|
|
22
|
+
zip_path = File.join(tmpdir, "example.zip")
|
|
23
|
+
|
|
24
|
+
Zip::File.open(zip_path, create: true) do |zipfile|
|
|
25
|
+
# Add files from block
|
|
26
|
+
zipfile.add("readme.txt") { "This is a README file" }
|
|
27
|
+
zipfile.add("config.yml") { "version: 1.0\nname: example" }
|
|
28
|
+
|
|
29
|
+
# Add directory
|
|
30
|
+
zipfile.add("data/")
|
|
31
|
+
zipfile.add("data/values.txt") { "value1\nvalue2\nvalue3" }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
puts " Created: #{zip_path}"
|
|
35
|
+
puts
|
|
36
|
+
|
|
37
|
+
# Example 2: Read archive contents
|
|
38
|
+
puts "2. Reading archive contents..."
|
|
39
|
+
Zip::File.open(zip_path) do |zipfile|
|
|
40
|
+
puts " Archive contains #{zipfile.entries.size} entries:"
|
|
41
|
+
zipfile.each do |entry|
|
|
42
|
+
type = entry.directory? ? "[DIR]" : "[FILE]"
|
|
43
|
+
puts " #{type} #{entry.name} (#{entry.size} bytes)"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
puts
|
|
47
|
+
|
|
48
|
+
# Example 3: Extract specific file
|
|
49
|
+
puts "3. Extracting specific file..."
|
|
50
|
+
Zip::File.open(zip_path) do |zipfile|
|
|
51
|
+
content = zipfile.read("readme.txt")
|
|
52
|
+
puts " readme.txt content: #{content}"
|
|
53
|
+
end
|
|
54
|
+
puts
|
|
55
|
+
|
|
56
|
+
# Example 4: Use streaming API with Zip::OutputStream
|
|
57
|
+
puts "4. Creating archive with streaming API..."
|
|
58
|
+
stream_zip = File.join(tmpdir, "stream.zip")
|
|
59
|
+
|
|
60
|
+
Zip::OutputStream.open(stream_zip) do |zos|
|
|
61
|
+
zos.put_next_entry("stream1.txt")
|
|
62
|
+
zos.write("First streamed entry")
|
|
63
|
+
|
|
64
|
+
zos.put_next_entry("stream2.txt")
|
|
65
|
+
zos << "Second"
|
|
66
|
+
zos << " entry"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
puts " Created: #{stream_zip}"
|
|
70
|
+
puts
|
|
71
|
+
|
|
72
|
+
# Example 5: Extract all files
|
|
73
|
+
puts "5. Extracting all files..."
|
|
74
|
+
output_dir = File.join(tmpdir, "extracted")
|
|
75
|
+
|
|
76
|
+
Zip::File.open(zip_path) do |zipfile|
|
|
77
|
+
zipfile.each do |entry|
|
|
78
|
+
next if entry.directory?
|
|
79
|
+
|
|
80
|
+
dest_path = File.join(output_dir, entry.name)
|
|
81
|
+
FileUtils.mkdir_p(File.dirname(dest_path))
|
|
82
|
+
zipfile.extract(entry, dest_path) { true } # Overwrite if exists
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
puts " Extracted to: #{output_dir}"
|
|
87
|
+
extracted_files = Dir.glob(File.join(output_dir, "**/*")).select do |f|
|
|
88
|
+
File.file?(f)
|
|
89
|
+
end
|
|
90
|
+
puts " Extracted #{extracted_files.size} files"
|
|
91
|
+
puts
|
|
92
|
+
|
|
93
|
+
# Example 6: Modify existing archive
|
|
94
|
+
puts "6. Modifying existing archive..."
|
|
95
|
+
Zip::File.open(zip_path) do |zipfile|
|
|
96
|
+
# Add new file
|
|
97
|
+
zipfile.add("new_file.txt") { "Added later" }
|
|
98
|
+
|
|
99
|
+
# Remove a file
|
|
100
|
+
zipfile.remove("config.yml")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
Zip::File.open(zip_path) do |zipfile|
|
|
104
|
+
puts " Archive now contains:"
|
|
105
|
+
zipfile.each { |e| puts " - #{e.name}" }
|
|
106
|
+
end
|
|
107
|
+
puts
|
|
108
|
+
|
|
109
|
+
puts "=== Demo Complete ==="
|
|
110
|
+
puts "All files created in: #{tmpdir}"
|
|
111
|
+
puts "Note: Temporary directory will be cleaned up automatically"
|
|
112
|
+
|
|
113
|
+
# Cleanup (optional - tmpdir usually handles this)
|
|
114
|
+
# FileUtils.rm_rf(tmpdir)
|
|
115
|
+
end
|