omnizip 0.4.7-aarch64-linux
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 +293 -0
- data/CHANGELOG.md +1647 -0
- data/CONTEXT.md +68 -0
- data/COPYING +502 -0
- data/Gemfile +19 -0
- data/LICENSE +12 -0
- data/README.adoc +1327 -0
- data/Rakefile +15 -0
- data/TODO.refactor/00-overview.md +67 -0
- data/TODO.refactor/01-registry-base-class.md +81 -0
- data/TODO.refactor/02-error-hierarchy.md +57 -0
- data/TODO.refactor/03-autoload-entry-point.md +69 -0
- data/TODO.refactor/04-filter-base-consolidation.md +49 -0
- data/TODO.refactor/05-send-private-methods.md +64 -0
- data/TODO.refactor/06-instance-variable-access.md +69 -0
- data/TODO.refactor/07-respond-to-replacement.md +237 -0
- data/TODO.refactor/08-spec-doubles.md +27 -0
- data/TODO.refactor/09-cli-shared-module.md +35 -0
- data/TODO.refactor/10-format-detector-ocp.md +34 -0
- data/TODO.refactor/11-convenience-decoupling.md +38 -0
- data/TODO.refactor/12-thread-safety.md +8 -0
- data/TODO.refactor/13-lutaml-model-migration.md +158 -0
- data/TODO.refactor/14-add-missing-specs.md +25 -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 +92 -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 +263 -0
- data/docs/getting-started/index.adoc +42 -0
- data/docs/getting-started/installation.adoc +138 -0
- data/docs/getting-started/quick-start.adoc +183 -0
- data/docs/getting-started/your-first-archive.adoc +219 -0
- data/docs/guides/advanced-features/encryption.adoc +277 -0
- data/docs/guides/advanced-features/index.adoc +59 -0
- data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
- data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
- data/docs/guides/advanced-features/streaming.adoc +142 -0
- data/docs/guides/archive-formats/gzip-format.adoc +105 -0
- data/docs/guides/archive-formats/index.adoc +160 -0
- data/docs/guides/archive-formats/ole-format.adoc +151 -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/rpm-format.adoc +108 -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 +114 -0
- data/docs/guides/compression-algorithms/deflate.adoc +313 -0
- data/docs/guides/compression-algorithms/index.adoc +190 -0
- data/docs/guides/compression-algorithms/lzma.adoc +394 -0
- data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
- data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
- data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
- data/docs/guides/creating-archives.adoc +348 -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 +228 -0
- data/docs/lychee.toml +67 -0
- data/docs/reference/api/overview.adoc +187 -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/rust-backend.md +0 -0
- data/docs/troubleshooting/index.adoc +207 -0
- data/docs/xar_format.md +216 -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 +176 -0
- data/lib/omnizip/algorithm_registry.rb +65 -0
- data/lib/omnizip/algorithms/.keep +0 -0
- data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
- data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
- data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
- data/lib/omnizip/algorithms/bzip2.rb +108 -0
- data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
- data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
- data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
- data/lib/omnizip/algorithms/deflate.rb +135 -0
- data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
- data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
- data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
- data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
- data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
- data/lib/omnizip/algorithms/deflate64.rb +118 -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 +146 -0
- data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
- data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
- data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
- data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
- data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
- data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
- data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
- data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
- data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -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 +233 -0
- data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
- data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
- data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
- data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
- data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
- data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
- data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
- data/lib/omnizip/algorithms/lzma/state.rb +127 -0
- data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
- data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
- data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
- data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
- data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
- data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
- data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
- data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
- data/lib/omnizip/algorithms/lzma.rb +266 -0
- data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
- data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
- data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
- data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
- data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
- data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
- data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
- data/lib/omnizip/algorithms/lzma2.rb +133 -0
- data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
- data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
- data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
- data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
- data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
- data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
- data/lib/omnizip/algorithms/ppmd7.rb +146 -0
- data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
- data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
- data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
- data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
- data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
- data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
- data/lib/omnizip/algorithms/ppmd8.rb +122 -0
- data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
- data/lib/omnizip/algorithms/registration.rb +28 -0
- data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
- data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
- data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
- data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
- data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
- data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
- data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
- data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
- data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
- data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
- data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
- data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
- data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
- data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
- data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
- data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
- data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
- data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
- data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
- data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
- data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
- data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
- data/lib/omnizip/algorithms/zstandard.rb +210 -0
- data/lib/omnizip/algorithms.rb +35 -0
- data/lib/omnizip/archive/builder.rb +48 -0
- data/lib/omnizip/archive/reader_session.rb +67 -0
- data/lib/omnizip/archive.rb +86 -0
- data/lib/omnizip/archive_handler.rb +82 -0
- data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
- data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
- data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
- data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
- data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
- data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
- data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
- data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
- data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
- data/lib/omnizip/archive_handlers.rb +18 -0
- data/lib/omnizip/backends.rb +160 -0
- data/lib/omnizip/buffer/memory_archive.rb +246 -0
- data/lib/omnizip/buffer/memory_extractor.rb +234 -0
- data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
- data/lib/omnizip/buffer.rb +187 -0
- data/lib/omnizip/checksum_registry.rb +41 -0
- data/lib/omnizip/checksums/crc32.rb +101 -0
- data/lib/omnizip/checksums/crc64.rb +102 -0
- data/lib/omnizip/checksums/crc_base.rb +158 -0
- data/lib/omnizip/checksums/registration.rb +16 -0
- data/lib/omnizip/checksums/verifier.rb +130 -0
- data/lib/omnizip/checksums.rb +11 -0
- data/lib/omnizip/chunked/memory_manager.rb +194 -0
- data/lib/omnizip/chunked/reader.rb +78 -0
- data/lib/omnizip/chunked/writer.rb +123 -0
- data/lib/omnizip/chunked.rb +123 -0
- data/lib/omnizip/cli/output_formatter.rb +112 -0
- data/lib/omnizip/cli.rb +604 -0
- data/lib/omnizip/commands/.keep +0 -0
- data/lib/omnizip/commands/archive_create_command.rb +245 -0
- data/lib/omnizip/commands/archive_extract_command.rb +231 -0
- data/lib/omnizip/commands/archive_list_command.rb +204 -0
- data/lib/omnizip/commands/archive_repair_command.rb +129 -0
- data/lib/omnizip/commands/archive_verify_command.rb +115 -0
- data/lib/omnizip/commands/compress_command.rb +115 -0
- data/lib/omnizip/commands/decompress_command.rb +149 -0
- data/lib/omnizip/commands/list_command.rb +51 -0
- data/lib/omnizip/commands/metadata_command.rb +215 -0
- data/lib/omnizip/commands/parity_create_command.rb +114 -0
- data/lib/omnizip/commands/parity_repair_command.rb +120 -0
- data/lib/omnizip/commands/parity_verify_command.rb +122 -0
- data/lib/omnizip/commands/profile_list_command.rb +54 -0
- data/lib/omnizip/commands/profile_show_command.rb +44 -0
- data/lib/omnizip/commands.rb +21 -0
- data/lib/omnizip/convenience.rb +389 -0
- data/lib/omnizip/converter/conversion_registry.rb +50 -0
- data/lib/omnizip/converter/conversion_strategy.rb +108 -0
- data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
- data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
- data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
- data/lib/omnizip/converter.rb +124 -0
- data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
- data/lib/omnizip/crypto/aes256/constants.rb +28 -0
- data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
- data/lib/omnizip/crypto/aes256.rb +102 -0
- data/lib/omnizip/crypto.rb +11 -0
- data/lib/omnizip/entry.rb +44 -0
- data/lib/omnizip/error.rb +110 -0
- data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
- data/lib/omnizip/eta/moving_average_estimator.rb +96 -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 +68 -0
- data/lib/omnizip/extraction/filter_chain.rb +179 -0
- data/lib/omnizip/extraction/glob_pattern.rb +140 -0
- data/lib/omnizip/extraction/pattern_matcher.rb +66 -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 +247 -0
- data/lib/omnizip/extraction.rb +115 -0
- data/lib/omnizip/file_type/mime_classifier.rb +144 -0
- data/lib/omnizip/file_type.rb +117 -0
- data/lib/omnizip/filter.rb +141 -0
- data/lib/omnizip/filter_pipeline.rb +108 -0
- data/lib/omnizip/filter_registry.rb +113 -0
- data/lib/omnizip/filters/bcj.rb +277 -0
- data/lib/omnizip/filters/bcj2/constants.rb +53 -0
- data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
- data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
- data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
- data/lib/omnizip/filters/bcj2.rb +93 -0
- data/lib/omnizip/filters/bcj_arm.rb +174 -0
- data/lib/omnizip/filters/bcj_arm64.rb +242 -0
- data/lib/omnizip/filters/bcj_ia64.rb +194 -0
- data/lib/omnizip/filters/bcj_ppc.rb +188 -0
- data/lib/omnizip/filters/bcj_sparc.rb +174 -0
- data/lib/omnizip/filters/bcj_x86.rb +191 -0
- data/lib/omnizip/filters/delta.rb +195 -0
- data/lib/omnizip/filters/xz_delta.rb +258 -0
- data/lib/omnizip/filters.rb +20 -0
- data/lib/omnizip/format_detector.rb +166 -0
- data/lib/omnizip/formats/.keep +0 -0
- data/lib/omnizip/formats/bzip2_file.rb +159 -0
- data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
- data/lib/omnizip/formats/cpio/constants.rb +55 -0
- data/lib/omnizip/formats/cpio/entry.rb +389 -0
- data/lib/omnizip/formats/cpio/reader.rb +194 -0
- data/lib/omnizip/formats/cpio/writer.rb +232 -0
- data/lib/omnizip/formats/cpio.rb +132 -0
- data/lib/omnizip/formats/format_spec_loader.rb +228 -0
- data/lib/omnizip/formats/gzip.rb +236 -0
- data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
- data/lib/omnizip/formats/iso/directory_record.rb +162 -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 +194 -0
- data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
- data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
- data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
- data/lib/omnizip/formats/iso/writer.rb +543 -0
- data/lib/omnizip/formats/iso.rb +133 -0
- data/lib/omnizip/formats/lzip.rb +161 -0
- data/lib/omnizip/formats/lzma_alone.rb +149 -0
- data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
- data/lib/omnizip/formats/msi/constants.rb +157 -0
- data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
- data/lib/omnizip/formats/msi/entry.rb +134 -0
- data/lib/omnizip/formats/msi/reader.rb +301 -0
- data/lib/omnizip/formats/msi/string_pool.rb +246 -0
- data/lib/omnizip/formats/msi/table_parser.rb +244 -0
- data/lib/omnizip/formats/msi.rb +73 -0
- data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
- data/lib/omnizip/formats/ole/constants.rb +61 -0
- data/lib/omnizip/formats/ole/dirent.rb +439 -0
- data/lib/omnizip/formats/ole/header.rb +199 -0
- data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
- data/lib/omnizip/formats/ole/storage.rb +482 -0
- data/lib/omnizip/formats/ole/types/variant.rb +338 -0
- data/lib/omnizip/formats/ole.rb +143 -0
- data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
- data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
- data/lib/omnizip/formats/rar/block_parser.rb +282 -0
- data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
- data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
- data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -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/lz77_huffman.rb +25 -0
- data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
- data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
- data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
- data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
- data/lib/omnizip/formats/rar/compression.rb +17 -0
- data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
- data/lib/omnizip/formats/rar/constants.rb +88 -0
- data/lib/omnizip/formats/rar/decompressor.rb +316 -0
- data/lib/omnizip/formats/rar/external_writer.rb +311 -0
- data/lib/omnizip/formats/rar/header.rb +209 -0
- data/lib/omnizip/formats/rar/license_validator.rb +111 -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/models.rb +14 -0
- data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
- data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -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 +96 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
- data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
- data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
- data/lib/omnizip/formats/rar/rar5/header.rb +208 -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 +260 -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 +176 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
- data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
- data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
- data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
- data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
- data/lib/omnizip/formats/rar/reader.rb +377 -0
- data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
- data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
- data/lib/omnizip/formats/rar/writer.rb +437 -0
- data/lib/omnizip/formats/rar.rb +193 -0
- data/lib/omnizip/formats/rar3/compressor.rb +71 -0
- data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar3/reader.rb +107 -0
- data/lib/omnizip/formats/rar3/writer.rb +220 -0
- data/lib/omnizip/formats/rar3.rb +15 -0
- data/lib/omnizip/formats/rar5/compressor.rb +71 -0
- data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
- data/lib/omnizip/formats/rar5/reader.rb +130 -0
- data/lib/omnizip/formats/rar5/writer.rb +65 -0
- data/lib/omnizip/formats/rar5.rb +15 -0
- data/lib/omnizip/formats/rpm/constants.rb +58 -0
- data/lib/omnizip/formats/rpm/entry.rb +106 -0
- data/lib/omnizip/formats/rpm/header.rb +106 -0
- data/lib/omnizip/formats/rpm/lead.rb +132 -0
- data/lib/omnizip/formats/rpm/tag.rb +228 -0
- data/lib/omnizip/formats/rpm/writer.rb +652 -0
- data/lib/omnizip/formats/rpm.rb +458 -0
- data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
- data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
- data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
- data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
- data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
- data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
- data/lib/omnizip/formats/seven_zip/header.rb +102 -0
- data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
- data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
- data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
- data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
- data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
- data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
- data/lib/omnizip/formats/seven_zip/models.rb +20 -0
- data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
- data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
- data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
- data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
- data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
- data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
- data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
- data/lib/omnizip/formats/seven_zip.rb +179 -0
- data/lib/omnizip/formats/tar/constants.rb +73 -0
- data/lib/omnizip/formats/tar/entry.rb +98 -0
- data/lib/omnizip/formats/tar/header.rb +206 -0
- data/lib/omnizip/formats/tar/reader.rb +119 -0
- data/lib/omnizip/formats/tar/writer.rb +212 -0
- data/lib/omnizip/formats/tar.rb +74 -0
- data/lib/omnizip/formats/xar/constants.rb +119 -0
- data/lib/omnizip/formats/xar/entry.rb +268 -0
- data/lib/omnizip/formats/xar/header.rb +223 -0
- data/lib/omnizip/formats/xar/reader.rb +400 -0
- data/lib/omnizip/formats/xar/toc.rb +570 -0
- data/lib/omnizip/formats/xar/writer.rb +461 -0
- data/lib/omnizip/formats/xar.rb +145 -0
- data/lib/omnizip/formats/xz/reader.rb +121 -0
- data/lib/omnizip/formats/xz/writer.rb +416 -0
- data/lib/omnizip/formats/xz.rb +210 -0
- data/lib/omnizip/formats/xz_const.rb +49 -0
- data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
- data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
- data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
- data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
- data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
- data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
- data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
- data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
- data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
- data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
- data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
- data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
- data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
- data/lib/omnizip/formats/xz_impl.rb +52 -0
- data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
- data/lib/omnizip/formats/zip/constants.rb +69 -0
- data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
- data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
- data/lib/omnizip/formats/zip/reader.rb +376 -0
- data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
- data/lib/omnizip/formats/zip/writer.rb +489 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
- data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
- data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
- data/lib/omnizip/formats/zip.rb +50 -0
- data/lib/omnizip/formats.rb +29 -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/base.rb +19 -0
- data/lib/omnizip/implementations/rust/archive.rb +93 -0
- data/lib/omnizip/implementations/rust/library.rb +221 -0
- data/lib/omnizip/implementations/rust.rb +26 -0
- data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
- data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
- data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
- data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
- data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
- data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
- data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
- data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
- data/lib/omnizip/implementations/seven_zip.rb +11 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
- data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
- data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
- data/lib/omnizip/implementations/xz_utils.rb +10 -0
- data/lib/omnizip/implementations.rb +25 -0
- data/lib/omnizip/io/buffered_input.rb +147 -0
- data/lib/omnizip/io/buffered_output.rb +106 -0
- data/lib/omnizip/io/source.rb +143 -0
- data/lib/omnizip/io/stream_manager.rb +117 -0
- data/lib/omnizip/io.rb +15 -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 +129 -0
- data/lib/omnizip/metadata/archive_metadata.rb +114 -0
- data/lib/omnizip/metadata/entry_metadata.rb +153 -0
- data/lib/omnizip/metadata/metadata_editor.rb +169 -0
- data/lib/omnizip/metadata/metadata_registry.rb +71 -0
- data/lib/omnizip/metadata/metadata_validator.rb +101 -0
- data/lib/omnizip/metadata.rb +58 -0
- data/lib/omnizip/models/.keep +0 -0
- data/lib/omnizip/models/algorithm_metadata.rb +41 -0
- data/lib/omnizip/models/attribute_apply.rb +40 -0
- data/lib/omnizip/models/compression_options.rb +53 -0
- data/lib/omnizip/models/conversion_options.rb +79 -0
- data/lib/omnizip/models/conversion_result.rb +141 -0
- data/lib/omnizip/models/eta_result.rb +45 -0
- data/lib/omnizip/models/extraction_rule.rb +115 -0
- data/lib/omnizip/models/filter_chain.rb +142 -0
- data/lib/omnizip/models/filter_config.rb +148 -0
- data/lib/omnizip/models/match_result.rb +141 -0
- data/lib/omnizip/models/optimization_suggestion.rb +95 -0
- data/lib/omnizip/models/parallel_options.rb +116 -0
- data/lib/omnizip/models/performance_result.rb +85 -0
- data/lib/omnizip/models/profile_report.rb +116 -0
- data/lib/omnizip/models/progress_options.rb +39 -0
- data/lib/omnizip/models/split_options.rb +116 -0
- data/lib/omnizip/optimization_registry.rb +45 -0
- data/lib/omnizip/parallel/engine.rb +52 -0
- data/lib/omnizip/parallel/job_queue.rb +209 -0
- data/lib/omnizip/parallel/job_scheduler.rb +225 -0
- data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
- data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
- data/lib/omnizip/parallel/thread_pool.rb +60 -0
- data/lib/omnizip/parallel/worker_pool.rb +227 -0
- data/lib/omnizip/parallel.rb +156 -0
- data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
- data/lib/omnizip/parity/galois16.rb +145 -0
- data/lib/omnizip/parity/models/creator_packet.rb +71 -0
- data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
- data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
- data/lib/omnizip/parity/models/main_packet.rb +126 -0
- data/lib/omnizip/parity/models/packet.rb +156 -0
- data/lib/omnizip/parity/models/packet_registry.rb +102 -0
- data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
- data/lib/omnizip/parity/models.rb +27 -0
- data/lib/omnizip/parity/par2_creator.rb +496 -0
- data/lib/omnizip/parity/par2_repairer.rb +409 -0
- data/lib/omnizip/parity/par2_verifier.rb +373 -0
- data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
- data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
- data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
- data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
- data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
- data/lib/omnizip/parity.rb +207 -0
- data/lib/omnizip/password/encryption_registry.rb +26 -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 +190 -0
- data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
- data/lib/omnizip/password.rb +88 -0
- data/lib/omnizip/pipe/stream_compressor.rb +124 -0
- data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
- data/lib/omnizip/pipe.rb +120 -0
- data/lib/omnizip/platform/ntfs_streams.rb +200 -0
- data/lib/omnizip/platform.rb +189 -0
- data/lib/omnizip/profile/archive_profile.rb +36 -0
- data/lib/omnizip/profile/balanced_profile.rb +31 -0
- data/lib/omnizip/profile/binary_profile.rb +33 -0
- data/lib/omnizip/profile/compression_profile.rb +157 -0
- data/lib/omnizip/profile/custom_profile.rb +155 -0
- data/lib/omnizip/profile/fast_profile.rb +31 -0
- data/lib/omnizip/profile/maximum_profile.rb +31 -0
- data/lib/omnizip/profile/profile_detector.rb +108 -0
- data/lib/omnizip/profile/profile_registry.rb +160 -0
- data/lib/omnizip/profile/text_profile.rb +33 -0
- data/lib/omnizip/profile.rb +261 -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 +158 -0
- data/lib/omnizip/profiler.rb +192 -0
- data/lib/omnizip/progress/callback_reporter.rb +34 -0
- data/lib/omnizip/progress/console_reporter.rb +59 -0
- data/lib/omnizip/progress/log_reporter.rb +89 -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 +215 -0
- data/lib/omnizip/progress/silent_reporter.rb +22 -0
- data/lib/omnizip/progress.rb +131 -0
- data/lib/omnizip/registry.rb +111 -0
- data/lib/omnizip/rubyzip_compat.rb +61 -0
- data/lib/omnizip/temp/safe_extract.rb +124 -0
- data/lib/omnizip/temp/temp_file.rb +123 -0
- data/lib/omnizip/temp/temp_file_pool.rb +109 -0
- data/lib/omnizip/temp.rb +184 -0
- data/lib/omnizip/version.rb +5 -0
- data/lib/omnizip/zip/entry.rb +160 -0
- data/lib/omnizip/zip/file.rb +485 -0
- data/lib/omnizip/zip/input_stream.rb +270 -0
- data/lib/omnizip/zip/output_stream.rb +320 -0
- data/lib/omnizip/zip.rb +23 -0
- data/lib/omnizip.rb +157 -0
- data/lib/tasks/msi_test_files.rake +66 -0
- data/lib/tasks/platform_gems.rake +147 -0
- data/lib/tasks/rust_backend.rake +48 -0
- data/readme-docs/advanced-features.adoc +514 -0
- data/readme-docs/api-usage.adoc +445 -0
- data/readme-docs/architecture.adoc +450 -0
- data/readme-docs/archive-formats.adoc +479 -0
- data/readme-docs/cli-usage.adoc +222 -0
- data/readme-docs/compression-algorithms.adoc +446 -0
- data/readme-docs/compression-profiles.adoc +247 -0
- data/readme-docs/encryption-checksums.adoc +328 -0
- data/readme-docs/format-converter.adoc +316 -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/vendor/libomnizip_ffi.so +0 -0
- data/xz-file-format-1.2.1.txt +1174 -0
- metadata +768 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# Copyright (C) 2024 Ribose Inc.
|
|
5
|
+
#
|
|
6
|
+
# This file is part of Omnizip.
|
|
7
|
+
#
|
|
8
|
+
# Omnizip is a pure Ruby port of 7-Zip compression algorithms.
|
|
9
|
+
# Based on the 7-Zip LZMA SDK by Igor Pavlov.
|
|
10
|
+
#
|
|
11
|
+
# This library is free software; you can redistribute it and/or
|
|
12
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
13
|
+
# License as published by the Free Software Foundation; either
|
|
14
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
15
|
+
#
|
|
16
|
+
# See the COPYING file for the complete text of the license.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
module Omnizip
|
|
20
|
+
module Checksums
|
|
21
|
+
# Abstract base class for CRC (Cyclic Redundancy Check) algorithms.
|
|
22
|
+
#
|
|
23
|
+
# This class provides the common framework for implementing CRC
|
|
24
|
+
# checksums using lookup tables for efficient computation. Subclasses
|
|
25
|
+
# must define their specific polynomial and bit width.
|
|
26
|
+
#
|
|
27
|
+
# The lookup table approach provides O(1) per-byte processing time,
|
|
28
|
+
# making it significantly faster than bit-by-bit calculation.
|
|
29
|
+
#
|
|
30
|
+
# Architecture:
|
|
31
|
+
# - Pre-computed lookup tables stored as class constants
|
|
32
|
+
# - Incremental computation support via update method
|
|
33
|
+
# - Initial and final XOR values for standard CRC variants
|
|
34
|
+
#
|
|
35
|
+
# @abstract Subclass and override polynomial-specific methods
|
|
36
|
+
class CrcBase
|
|
37
|
+
# @return [Integer] current CRC value
|
|
38
|
+
attr_reader :value
|
|
39
|
+
|
|
40
|
+
# Initialize a new CRC calculator with default initial value.
|
|
41
|
+
#
|
|
42
|
+
# The initial value is typically all 1s (inverted 0) to detect
|
|
43
|
+
# leading zeros in the input data.
|
|
44
|
+
def initialize
|
|
45
|
+
@value = initial_value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Update the CRC value with new data.
|
|
49
|
+
#
|
|
50
|
+
# This method processes the input data byte-by-byte using the
|
|
51
|
+
# lookup table, allowing incremental CRC calculation.
|
|
52
|
+
#
|
|
53
|
+
# @param data [String] binary string to process
|
|
54
|
+
# @return [self] for method chaining
|
|
55
|
+
def update(data)
|
|
56
|
+
data.each_byte do |byte|
|
|
57
|
+
@value = process_byte(@value, byte)
|
|
58
|
+
end
|
|
59
|
+
self
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Reset the CRC calculator to initial state.
|
|
63
|
+
#
|
|
64
|
+
# @return [self] for method chaining
|
|
65
|
+
def reset
|
|
66
|
+
@value = initial_value
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Get the finalized CRC value.
|
|
71
|
+
#
|
|
72
|
+
# Applies the final XOR operation required by most CRC standards
|
|
73
|
+
# to produce the final checksum value.
|
|
74
|
+
#
|
|
75
|
+
# @return [Integer] final CRC checksum
|
|
76
|
+
def finalize
|
|
77
|
+
@value ^ final_xor
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Calculate CRC for data in one operation.
|
|
81
|
+
#
|
|
82
|
+
# This is a convenience method that combines initialize, update,
|
|
83
|
+
# and finalize into a single call.
|
|
84
|
+
#
|
|
85
|
+
# @param data [String] binary string to checksum
|
|
86
|
+
# @return [Integer] final CRC checksum
|
|
87
|
+
def self.calculate(data)
|
|
88
|
+
new.update(data).finalize
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
protected
|
|
92
|
+
|
|
93
|
+
# Process a single byte through the CRC algorithm.
|
|
94
|
+
#
|
|
95
|
+
# This method must be implemented by subclasses to perform the
|
|
96
|
+
# actual CRC calculation using the lookup table.
|
|
97
|
+
#
|
|
98
|
+
# @param crc [Integer] current CRC value
|
|
99
|
+
# @param byte [Integer] byte to process (0-255)
|
|
100
|
+
# @return [Integer] updated CRC value
|
|
101
|
+
# @abstract
|
|
102
|
+
def process_byte(crc, byte)
|
|
103
|
+
raise NotImplementedError,
|
|
104
|
+
"#{self.class} must implement #process_byte"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Get the initial CRC value.
|
|
108
|
+
#
|
|
109
|
+
# @return [Integer] initial value (typically all 1s)
|
|
110
|
+
# @abstract
|
|
111
|
+
def initial_value
|
|
112
|
+
raise NotImplementedError,
|
|
113
|
+
"#{self.class} must implement #initial_value"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Get the final XOR value.
|
|
117
|
+
#
|
|
118
|
+
# @return [Integer] value to XOR with final result
|
|
119
|
+
# @abstract
|
|
120
|
+
def final_xor
|
|
121
|
+
raise NotImplementedError,
|
|
122
|
+
"#{self.class} must implement #final_xor"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Get the lookup table for this CRC variant.
|
|
126
|
+
#
|
|
127
|
+
# @return [Array<Integer>] 256-entry lookup table
|
|
128
|
+
# @abstract
|
|
129
|
+
def self.lookup_table
|
|
130
|
+
raise NotImplementedError,
|
|
131
|
+
"#{self} must implement .lookup_table"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Generate a CRC lookup table for given polynomial.
|
|
135
|
+
#
|
|
136
|
+
# This method pre-computes all possible CRC values for single-byte
|
|
137
|
+
# inputs, enabling efficient O(1) per-byte processing.
|
|
138
|
+
#
|
|
139
|
+
# @param polynomial [Integer] CRC polynomial
|
|
140
|
+
# @param bits [Integer] bit width (32 or 64)
|
|
141
|
+
# @return [Array<Integer>] 256-entry lookup table
|
|
142
|
+
def self.generate_table(polynomial, bits)
|
|
143
|
+
mask = (1 << bits) - 1
|
|
144
|
+
(0..255).map do |i|
|
|
145
|
+
crc = i
|
|
146
|
+
8.times do
|
|
147
|
+
if crc.anybits?(1)
|
|
148
|
+
crc = (crc >> 1) ^ polynomial
|
|
149
|
+
else
|
|
150
|
+
crc >>= 1
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
crc & mask
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Checksum registration - triggers autoload and registers all checksums
|
|
4
|
+
# This file should be required after checksums.rb which sets up autoloads
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Checksums
|
|
8
|
+
# Touch constants to trigger autoload
|
|
9
|
+
Crc32
|
|
10
|
+
Crc64
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Register checksum algorithms
|
|
15
|
+
Omnizip::ChecksumRegistry.register(:crc32, Omnizip::Checksums::Crc32)
|
|
16
|
+
Omnizip::ChecksumRegistry.register(:crc64, Omnizip::Checksums::Crc64)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2025 Ribose Inc.
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
6
|
+
# copy of this software and associated documentation files (the "Software"),
|
|
7
|
+
# to deal in the Software without restriction, including without limitation
|
|
8
|
+
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
9
|
+
# and/or sell copies of the Software, and to permit persons to whom the
|
|
10
|
+
# Software is furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
|
13
|
+
# all copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
21
|
+
# DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
require "zlib"
|
|
24
|
+
require "digest"
|
|
25
|
+
|
|
26
|
+
module Omnizip
|
|
27
|
+
module Checksums
|
|
28
|
+
# Checksum verification utilities for XZ format
|
|
29
|
+
#
|
|
30
|
+
# XZ supports multiple check types:
|
|
31
|
+
# - 0: None (no checksum)
|
|
32
|
+
# - 1: CRC32 (4 bytes)
|
|
33
|
+
# - 4: CRC64 (8 bytes)
|
|
34
|
+
# - 10: SHA256 (32 bytes)
|
|
35
|
+
class Verifier
|
|
36
|
+
# Check type constants (from XZ spec)
|
|
37
|
+
CHECK_NONE = 0
|
|
38
|
+
CHECK_CRC32 = 1
|
|
39
|
+
CHECK_CRC64 = 4
|
|
40
|
+
CHECK_SHA256 = 10
|
|
41
|
+
|
|
42
|
+
# Check sizes in bytes
|
|
43
|
+
CHECK_SIZES = {
|
|
44
|
+
CHECK_NONE => 0,
|
|
45
|
+
CHECK_CRC32 => 4,
|
|
46
|
+
CHECK_CRC64 => 8,
|
|
47
|
+
CHECK_SHA256 => 32,
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
# Verify CRC32 checksum
|
|
51
|
+
#
|
|
52
|
+
# @param data [String] Data to verify
|
|
53
|
+
# @param expected [Integer] Expected CRC32 value
|
|
54
|
+
# @return [Boolean] True if checksum matches
|
|
55
|
+
def self.verify_crc32(data, expected)
|
|
56
|
+
Zlib.crc32(data) == expected
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Verify CRC64 checksum
|
|
60
|
+
#
|
|
61
|
+
# @param data [String] Data to verify
|
|
62
|
+
# @param expected [Integer] Expected CRC64 value
|
|
63
|
+
# @return [Boolean] True if checksum matches
|
|
64
|
+
def self.verify_crc64(data, expected)
|
|
65
|
+
Crc64.calculate(data) == expected
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Verify SHA256 checksum
|
|
69
|
+
#
|
|
70
|
+
# @param data [String] Data to verify
|
|
71
|
+
# @param expected [String] Expected SHA256 digest (binary, 32 bytes)
|
|
72
|
+
# @return [Boolean] True if checksum matches
|
|
73
|
+
def self.verify_sha256(data, expected)
|
|
74
|
+
Digest::SHA256.digest(data) == expected
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Generic verify based on check type
|
|
78
|
+
#
|
|
79
|
+
# @param data [String] Data to verify
|
|
80
|
+
# @param expected [String] Expected checksum (binary format)
|
|
81
|
+
# @param check_type [Integer] Check type (0=None, 1=CRC32, 4=CRC64, 10=SHA256)
|
|
82
|
+
# @return [Boolean] True if checksum matches or check type is None
|
|
83
|
+
# @raise [ArgumentError] If check type is unknown
|
|
84
|
+
def self.verify(data, expected, check_type)
|
|
85
|
+
case check_type
|
|
86
|
+
when CHECK_NONE
|
|
87
|
+
true # No checksum to verify
|
|
88
|
+
when CHECK_CRC32
|
|
89
|
+
expected_crc = expected.unpack1("V")
|
|
90
|
+
verify_crc32(data, expected_crc)
|
|
91
|
+
when CHECK_CRC64
|
|
92
|
+
expected_crc = expected.unpack1("Q<")
|
|
93
|
+
verify_crc64(data, expected_crc)
|
|
94
|
+
when CHECK_SHA256
|
|
95
|
+
verify_sha256(data, expected)
|
|
96
|
+
else
|
|
97
|
+
raise Omnizip::UnknownChecksumError, "Unknown check type: #{check_type}"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Get check size in bytes
|
|
102
|
+
#
|
|
103
|
+
# @param check_type [Integer] Check type
|
|
104
|
+
# @return [Integer] Size of checksum in bytes
|
|
105
|
+
def self.check_size(check_type)
|
|
106
|
+
CHECK_SIZES.fetch(check_type, 0)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Calculate checksum for data based on check type
|
|
110
|
+
#
|
|
111
|
+
# @param data [String] Data to checksum
|
|
112
|
+
# @param check_type [Integer] Check type
|
|
113
|
+
# @return [String] Checksum in binary format
|
|
114
|
+
def self.calculate(data, check_type)
|
|
115
|
+
case check_type
|
|
116
|
+
when CHECK_NONE
|
|
117
|
+
""
|
|
118
|
+
when CHECK_CRC32
|
|
119
|
+
[Zlib.crc32(data)].pack("V")
|
|
120
|
+
when CHECK_CRC64
|
|
121
|
+
[Crc64.calculate(data)].pack("Q<")
|
|
122
|
+
when CHECK_SHA256
|
|
123
|
+
Digest::SHA256.digest(data)
|
|
124
|
+
else
|
|
125
|
+
raise Omnizip::UnknownChecksumError, "Unknown check type: #{check_type}"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
# Checksum implementations
|
|
5
|
+
module Checksums
|
|
6
|
+
autoload :CrcBase, "omnizip/checksums/crc_base"
|
|
7
|
+
autoload :Crc32, "omnizip/checksums/crc32"
|
|
8
|
+
autoload :Crc64, "omnizip/checksums/crc64"
|
|
9
|
+
autoload :Verifier, "omnizip/checksums/verifier"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "tempfile"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Chunked
|
|
7
|
+
# Manage memory usage and enforce limits during chunked operations
|
|
8
|
+
class MemoryManager
|
|
9
|
+
DEFAULT_MAX_MEMORY = 256 * 1024 * 1024 # 256MB
|
|
10
|
+
|
|
11
|
+
attr_reader :current_usage, :max_memory
|
|
12
|
+
|
|
13
|
+
# Initialize memory manager
|
|
14
|
+
# @param options [Hash] Manager options
|
|
15
|
+
# @option options [Integer] :max Maximum memory in bytes
|
|
16
|
+
# @option options [String] :temp_dir Temporary directory for spill files
|
|
17
|
+
# @option options [Symbol] :strategy Spill strategy (:disk or :error)
|
|
18
|
+
def initialize(max: DEFAULT_MAX_MEMORY, temp_dir: nil, strategy: :disk)
|
|
19
|
+
@max_memory = max
|
|
20
|
+
@current_usage = 0
|
|
21
|
+
@buffers = {} # buffer => size mapping
|
|
22
|
+
@temp_files = []
|
|
23
|
+
@temp_dir = temp_dir
|
|
24
|
+
@strategy = strategy
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Allocate memory or spill to disk
|
|
28
|
+
# @param size [Integer] Size to allocate in bytes
|
|
29
|
+
# @return [String, Tempfile] Buffer or temp file
|
|
30
|
+
def allocate(size)
|
|
31
|
+
if can_allocate_in_memory?(size)
|
|
32
|
+
allocate_buffer(size)
|
|
33
|
+
else
|
|
34
|
+
handle_overflow(size)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Release allocated memory or temp file
|
|
39
|
+
# @param buffer [String, Tempfile] Buffer to release
|
|
40
|
+
# @return [Integer] Bytes released
|
|
41
|
+
def release(buffer)
|
|
42
|
+
case buffer
|
|
43
|
+
when String
|
|
44
|
+
release_buffer(buffer)
|
|
45
|
+
when Tempfile, File
|
|
46
|
+
release_temp_file(buffer)
|
|
47
|
+
else
|
|
48
|
+
0
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Get available memory
|
|
53
|
+
# @return [Integer] Available memory in bytes
|
|
54
|
+
def available
|
|
55
|
+
[@max_memory - @current_usage, 0].max
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Check if over memory limit
|
|
59
|
+
# @return [Boolean] True if over limit
|
|
60
|
+
def over_limit?
|
|
61
|
+
@current_usage > @max_memory
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Get memory usage ratio
|
|
65
|
+
# @return [Float] Usage from 0.0 to 1.0
|
|
66
|
+
def usage_ratio
|
|
67
|
+
return 0.0 if @max_memory.zero?
|
|
68
|
+
|
|
69
|
+
@current_usage.to_f / @max_memory
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Cleanup all resources
|
|
73
|
+
# @return [self]
|
|
74
|
+
def cleanup
|
|
75
|
+
@buffers.clear
|
|
76
|
+
@temp_files.each do |tf|
|
|
77
|
+
begin
|
|
78
|
+
tf.close
|
|
79
|
+
rescue StandardError
|
|
80
|
+
nil
|
|
81
|
+
end
|
|
82
|
+
begin
|
|
83
|
+
tf.unlink
|
|
84
|
+
rescue StandardError
|
|
85
|
+
nil
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
@temp_files.clear
|
|
89
|
+
@current_usage = 0
|
|
90
|
+
self
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Execute block with automatic cleanup
|
|
94
|
+
# @yield [manager] Block to execute with manager
|
|
95
|
+
# @return [Object] Block result
|
|
96
|
+
def self.with_manager(**options)
|
|
97
|
+
manager = new(**options)
|
|
98
|
+
begin
|
|
99
|
+
yield manager
|
|
100
|
+
ensure
|
|
101
|
+
manager.cleanup
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Spill buffer to disk
|
|
106
|
+
# @param buffer [String] Buffer data to spill
|
|
107
|
+
# @return [Tempfile] Temporary file
|
|
108
|
+
def spill_to_disk(buffer = nil)
|
|
109
|
+
tf = create_temp_file
|
|
110
|
+
tf.write(buffer) if buffer
|
|
111
|
+
tf.rewind
|
|
112
|
+
@temp_files << tf
|
|
113
|
+
tf
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
private
|
|
117
|
+
|
|
118
|
+
# Check if size can be allocated in memory
|
|
119
|
+
def can_allocate_in_memory?(size)
|
|
120
|
+
@current_usage + size <= @max_memory
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Allocate in-memory buffer
|
|
124
|
+
def allocate_buffer(size)
|
|
125
|
+
buffer = String.new(capacity: size, encoding: Encoding::BINARY)
|
|
126
|
+
@buffers[buffer] = size
|
|
127
|
+
@current_usage += size
|
|
128
|
+
buffer
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Release in-memory buffer
|
|
132
|
+
def release_buffer(buffer)
|
|
133
|
+
size = @buffers.delete(buffer)
|
|
134
|
+
if size
|
|
135
|
+
@current_usage -= size
|
|
136
|
+
size
|
|
137
|
+
else
|
|
138
|
+
0
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Release temp file
|
|
143
|
+
def release_temp_file(file)
|
|
144
|
+
if @temp_files.delete(file)
|
|
145
|
+
size = begin
|
|
146
|
+
file.size
|
|
147
|
+
rescue StandardError
|
|
148
|
+
0
|
|
149
|
+
end
|
|
150
|
+
begin
|
|
151
|
+
file.close
|
|
152
|
+
rescue StandardError
|
|
153
|
+
nil
|
|
154
|
+
end
|
|
155
|
+
begin
|
|
156
|
+
file.unlink
|
|
157
|
+
rescue StandardError
|
|
158
|
+
nil
|
|
159
|
+
end
|
|
160
|
+
size
|
|
161
|
+
else
|
|
162
|
+
0
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Handle memory overflow based on strategy
|
|
167
|
+
def handle_overflow(size)
|
|
168
|
+
case @strategy
|
|
169
|
+
when :disk
|
|
170
|
+
spill_to_disk
|
|
171
|
+
when :error
|
|
172
|
+
message = "Memory limit exceeded: " \
|
|
173
|
+
"#{@current_usage + size} > #{@max_memory}"
|
|
174
|
+
raise MemoryError, message
|
|
175
|
+
else
|
|
176
|
+
raise ArgumentError, "Unknown spill strategy: #{@strategy}"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Create temporary file
|
|
181
|
+
def create_temp_file
|
|
182
|
+
Tempfile.new(
|
|
183
|
+
["omnizip_chunk_", ".tmp"],
|
|
184
|
+
@temp_dir,
|
|
185
|
+
binmode: true,
|
|
186
|
+
)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Error raised when memory limit is exceeded
|
|
191
|
+
class MemoryError < Omnizip::Error
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Chunked
|
|
5
|
+
# Read large files in chunks for memory-efficient processing
|
|
6
|
+
class Reader
|
|
7
|
+
DEFAULT_CHUNK_SIZE = 64 * 1024 * 1024 # 64MB
|
|
8
|
+
|
|
9
|
+
attr_reader :file_path, :chunk_size, :total_size
|
|
10
|
+
|
|
11
|
+
# Initialize a chunked reader
|
|
12
|
+
# @param file_path [String] Path to file to read
|
|
13
|
+
# @param options [Hash] Reader options
|
|
14
|
+
# @option options [Integer] :chunk_size Chunk size in bytes
|
|
15
|
+
def initialize(file_path, chunk_size: DEFAULT_CHUNK_SIZE)
|
|
16
|
+
@file_path = file_path
|
|
17
|
+
@chunk_size = chunk_size
|
|
18
|
+
@total_size = File.size(file_path)
|
|
19
|
+
@position = 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Read next chunk from file
|
|
23
|
+
# @return [String, nil] Chunk data or nil if EOF
|
|
24
|
+
def read_chunk
|
|
25
|
+
return nil if @position >= @total_size
|
|
26
|
+
|
|
27
|
+
File.open(@file_path, "rb") do |f|
|
|
28
|
+
f.seek(@position)
|
|
29
|
+
chunk = f.read(@chunk_size)
|
|
30
|
+
@position += chunk.bytesize if chunk
|
|
31
|
+
chunk
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Iterate through all chunks
|
|
36
|
+
# @yield [chunk, position, total] Block called for each chunk
|
|
37
|
+
def each_chunk
|
|
38
|
+
reset
|
|
39
|
+
while (chunk = read_chunk)
|
|
40
|
+
yield chunk, @position - chunk.bytesize, @total_size
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Get current progress as percentage
|
|
45
|
+
# @return [Float] Progress from 0.0 to 1.0
|
|
46
|
+
def progress
|
|
47
|
+
return 1.0 if @total_size.zero?
|
|
48
|
+
|
|
49
|
+
@position.to_f / @total_size
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Reset reader to beginning of file
|
|
53
|
+
# @return [self]
|
|
54
|
+
def reset
|
|
55
|
+
@position = 0
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Check if at end of file
|
|
60
|
+
# @return [Boolean] True if at EOF
|
|
61
|
+
def eof?
|
|
62
|
+
@position >= @total_size
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Get number of chunks needed for file
|
|
66
|
+
# @return [Integer] Number of chunks
|
|
67
|
+
def chunk_count
|
|
68
|
+
(@total_size.to_f / @chunk_size).ceil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Get remaining bytes to read
|
|
72
|
+
# @return [Integer] Remaining bytes
|
|
73
|
+
def remaining
|
|
74
|
+
@total_size - @position
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "stringio"
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Chunked
|
|
8
|
+
# Write large files incrementally in chunks
|
|
9
|
+
class Writer
|
|
10
|
+
DEFAULT_CHUNK_SIZE = 64 * 1024 * 1024 # 64MB
|
|
11
|
+
FLUSH_THRESHOLD = 10 # Flush every N chunks
|
|
12
|
+
|
|
13
|
+
attr_reader :output_path, :chunk_size, :written
|
|
14
|
+
|
|
15
|
+
# Initialize a chunked writer
|
|
16
|
+
# @param output_path [String] Path to output file
|
|
17
|
+
# @param options [Hash] Writer options
|
|
18
|
+
# @option options [Integer] :chunk_size Chunk size in bytes
|
|
19
|
+
def initialize(output_path, chunk_size: DEFAULT_CHUNK_SIZE)
|
|
20
|
+
@output_path = output_path
|
|
21
|
+
@chunk_size = chunk_size
|
|
22
|
+
@written = 0
|
|
23
|
+
@chunks_written = 0
|
|
24
|
+
@file_handle = nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Write a chunk to file
|
|
28
|
+
# @param chunk [String] Data to write
|
|
29
|
+
# @return [Integer] Bytes written
|
|
30
|
+
def write_chunk(chunk)
|
|
31
|
+
ensure_file_open
|
|
32
|
+
|
|
33
|
+
bytes = @file_handle.write(chunk)
|
|
34
|
+
@written += bytes
|
|
35
|
+
@chunks_written += 1
|
|
36
|
+
|
|
37
|
+
# Flush periodically to disk
|
|
38
|
+
flush if (@chunks_written % FLUSH_THRESHOLD).zero?
|
|
39
|
+
|
|
40
|
+
bytes
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Write data from a source in chunks
|
|
44
|
+
# @param source [String, IO] Source to read from
|
|
45
|
+
# @return [Integer] Total bytes written
|
|
46
|
+
def write_from(source)
|
|
47
|
+
case source
|
|
48
|
+
when String
|
|
49
|
+
# File path
|
|
50
|
+
if File.exist?(source)
|
|
51
|
+
Reader.new(source, chunk_size: @chunk_size).each_chunk do |chunk|
|
|
52
|
+
write_chunk(chunk)
|
|
53
|
+
end
|
|
54
|
+
else
|
|
55
|
+
# Treat as data
|
|
56
|
+
write_chunk(source)
|
|
57
|
+
end
|
|
58
|
+
when IO, StringIO
|
|
59
|
+
# IO object
|
|
60
|
+
while (chunk = source.read(@chunk_size))
|
|
61
|
+
break if chunk.empty?
|
|
62
|
+
|
|
63
|
+
write_chunk(chunk)
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
raise ArgumentError, "Unsupported source type: #{source.class}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
@written
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Flush buffered data to disk
|
|
73
|
+
# @return [self]
|
|
74
|
+
def flush
|
|
75
|
+
@file_handle&.flush
|
|
76
|
+
self
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Close the file handle
|
|
80
|
+
# @return [self]
|
|
81
|
+
def close
|
|
82
|
+
if @file_handle
|
|
83
|
+
flush
|
|
84
|
+
@file_handle.close
|
|
85
|
+
@file_handle = nil
|
|
86
|
+
end
|
|
87
|
+
self
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Finalize the file (alias for close)
|
|
91
|
+
# @return [self]
|
|
92
|
+
def finish
|
|
93
|
+
close
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Execute block with writer, auto-close
|
|
97
|
+
# @yield [writer] Block to write data
|
|
98
|
+
# @return [Integer] Total bytes written
|
|
99
|
+
def self.with_writer(output_path, **options)
|
|
100
|
+
writer = new(output_path, **options)
|
|
101
|
+
begin
|
|
102
|
+
yield writer
|
|
103
|
+
writer.written
|
|
104
|
+
ensure
|
|
105
|
+
writer.close
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# Ensure file handle is open
|
|
112
|
+
def ensure_file_open
|
|
113
|
+
return if @file_handle
|
|
114
|
+
|
|
115
|
+
# Create parent directory if needed
|
|
116
|
+
dir = File.dirname(@output_path)
|
|
117
|
+
FileUtils.mkdir_p(dir)
|
|
118
|
+
|
|
119
|
+
@file_handle = File.open(@output_path, "wb")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|