omnizip 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (511) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +754 -0
  5. data/COPYING +502 -0
  6. data/Gemfile +17 -0
  7. data/LICENSE +12 -0
  8. data/README.adoc +1045 -0
  9. data/Rakefile +12 -0
  10. data/benchmark/README.md +260 -0
  11. data/benchmark/benchmark_suite.rb +125 -0
  12. data/benchmark/compression_bench.rb +181 -0
  13. data/benchmark/filter_bench.rb +180 -0
  14. data/benchmark/models/benchmark_result.rb +59 -0
  15. data/benchmark/models/comparison_result.rb +69 -0
  16. data/benchmark/profile_suite.rb +167 -0
  17. data/benchmark/reporter.rb +150 -0
  18. data/benchmark/run_benchmarks.rb +66 -0
  19. data/benchmark/test_data.rb +137 -0
  20. data/config/formats/rar3_spec.yml +91 -0
  21. data/config/formats/rar5_spec.yml +102 -0
  22. data/docs/.github/workflows/docs.yml +142 -0
  23. data/docs/.gitignore +21 -0
  24. data/docs/.lychee.toml +67 -0
  25. data/docs/Gemfile +13 -0
  26. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  27. data/docs/README.md +101 -0
  28. data/docs/_config.yml +112 -0
  29. data/docs/assets/logo.svg +1 -0
  30. data/docs/assets/omnizip-logo.pdf +1540 -11
  31. data/docs/comparison/feature-matrix.adoc +694 -0
  32. data/docs/comparison/index.adoc +113 -0
  33. data/docs/comparison/vs-7zip.adoc +309 -0
  34. data/docs/comparison/vs-peazip.adoc +77 -0
  35. data/docs/comparison/vs-rubyzip.adoc +342 -0
  36. data/docs/comparison/vs-winrar.adoc +100 -0
  37. data/docs/compatibility.adoc +579 -0
  38. data/docs/concepts/index.adoc +129 -0
  39. data/docs/developer/architecture.adoc +256 -0
  40. data/docs/developer/contributing.adoc +158 -0
  41. data/docs/developer/index.adoc +25 -0
  42. data/docs/developer/testing.adoc +212 -0
  43. data/docs/getting-started/basic-usage.adoc +271 -0
  44. data/docs/getting-started/index.adoc +42 -0
  45. data/docs/getting-started/installation.adoc +138 -0
  46. data/docs/getting-started/quick-start.adoc +185 -0
  47. data/docs/getting-started/your-first-archive.adoc +218 -0
  48. data/docs/guides/advanced-features/encryption.adoc +300 -0
  49. data/docs/guides/advanced-features/index.adoc +49 -0
  50. data/docs/guides/advanced-features/parallel-processing.adoc +246 -0
  51. data/docs/guides/advanced-features/progress-tracking.adoc +320 -0
  52. data/docs/guides/advanced-features/streaming.adoc +212 -0
  53. data/docs/guides/archive-formats/gzip-format.adoc +107 -0
  54. data/docs/guides/archive-formats/index.adoc +130 -0
  55. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  56. data/docs/guides/archive-formats/rar5.adoc +521 -0
  57. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  58. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  59. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  60. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  61. data/docs/guides/compression-algorithms/bzip2.adoc +113 -0
  62. data/docs/guides/compression-algorithms/deflate.adoc +319 -0
  63. data/docs/guides/compression-algorithms/index.adoc +190 -0
  64. data/docs/guides/compression-algorithms/lzma.adoc +398 -0
  65. data/docs/guides/compression-algorithms/lzma2.adoc +327 -0
  66. data/docs/guides/compression-algorithms/ppmd.adoc +316 -0
  67. data/docs/guides/compression-algorithms/zstandard.adoc +361 -0
  68. data/docs/guides/creating-archives.adoc +354 -0
  69. data/docs/guides/extracting-archives.adoc +53 -0
  70. data/docs/guides/format-conversion.adoc +64 -0
  71. data/docs/guides/index.adoc +49 -0
  72. data/docs/guides/migration-rubyzip.adoc +217 -0
  73. data/docs/guides/parity-archives.adoc +605 -0
  74. data/docs/guides/performance-tuning.adoc +88 -0
  75. data/docs/index.adoc +218 -0
  76. data/docs/lychee.toml +67 -0
  77. data/docs/reference/api/overview.adoc +188 -0
  78. data/docs/reference/cli/compress-command.adoc +114 -0
  79. data/docs/reference/cli/overview.adoc +140 -0
  80. data/docs/reference/index.adoc +26 -0
  81. data/docs/resources/faq.adoc +185 -0
  82. data/docs/resources/quick-reference.adoc +222 -0
  83. data/docs/troubleshooting/index.adoc +208 -0
  84. data/examples/api_comparison.rb +205 -0
  85. data/examples/deflate64_example.rb +96 -0
  86. data/examples/par2_demo.rb +121 -0
  87. data/examples/quick_start_native.rb +150 -0
  88. data/examples/quick_start_rubyzip.rb +115 -0
  89. data/examples/rubyzip_compatibility_demo.rb +194 -0
  90. data/exe/omnizip +27 -0
  91. data/lib/omnizip/algorithm.rb +130 -0
  92. data/lib/omnizip/algorithm_registry.rb +86 -0
  93. data/lib/omnizip/algorithms/.keep +0 -0
  94. data/lib/omnizip/algorithms/bzip2/bwt.rb +225 -0
  95. data/lib/omnizip/algorithms/bzip2/decoder.rb +193 -0
  96. data/lib/omnizip/algorithms/bzip2/encoder.rb +237 -0
  97. data/lib/omnizip/algorithms/bzip2/huffman.rb +206 -0
  98. data/lib/omnizip/algorithms/bzip2/mtf.rb +101 -0
  99. data/lib/omnizip/algorithms/bzip2/rle.rb +151 -0
  100. data/lib/omnizip/algorithms/bzip2.rb +130 -0
  101. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  102. data/lib/omnizip/algorithms/deflate/decoder.rb +38 -0
  103. data/lib/omnizip/algorithms/deflate/encoder.rb +46 -0
  104. data/lib/omnizip/algorithms/deflate.rb +128 -0
  105. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  106. data/lib/omnizip/algorithms/deflate64/decoder.rb +153 -0
  107. data/lib/omnizip/algorithms/deflate64/encoder.rb +98 -0
  108. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +354 -0
  109. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +142 -0
  110. data/lib/omnizip/algorithms/deflate64.rb +109 -0
  111. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  112. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  113. data/lib/omnizip/algorithms/lzma/decoder.rb +148 -0
  114. data/lib/omnizip/algorithms/lzma/dictionary.rb +69 -0
  115. data/lib/omnizip/algorithms/lzma/distance_coder.rb +415 -0
  116. data/lib/omnizip/algorithms/lzma/encoder.rb +142 -0
  117. data/lib/omnizip/algorithms/lzma/length_coder.rb +260 -0
  118. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +320 -0
  119. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +210 -0
  120. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +341 -0
  121. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +192 -0
  122. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  123. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  124. data/lib/omnizip/algorithms/lzma/match_finder.rb +205 -0
  125. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  126. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +88 -0
  127. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +130 -0
  128. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  129. data/lib/omnizip/algorithms/lzma/range_coder.rb +85 -0
  130. data/lib/omnizip/algorithms/lzma/range_decoder.rb +434 -0
  131. data/lib/omnizip/algorithms/lzma/range_encoder.rb +194 -0
  132. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  133. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +325 -0
  134. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +426 -0
  135. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +645 -0
  136. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +227 -0
  137. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +169 -0
  138. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +261 -0
  139. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  140. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +331 -0
  141. data/lib/omnizip/algorithms/lzma/xz_state.rb +116 -0
  142. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +2055 -0
  143. data/lib/omnizip/algorithms/lzma.rb +238 -0
  144. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +182 -0
  145. data/lib/omnizip/algorithms/lzma2/constants.rb +41 -0
  146. data/lib/omnizip/algorithms/lzma2/encoder.rb +147 -0
  147. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +161 -0
  148. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  149. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +127 -0
  150. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  151. data/lib/omnizip/algorithms/lzma2.rb +141 -0
  152. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  153. data/lib/omnizip/algorithms/ppmd7/context.rb +154 -0
  154. data/lib/omnizip/algorithms/ppmd7/decoder.rb +126 -0
  155. data/lib/omnizip/algorithms/ppmd7/encoder.rb +163 -0
  156. data/lib/omnizip/algorithms/ppmd7/model.rb +248 -0
  157. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  158. data/lib/omnizip/algorithms/ppmd7.rb +116 -0
  159. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  160. data/lib/omnizip/algorithms/ppmd8/context.rb +34 -0
  161. data/lib/omnizip/algorithms/ppmd8/decoder.rb +107 -0
  162. data/lib/omnizip/algorithms/ppmd8/encoder.rb +138 -0
  163. data/lib/omnizip/algorithms/ppmd8/model.rb +250 -0
  164. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  165. data/lib/omnizip/algorithms/ppmd8.rb +82 -0
  166. data/lib/omnizip/algorithms/ppmd_base.rb +138 -0
  167. data/lib/omnizip/algorithms/sevenzip_lzma2.rb +123 -0
  168. data/lib/omnizip/algorithms/xz_lzma2.rb +118 -0
  169. data/lib/omnizip/algorithms/zstandard/constants.rb +25 -0
  170. data/lib/omnizip/algorithms/zstandard/decoder.rb +46 -0
  171. data/lib/omnizip/algorithms/zstandard/encoder.rb +51 -0
  172. data/lib/omnizip/algorithms/zstandard.rb +138 -0
  173. data/lib/omnizip/buffer/memory_archive.rb +251 -0
  174. data/lib/omnizip/buffer/memory_extractor.rb +224 -0
  175. data/lib/omnizip/buffer.rb +176 -0
  176. data/lib/omnizip/checksum_registry.rb +114 -0
  177. data/lib/omnizip/checksums/crc32.rb +100 -0
  178. data/lib/omnizip/checksums/crc64.rb +101 -0
  179. data/lib/omnizip/checksums/crc_base.rb +158 -0
  180. data/lib/omnizip/checksums/verifier.rb +131 -0
  181. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  182. data/lib/omnizip/chunked/reader.rb +78 -0
  183. data/lib/omnizip/chunked/writer.rb +120 -0
  184. data/lib/omnizip/chunked.rb +129 -0
  185. data/lib/omnizip/cli/output_formatter.rb +104 -0
  186. data/lib/omnizip/cli.rb +572 -0
  187. data/lib/omnizip/commands/.keep +0 -0
  188. data/lib/omnizip/commands/archive_create_command.rb +427 -0
  189. data/lib/omnizip/commands/archive_extract_command.rb +272 -0
  190. data/lib/omnizip/commands/archive_list_command.rb +218 -0
  191. data/lib/omnizip/commands/archive_repair_command.rb +131 -0
  192. data/lib/omnizip/commands/archive_verify_command.rb +117 -0
  193. data/lib/omnizip/commands/compress_command.rb +117 -0
  194. data/lib/omnizip/commands/decompress_command.rb +120 -0
  195. data/lib/omnizip/commands/list_command.rb +53 -0
  196. data/lib/omnizip/commands/metadata_command.rb +153 -0
  197. data/lib/omnizip/commands/parity_create_command.rb +122 -0
  198. data/lib/omnizip/commands/parity_repair_command.rb +122 -0
  199. data/lib/omnizip/commands/parity_verify_command.rb +124 -0
  200. data/lib/omnizip/commands/profile_list_command.rb +56 -0
  201. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  202. data/lib/omnizip/convenience.rb +359 -0
  203. data/lib/omnizip/converter/conversion_registry.rb +49 -0
  204. data/lib/omnizip/converter/conversion_strategy.rb +121 -0
  205. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +97 -0
  206. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +112 -0
  207. data/lib/omnizip/converter.rb +105 -0
  208. data/lib/omnizip/crypto/aes256/cipher.rb +100 -0
  209. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  210. data/lib/omnizip/crypto/aes256/key_derivation.rb +101 -0
  211. data/lib/omnizip/crypto/aes256.rb +102 -0
  212. data/lib/omnizip/error.rb +106 -0
  213. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +98 -0
  214. data/lib/omnizip/eta/moving_average_estimator.rb +99 -0
  215. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  216. data/lib/omnizip/eta/sample_history.rb +143 -0
  217. data/lib/omnizip/eta/time_estimator.rb +106 -0
  218. data/lib/omnizip/eta.rb +63 -0
  219. data/lib/omnizip/extraction/filter_chain.rb +177 -0
  220. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  221. data/lib/omnizip/extraction/pattern_matcher.rb +70 -0
  222. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  223. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  224. data/lib/omnizip/extraction/selective_extractor.rb +240 -0
  225. data/lib/omnizip/extraction.rb +111 -0
  226. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  227. data/lib/omnizip/file_type.rb +113 -0
  228. data/lib/omnizip/filter.rb +139 -0
  229. data/lib/omnizip/filter_pipeline.rb +108 -0
  230. data/lib/omnizip/filter_registry.rb +166 -0
  231. data/lib/omnizip/filters/bcj.rb +279 -0
  232. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  233. data/lib/omnizip/filters/bcj2/decoder.rb +200 -0
  234. data/lib/omnizip/filters/bcj2/encoder.rb +61 -0
  235. data/lib/omnizip/filters/bcj2/stream_data.rb +93 -0
  236. data/lib/omnizip/filters/bcj2.rb +99 -0
  237. data/lib/omnizip/filters/bcj_arm.rb +176 -0
  238. data/lib/omnizip/filters/bcj_arm64.rb +244 -0
  239. data/lib/omnizip/filters/bcj_ia64.rb +196 -0
  240. data/lib/omnizip/filters/bcj_ppc.rb +190 -0
  241. data/lib/omnizip/filters/bcj_sparc.rb +176 -0
  242. data/lib/omnizip/filters/bcj_x86.rb +193 -0
  243. data/lib/omnizip/filters/delta.rb +196 -0
  244. data/lib/omnizip/filters/filter_base.rb +72 -0
  245. data/lib/omnizip/filters/registry.rb +123 -0
  246. data/lib/omnizip/filters/xz_delta.rb +258 -0
  247. data/lib/omnizip/format_detector.rb +162 -0
  248. data/lib/omnizip/format_registry.rb +59 -0
  249. data/lib/omnizip/formats/.keep +0 -0
  250. data/lib/omnizip/formats/bzip2_file.rb +172 -0
  251. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  252. data/lib/omnizip/formats/cpio/entry.rb +385 -0
  253. data/lib/omnizip/formats/cpio/reader.rb +196 -0
  254. data/lib/omnizip/formats/cpio/writer.rb +234 -0
  255. data/lib/omnizip/formats/cpio.rb +140 -0
  256. data/lib/omnizip/formats/format_spec_loader.rb +230 -0
  257. data/lib/omnizip/formats/gzip.rb +238 -0
  258. data/lib/omnizip/formats/iso/directory_builder.rb +297 -0
  259. data/lib/omnizip/formats/iso/directory_record.rb +152 -0
  260. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  261. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  262. data/lib/omnizip/formats/iso/reader.rb +197 -0
  263. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  264. data/lib/omnizip/formats/iso/volume_builder.rb +320 -0
  265. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  266. data/lib/omnizip/formats/iso/writer.rb +530 -0
  267. data/lib/omnizip/formats/iso.rb +140 -0
  268. data/lib/omnizip/formats/lzip.rb +175 -0
  269. data/lib/omnizip/formats/lzma_alone.rb +171 -0
  270. data/lib/omnizip/formats/rar/archive_repairer.rb +243 -0
  271. data/lib/omnizip/formats/rar/archive_verifier.rb +195 -0
  272. data/lib/omnizip/formats/rar/block_parser.rb +243 -0
  273. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  274. data/lib/omnizip/formats/rar/compression/dispatcher.rb +217 -0
  275. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +216 -0
  276. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +158 -0
  277. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  278. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  279. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  280. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  281. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +105 -0
  282. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +219 -0
  283. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +262 -0
  284. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  285. data/lib/omnizip/formats/rar/constants.rb +82 -0
  286. data/lib/omnizip/formats/rar/decompressor.rb +238 -0
  287. data/lib/omnizip/formats/rar/external_writer.rb +312 -0
  288. data/lib/omnizip/formats/rar/header.rb +192 -0
  289. data/lib/omnizip/formats/rar/license_validator.rb +109 -0
  290. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  291. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  292. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  293. data/lib/omnizip/formats/rar/parity_handler.rb +292 -0
  294. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +202 -0
  295. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +578 -0
  296. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  297. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  298. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +97 -0
  299. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  300. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +166 -0
  301. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  302. data/lib/omnizip/formats/rar/rar5/header.rb +187 -0
  303. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  304. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  305. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  306. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  307. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  308. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +264 -0
  309. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  310. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +194 -0
  311. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +109 -0
  312. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +142 -0
  313. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  314. data/lib/omnizip/formats/rar/rar5/vint.rb +65 -0
  315. data/lib/omnizip/formats/rar/rar5/writer.rb +466 -0
  316. data/lib/omnizip/formats/rar/rar_format_base.rb +241 -0
  317. data/lib/omnizip/formats/rar/reader.rb +366 -0
  318. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  319. data/lib/omnizip/formats/rar/volume_manager.rb +168 -0
  320. data/lib/omnizip/formats/rar/writer.rb +431 -0
  321. data/lib/omnizip/formats/rar.rb +205 -0
  322. data/lib/omnizip/formats/rar3/compressor.rb +73 -0
  323. data/lib/omnizip/formats/rar3/decompressor.rb +66 -0
  324. data/lib/omnizip/formats/rar3/reader.rb +386 -0
  325. data/lib/omnizip/formats/rar3/writer.rb +219 -0
  326. data/lib/omnizip/formats/rar5/compressor.rb +73 -0
  327. data/lib/omnizip/formats/rar5/decompressor.rb +66 -0
  328. data/lib/omnizip/formats/rar5/reader.rb +342 -0
  329. data/lib/omnizip/formats/rar5/writer.rb +214 -0
  330. data/lib/omnizip/formats/seven_zip/coder_chain.rb +150 -0
  331. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  332. data/lib/omnizip/formats/seven_zip/encoded_header.rb +114 -0
  333. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +142 -0
  334. data/lib/omnizip/formats/seven_zip/file_collector.rb +144 -0
  335. data/lib/omnizip/formats/seven_zip/header.rb +106 -0
  336. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +134 -0
  337. data/lib/omnizip/formats/seven_zip/header_writer.rb +466 -0
  338. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  339. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +58 -0
  340. data/lib/omnizip/formats/seven_zip/models/folder.rb +69 -0
  341. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  342. data/lib/omnizip/formats/seven_zip/parser.rb +660 -0
  343. data/lib/omnizip/formats/seven_zip/reader.rb +458 -0
  344. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +632 -0
  345. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +315 -0
  346. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  347. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +162 -0
  348. data/lib/omnizip/formats/seven_zip/writer.rb +740 -0
  349. data/lib/omnizip/formats/seven_zip.rb +93 -0
  350. data/lib/omnizip/formats/tar/constants.rb +73 -0
  351. data/lib/omnizip/formats/tar/entry.rb +94 -0
  352. data/lib/omnizip/formats/tar/header.rb +168 -0
  353. data/lib/omnizip/formats/tar/reader.rb +121 -0
  354. data/lib/omnizip/formats/tar/writer.rb +216 -0
  355. data/lib/omnizip/formats/tar.rb +84 -0
  356. data/lib/omnizip/formats/xz/reader.rb +116 -0
  357. data/lib/omnizip/formats/xz.rb +237 -0
  358. data/lib/omnizip/formats/xz_impl/block_decoder.rb +754 -0
  359. data/lib/omnizip/formats/xz_impl/block_encoder.rb +306 -0
  360. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  361. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +186 -0
  362. data/lib/omnizip/formats/xz_impl/constants.rb +49 -0
  363. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  364. data/lib/omnizip/formats/xz_impl/index_encoder.rb +122 -0
  365. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +468 -0
  366. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +99 -0
  367. data/lib/omnizip/formats/xz_impl/stream_footer.rb +81 -0
  368. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +117 -0
  369. data/lib/omnizip/formats/xz_impl/stream_header.rb +55 -0
  370. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +108 -0
  371. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  372. data/lib/omnizip/formats/xz_impl/writer.rb +421 -0
  373. data/lib/omnizip/formats/zip/central_directory_header.rb +195 -0
  374. data/lib/omnizip/formats/zip/constants.rb +69 -0
  375. data/lib/omnizip/formats/zip/end_of_central_directory.rb +133 -0
  376. data/lib/omnizip/formats/zip/local_file_header.rb +138 -0
  377. data/lib/omnizip/formats/zip/reader.rb +250 -0
  378. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  379. data/lib/omnizip/formats/zip/writer.rb +375 -0
  380. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +104 -0
  381. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +66 -0
  382. data/lib/omnizip/formats/zip/zip64_extra_field.rb +114 -0
  383. data/lib/omnizip/formats/zip.rb +50 -0
  384. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  385. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  386. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  387. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  388. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  389. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +421 -0
  390. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +465 -0
  391. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +288 -0
  392. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +200 -0
  393. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +197 -0
  394. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +141 -0
  395. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +519 -0
  396. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +723 -0
  397. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +750 -0
  398. data/lib/omnizip/io/buffered_input.rb +146 -0
  399. data/lib/omnizip/io/buffered_output.rb +105 -0
  400. data/lib/omnizip/io/stream_manager.rb +115 -0
  401. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  402. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  403. data/lib/omnizip/link_handler.rb +124 -0
  404. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  405. data/lib/omnizip/metadata/entry_metadata.rb +146 -0
  406. data/lib/omnizip/metadata/metadata_editor.rb +171 -0
  407. data/lib/omnizip/metadata/metadata_registry.rb +64 -0
  408. data/lib/omnizip/metadata/metadata_validator.rb +99 -0
  409. data/lib/omnizip/metadata.rb +57 -0
  410. data/lib/omnizip/models/.keep +0 -0
  411. data/lib/omnizip/models/algorithm_metadata.rb +73 -0
  412. data/lib/omnizip/models/compression_options.rb +71 -0
  413. data/lib/omnizip/models/conversion_options.rb +87 -0
  414. data/lib/omnizip/models/conversion_result.rb +135 -0
  415. data/lib/omnizip/models/eta_result.rb +46 -0
  416. data/lib/omnizip/models/extraction_rule.rb +115 -0
  417. data/lib/omnizip/models/filter_chain.rb +144 -0
  418. data/lib/omnizip/models/filter_config.rb +183 -0
  419. data/lib/omnizip/models/match_result.rb +124 -0
  420. data/lib/omnizip/models/optimization_suggestion.rb +91 -0
  421. data/lib/omnizip/models/parallel_options.rb +104 -0
  422. data/lib/omnizip/models/performance_result.rb +79 -0
  423. data/lib/omnizip/models/profile_report.rb +82 -0
  424. data/lib/omnizip/models/progress_options.rb +38 -0
  425. data/lib/omnizip/models/split_options.rb +116 -0
  426. data/lib/omnizip/optimization_registry.rb +81 -0
  427. data/lib/omnizip/parallel/job_queue.rb +209 -0
  428. data/lib/omnizip/parallel/job_scheduler.rb +203 -0
  429. data/lib/omnizip/parallel/parallel_compressor.rb +347 -0
  430. data/lib/omnizip/parallel/parallel_extractor.rb +329 -0
  431. data/lib/omnizip/parallel/worker_pool.rb +223 -0
  432. data/lib/omnizip/parallel.rb +149 -0
  433. data/lib/omnizip/parity/chunked_block_processor.rb +196 -0
  434. data/lib/omnizip/parity/galois16.rb +145 -0
  435. data/lib/omnizip/parity/models/creator_packet.rb +73 -0
  436. data/lib/omnizip/parity/models/file_description_packet.rb +133 -0
  437. data/lib/omnizip/parity/models/ifsc_packet.rb +123 -0
  438. data/lib/omnizip/parity/models/main_packet.rb +128 -0
  439. data/lib/omnizip/parity/models/packet.rb +156 -0
  440. data/lib/omnizip/parity/models/packet_registry.rb +109 -0
  441. data/lib/omnizip/parity/models/recovery_slice_packet.rb +78 -0
  442. data/lib/omnizip/parity/par2_creator.rb +531 -0
  443. data/lib/omnizip/parity/par2_repairer.rb +407 -0
  444. data/lib/omnizip/parity/par2_verifier.rb +364 -0
  445. data/lib/omnizip/parity/par2cmdline_algorithm.rb +110 -0
  446. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  447. data/lib/omnizip/parity/reed_solomon_decoder.rb +266 -0
  448. data/lib/omnizip/parity/reed_solomon_encoder.rb +111 -0
  449. data/lib/omnizip/parity/reed_solomon_matrix.rb +342 -0
  450. data/lib/omnizip/parity.rb +186 -0
  451. data/lib/omnizip/password/encryption_registry.rb +65 -0
  452. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  453. data/lib/omnizip/password/password_validator.rb +129 -0
  454. data/lib/omnizip/password/winzip_aes_strategy.rb +192 -0
  455. data/lib/omnizip/password/zip_crypto_strategy.rb +141 -0
  456. data/lib/omnizip/password.rb +87 -0
  457. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  458. data/lib/omnizip/pipe/stream_decompressor.rb +174 -0
  459. data/lib/omnizip/pipe.rb +121 -0
  460. data/lib/omnizip/platform/ntfs_streams.rb +201 -0
  461. data/lib/omnizip/platform.rb +189 -0
  462. data/lib/omnizip/profile/archive_profile.rb +39 -0
  463. data/lib/omnizip/profile/balanced_profile.rb +33 -0
  464. data/lib/omnizip/profile/binary_profile.rb +36 -0
  465. data/lib/omnizip/profile/compression_profile.rb +158 -0
  466. data/lib/omnizip/profile/custom_profile.rb +157 -0
  467. data/lib/omnizip/profile/fast_profile.rb +33 -0
  468. data/lib/omnizip/profile/maximum_profile.rb +33 -0
  469. data/lib/omnizip/profile/profile_detector.rb +110 -0
  470. data/lib/omnizip/profile/profile_registry.rb +161 -0
  471. data/lib/omnizip/profile/text_profile.rb +36 -0
  472. data/lib/omnizip/profile.rb +190 -0
  473. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  474. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  475. data/lib/omnizip/profiler/report_generator.rb +169 -0
  476. data/lib/omnizip/profiler.rb +204 -0
  477. data/lib/omnizip/progress/callback_reporter.rb +36 -0
  478. data/lib/omnizip/progress/console_reporter.rb +62 -0
  479. data/lib/omnizip/progress/log_reporter.rb +91 -0
  480. data/lib/omnizip/progress/operation_progress.rb +118 -0
  481. data/lib/omnizip/progress/progress_bar.rb +156 -0
  482. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  483. data/lib/omnizip/progress/progress_tracker.rb +190 -0
  484. data/lib/omnizip/progress/silent_reporter.rb +24 -0
  485. data/lib/omnizip/progress.rb +127 -0
  486. data/lib/omnizip/rubyzip_compat.rb +63 -0
  487. data/lib/omnizip/temp/safe_extract.rb +168 -0
  488. data/lib/omnizip/temp/temp_file.rb +124 -0
  489. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  490. data/lib/omnizip/temp.rb +181 -0
  491. data/lib/omnizip/version.rb +5 -0
  492. data/lib/omnizip/zip/entry.rb +156 -0
  493. data/lib/omnizip/zip/file.rb +485 -0
  494. data/lib/omnizip/zip/input_stream.rb +273 -0
  495. data/lib/omnizip/zip/output_stream.rb +324 -0
  496. data/lib/omnizip.rb +156 -0
  497. data/readme-docs/advanced-features.adoc +515 -0
  498. data/readme-docs/api-usage.adoc +444 -0
  499. data/readme-docs/architecture.adoc +449 -0
  500. data/readme-docs/archive-formats.adoc +479 -0
  501. data/readme-docs/cli-usage.adoc +222 -0
  502. data/readme-docs/compression-algorithms.adoc +442 -0
  503. data/readme-docs/compression-profiles.adoc +247 -0
  504. data/readme-docs/encryption-checksums.adoc +328 -0
  505. data/readme-docs/format-converter.adoc +325 -0
  506. data/readme-docs/installation.adoc +228 -0
  507. data/readme-docs/par2-archives.adoc +608 -0
  508. data/readme-docs/performance-profiler.adoc +389 -0
  509. data/readme-docs/preprocessing-filters.adoc +280 -0
  510. data/xz-file-format-1.2.1.txt +1174 -0
  511. metadata +617 -0
