omnizip 0.4.7-arm-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,204 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Iso
|
|
6
|
+
# Joliet Extensions for ISO 9660
|
|
7
|
+
#
|
|
8
|
+
# Implements Microsoft's Joliet extensions to support long filenames
|
|
9
|
+
# (up to 64 characters) and Unicode (UCS-2) encoding in ISO 9660 images.
|
|
10
|
+
#
|
|
11
|
+
# Joliet creates a parallel directory structure in a Supplementary Volume
|
|
12
|
+
# Descriptor with UCS-2 encoded filenames, allowing Windows systems to
|
|
13
|
+
# display proper long filenames while maintaining ISO 9660 compatibility.
|
|
14
|
+
module Joliet
|
|
15
|
+
# Joliet escape sequences for UCS-2 encoding
|
|
16
|
+
# Level 1: %/@
|
|
17
|
+
# Level 2: %/C
|
|
18
|
+
# Level 3: %/E (most common, supports UCS-2)
|
|
19
|
+
ESCAPE_SEQUENCE_LEVEL_3 = "%/E"
|
|
20
|
+
|
|
21
|
+
# Maximum Joliet filename length in characters
|
|
22
|
+
MAX_FILENAME_LENGTH = 64
|
|
23
|
+
|
|
24
|
+
# Encode string to UCS-2 (UTF-16BE)
|
|
25
|
+
#
|
|
26
|
+
# @param str [String] String to encode
|
|
27
|
+
# @param max_length [Integer] Maximum length in characters
|
|
28
|
+
# @return [String] UCS-2 encoded string
|
|
29
|
+
def self.encode_ucs2(str, max_length = MAX_FILENAME_LENGTH)
|
|
30
|
+
# Truncate to max length
|
|
31
|
+
str = str[0, max_length] if str.length > max_length
|
|
32
|
+
|
|
33
|
+
# Encode to UTF-16BE (UCS-2)
|
|
34
|
+
str.encode("UTF-16BE")
|
|
35
|
+
rescue Encoding::UndefinedConversionError
|
|
36
|
+
# Fallback to ASCII if conversion fails
|
|
37
|
+
str.encode("UTF-16BE", undef: :replace, replace: "_")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Decode UCS-2 string to UTF-8
|
|
41
|
+
#
|
|
42
|
+
# @param ucs2_data [String] UCS-2 encoded data
|
|
43
|
+
# @return [String] UTF-8 string
|
|
44
|
+
def self.decode_ucs2(ucs2_data)
|
|
45
|
+
ucs2_data.force_encoding("UTF-16BE").encode("UTF-8")
|
|
46
|
+
rescue Encoding::UndefinedConversionError
|
|
47
|
+
# Fallback if decoding fails
|
|
48
|
+
ucs2_data.force_encoding("UTF-16BE").encode("UTF-8",
|
|
49
|
+
undef: :replace,
|
|
50
|
+
replace: "?")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Build Joliet directory record
|
|
54
|
+
#
|
|
55
|
+
# @param name [String] Entry name
|
|
56
|
+
# @param entry_info [Hash] Entry information
|
|
57
|
+
# @param is_directory [Boolean] Is this a directory
|
|
58
|
+
# @return [String] Joliet directory record
|
|
59
|
+
def self.build_directory_record(name, entry_info, is_directory: false)
|
|
60
|
+
# Encode name to UCS-2
|
|
61
|
+
name_ucs2 = encode_ucs2(name)
|
|
62
|
+
name_len = name_ucs2.bytesize
|
|
63
|
+
|
|
64
|
+
# Calculate record length
|
|
65
|
+
# No padding needed for UCS-2 names (always even length)
|
|
66
|
+
record_len = 33 + name_len
|
|
67
|
+
|
|
68
|
+
record = +""
|
|
69
|
+
|
|
70
|
+
# Byte 0: Length of directory record
|
|
71
|
+
record << [record_len].pack("C")
|
|
72
|
+
|
|
73
|
+
# Byte 1: Extended attribute record length
|
|
74
|
+
record << [0].pack("C")
|
|
75
|
+
|
|
76
|
+
# Bytes 2-9: Location of extent (both-endian)
|
|
77
|
+
location = entry_info[:location] || 0
|
|
78
|
+
record << [location].pack("V")
|
|
79
|
+
record << [location].pack("N")
|
|
80
|
+
|
|
81
|
+
# Bytes 10-17: Data length (both-endian)
|
|
82
|
+
data_length = entry_info[:size] || 0
|
|
83
|
+
record << [data_length].pack("V")
|
|
84
|
+
record << [data_length].pack("N")
|
|
85
|
+
|
|
86
|
+
# Bytes 18-24: Recording date and time
|
|
87
|
+
mtime = entry_info[:mtime] || entry_info[:stat]&.mtime || Time.now
|
|
88
|
+
record << encode_record_datetime(mtime)
|
|
89
|
+
|
|
90
|
+
# Byte 25: File flags
|
|
91
|
+
flags = 0
|
|
92
|
+
flags |= Iso::FLAG_DIRECTORY if is_directory
|
|
93
|
+
record << [flags].pack("C")
|
|
94
|
+
|
|
95
|
+
# Byte 26: File unit size
|
|
96
|
+
record << [0].pack("C")
|
|
97
|
+
|
|
98
|
+
# Byte 27: Interleave gap size
|
|
99
|
+
record << [0].pack("C")
|
|
100
|
+
|
|
101
|
+
# Bytes 28-31: Volume sequence number (both-endian)
|
|
102
|
+
record << [1].pack("v")
|
|
103
|
+
record << [1].pack("n")
|
|
104
|
+
|
|
105
|
+
# Byte 32: Length of file identifier
|
|
106
|
+
record << [name_len].pack("C")
|
|
107
|
+
|
|
108
|
+
# Bytes 33+: File identifier (UCS-2 encoded)
|
|
109
|
+
record << name_ucs2
|
|
110
|
+
|
|
111
|
+
record
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Sanitize filename for Joliet
|
|
115
|
+
#
|
|
116
|
+
# @param name [String] Original filename
|
|
117
|
+
# @return [String] Sanitized filename
|
|
118
|
+
def self.sanitize_filename(name)
|
|
119
|
+
# Joliet allows most Unicode characters
|
|
120
|
+
# Maximum 64 characters
|
|
121
|
+
# Disallow: / * ? < > | " : \
|
|
122
|
+
|
|
123
|
+
sanitized = name.gsub(/[\/*?<>|":\\]/, "_")
|
|
124
|
+
if sanitized.length > MAX_FILENAME_LENGTH
|
|
125
|
+
sanitized = sanitized[0,
|
|
126
|
+
MAX_FILENAME_LENGTH]
|
|
127
|
+
end
|
|
128
|
+
sanitized
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Check if filename requires Joliet
|
|
132
|
+
#
|
|
133
|
+
# @param name [String] Filename
|
|
134
|
+
# @return [Boolean] true if Joliet needed
|
|
135
|
+
def self.requires_joliet?(name)
|
|
136
|
+
# Check if name exceeds ISO 9660 Level 2 limits
|
|
137
|
+
return true if name.length > 31
|
|
138
|
+
|
|
139
|
+
# Check if name contains non-ASCII or lowercase
|
|
140
|
+
return true if /[^A-Z0-9_.-]/.match?(name)
|
|
141
|
+
|
|
142
|
+
# Check if name contains Unicode
|
|
143
|
+
name.encoding != Encoding::ASCII && name.bytes.any? { |b| b > 127 }
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Build Joliet supplementary volume descriptor
|
|
147
|
+
#
|
|
148
|
+
# @param primary_vd [String] Primary volume descriptor data
|
|
149
|
+
# @param root_dir [Hash] Root directory information
|
|
150
|
+
# @return [String] Joliet SVD (2048 bytes)
|
|
151
|
+
def self.build_supplementary_vd(primary_vd, _root_dir)
|
|
152
|
+
# Start with primary VD as template
|
|
153
|
+
svd = primary_vd.dup
|
|
154
|
+
|
|
155
|
+
# Change type to supplementary
|
|
156
|
+
svd[0] = [Iso::VD_SUPPLEMENTARY].pack("C")
|
|
157
|
+
|
|
158
|
+
# Add Joliet escape sequence
|
|
159
|
+
# Bytes 88-90: Escape sequences
|
|
160
|
+
svd[88, 3] = ESCAPE_SEQUENCE_LEVEL_3
|
|
161
|
+
|
|
162
|
+
# Encode volume identifier to UCS-2
|
|
163
|
+
volume_id = primary_vd[40, 32].strip
|
|
164
|
+
volume_id_ucs2 = encode_ucs2(volume_id, 16)
|
|
165
|
+
svd[40, 32] = pad_ucs2_string(volume_id_ucs2, 32)
|
|
166
|
+
|
|
167
|
+
# Update root directory record with UCS-2 name
|
|
168
|
+
# Root is always "\x00" so no change needed
|
|
169
|
+
|
|
170
|
+
svd
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Pad UCS-2 string to specified length
|
|
174
|
+
#
|
|
175
|
+
# @param ucs2_str [String] UCS-2 string
|
|
176
|
+
# @param byte_length [Integer] Target length in bytes
|
|
177
|
+
# @return [String] Padded string
|
|
178
|
+
def self.pad_ucs2_string(ucs2_str, byte_length)
|
|
179
|
+
if ucs2_str.bytesize > byte_length
|
|
180
|
+
ucs2_str[0, byte_length]
|
|
181
|
+
else
|
|
182
|
+
ucs2_str + (" ".encode("UTF-16BE") * ((byte_length - ucs2_str.bytesize) / 2))
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Encode recording date/time (7-byte format)
|
|
187
|
+
#
|
|
188
|
+
# @param time [Time] Time to encode
|
|
189
|
+
# @return [String] 7-byte encoded time
|
|
190
|
+
def self.encode_record_datetime(time)
|
|
191
|
+
[
|
|
192
|
+
time.year - 1900,
|
|
193
|
+
time.month,
|
|
194
|
+
time.day,
|
|
195
|
+
time.hour,
|
|
196
|
+
time.min,
|
|
197
|
+
time.sec,
|
|
198
|
+
0, # GMT offset
|
|
199
|
+
].pack("C7")
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Iso
|
|
6
|
+
# ISO 9660 Path Table
|
|
7
|
+
# Provides efficient directory hierarchy lookup
|
|
8
|
+
class PathTable
|
|
9
|
+
attr_reader :entries
|
|
10
|
+
|
|
11
|
+
# Path table entry
|
|
12
|
+
class Entry
|
|
13
|
+
attr_reader :name, :location, :parent_directory_number
|
|
14
|
+
|
|
15
|
+
# Initialize entry
|
|
16
|
+
#
|
|
17
|
+
# @param name [String] Directory name
|
|
18
|
+
# @param location [Integer] LBA location
|
|
19
|
+
# @param parent_directory_number [Integer] Parent directory index
|
|
20
|
+
def initialize(name, location, parent_directory_number)
|
|
21
|
+
@name = name
|
|
22
|
+
@location = location
|
|
23
|
+
@parent_directory_number = parent_directory_number
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Get full path by traversing parent entries
|
|
27
|
+
#
|
|
28
|
+
# @param entries [Array<Entry>] All path table entries
|
|
29
|
+
# @return [String] Full path
|
|
30
|
+
def full_path(entries)
|
|
31
|
+
return "/" if @parent_directory_number == 1 # Root
|
|
32
|
+
|
|
33
|
+
parts = [@name]
|
|
34
|
+
current_parent = @parent_directory_number
|
|
35
|
+
|
|
36
|
+
while current_parent > 1
|
|
37
|
+
parent = entries[current_parent - 1]
|
|
38
|
+
break unless parent
|
|
39
|
+
|
|
40
|
+
parts.unshift(parent.name)
|
|
41
|
+
current_parent = parent.parent_directory_number
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
"/#{parts.join('/')}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Initialize path table
|
|
49
|
+
def initialize
|
|
50
|
+
@entries = []
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Parse path table from binary data
|
|
54
|
+
#
|
|
55
|
+
# @param data [String] Binary path table data
|
|
56
|
+
# @param size [Integer] Size of path table in bytes
|
|
57
|
+
# @return [PathTable] Parsed path table
|
|
58
|
+
def self.parse(data, size)
|
|
59
|
+
new.tap { |pt| pt.parse(data, size) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Parse path table data
|
|
63
|
+
#
|
|
64
|
+
# @param data [String] Binary data
|
|
65
|
+
# @param size [Integer] Size in bytes
|
|
66
|
+
def parse(data, size)
|
|
67
|
+
offset = 0
|
|
68
|
+
|
|
69
|
+
while offset < size
|
|
70
|
+
# Byte 0: Length of directory identifier
|
|
71
|
+
name_length = data.getbyte(offset)
|
|
72
|
+
break if name_length.zero?
|
|
73
|
+
|
|
74
|
+
# Byte 1: Extended attribute record length
|
|
75
|
+
data.getbyte(offset + 1)
|
|
76
|
+
|
|
77
|
+
# Bytes 2-5: Location of extent (little-endian)
|
|
78
|
+
location = data[offset + 2, 4].unpack1("V")
|
|
79
|
+
|
|
80
|
+
# Bytes 6-7: Parent directory number
|
|
81
|
+
parent = data[offset + 6, 2].unpack1("v")
|
|
82
|
+
|
|
83
|
+
# Bytes 8+: Directory identifier
|
|
84
|
+
name = data[offset + 8, name_length].strip
|
|
85
|
+
|
|
86
|
+
# Handle root directory (zero-length name)
|
|
87
|
+
name = "/" if name.empty?
|
|
88
|
+
|
|
89
|
+
# Create entry
|
|
90
|
+
@entries << Entry.new(name, location, parent)
|
|
91
|
+
|
|
92
|
+
# Move to next entry
|
|
93
|
+
# Length is 8 + name_length, padded to even boundary
|
|
94
|
+
record_length = 8 + name_length
|
|
95
|
+
record_length += 1 if record_length.odd?
|
|
96
|
+
offset += record_length
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Find entry by directory name
|
|
101
|
+
#
|
|
102
|
+
# @param name [String] Directory name
|
|
103
|
+
# @return [Entry, nil] Found entry or nil
|
|
104
|
+
def find_by_name(name)
|
|
105
|
+
@entries.find { |e| e.name == name }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Find entry by location
|
|
109
|
+
#
|
|
110
|
+
# @param location [Integer] LBA location
|
|
111
|
+
# @return [Entry, nil] Found entry or nil
|
|
112
|
+
def find_by_location(location)
|
|
113
|
+
@entries.find { |e| e.location == location }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Get root directory entry
|
|
117
|
+
#
|
|
118
|
+
# @return [Entry] Root entry
|
|
119
|
+
def root
|
|
120
|
+
@entries.first
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Omnizip
|
|
6
|
+
module Formats
|
|
7
|
+
module Iso
|
|
8
|
+
# ISO 9660 image reader
|
|
9
|
+
# Provides read-only access to ISO filesystem
|
|
10
|
+
class Reader
|
|
11
|
+
attr_reader :file_path, :primary_volume_descriptor, :entries,
|
|
12
|
+
:path_table
|
|
13
|
+
|
|
14
|
+
# Initialize reader
|
|
15
|
+
#
|
|
16
|
+
# @param file_path [String] Path to ISO file
|
|
17
|
+
def initialize(file_path)
|
|
18
|
+
@file_path = file_path
|
|
19
|
+
@primary_volume_descriptor = nil
|
|
20
|
+
@entries = []
|
|
21
|
+
@path_table = nil
|
|
22
|
+
@io = nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Open and parse ISO image
|
|
26
|
+
#
|
|
27
|
+
# @raise [RuntimeError] if file cannot be opened or is invalid
|
|
28
|
+
def open
|
|
29
|
+
@io = File.open(@file_path, "rb")
|
|
30
|
+
parse_volume_descriptors
|
|
31
|
+
parse_directory_structure
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Close ISO file
|
|
36
|
+
def close
|
|
37
|
+
@io&.close
|
|
38
|
+
@io = nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Get volume identifier
|
|
42
|
+
#
|
|
43
|
+
# @return [String] Volume name
|
|
44
|
+
def volume_identifier
|
|
45
|
+
@primary_volume_descriptor&.volume_identifier || ""
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Get system identifier
|
|
49
|
+
#
|
|
50
|
+
# @return [String] System identifier
|
|
51
|
+
def system_identifier
|
|
52
|
+
@primary_volume_descriptor&.system_identifier || ""
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Get volume size in bytes
|
|
56
|
+
#
|
|
57
|
+
# @return [Integer] Total volume size
|
|
58
|
+
def volume_size
|
|
59
|
+
return 0 unless @primary_volume_descriptor
|
|
60
|
+
|
|
61
|
+
@primary_volume_descriptor.volume_space_size * Iso::SECTOR_SIZE
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Extract entry to file
|
|
65
|
+
#
|
|
66
|
+
# @param entry_path [String] Path in ISO
|
|
67
|
+
# @param output_path [String] Destination path
|
|
68
|
+
def extract_entry(entry_path, output_path)
|
|
69
|
+
entry = find_entry(entry_path)
|
|
70
|
+
raise Errno::ENOENT, "Entry not found: #{entry_path}" unless entry
|
|
71
|
+
|
|
72
|
+
if entry.directory?
|
|
73
|
+
FileUtils.mkdir_p(output_path)
|
|
74
|
+
else
|
|
75
|
+
FileUtils.mkdir_p(File.dirname(output_path))
|
|
76
|
+
data = read_file_data(entry)
|
|
77
|
+
File.binwrite(output_path, data)
|
|
78
|
+
|
|
79
|
+
# Set modification time if available
|
|
80
|
+
File.utime(entry.mtime, entry.mtime, output_path) if entry.mtime
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Extract all entries
|
|
85
|
+
#
|
|
86
|
+
# @param output_dir [String] Output directory
|
|
87
|
+
def extract_all(output_dir)
|
|
88
|
+
FileUtils.mkdir_p(output_dir)
|
|
89
|
+
|
|
90
|
+
@entries.each do |entry|
|
|
91
|
+
next if entry.current_directory? || entry.parent_directory?
|
|
92
|
+
|
|
93
|
+
output_path = File.join(output_dir, entry.full_path)
|
|
94
|
+
extract_entry(entry.full_path, output_path)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# List all entries
|
|
99
|
+
#
|
|
100
|
+
# @return [Array<DirectoryRecord>] All entries
|
|
101
|
+
def list_files
|
|
102
|
+
@entries.reject { |e| e.current_directory? || e.parent_directory? }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
# Parse volume descriptors
|
|
108
|
+
def parse_volume_descriptors
|
|
109
|
+
sector = Iso::VOLUME_DESCRIPTOR_START
|
|
110
|
+
|
|
111
|
+
loop do
|
|
112
|
+
@io.seek(sector * Iso::SECTOR_SIZE)
|
|
113
|
+
data = @io.read(Iso::SECTOR_SIZE)
|
|
114
|
+
raise Omnizip::InvalidArchiveError, "Failed to read volume descriptor" unless data
|
|
115
|
+
|
|
116
|
+
vd = VolumeDescriptor.parse(data)
|
|
117
|
+
|
|
118
|
+
case vd.type
|
|
119
|
+
when Iso::VD_PRIMARY
|
|
120
|
+
@primary_volume_descriptor = vd
|
|
121
|
+
when Iso::VD_TERMINATOR
|
|
122
|
+
break
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
sector += 1
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
return if @primary_volume_descriptor
|
|
129
|
+
|
|
130
|
+
raise Omnizip::InvalidArchiveError, "No primary volume descriptor found"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Parse directory structure
|
|
134
|
+
def parse_directory_structure
|
|
135
|
+
return unless @primary_volume_descriptor
|
|
136
|
+
|
|
137
|
+
root = @primary_volume_descriptor.root_directory_record
|
|
138
|
+
parse_directory(root, "")
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Recursively parse directory
|
|
142
|
+
#
|
|
143
|
+
# @param dir_record [DirectoryRecord] Directory record
|
|
144
|
+
# @param path_prefix [String] Path prefix
|
|
145
|
+
def parse_directory(dir_record, path_prefix)
|
|
146
|
+
# Read directory data
|
|
147
|
+
@io.seek(dir_record.location * Iso::SECTOR_SIZE)
|
|
148
|
+
dir_data = @io.read(dir_record.data_length)
|
|
149
|
+
|
|
150
|
+
offset = 0
|
|
151
|
+
while offset < dir_data.bytesize
|
|
152
|
+
length = dir_data.getbyte(offset)
|
|
153
|
+
break if length.zero? # End of directory
|
|
154
|
+
|
|
155
|
+
record = DirectoryRecord.parse(dir_data, offset)
|
|
156
|
+
|
|
157
|
+
# Skip current and parent directory entries
|
|
158
|
+
unless record.current_directory? || record.parent_directory?
|
|
159
|
+
# Set full path
|
|
160
|
+
full_path = path_prefix.empty? ? record.name : "#{path_prefix}/#{record.name}"
|
|
161
|
+
record.full_path = full_path
|
|
162
|
+
|
|
163
|
+
@entries << record
|
|
164
|
+
|
|
165
|
+
# Recursively parse subdirectories
|
|
166
|
+
parse_directory(record, full_path) if record.directory?
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
offset += length
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Find entry by path
|
|
174
|
+
#
|
|
175
|
+
# @param path [String] Entry path
|
|
176
|
+
# @return [DirectoryRecord, nil] Found entry
|
|
177
|
+
def find_entry(path)
|
|
178
|
+
# Normalize path
|
|
179
|
+
path = path.gsub(%r{^/+}, "").gsub(%r{/+$}, "")
|
|
180
|
+
@entries.find { |e| e.full_path == path }
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Read file data
|
|
184
|
+
#
|
|
185
|
+
# @param entry [DirectoryRecord] File entry
|
|
186
|
+
# @return [String] File data
|
|
187
|
+
def read_file_data(entry)
|
|
188
|
+
@io.seek(entry.location * Iso::SECTOR_SIZE)
|
|
189
|
+
@io.read(entry.size)
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|