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,236 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zlib"
|
|
4
|
+
require "stringio"
|
|
5
|
+
|
|
6
|
+
module Omnizip
|
|
7
|
+
module Formats
|
|
8
|
+
# GZIP compression format
|
|
9
|
+
#
|
|
10
|
+
# GZIP is a file compression format that wraps Deflate compression
|
|
11
|
+
# with a 10-byte header and 8-byte footer containing CRC32 and
|
|
12
|
+
# uncompressed size.
|
|
13
|
+
#
|
|
14
|
+
# Format structure:
|
|
15
|
+
# - Header (10 bytes minimum):
|
|
16
|
+
# - Magic bytes: 0x1F 0x8B
|
|
17
|
+
# - Compression method: 0x08 (Deflate)
|
|
18
|
+
# - Flags
|
|
19
|
+
# - Modification time (4 bytes)
|
|
20
|
+
# - Extra flags
|
|
21
|
+
# - OS type
|
|
22
|
+
# - Compressed data (Deflate)
|
|
23
|
+
# - Footer (8 bytes):
|
|
24
|
+
# - CRC32 (4 bytes)
|
|
25
|
+
# - Uncompressed size (4 bytes, modulo 2^32)
|
|
26
|
+
module Gzip
|
|
27
|
+
# GZIP magic bytes
|
|
28
|
+
GZIP_MAGIC = [0x1F, 0x8B].pack("C*")
|
|
29
|
+
|
|
30
|
+
# Compression method (Deflate)
|
|
31
|
+
CM_DEFLATE = 8
|
|
32
|
+
|
|
33
|
+
# Flag bits
|
|
34
|
+
FTEXT = 0x01 # File is text
|
|
35
|
+
FHCRC = 0x02 # Header CRC present
|
|
36
|
+
FEXTRA = 0x04 # Extra fields present
|
|
37
|
+
FNAME = 0x08 # Original filename present
|
|
38
|
+
FCOMMENT = 0x10 # Comment present
|
|
39
|
+
|
|
40
|
+
# OS types
|
|
41
|
+
OS_FAT = 0 # FAT filesystem
|
|
42
|
+
OS_UNIX = 3 # Unix
|
|
43
|
+
OS_UNKNOWN = 255 # Unknown
|
|
44
|
+
|
|
45
|
+
class << self
|
|
46
|
+
# Compress a file with GZIP
|
|
47
|
+
#
|
|
48
|
+
# @param input_path [String] Input file path
|
|
49
|
+
# @param output_path [String] Output GZIP file path
|
|
50
|
+
# @param options [Hash] Compression options
|
|
51
|
+
# @option options [Integer] :level Compression level (0-9)
|
|
52
|
+
# @option options [String] :original_name Original filename
|
|
53
|
+
# @option options [Time] :mtime Modification time
|
|
54
|
+
def compress(input_path, output_path, options = {})
|
|
55
|
+
input_data = File.binread(input_path)
|
|
56
|
+
|
|
57
|
+
File.open(output_path, "wb") do |output|
|
|
58
|
+
original_name = options[:original_name] ||
|
|
59
|
+
File.basename(input_path)
|
|
60
|
+
compress_stream(
|
|
61
|
+
StringIO.new(input_data),
|
|
62
|
+
output,
|
|
63
|
+
options.merge(original_name: original_name),
|
|
64
|
+
)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Decompress a GZIP file
|
|
69
|
+
#
|
|
70
|
+
# @param input_path [String] Input GZIP file path
|
|
71
|
+
# @param output_path [String] Output file path
|
|
72
|
+
def decompress(input_path, output_path)
|
|
73
|
+
File.open(input_path, "rb") do |input|
|
|
74
|
+
File.open(output_path, "wb") do |output|
|
|
75
|
+
decompress_stream(input, output)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Compress data stream with GZIP
|
|
81
|
+
#
|
|
82
|
+
# @param input_io [IO] Input stream
|
|
83
|
+
# @param output_io [IO] Output stream
|
|
84
|
+
# @param options [Hash] Compression options
|
|
85
|
+
def compress_stream(input_io, output_io, options = {})
|
|
86
|
+
input_data = input_io.read
|
|
87
|
+
level = options[:level] || Zlib::DEFAULT_COMPRESSION
|
|
88
|
+
mtime = options[:mtime] || Time.now
|
|
89
|
+
original_name = options[:original_name]
|
|
90
|
+
|
|
91
|
+
# Write GZIP header
|
|
92
|
+
write_header(output_io, mtime, original_name)
|
|
93
|
+
|
|
94
|
+
# RFC 1952 member: header + RAW deflate + CRC32/ISIZE footer.
|
|
95
|
+
# The old implementation layered zlib's own GZIP wrapper
|
|
96
|
+
# under this header (a second 1F 8B magic) — the gem's
|
|
97
|
+
# reader tolerated it, but every standard gzip tool
|
|
98
|
+
# rejected the output. Raw-window mode emits bare DEFLATE.
|
|
99
|
+
deflate = Zlib::Deflate.new(level, -Zlib::MAX_WBITS)
|
|
100
|
+
output_io.write(deflate.deflate(input_data, Zlib::FINISH))
|
|
101
|
+
deflate.close
|
|
102
|
+
|
|
103
|
+
# Write GZIP footer
|
|
104
|
+
write_footer(output_io, input_data)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Decompress GZIP stream
|
|
108
|
+
#
|
|
109
|
+
# @param input_io [IO] Input stream
|
|
110
|
+
# @param output_io [IO] Output stream
|
|
111
|
+
# @return [Hash] Metadata (original_name, mtime)
|
|
112
|
+
def decompress_stream(input_io, output_io)
|
|
113
|
+
data = input_io.read
|
|
114
|
+
|
|
115
|
+
# Metadata comes from the header either way (cheap parse).
|
|
116
|
+
metadata = read_header(StringIO.new(data))
|
|
117
|
+
|
|
118
|
+
# The tier gets the WHOLE member (header + deflate + trailer)
|
|
119
|
+
# — the Rust "gzip" name decodes the container end-to-end.
|
|
120
|
+
decompressed = Backends.decompress("gzip", data, Backends::UNKNOWN_LENGTH) do
|
|
121
|
+
body = StringIO.new(data)
|
|
122
|
+
read_header(body) # skip past the header
|
|
123
|
+
# Legacy double-header members (written before the RFC
|
|
124
|
+
# 1952 fix) carry zlib's own 10-byte GZIP header here;
|
|
125
|
+
# standard members carry bare DEFLATE.
|
|
126
|
+
rest = body.read
|
|
127
|
+
rest = rest.byteslice(10..) if rest.byteslice(0, 2) == "\x1F\x8B".b
|
|
128
|
+
inflate = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
|
129
|
+
result = inflate.inflate(rest)
|
|
130
|
+
inflate.close
|
|
131
|
+
result
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
output_io.write(decompressed)
|
|
135
|
+
|
|
136
|
+
metadata
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
# Write GZIP header
|
|
142
|
+
#
|
|
143
|
+
# @param output [IO] Output stream
|
|
144
|
+
# @param mtime [Time] Modification time
|
|
145
|
+
# @param original_name [String, nil] Original filename
|
|
146
|
+
def write_header(output, mtime, original_name = nil)
|
|
147
|
+
flags = 0
|
|
148
|
+
flags |= FNAME if original_name
|
|
149
|
+
|
|
150
|
+
header = [
|
|
151
|
+
0x1F, 0x8B, # Magic
|
|
152
|
+
CM_DEFLATE, # Compression method
|
|
153
|
+
flags, # Flags
|
|
154
|
+
mtime.to_i, # Modification time
|
|
155
|
+
0, # Extra flags
|
|
156
|
+
OS_UNIX # OS type
|
|
157
|
+
].pack("C C C C V C C")
|
|
158
|
+
|
|
159
|
+
output.write(header)
|
|
160
|
+
|
|
161
|
+
# Write original filename if present
|
|
162
|
+
return unless original_name
|
|
163
|
+
|
|
164
|
+
output.write(original_name)
|
|
165
|
+
output.write("\0")
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Read GZIP header
|
|
169
|
+
#
|
|
170
|
+
# @param input [IO] Input stream
|
|
171
|
+
# @return [Hash] Header metadata
|
|
172
|
+
def read_header(input)
|
|
173
|
+
magic = input.read(2)
|
|
174
|
+
unless magic == GZIP_MAGIC
|
|
175
|
+
raise Error, "Not a GZIP file (invalid magic bytes)"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
cm = input.read(1).unpack1("C")
|
|
179
|
+
unless cm == CM_DEFLATE
|
|
180
|
+
raise Error, "Unsupported GZIP compression method: #{cm}"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
flags = input.read(1).unpack1("C")
|
|
184
|
+
mtime = Time.at(input.read(4).unpack1("V"))
|
|
185
|
+
_xfl = input.read(1)
|
|
186
|
+
_os = input.read(1)
|
|
187
|
+
|
|
188
|
+
metadata = { mtime: mtime }
|
|
189
|
+
|
|
190
|
+
# Read extra fields if present
|
|
191
|
+
if flags.anybits?(FEXTRA)
|
|
192
|
+
xlen = input.read(2).unpack1("v")
|
|
193
|
+
input.read(xlen) # Skip extra data
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Read original filename if present
|
|
197
|
+
if flags.anybits?(FNAME)
|
|
198
|
+
name = +""
|
|
199
|
+
loop do
|
|
200
|
+
byte = input.read(1)
|
|
201
|
+
break if byte == "\0"
|
|
202
|
+
|
|
203
|
+
name << byte
|
|
204
|
+
end
|
|
205
|
+
metadata[:original_name] = name
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Read comment if present
|
|
209
|
+
if flags.anybits?(FCOMMENT)
|
|
210
|
+
loop do
|
|
211
|
+
byte = input.read(1)
|
|
212
|
+
break if byte == "\0"
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
# Read header CRC if present
|
|
217
|
+
input.read(2) if flags.anybits?(FHCRC)
|
|
218
|
+
|
|
219
|
+
metadata
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Write GZIP footer
|
|
223
|
+
#
|
|
224
|
+
# @param output [IO] Output stream
|
|
225
|
+
# @param uncompressed_data [String] Original uncompressed data
|
|
226
|
+
def write_footer(output, uncompressed_data)
|
|
227
|
+
crc32 = Zlib.crc32(uncompressed_data)
|
|
228
|
+
size = uncompressed_data.bytesize & 0xFFFFFFFF
|
|
229
|
+
|
|
230
|
+
footer = [crc32, size].pack("VV")
|
|
231
|
+
output.write(footer)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Iso
|
|
6
|
+
# ISO 9660 Directory Structure Builder
|
|
7
|
+
#
|
|
8
|
+
# Builds the hierarchical directory structure for an ISO image,
|
|
9
|
+
# allocating sectors for directories and files.
|
|
10
|
+
class DirectoryBuilder
|
|
11
|
+
# @return [Array<Hash>] Files to add
|
|
12
|
+
attr_reader :files
|
|
13
|
+
|
|
14
|
+
# @return [Array<Hash>] Directories to add
|
|
15
|
+
attr_reader :directories
|
|
16
|
+
|
|
17
|
+
# @return [Integer] ISO level
|
|
18
|
+
attr_reader :level
|
|
19
|
+
|
|
20
|
+
# @return [Boolean] Rock Ridge enabled
|
|
21
|
+
attr_reader :rock_ridge
|
|
22
|
+
|
|
23
|
+
# Initialize directory builder
|
|
24
|
+
#
|
|
25
|
+
# @param files [Array<Hash>] Files to include
|
|
26
|
+
# @param directories [Array<Hash>] Directories to include
|
|
27
|
+
# @param options [Hash] Builder options
|
|
28
|
+
def initialize(files, directories, options = {})
|
|
29
|
+
@files = files
|
|
30
|
+
@directories = directories
|
|
31
|
+
@level = options.fetch(:level, 2)
|
|
32
|
+
@rock_ridge = options.fetch(:rock_ridge, false)
|
|
33
|
+
@current_sector = 22 # After volume descriptors and path tables
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Build directory structure
|
|
37
|
+
#
|
|
38
|
+
# @return [Hash] Complete directory structure with allocations
|
|
39
|
+
def build
|
|
40
|
+
# Build directory tree
|
|
41
|
+
tree = build_directory_tree
|
|
42
|
+
|
|
43
|
+
# Allocate sectors for directories and files
|
|
44
|
+
allocate_sectors(tree)
|
|
45
|
+
|
|
46
|
+
# Tree nodes are separate hashes from @files entries; copy
|
|
47
|
+
# the allocated file locations onto the tree so directory
|
|
48
|
+
# records reference the real extents (otherwise every
|
|
49
|
+
# record points at sector 0).
|
|
50
|
+
assign_file_locations(tree)
|
|
51
|
+
|
|
52
|
+
# Build path table
|
|
53
|
+
path_table = build_path_table(tree)
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
root: tree,
|
|
57
|
+
directories: flatten_directories(tree),
|
|
58
|
+
files: @files,
|
|
59
|
+
path_table: path_table,
|
|
60
|
+
path_table_size: path_table.bytesize,
|
|
61
|
+
total_sectors: @current_sector,
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
# Build directory tree from files and directories
|
|
68
|
+
#
|
|
69
|
+
# @return [Hash] Root directory node
|
|
70
|
+
def build_directory_tree
|
|
71
|
+
root = {
|
|
72
|
+
name: "\x00", # Root directory identifier
|
|
73
|
+
iso_path: "",
|
|
74
|
+
children: [],
|
|
75
|
+
directory: true,
|
|
76
|
+
stat: nil,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Add all directories first
|
|
80
|
+
@directories.each do |dir_info|
|
|
81
|
+
add_to_tree(root, dir_info[:iso_path], dir_info)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Add all files
|
|
85
|
+
@files.each do |file_info|
|
|
86
|
+
add_to_tree(root, file_info[:iso_path], file_info)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
root
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Add entry to directory tree
|
|
93
|
+
#
|
|
94
|
+
# @param root [Hash] Root node
|
|
95
|
+
# @param path [String] Entry path
|
|
96
|
+
# @param info [Hash] Entry information
|
|
97
|
+
def add_to_tree(root, path, info)
|
|
98
|
+
parts = path.split("/")
|
|
99
|
+
current = root
|
|
100
|
+
|
|
101
|
+
# Navigate/create directory structure
|
|
102
|
+
parts[0...-1].each do |part|
|
|
103
|
+
# Ensure current node has children array (it should be a directory)
|
|
104
|
+
current[:children] ||= []
|
|
105
|
+
child = current[:children].find { |c| c[:name] == part }
|
|
106
|
+
|
|
107
|
+
unless child
|
|
108
|
+
child = {
|
|
109
|
+
name: part,
|
|
110
|
+
iso_path: [current[:iso_path], part].reject(&:empty?).join("/"),
|
|
111
|
+
children: [],
|
|
112
|
+
directory: true,
|
|
113
|
+
stat: nil,
|
|
114
|
+
}
|
|
115
|
+
current[:children] << child
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
current = child
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Add the actual entry
|
|
122
|
+
entry_name = parts.last
|
|
123
|
+
entry = {
|
|
124
|
+
name: entry_name,
|
|
125
|
+
iso_path: path,
|
|
126
|
+
children: info[:directory] ? [] : nil,
|
|
127
|
+
directory: info[:directory] || false,
|
|
128
|
+
stat: info[:stat],
|
|
129
|
+
source: info[:source],
|
|
130
|
+
size: info[:directory] ? 0 : File.size(info[:source]),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
# Ensure current node has children array
|
|
134
|
+
current[:children] ||= []
|
|
135
|
+
current[:children] << entry
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Allocate sectors for all entries
|
|
139
|
+
#
|
|
140
|
+
# @param tree [Hash] Directory tree
|
|
141
|
+
def allocate_sectors(tree)
|
|
142
|
+
# Allocate for root directory
|
|
143
|
+
allocate_directory_sectors(tree)
|
|
144
|
+
|
|
145
|
+
# Recursively allocate for children
|
|
146
|
+
allocate_children_sectors(tree)
|
|
147
|
+
|
|
148
|
+
# Allocate for files
|
|
149
|
+
allocate_file_sectors
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Copy allocated file locations onto the matching tree nodes
|
|
153
|
+
#
|
|
154
|
+
# @param tree [Hash] Directory tree root
|
|
155
|
+
def assign_file_locations(tree)
|
|
156
|
+
walk = lambda do |node|
|
|
157
|
+
(node[:children] || []).each do |child|
|
|
158
|
+
if child[:directory]
|
|
159
|
+
walk.call(child)
|
|
160
|
+
else
|
|
161
|
+
match = @files.find { |f| f[:iso_path] == child[:iso_path] }
|
|
162
|
+
child[:location] = match[:location] if match
|
|
163
|
+
child[:size] = match[:size] if match
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
walk.call(tree)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Allocate sectors for a directory
|
|
171
|
+
#
|
|
172
|
+
# @param dir_node [Hash] Directory node
|
|
173
|
+
def allocate_directory_sectors(dir_node)
|
|
174
|
+
# Calculate directory size
|
|
175
|
+
dir_size = calculate_directory_size(dir_node)
|
|
176
|
+
sectors_needed = (dir_size.to_f / Iso::SECTOR_SIZE).ceil
|
|
177
|
+
|
|
178
|
+
# Allocate location
|
|
179
|
+
dir_node[:location] = @current_sector
|
|
180
|
+
dir_node[:size] = dir_size
|
|
181
|
+
|
|
182
|
+
@current_sector += sectors_needed
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Calculate directory data size
|
|
186
|
+
#
|
|
187
|
+
# @param dir_node [Hash] Directory node
|
|
188
|
+
# @return [Integer] Size in bytes
|
|
189
|
+
def calculate_directory_size(dir_node)
|
|
190
|
+
size = 0
|
|
191
|
+
|
|
192
|
+
# Size for "." entry (34 bytes minimum)
|
|
193
|
+
size += 34
|
|
194
|
+
|
|
195
|
+
# Size for ".." entry
|
|
196
|
+
size += 34
|
|
197
|
+
|
|
198
|
+
# Size for each child entry
|
|
199
|
+
dir_node[:children].each do |child|
|
|
200
|
+
name_len = child[:name].bytesize
|
|
201
|
+
padding = name_len.even? ? 1 : 0
|
|
202
|
+
entry_size = 33 + name_len + padding
|
|
203
|
+
|
|
204
|
+
# Add Rock Ridge System Use fields if enabled
|
|
205
|
+
entry_size += calculate_rock_ridge_size(child) if @rock_ridge
|
|
206
|
+
|
|
207
|
+
size += entry_size
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Round up to sector boundary
|
|
211
|
+
((size.to_f / Iso::SECTOR_SIZE).ceil * Iso::SECTOR_SIZE)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Calculate Rock Ridge System Use field size
|
|
215
|
+
#
|
|
216
|
+
# @param entry [Hash] Entry information
|
|
217
|
+
# @return [Integer] Size in bytes
|
|
218
|
+
def calculate_rock_ridge_size(_entry)
|
|
219
|
+
# Basic Rock Ridge fields:
|
|
220
|
+
# - PX (POSIX attributes): 44 bytes
|
|
221
|
+
# - TF (timestamps): 26 bytes
|
|
222
|
+
# - NM (alternate name): variable
|
|
223
|
+
# For now, estimate 100 bytes
|
|
224
|
+
100
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
# Allocate sectors for children recursively
|
|
228
|
+
#
|
|
229
|
+
# @param dir_node [Hash] Directory node
|
|
230
|
+
def allocate_children_sectors(dir_node)
|
|
231
|
+
dir_node[:children].each do |child|
|
|
232
|
+
next unless child[:directory]
|
|
233
|
+
|
|
234
|
+
allocate_directory_sectors(child)
|
|
235
|
+
allocate_children_sectors(child)
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Allocate sectors for files
|
|
240
|
+
def allocate_file_sectors
|
|
241
|
+
@files.each do |file_info|
|
|
242
|
+
file_size = file_info[:stat].size
|
|
243
|
+
sectors_needed = (file_size.to_f / Iso::SECTOR_SIZE).ceil
|
|
244
|
+
|
|
245
|
+
file_info[:location] = @current_sector
|
|
246
|
+
file_info[:size] = file_size
|
|
247
|
+
|
|
248
|
+
@current_sector += sectors_needed
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Build path table from directory tree
|
|
253
|
+
#
|
|
254
|
+
# @param tree [Hash] Directory tree
|
|
255
|
+
# @return [String] Path table data
|
|
256
|
+
def build_path_table(tree)
|
|
257
|
+
table = +""
|
|
258
|
+
directories = []
|
|
259
|
+
|
|
260
|
+
# Collect all directories in path table order
|
|
261
|
+
collect_directories_for_path_table(tree, directories)
|
|
262
|
+
|
|
263
|
+
# Build path table entries
|
|
264
|
+
directories.each_with_index do |dir, _idx|
|
|
265
|
+
name = dir[:name] == "\x00" ? "\x00" : dir[:name]
|
|
266
|
+
parent_idx = dir[:parent_idx] || 0
|
|
267
|
+
|
|
268
|
+
# Name length
|
|
269
|
+
table << [name.bytesize].pack("C")
|
|
270
|
+
|
|
271
|
+
# Extended attribute length
|
|
272
|
+
table << [0].pack("C")
|
|
273
|
+
|
|
274
|
+
# Location of extent
|
|
275
|
+
table << [dir[:location]].pack("V")
|
|
276
|
+
|
|
277
|
+
# Parent directory number (1-based)
|
|
278
|
+
table << [parent_idx + 1].pack("v")
|
|
279
|
+
|
|
280
|
+
# Directory name
|
|
281
|
+
table << name
|
|
282
|
+
|
|
283
|
+
# Pad to even length
|
|
284
|
+
table << "\x00" if name.bytesize.odd?
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
table
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Collect directories in depth-first order for path table
|
|
291
|
+
#
|
|
292
|
+
# @param node [Hash] Current node
|
|
293
|
+
# @param list [Array<Hash>] Output list
|
|
294
|
+
# @param parent_idx [Integer, nil] Parent index
|
|
295
|
+
def collect_directories_for_path_table(node, list, parent_idx = nil)
|
|
296
|
+
current_idx = list.size
|
|
297
|
+
node[:parent_idx] = parent_idx
|
|
298
|
+
list << node
|
|
299
|
+
|
|
300
|
+
node[:children].select { |c| c[:directory] }.each do |child|
|
|
301
|
+
collect_directories_for_path_table(child, list, current_idx)
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Flatten directory tree to array
|
|
306
|
+
#
|
|
307
|
+
# @param tree [Hash] Directory tree
|
|
308
|
+
# @return [Array<Hash>] Flat directory list
|
|
309
|
+
def flatten_directories(tree)
|
|
310
|
+
result = [tree]
|
|
311
|
+
|
|
312
|
+
tree[:children].select { |c| c[:directory] }.each do |child|
|
|
313
|
+
result.concat(flatten_directories(child))
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
result
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Omnizip
|
|
4
|
+
module Formats
|
|
5
|
+
module Iso
|
|
6
|
+
# ISO 9660 Directory Record
|
|
7
|
+
# Represents a file or directory entry
|
|
8
|
+
class DirectoryRecord
|
|
9
|
+
include Omnizip::Entry
|
|
10
|
+
|
|
11
|
+
attr_accessor :full_path
|
|
12
|
+
attr_reader :length, :extended_attr_length, :location, :data_length, :recording_date, :flags, :file_unit_size, :interleave_gap_size, :volume_sequence_number, :name, :system_use
|
|
13
|
+
|
|
14
|
+
def entry_name = full_path || name
|
|
15
|
+
def entry_directory? = directory?
|
|
16
|
+
def entry_size = data_length
|
|
17
|
+
def entry_mtime = recording_date
|
|
18
|
+
|
|
19
|
+
# Set the full path for this record, used by Reader when walking
|
|
20
|
+
# a directory tree. Allows callers to look up records by path
|
|
21
|
+
# without re-joining parent names.
|
|
22
|
+
|
|
23
|
+
# Parse directory record from binary data
|
|
24
|
+
#
|
|
25
|
+
# @param data [String] Binary record data
|
|
26
|
+
# @param offset [Integer] Offset in data to start parsing
|
|
27
|
+
# @return [DirectoryRecord] Parsed record
|
|
28
|
+
def self.parse(data, offset = 0)
|
|
29
|
+
new.tap { |record| record.parse(data, offset) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Parse record data
|
|
33
|
+
#
|
|
34
|
+
# @param data [String] Binary data
|
|
35
|
+
# @param offset [Integer] Starting offset
|
|
36
|
+
def parse(data, offset = 0)
|
|
37
|
+
# Byte 0: Length of directory record
|
|
38
|
+
@length = data.getbyte(offset)
|
|
39
|
+
return if @length.zero? # Padding
|
|
40
|
+
|
|
41
|
+
# Byte 1: Extended attribute record length
|
|
42
|
+
@extended_attr_length = data.getbyte(offset + 1)
|
|
43
|
+
|
|
44
|
+
# Bytes 2-9: Location of extent (both-endian)
|
|
45
|
+
@location = data[offset + 2, 4].unpack1("V")
|
|
46
|
+
|
|
47
|
+
# Bytes 10-17: Data length (both-endian)
|
|
48
|
+
@data_length = data[offset + 10, 4].unpack1("V")
|
|
49
|
+
|
|
50
|
+
# Bytes 18-24: Recording date and time
|
|
51
|
+
@recording_date = parse_record_datetime(data[offset + 18, 7])
|
|
52
|
+
|
|
53
|
+
# Byte 25: File flags
|
|
54
|
+
@flags = data.getbyte(offset + 25)
|
|
55
|
+
|
|
56
|
+
# Byte 26: File unit size (for interleaved files)
|
|
57
|
+
@file_unit_size = data.getbyte(offset + 26)
|
|
58
|
+
|
|
59
|
+
# Byte 27: Interleave gap size
|
|
60
|
+
@interleave_gap_size = data.getbyte(offset + 27)
|
|
61
|
+
|
|
62
|
+
# Bytes 28-31: Volume sequence number (both-endian)
|
|
63
|
+
@volume_sequence_number = data[offset + 28, 2].unpack1("v")
|
|
64
|
+
|
|
65
|
+
# Byte 32: Length of file identifier
|
|
66
|
+
name_length = data.getbyte(offset + 32)
|
|
67
|
+
|
|
68
|
+
# Bytes 33+: File identifier
|
|
69
|
+
@name = data[offset + 33, name_length]
|
|
70
|
+
|
|
71
|
+
# Parse file identifier
|
|
72
|
+
parse_name
|
|
73
|
+
|
|
74
|
+
# System Use field (Rock Ridge extensions, etc.)
|
|
75
|
+
# Located after name and padding
|
|
76
|
+
su_offset = offset + 33 + name_length
|
|
77
|
+
su_offset += 1 if name_length.even? # Padding byte
|
|
78
|
+
|
|
79
|
+
return unless su_offset < offset + @length
|
|
80
|
+
|
|
81
|
+
@system_use = data[su_offset, offset + @length - su_offset]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Check if entry is a directory
|
|
85
|
+
#
|
|
86
|
+
# @return [Boolean] true if directory
|
|
87
|
+
def directory?
|
|
88
|
+
@flags.anybits?(Iso::FLAG_DIRECTORY)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Check if entry is hidden
|
|
92
|
+
#
|
|
93
|
+
# @return [Boolean] true if hidden
|
|
94
|
+
def hidden?
|
|
95
|
+
@flags.anybits?(Iso::FLAG_HIDDEN)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Check if this is the current directory entry
|
|
99
|
+
#
|
|
100
|
+
# @return [Boolean] true if current directory
|
|
101
|
+
def current_directory?
|
|
102
|
+
@name == "\x00"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Check if this is the parent directory entry
|
|
106
|
+
#
|
|
107
|
+
# @return [Boolean] true if parent directory
|
|
108
|
+
def parent_directory?
|
|
109
|
+
@name == "\x01"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Get file size
|
|
113
|
+
#
|
|
114
|
+
# @return [Integer] Size in bytes
|
|
115
|
+
def size
|
|
116
|
+
@data_length
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Get modification time
|
|
120
|
+
#
|
|
121
|
+
# @return [Time, nil] Modification time
|
|
122
|
+
def mtime
|
|
123
|
+
@recording_date
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
# Parse directory record datetime (7-byte format)
|
|
129
|
+
#
|
|
130
|
+
# @param data [String] 7-byte datetime
|
|
131
|
+
# @return [Time, nil] Parsed time
|
|
132
|
+
def parse_record_datetime(data)
|
|
133
|
+
return nil if data.nil? || data.bytesize < 7
|
|
134
|
+
|
|
135
|
+
year = 1900 + data.getbyte(0)
|
|
136
|
+
month = data.getbyte(1)
|
|
137
|
+
day = data.getbyte(2)
|
|
138
|
+
hour = data.getbyte(3)
|
|
139
|
+
minute = data.getbyte(4)
|
|
140
|
+
second = data.getbyte(5)
|
|
141
|
+
# Timezone offset at byte 6 (15-minute intervals from GMT)
|
|
142
|
+
|
|
143
|
+
Time.new(year, month, day, hour, minute, second)
|
|
144
|
+
rescue ArgumentError
|
|
145
|
+
nil
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Parse file identifier name
|
|
149
|
+
def parse_name
|
|
150
|
+
# Special cases for current and parent directory
|
|
151
|
+
return if @name == "\x00" || @name == "\x01"
|
|
152
|
+
|
|
153
|
+
# Remove version number (;1) if present
|
|
154
|
+
@name = @name.split(";").first if @name.include?(";")
|
|
155
|
+
|
|
156
|
+
# Convert to UTF-8 and strip
|
|
157
|
+
@name = @name.force_encoding("UTF-8").strip
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|