@@ -0,0 +1,320 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+ require_relative "../iso"
5
+
6
+ module Omnizip
7
+ module Formats
8
+ module Iso
9
+ # ISO 9660 Volume Descriptor Builder
10
+ #
11
+ # Builds primary and supplementary volume descriptors for ISO images.
12
+ # Handles proper encoding of volume metadata and root directory information.
13
+ class VolumeBuilder
14
+ # @return [String] Volume identifier
15
+ attr_reader :volume_id
16
+
17
+ # @return [String] System identifier
18
+ attr_reader :system_id
19
+
20
+ # @return [String] Publisher
21
+ attr_reader :publisher
22
+
23
+ # @return [String] Preparer
24
+ attr_reader :preparer
25
+
26
+ # @return [String] Application
27
+ attr_reader :application
28
+
29
+ # @return [Integer] ISO level
30
+ attr_reader :level
31
+
32
+ # @return [Boolean] Rock Ridge enabled
33
+ attr_reader :rock_ridge
34
+
35
+ # @return [Boolean] Joliet enabled
36
+ attr_reader :joliet
37
+
38
+ # Initialize volume builder
39
+ #
40
+ # @param options [Hash] Builder options
41
+ def initialize(options = {})
42
+ @volume_id = options.fetch(:volume_id, "OMNIZIP")
43
+ @system_id = options.fetch(:system_id, "LINUX")
44
+ @publisher = options.fetch(:publisher, "")
45
+ @preparer = options.fetch(:preparer, "")
46
+ @application = options.fetch(:application, "OMNIZIP")
47
+ @level = options.fetch(:level, 2)
48
+ @rock_ridge = options.fetch(:rock_ridge, false)
49
+ @joliet = options.fetch(:joliet, false)
50
+ end
51
+
52
+ # Build primary volume descriptor
53
+ #
54
+ # @param root_dir [Hash] Root directory information
55
+ # @return [String] Primary VD sector (2048 bytes)
56
+ def build_primary(root_dir)
57
+ sector = +""
58
+
59
+ # Byte 0: Volume descriptor type (1 = Primary)
60
+ sector << [Iso::VD_PRIMARY].pack("C")
61
+
62
+ # Bytes 1-5: Standard identifier "CD001"
63
+ sector << VolumeDescriptor::ISO_IDENTIFIER
64
+
65
+ # Byte 6: Version (1)
66
+ sector << [1].pack("C")
67
+
68
+ # Byte 7: Unused (0)
69
+ sector << "\x00"
70
+
71
+ # Bytes 8-39: System identifier (a-characters, space-padded)
72
+ sector << pad_a_string(@system_id, 32)
73
+
74
+ # Bytes 40-71: Volume identifier (d-characters, space-padded)
75
+ sector << pad_d_string(@volume_id, 32)
76
+
77
+ # Bytes 72-79: Unused (zeros)
78
+ sector << ("\x00" * 8)
79
+
80
+ # Bytes 80-87: Volume space size (both-endian)
81
+ volume_sectors = root_dir[:total_sectors] || 100
82
+ sector << [volume_sectors].pack("V") # Little-endian
83
+ sector << [volume_sectors].pack("N") # Big-endian
84
+
85
+ # Bytes 88-119: Unused (zeros)
86
+ sector << ("\x00" * 32)
87
+
88
+ # Bytes 120-123: Volume set size (both-endian)
89
+ sector << [1].pack("v")
90
+ sector << [1].pack("n")
91
+
92
+ # Bytes 124-127: Volume sequence number (both-endian)
93
+ sector << [1].pack("v")
94
+ sector << [1].pack("n")
95
+
96
+ # Bytes 128-131: Logical block size (both-endian)
97
+ sector << [Iso::SECTOR_SIZE].pack("v")
98
+ sector << [Iso::SECTOR_SIZE].pack("n")
99
+
100
+ # Bytes 132-139: Path table size (both-endian)
101
+ path_table_size = root_dir[:path_table_size] || 10
102
+ sector << [path_table_size].pack("V")
103
+ sector << [path_table_size].pack("N")
104
+
105
+ # Bytes 140-143: Location of type L path table
106
+ sector << [root_dir[:path_table_location] || 19].pack("V")
107
+
108
+ # Bytes 144-147: Location of optional type L path table
109
+ sector << [0].pack("V")
110
+
111
+ # Bytes 148-151: Location of type M path table
112
+ sector << [root_dir[:path_table_location_be] || 20].pack("N")
113
+
114
+ # Bytes 152-155: Location of optional type M path table
115
+ sector << [0].pack("N")
116
+
117
+ # Bytes 156-189: Root directory record (34 bytes)
118
+ sector << build_root_directory_record(root_dir)
119
+
120
+ # Bytes 190-317: Volume set identifier
121
+ sector << pad_d_string("", 128)
122
+
123
+ # Bytes 318-445: Publisher identifier
124
+ sector << pad_a_string(@publisher, 128)
125
+
126
+ # Bytes 446-573: Data preparer identifier
127
+ sector << pad_a_string(@preparer, 128)
128
+
129
+ # Bytes 574-701: Application identifier
130
+ sector << pad_a_string(@application, 128)
131
+
132
+ # Bytes 702-738: Copyright file identifier
133
+ sector << pad_d_string("", 37)
134
+
135
+ # Bytes 739-775: Abstract file identifier
136
+ sector << pad_d_string("", 37)
137
+
138
+ # Bytes 776-812: Bibliographic file identifier
139
+ sector << pad_d_string("", 37)
140
+
141
+ # Bytes 813-829: Volume creation date/time
142
+ now = Time.now
143
+ sector << encode_volume_datetime(now)
144
+
145
+ # Bytes 830-846: Volume modification date/time
146
+ sector << encode_volume_datetime(now)
147
+
148
+ # Bytes 847-863: Volume expiration date/time (not set)
149
+ sector << encode_volume_datetime(nil)
150
+
151
+ # Bytes 864-880: Volume effective date/time (not set)
152
+ sector << encode_volume_datetime(nil)
153
+
154
+ # Byte 881: File structure version (1)
155
+ sector << [1].pack("C")
156
+
157
+ # Byte 882: Unused (0)
158
+ sector << "\x00"
159
+
160
+ # Bytes 883-1395: Application use
161
+ sector << ("\x00" * 513)
162
+
163
+ # Bytes 1396-2047: Reserved
164
+ sector << ("\x00" * 652)
165
+
166
+ sector
167
+ end
168
+
169
+ # Build Joliet supplementary volume descriptor
170
+ #
171
+ # @param root_dir [Hash] Root directory information
172
+ # @return [String] Joliet SVD sector (2048 bytes)
173
+ def build_joliet(root_dir)
174
+ # Joliet is similar to primary VD but with:
175
+ # - Type = 2 (supplementary)
176
+ # - UCS-2 encoding for strings
177
+ # - Escape sequences for character set
178
+
179
+ sector = build_primary(root_dir)
180
+
181
+ # Modify type to supplementary
182
+ sector.setbyte(0, Iso::VD_SUPPLEMENTARY)
183
+
184
+ # Add escape sequences for UCS-2
185
+ # Bytes 88-90: %/@ %/C %/E for levels 1, 2, 3
186
+ sector.setbyte(88, 0x25) # '%'
187
+ sector.setbyte(89, 0x2F) # '/'
188
+ sector.setbyte(90, 0x45) # 'E'
189
+
190
+ # Convert volume ID to UCS-2
191
+ volume_id_ucs2 = @volume_id.encode("UTF-16BE")
192
+ padded_volume_id = pad_string(volume_id_ucs2,
193
+ 32).force_encoding("ASCII-8BIT")
194
+
195
+ # Replace bytes 40-71 with UCS-2 volume ID
196
+ 32.times do |i|
197
+ sector.setbyte(40 + i, padded_volume_id.getbyte(i))
198
+ end
199
+
200
+ sector
201
+ end
202
+
203
+ private
204
+
205
+ # Build root directory record
206
+ #
207
+ # @param root_dir [Hash] Root directory info
208
+ # @return [String] 34-byte directory record
209
+ def build_root_directory_record(root_dir)
210
+ record = +""
211
+
212
+ # Length of record (34 bytes for root)
213
+ record << [34].pack("C")
214
+
215
+ # Extended attribute length (0)
216
+ record << [0].pack("C")
217
+
218
+ # Location of extent (both-endian)
219
+ location = root_dir[:location] || 21
220
+ record << [location].pack("V")
221
+ record << [location].pack("N")
222
+
223
+ # Data length (both-endian)
224
+ data_length = root_dir[:size] || Iso::SECTOR_SIZE
225
+ record << [data_length].pack("V")
226
+ record << [data_length].pack("N")
227
+
228
+ # Recording date
229
+ record << encode_record_datetime(Time.now)
230
+
231
+ # Flags (directory)
232
+ record << [Iso::FLAG_DIRECTORY].pack("C")
233
+
234
+ # File unit size, interleave gap
235
+ record << [0, 0].pack("C2")
236
+
237
+ # Volume sequence number (both-endian)
238
+ record << [1].pack("v")
239
+ record << [1].pack("n")
240
+
241
+ # File identifier length (1 for root)
242
+ record << [1].pack("C")
243
+
244
+ # File identifier (0x00 for root)
245
+ record << "\x00"
246
+
247
+ record
248
+ end
249
+
250
+ # Encode volume date/time (17-byte format)
251
+ #
252
+ # @param time [Time, nil] Time to encode
253
+ # @return [String] 17-byte encoded time
254
+ def encode_volume_datetime(time)
255
+ if time.nil?
256
+ # All zeros for unset time
257
+ return "#{'0' * 16}\u0000"
258
+ end
259
+
260
+ format(
261
+ "%04d%02d%02d%02d%02d%02d%02d",
262
+ time.year,
263
+ time.month,
264
+ time.day,
265
+ time.hour,
266
+ time.min,
267
+ time.sec,
268
+ 0, # Centiseconds
269
+ ) + [0].pack("c") # GMT offset
270
+ end
271
+
272
+ # Encode recording date/time (7-byte format)
273
+ #
274
+ # @param time [Time] Time to encode
275
+ # @return [String] 7-byte encoded time
276
+ def encode_record_datetime(time)
277
+ [
278
+ time.year - 1900,
279
+ time.month,
280
+ time.day,
281
+ time.hour,
282
+ time.min,
283
+ time.sec,
284
+ 0, # GMT offset
285
+ ].pack("C7")
286
+ end
287
+
288
+ # Pad string with spaces (a-characters)
289
+ #
290
+ # @param str [String] String to pad
291
+ # @param length [Integer] Target length
292
+ # @return [String] Padded string
293
+ def pad_a_string(str, length)
294
+ str = str[0, length] if str.bytesize > length
295
+ str + (" " * (length - str.bytesize))
296
+ end
297
+
298
+ # Pad string with spaces (d-characters)
299
+ #
300
+ # @param str [String] String to pad
301
+ # @param length [Integer] Target length
302
+ # @return [String] Padded string
303
+ def pad_d_string(str, length)
304
+ pad_a_string(str, length)
305
+ end
306
+
307
+ # Pad generic string
308
+ #
309
+ # @param str [String] String to pad
310
+ # @param length [Integer] Target length
311
+ # @return [String] Padded string
312
+ def pad_string(str, length)
313
+ str = str[0, length] if str.bytesize > length
314
+ padding = "\x00".encode(str.encoding) * (length - str.bytesize)
315
+ str + padding
316
+ end
317
+ end
318
+ end
319
+ end
320
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Iso
6
+ # ISO 9660 Volume Descriptor
7
+ # Represents the primary volume descriptor containing metadata
8
+ class VolumeDescriptor
9
+ attr_reader :type, :identifier, :version, :volume_identifier,
10
+ :volume_space_size, :volume_set_size, :volume_sequence_number,
11
+ :logical_block_size, :path_table_size, :path_table_location,
12
+ :root_directory_record, :volume_set_identifier,
13
+ :publisher_identifier, :preparer_identifier,
14
+ :application_identifier, :creation_date, :modification_date,
15
+ :system_identifier
16
+
17
+ # Standard identifier for ISO 9660
18
+ ISO_IDENTIFIER = "CD001"
19
+
20
+ # Parse volume descriptor from binary data
21
+ #
22
+ # @param data [String] Binary sector data (2048 bytes)
23
+ # @return [VolumeDescriptor] Parsed descriptor
24
+ def self.parse(data)
25
+ new.tap { |vd| vd.parse(data) }
26
+ end
27
+
28
+ # Parse descriptor data
29
+ #
30
+ # @param data [String] Binary data
31
+ def parse(data)
32
+ raise "Invalid volume descriptor size" unless data.bytesize >= 2048
33
+
34
+ # Byte 0: Volume descriptor type
35
+ @type = data.getbyte(0)
36
+
37
+ # Bytes 1-5: Standard identifier "CD001"
38
+ @identifier = data[1, 5]
39
+ unless @identifier == ISO_IDENTIFIER
40
+ raise "Invalid ISO identifier: expected #{ISO_IDENTIFIER}, got #{@identifier}"
41
+ end
42
+
43
+ # Byte 6: Version (should be 1)
44
+ @version = data.getbyte(6)
45
+
46
+ # Parse based on type
47
+ case @type
48
+ when Iso::VD_PRIMARY
49
+ parse_primary_volume_descriptor(data)
50
+ when Iso::VD_TERMINATOR
51
+ # Terminator has no additional data
52
+ else
53
+ # Skip other types for now
54
+ end
55
+ end
56
+
57
+ # Check if this is a primary volume descriptor
58
+ #
59
+ # @return [Boolean] true if primary VD
60
+ def primary?
61
+ @type == Iso::VD_PRIMARY
62
+ end
63
+
64
+ # Check if this is a terminator
65
+ #
66
+ # @return [Boolean] true if terminator
67
+ def terminator?
68
+ @type == Iso::VD_TERMINATOR
69
+ end
70
+
71
+ private
72
+
73
+ # Parse primary volume descriptor fields
74
+ #
75
+ # @param data [String] Binary data
76
+ def parse_primary_volume_descriptor(data)
77
+ # Byte 7: Unused (0)
78
+ # Bytes 8-39: System identifier
79
+ @system_identifier = data[8, 32].strip
80
+
81
+ # Bytes 40-71: Volume identifier
82
+ @volume_identifier = data[40, 32].strip
83
+
84
+ # Bytes 72-79: Unused (zeros)
85
+
86
+ # Bytes 80-87: Volume space size (both-endian)
87
+ @volume_space_size = data[80, 4].unpack1("V")
88
+
89
+ # Bytes 88-119: Unused (zeros)
90
+
91
+ # Bytes 120-123: Volume set size (both-endian)
92
+ @volume_set_size = data[120, 2].unpack1("v")
93
+
94
+ # Bytes 124-127: Volume sequence number (both-endian)
95
+ @volume_sequence_number = data[124, 2].unpack1("v")
96
+
97
+ # Bytes 128-131: Logical block size (both-endian)
98
+ @logical_block_size = data[128, 2].unpack1("v")
99
+
100
+ # Bytes 132-139: Path table size (both-endian)
101
+ @path_table_size = data[132, 4].unpack1("V")
102
+
103
+ # Bytes 140-143: Path table location (little-endian)
104
+ @path_table_location = data[140, 4].unpack1("V")
105
+
106
+ # Bytes 144-147: Optional path table location
107
+ # Bytes 148-151: Path table location (big-endian)
108
+ # Bytes 152-155: Optional path table location
109
+
110
+ # Bytes 156-189: Root directory record (34 bytes)
111
+ @root_directory_record = DirectoryRecord.parse(data[156, 34])
112
+
113
+ # Bytes 190-317: Volume set identifier
114
+ @volume_set_identifier = data[190, 128].strip
115
+
116
+ # Bytes 318-445: Publisher identifier
117
+ @publisher_identifier = data[318, 128].strip
118
+
119
+ # Bytes 446-573: Data preparer identifier
120
+ @preparer_identifier = data[446, 128].strip
121
+
122
+ # Bytes 574-701: Application identifier
123
+ @application_identifier = data[574, 128].strip
124
+
125
+ # Bytes 702-738: Copyright file identifier
126
+ # Bytes 739-775: Abstract file identifier
127
+ # Bytes 776-812: Bibliographic file identifier
128
+
129
+ # Bytes 813-829: Volume creation date/time
130
+ @creation_date = parse_datetime(data[813, 17])
131
+
132
+ # Bytes 830-846: Volume modification date/time
133
+ @modification_date = parse_datetime(data[830, 17])
134
+
135
+ # Bytes 847-863: Volume expiration date/time
136
+ # Bytes 864-880: Volume effective date/time
137
+
138
+ # Byte 881: File structure version
139
+ # Bytes 882-1395: Application use
140
+ # Bytes 1396-2047: Reserved
141
+ end
142
+
143
+ # Parse ISO 9660 datetime format
144
+ #
145
+ # @param data [String] 17-byte datetime string
146
+ # @return [Time, nil] Parsed time or nil if invalid
147
+ def parse_datetime(data)
148
+ return nil if data.nil? || data.bytesize < 17
149
+
150
+ year = data[0, 4].to_i
151
+ month = data[4, 2].to_i
152
+ day = data[6, 2].to_i
153
+ hour = data[8, 2].to_i
154
+ minute = data[10, 2].to_i
155
+ second = data[12, 2].to_i
156
+ # Centiseconds at 14-15 (ignored)
157
+ # Timezone offset at 16 (ignored for now)
158
+
159
+ return nil if year.zero?
160
+
161
+ Time.new(year, month, day, hour, minute, second)
162
+ rescue ArgumentError
163
+ nil
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end