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.
Files changed (632) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +293 -0
  5. data/CHANGELOG.md +1647 -0
  6. data/CONTEXT.md +68 -0
  7. data/COPYING +502 -0
  8. data/Gemfile +19 -0
  9. data/LICENSE +12 -0
  10. data/README.adoc +1327 -0
  11. data/Rakefile +15 -0
  12. data/TODO.refactor/00-overview.md +67 -0
  13. data/TODO.refactor/01-registry-base-class.md +81 -0
  14. data/TODO.refactor/02-error-hierarchy.md +57 -0
  15. data/TODO.refactor/03-autoload-entry-point.md +69 -0
  16. data/TODO.refactor/04-filter-base-consolidation.md +49 -0
  17. data/TODO.refactor/05-send-private-methods.md +64 -0
  18. data/TODO.refactor/06-instance-variable-access.md +69 -0
  19. data/TODO.refactor/07-respond-to-replacement.md +237 -0
  20. data/TODO.refactor/08-spec-doubles.md +27 -0
  21. data/TODO.refactor/09-cli-shared-module.md +35 -0
  22. data/TODO.refactor/10-format-detector-ocp.md +34 -0
  23. data/TODO.refactor/11-convenience-decoupling.md +38 -0
  24. data/TODO.refactor/12-thread-safety.md +8 -0
  25. data/TODO.refactor/13-lutaml-model-migration.md +158 -0
  26. data/TODO.refactor/14-add-missing-specs.md +25 -0
  27. data/benchmark/README.md +260 -0
  28. data/benchmark/benchmark_suite.rb +125 -0
  29. data/benchmark/compression_bench.rb +181 -0
  30. data/benchmark/filter_bench.rb +180 -0
  31. data/benchmark/models/benchmark_result.rb +59 -0
  32. data/benchmark/models/comparison_result.rb +69 -0
  33. data/benchmark/profile_suite.rb +167 -0
  34. data/benchmark/reporter.rb +150 -0
  35. data/benchmark/run_benchmarks.rb +66 -0
  36. data/benchmark/test_data.rb +137 -0
  37. data/config/formats/rar3_spec.yml +92 -0
  38. data/config/formats/rar5_spec.yml +102 -0
  39. data/docs/.github/workflows/docs.yml +142 -0
  40. data/docs/.gitignore +21 -0
  41. data/docs/.lychee.toml +67 -0
  42. data/docs/Gemfile +13 -0
  43. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  44. data/docs/README.md +101 -0
  45. data/docs/_config.yml +112 -0
  46. data/docs/assets/logo.svg +1 -0
  47. data/docs/assets/omnizip-logo.pdf +1540 -11
  48. data/docs/comparison/feature-matrix.adoc +694 -0
  49. data/docs/comparison/index.adoc +113 -0
  50. data/docs/comparison/vs-7zip.adoc +309 -0
  51. data/docs/comparison/vs-peazip.adoc +77 -0
  52. data/docs/comparison/vs-rubyzip.adoc +342 -0
  53. data/docs/comparison/vs-winrar.adoc +100 -0
  54. data/docs/compatibility.adoc +579 -0
  55. data/docs/concepts/index.adoc +129 -0
  56. data/docs/developer/architecture.adoc +256 -0
  57. data/docs/developer/contributing.adoc +158 -0
  58. data/docs/developer/index.adoc +25 -0
  59. data/docs/developer/testing.adoc +212 -0
  60. data/docs/getting-started/basic-usage.adoc +263 -0
  61. data/docs/getting-started/index.adoc +42 -0
  62. data/docs/getting-started/installation.adoc +138 -0
  63. data/docs/getting-started/quick-start.adoc +183 -0
  64. data/docs/getting-started/your-first-archive.adoc +219 -0
  65. data/docs/guides/advanced-features/encryption.adoc +277 -0
  66. data/docs/guides/advanced-features/index.adoc +59 -0
  67. data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
  68. data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
  69. data/docs/guides/advanced-features/streaming.adoc +142 -0
  70. data/docs/guides/archive-formats/gzip-format.adoc +105 -0
  71. data/docs/guides/archive-formats/index.adoc +160 -0
  72. data/docs/guides/archive-formats/ole-format.adoc +151 -0
  73. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  74. data/docs/guides/archive-formats/rar5.adoc +521 -0
  75. data/docs/guides/archive-formats/rpm-format.adoc +108 -0
  76. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  77. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  78. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  79. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  80. data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
  81. data/docs/guides/compression-algorithms/deflate.adoc +313 -0
  82. data/docs/guides/compression-algorithms/index.adoc +190 -0
  83. data/docs/guides/compression-algorithms/lzma.adoc +394 -0
  84. data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
  85. data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
  86. data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
  87. data/docs/guides/creating-archives.adoc +348 -0
  88. data/docs/guides/extracting-archives.adoc +53 -0
  89. data/docs/guides/format-conversion.adoc +64 -0
  90. data/docs/guides/index.adoc +49 -0
  91. data/docs/guides/migration-rubyzip.adoc +217 -0
  92. data/docs/guides/parity-archives.adoc +605 -0
  93. data/docs/guides/performance-tuning.adoc +88 -0
  94. data/docs/index.adoc +228 -0
  95. data/docs/lychee.toml +67 -0
  96. data/docs/reference/api/overview.adoc +187 -0
  97. data/docs/reference/cli/compress-command.adoc +114 -0
  98. data/docs/reference/cli/overview.adoc +140 -0
  99. data/docs/reference/index.adoc +26 -0
  100. data/docs/resources/faq.adoc +185 -0
  101. data/docs/resources/quick-reference.adoc +222 -0
  102. data/docs/rust-backend.md +0 -0
  103. data/docs/troubleshooting/index.adoc +207 -0
  104. data/docs/xar_format.md +216 -0
  105. data/examples/api_comparison.rb +205 -0
  106. data/examples/deflate64_example.rb +96 -0
  107. data/examples/par2_demo.rb +121 -0
  108. data/examples/quick_start_native.rb +150 -0
  109. data/examples/quick_start_rubyzip.rb +115 -0
  110. data/examples/rubyzip_compatibility_demo.rb +194 -0
  111. data/exe/omnizip +27 -0
  112. data/lib/omnizip/algorithm.rb +176 -0
  113. data/lib/omnizip/algorithm_registry.rb +65 -0
  114. data/lib/omnizip/algorithms/.keep +0 -0
  115. data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
  116. data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
  117. data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
  118. data/lib/omnizip/algorithms/bzip2.rb +108 -0
  119. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  120. data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
  121. data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
  122. data/lib/omnizip/algorithms/deflate.rb +135 -0
  123. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  124. data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
  125. data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
  126. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
  127. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
  128. data/lib/omnizip/algorithms/deflate64.rb +118 -0
  129. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  130. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  131. data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
  132. data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
  133. data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
  134. data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
  135. data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
  136. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
  137. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
  138. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
  139. data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
  140. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
  141. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  142. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  143. data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
  144. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  145. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
  146. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
  147. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  148. data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
  149. data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
  150. data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
  151. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  152. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
  153. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
  154. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
  155. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
  156. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
  157. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
  158. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  159. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
  160. data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
  161. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
  162. data/lib/omnizip/algorithms/lzma.rb +266 -0
  163. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
  164. data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
  165. data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
  166. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
  167. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  168. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
  169. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  170. data/lib/omnizip/algorithms/lzma2.rb +133 -0
  171. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  172. data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
  173. data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
  174. data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
  175. data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
  176. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  177. data/lib/omnizip/algorithms/ppmd7.rb +146 -0
  178. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  179. data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
  180. data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
  181. data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
  182. data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
  183. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  184. data/lib/omnizip/algorithms/ppmd8.rb +122 -0
  185. data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
  186. data/lib/omnizip/algorithms/registration.rb +28 -0
  187. data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
  188. data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
  189. data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
  190. data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
  191. data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
  192. data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
  193. data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
  194. data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
  195. data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
  196. data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
  197. data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
  198. data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
  199. data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
  200. data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
  201. data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
  202. data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
  203. data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
  204. data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
  205. data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
  206. data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
  207. data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
  208. data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
  209. data/lib/omnizip/algorithms/zstandard.rb +210 -0
  210. data/lib/omnizip/algorithms.rb +35 -0
  211. data/lib/omnizip/archive/builder.rb +48 -0
  212. data/lib/omnizip/archive/reader_session.rb +67 -0
  213. data/lib/omnizip/archive.rb +86 -0
  214. data/lib/omnizip/archive_handler.rb +82 -0
  215. data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
  216. data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
  217. data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
  218. data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
  219. data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
  220. data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
  221. data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
  222. data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
  223. data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
  224. data/lib/omnizip/archive_handlers.rb +18 -0
  225. data/lib/omnizip/backends.rb +160 -0
  226. data/lib/omnizip/buffer/memory_archive.rb +246 -0
  227. data/lib/omnizip/buffer/memory_extractor.rb +234 -0
  228. data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
  229. data/lib/omnizip/buffer.rb +187 -0
  230. data/lib/omnizip/checksum_registry.rb +41 -0
  231. data/lib/omnizip/checksums/crc32.rb +101 -0
  232. data/lib/omnizip/checksums/crc64.rb +102 -0
  233. data/lib/omnizip/checksums/crc_base.rb +158 -0
  234. data/lib/omnizip/checksums/registration.rb +16 -0
  235. data/lib/omnizip/checksums/verifier.rb +130 -0
  236. data/lib/omnizip/checksums.rb +11 -0
  237. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  238. data/lib/omnizip/chunked/reader.rb +78 -0
  239. data/lib/omnizip/chunked/writer.rb +123 -0
  240. data/lib/omnizip/chunked.rb +123 -0
  241. data/lib/omnizip/cli/output_formatter.rb +112 -0
  242. data/lib/omnizip/cli.rb +604 -0
  243. data/lib/omnizip/commands/.keep +0 -0
  244. data/lib/omnizip/commands/archive_create_command.rb +245 -0
  245. data/lib/omnizip/commands/archive_extract_command.rb +231 -0
  246. data/lib/omnizip/commands/archive_list_command.rb +204 -0
  247. data/lib/omnizip/commands/archive_repair_command.rb +129 -0
  248. data/lib/omnizip/commands/archive_verify_command.rb +115 -0
  249. data/lib/omnizip/commands/compress_command.rb +115 -0
  250. data/lib/omnizip/commands/decompress_command.rb +149 -0
  251. data/lib/omnizip/commands/list_command.rb +51 -0
  252. data/lib/omnizip/commands/metadata_command.rb +215 -0
  253. data/lib/omnizip/commands/parity_create_command.rb +114 -0
  254. data/lib/omnizip/commands/parity_repair_command.rb +120 -0
  255. data/lib/omnizip/commands/parity_verify_command.rb +122 -0
  256. data/lib/omnizip/commands/profile_list_command.rb +54 -0
  257. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  258. data/lib/omnizip/commands.rb +21 -0
  259. data/lib/omnizip/convenience.rb +389 -0
  260. data/lib/omnizip/converter/conversion_registry.rb +50 -0
  261. data/lib/omnizip/converter/conversion_strategy.rb +108 -0
  262. data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
  263. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
  264. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
  265. data/lib/omnizip/converter.rb +124 -0
  266. data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
  267. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  268. data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
  269. data/lib/omnizip/crypto/aes256.rb +102 -0
  270. data/lib/omnizip/crypto.rb +11 -0
  271. data/lib/omnizip/entry.rb +44 -0
  272. data/lib/omnizip/error.rb +110 -0
  273. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
  274. data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
  275. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  276. data/lib/omnizip/eta/sample_history.rb +143 -0
  277. data/lib/omnizip/eta/time_estimator.rb +106 -0
  278. data/lib/omnizip/eta.rb +68 -0
  279. data/lib/omnizip/extraction/filter_chain.rb +179 -0
  280. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  281. data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
  282. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  283. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  284. data/lib/omnizip/extraction/selective_extractor.rb +247 -0
  285. data/lib/omnizip/extraction.rb +115 -0
  286. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  287. data/lib/omnizip/file_type.rb +117 -0
  288. data/lib/omnizip/filter.rb +141 -0
  289. data/lib/omnizip/filter_pipeline.rb +108 -0
  290. data/lib/omnizip/filter_registry.rb +113 -0
  291. data/lib/omnizip/filters/bcj.rb +277 -0
  292. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  293. data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
  294. data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
  295. data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
  296. data/lib/omnizip/filters/bcj2.rb +93 -0
  297. data/lib/omnizip/filters/bcj_arm.rb +174 -0
  298. data/lib/omnizip/filters/bcj_arm64.rb +242 -0
  299. data/lib/omnizip/filters/bcj_ia64.rb +194 -0
  300. data/lib/omnizip/filters/bcj_ppc.rb +188 -0
  301. data/lib/omnizip/filters/bcj_sparc.rb +174 -0
  302. data/lib/omnizip/filters/bcj_x86.rb +191 -0
  303. data/lib/omnizip/filters/delta.rb +195 -0
  304. data/lib/omnizip/filters/xz_delta.rb +258 -0
  305. data/lib/omnizip/filters.rb +20 -0
  306. data/lib/omnizip/format_detector.rb +166 -0
  307. data/lib/omnizip/formats/.keep +0 -0
  308. data/lib/omnizip/formats/bzip2_file.rb +159 -0
  309. data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
  310. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  311. data/lib/omnizip/formats/cpio/entry.rb +389 -0
  312. data/lib/omnizip/formats/cpio/reader.rb +194 -0
  313. data/lib/omnizip/formats/cpio/writer.rb +232 -0
  314. data/lib/omnizip/formats/cpio.rb +132 -0
  315. data/lib/omnizip/formats/format_spec_loader.rb +228 -0
  316. data/lib/omnizip/formats/gzip.rb +236 -0
  317. data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
  318. data/lib/omnizip/formats/iso/directory_record.rb +162 -0
  319. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  320. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  321. data/lib/omnizip/formats/iso/reader.rb +194 -0
  322. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  323. data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
  324. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  325. data/lib/omnizip/formats/iso/writer.rb +543 -0
  326. data/lib/omnizip/formats/iso.rb +133 -0
  327. data/lib/omnizip/formats/lzip.rb +161 -0
  328. data/lib/omnizip/formats/lzma_alone.rb +149 -0
  329. data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
  330. data/lib/omnizip/formats/msi/constants.rb +157 -0
  331. data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
  332. data/lib/omnizip/formats/msi/entry.rb +134 -0
  333. data/lib/omnizip/formats/msi/reader.rb +301 -0
  334. data/lib/omnizip/formats/msi/string_pool.rb +246 -0
  335. data/lib/omnizip/formats/msi/table_parser.rb +244 -0
  336. data/lib/omnizip/formats/msi.rb +73 -0
  337. data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
  338. data/lib/omnizip/formats/ole/constants.rb +61 -0
  339. data/lib/omnizip/formats/ole/dirent.rb +439 -0
  340. data/lib/omnizip/formats/ole/header.rb +199 -0
  341. data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
  342. data/lib/omnizip/formats/ole/storage.rb +482 -0
  343. data/lib/omnizip/formats/ole/types/variant.rb +338 -0
  344. data/lib/omnizip/formats/ole.rb +143 -0
  345. data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
  346. data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
  347. data/lib/omnizip/formats/rar/block_parser.rb +282 -0
  348. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  349. data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
  350. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
  351. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
  352. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  353. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  354. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  355. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  356. data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
  357. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
  358. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
  359. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
  360. data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
  361. data/lib/omnizip/formats/rar/compression.rb +17 -0
  362. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  363. data/lib/omnizip/formats/rar/constants.rb +88 -0
  364. data/lib/omnizip/formats/rar/decompressor.rb +316 -0
  365. data/lib/omnizip/formats/rar/external_writer.rb +311 -0
  366. data/lib/omnizip/formats/rar/header.rb +209 -0
  367. data/lib/omnizip/formats/rar/license_validator.rb +111 -0
  368. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  369. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  370. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  371. data/lib/omnizip/formats/rar/models.rb +14 -0
  372. data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
  373. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
  374. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
  375. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  376. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  377. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
  378. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  379. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
  380. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  381. data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
  382. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  383. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  384. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  385. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  386. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  387. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
  388. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  389. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
  390. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
  391. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
  392. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  393. data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
  394. data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
  395. data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
  396. data/lib/omnizip/formats/rar/reader.rb +377 -0
  397. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  398. data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
  399. data/lib/omnizip/formats/rar/writer.rb +437 -0
  400. data/lib/omnizip/formats/rar.rb +193 -0
  401. data/lib/omnizip/formats/rar3/compressor.rb +71 -0
  402. data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
  403. data/lib/omnizip/formats/rar3/reader.rb +107 -0
  404. data/lib/omnizip/formats/rar3/writer.rb +220 -0
  405. data/lib/omnizip/formats/rar3.rb +15 -0
  406. data/lib/omnizip/formats/rar5/compressor.rb +71 -0
  407. data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
  408. data/lib/omnizip/formats/rar5/reader.rb +130 -0
  409. data/lib/omnizip/formats/rar5/writer.rb +65 -0
  410. data/lib/omnizip/formats/rar5.rb +15 -0
  411. data/lib/omnizip/formats/rpm/constants.rb +58 -0
  412. data/lib/omnizip/formats/rpm/entry.rb +106 -0
  413. data/lib/omnizip/formats/rpm/header.rb +106 -0
  414. data/lib/omnizip/formats/rpm/lead.rb +132 -0
  415. data/lib/omnizip/formats/rpm/tag.rb +228 -0
  416. data/lib/omnizip/formats/rpm/writer.rb +652 -0
  417. data/lib/omnizip/formats/rpm.rb +458 -0
  418. data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
  419. data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
  420. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  421. data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
  422. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
  423. data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
  424. data/lib/omnizip/formats/seven_zip/header.rb +102 -0
  425. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
  426. data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
  427. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  428. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
  429. data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
  430. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  431. data/lib/omnizip/formats/seven_zip/models.rb +20 -0
  432. data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
  433. data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
  434. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
  435. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
  436. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  437. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
  438. data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
  439. data/lib/omnizip/formats/seven_zip.rb +179 -0
  440. data/lib/omnizip/formats/tar/constants.rb +73 -0
  441. data/lib/omnizip/formats/tar/entry.rb +98 -0
  442. data/lib/omnizip/formats/tar/header.rb +206 -0
  443. data/lib/omnizip/formats/tar/reader.rb +119 -0
  444. data/lib/omnizip/formats/tar/writer.rb +212 -0
  445. data/lib/omnizip/formats/tar.rb +74 -0
  446. data/lib/omnizip/formats/xar/constants.rb +119 -0
  447. data/lib/omnizip/formats/xar/entry.rb +268 -0
  448. data/lib/omnizip/formats/xar/header.rb +223 -0
  449. data/lib/omnizip/formats/xar/reader.rb +400 -0
  450. data/lib/omnizip/formats/xar/toc.rb +570 -0
  451. data/lib/omnizip/formats/xar/writer.rb +461 -0
  452. data/lib/omnizip/formats/xar.rb +145 -0
  453. data/lib/omnizip/formats/xz/reader.rb +121 -0
  454. data/lib/omnizip/formats/xz/writer.rb +416 -0
  455. data/lib/omnizip/formats/xz.rb +210 -0
  456. data/lib/omnizip/formats/xz_const.rb +49 -0
  457. data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
  458. data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
  459. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  460. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
  461. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  462. data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
  463. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
  464. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
  465. data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
  466. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
  467. data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
  468. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
  469. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  470. data/lib/omnizip/formats/xz_impl.rb +52 -0
  471. data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
  472. data/lib/omnizip/formats/zip/constants.rb +69 -0
  473. data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
  474. data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
  475. data/lib/omnizip/formats/zip/reader.rb +376 -0
  476. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  477. data/lib/omnizip/formats/zip/writer.rb +489 -0
  478. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
  479. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
  480. data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
  481. data/lib/omnizip/formats/zip.rb +50 -0
  482. data/lib/omnizip/formats.rb +29 -0
  483. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  484. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  485. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  486. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  487. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  488. data/lib/omnizip/implementations/base.rb +19 -0
  489. data/lib/omnizip/implementations/rust/archive.rb +93 -0
  490. data/lib/omnizip/implementations/rust/library.rb +221 -0
  491. data/lib/omnizip/implementations/rust.rb +26 -0
  492. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
  493. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
  494. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
  495. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
  496. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
  497. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
  498. data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
  499. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
  500. data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
  501. data/lib/omnizip/implementations/seven_zip.rb +11 -0
  502. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
  503. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
  504. data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
  505. data/lib/omnizip/implementations/xz_utils.rb +10 -0
  506. data/lib/omnizip/implementations.rb +25 -0
  507. data/lib/omnizip/io/buffered_input.rb +147 -0
  508. data/lib/omnizip/io/buffered_output.rb +106 -0
  509. data/lib/omnizip/io/source.rb +143 -0
  510. data/lib/omnizip/io/stream_manager.rb +117 -0
  511. data/lib/omnizip/io.rb +15 -0
  512. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  513. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  514. data/lib/omnizip/link_handler.rb +129 -0
  515. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  516. data/lib/omnizip/metadata/entry_metadata.rb +153 -0
  517. data/lib/omnizip/metadata/metadata_editor.rb +169 -0
  518. data/lib/omnizip/metadata/metadata_registry.rb +71 -0
  519. data/lib/omnizip/metadata/metadata_validator.rb +101 -0
  520. data/lib/omnizip/metadata.rb +58 -0
  521. data/lib/omnizip/models/.keep +0 -0
  522. data/lib/omnizip/models/algorithm_metadata.rb +41 -0
  523. data/lib/omnizip/models/attribute_apply.rb +40 -0
  524. data/lib/omnizip/models/compression_options.rb +53 -0
  525. data/lib/omnizip/models/conversion_options.rb +79 -0
  526. data/lib/omnizip/models/conversion_result.rb +141 -0
  527. data/lib/omnizip/models/eta_result.rb +45 -0
  528. data/lib/omnizip/models/extraction_rule.rb +115 -0
  529. data/lib/omnizip/models/filter_chain.rb +142 -0
  530. data/lib/omnizip/models/filter_config.rb +148 -0
  531. data/lib/omnizip/models/match_result.rb +141 -0
  532. data/lib/omnizip/models/optimization_suggestion.rb +95 -0
  533. data/lib/omnizip/models/parallel_options.rb +116 -0
  534. data/lib/omnizip/models/performance_result.rb +85 -0
  535. data/lib/omnizip/models/profile_report.rb +116 -0
  536. data/lib/omnizip/models/progress_options.rb +39 -0
  537. data/lib/omnizip/models/split_options.rb +116 -0
  538. data/lib/omnizip/optimization_registry.rb +45 -0
  539. data/lib/omnizip/parallel/engine.rb +52 -0
  540. data/lib/omnizip/parallel/job_queue.rb +209 -0
  541. data/lib/omnizip/parallel/job_scheduler.rb +225 -0
  542. data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
  543. data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
  544. data/lib/omnizip/parallel/thread_pool.rb +60 -0
  545. data/lib/omnizip/parallel/worker_pool.rb +227 -0
  546. data/lib/omnizip/parallel.rb +156 -0
  547. data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
  548. data/lib/omnizip/parity/galois16.rb +145 -0
  549. data/lib/omnizip/parity/models/creator_packet.rb +71 -0
  550. data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
  551. data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
  552. data/lib/omnizip/parity/models/main_packet.rb +126 -0
  553. data/lib/omnizip/parity/models/packet.rb +156 -0
  554. data/lib/omnizip/parity/models/packet_registry.rb +102 -0
  555. data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
  556. data/lib/omnizip/parity/models.rb +27 -0
  557. data/lib/omnizip/parity/par2_creator.rb +496 -0
  558. data/lib/omnizip/parity/par2_repairer.rb +409 -0
  559. data/lib/omnizip/parity/par2_verifier.rb +373 -0
  560. data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
  561. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  562. data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
  563. data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
  564. data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
  565. data/lib/omnizip/parity.rb +207 -0
  566. data/lib/omnizip/password/encryption_registry.rb +26 -0
  567. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  568. data/lib/omnizip/password/password_validator.rb +129 -0
  569. data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
  570. data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
  571. data/lib/omnizip/password.rb +88 -0
  572. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  573. data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
  574. data/lib/omnizip/pipe.rb +120 -0
  575. data/lib/omnizip/platform/ntfs_streams.rb +200 -0
  576. data/lib/omnizip/platform.rb +189 -0
  577. data/lib/omnizip/profile/archive_profile.rb +36 -0
  578. data/lib/omnizip/profile/balanced_profile.rb +31 -0
  579. data/lib/omnizip/profile/binary_profile.rb +33 -0
  580. data/lib/omnizip/profile/compression_profile.rb +157 -0
  581. data/lib/omnizip/profile/custom_profile.rb +155 -0
  582. data/lib/omnizip/profile/fast_profile.rb +31 -0
  583. data/lib/omnizip/profile/maximum_profile.rb +31 -0
  584. data/lib/omnizip/profile/profile_detector.rb +108 -0
  585. data/lib/omnizip/profile/profile_registry.rb +160 -0
  586. data/lib/omnizip/profile/text_profile.rb +33 -0
  587. data/lib/omnizip/profile.rb +261 -0
  588. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  589. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  590. data/lib/omnizip/profiler/report_generator.rb +158 -0
  591. data/lib/omnizip/profiler.rb +192 -0
  592. data/lib/omnizip/progress/callback_reporter.rb +34 -0
  593. data/lib/omnizip/progress/console_reporter.rb +59 -0
  594. data/lib/omnizip/progress/log_reporter.rb +89 -0
  595. data/lib/omnizip/progress/operation_progress.rb +118 -0
  596. data/lib/omnizip/progress/progress_bar.rb +156 -0
  597. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  598. data/lib/omnizip/progress/progress_tracker.rb +215 -0
  599. data/lib/omnizip/progress/silent_reporter.rb +22 -0
  600. data/lib/omnizip/progress.rb +131 -0
  601. data/lib/omnizip/registry.rb +111 -0
  602. data/lib/omnizip/rubyzip_compat.rb +61 -0
  603. data/lib/omnizip/temp/safe_extract.rb +124 -0
  604. data/lib/omnizip/temp/temp_file.rb +123 -0
  605. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  606. data/lib/omnizip/temp.rb +184 -0
  607. data/lib/omnizip/version.rb +5 -0
  608. data/lib/omnizip/zip/entry.rb +160 -0
  609. data/lib/omnizip/zip/file.rb +485 -0
  610. data/lib/omnizip/zip/input_stream.rb +270 -0
  611. data/lib/omnizip/zip/output_stream.rb +320 -0
  612. data/lib/omnizip/zip.rb +23 -0
  613. data/lib/omnizip.rb +157 -0
  614. data/lib/tasks/msi_test_files.rake +66 -0
  615. data/lib/tasks/platform_gems.rake +147 -0
  616. data/lib/tasks/rust_backend.rake +48 -0
  617. data/readme-docs/advanced-features.adoc +514 -0
  618. data/readme-docs/api-usage.adoc +445 -0
  619. data/readme-docs/architecture.adoc +450 -0
  620. data/readme-docs/archive-formats.adoc +479 -0
  621. data/readme-docs/cli-usage.adoc +222 -0
  622. data/readme-docs/compression-algorithms.adoc +446 -0
  623. data/readme-docs/compression-profiles.adoc +247 -0
  624. data/readme-docs/encryption-checksums.adoc +328 -0
  625. data/readme-docs/format-converter.adoc +316 -0
  626. data/readme-docs/installation.adoc +228 -0
  627. data/readme-docs/par2-archives.adoc +608 -0
  628. data/readme-docs/performance-profiler.adoc +389 -0
  629. data/readme-docs/preprocessing-filters.adoc +280 -0
  630. data/vendor/libomnizip_ffi.so +0 -0
  631. data/xz-file-format-1.2.1.txt +1174 -0
  632. metadata +768 -0
@@ -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 Omnizip::InvalidArchiveError, "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 Omnizip::InvalidArchiveError, "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
@@ -0,0 +1,543 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "time"
5
+
6
+ module Omnizip
7
+ module Formats
8
+ module Iso
9
+ # ISO 9660 image writer
10
+ #
11
+ # Creates ISO 9660 filesystem images (CD/DVD images) from files and directories.
12
+ # Supports ISO 9660 levels 1-3, Rock Ridge, and Joliet extensions.
13
+ #
14
+ # @example Create simple ISO image
15
+ # writer = Iso::Writer.new('cdrom.iso')
16
+ # writer.add_directory('files/')
17
+ # writer.write
18
+ #
19
+ # @example With Rock Ridge and Joliet
20
+ # writer = Iso::Writer.new('backup.iso',
21
+ # volume_id: 'BACKUP_2024',
22
+ # rock_ridge: true,
23
+ # joliet: true
24
+ # )
25
+ # writer.add_directory('documents/')
26
+ # writer.write
27
+ class Writer
28
+ # @return [String] Output ISO file path
29
+ attr_reader :output_path
30
+
31
+ # @return [Hash] Writer options
32
+ attr_reader :options
33
+
34
+ # @return [String] Volume identifier (label)
35
+ attr_accessor :volume_id
36
+
37
+ # @return [String] System identifier
38
+ attr_accessor :system_id
39
+
40
+ # @return [String] Publisher
41
+ attr_accessor :publisher
42
+
43
+ # @return [String] Preparer
44
+ attr_accessor :preparer
45
+
46
+ # @return [String] Application identifier
47
+ attr_accessor :application
48
+
49
+ # @return [Integer] ISO 9660 level (1, 2, or 3)
50
+ attr_accessor :level
51
+
52
+ # @return [Boolean] Use Rock Ridge extensions
53
+ attr_accessor :rock_ridge
54
+
55
+ # @return [Boolean] Use Joliet extensions
56
+ attr_accessor :joliet
57
+
58
+ # @return [Array<Hash>] Files to add
59
+ attr_reader :files
60
+
61
+ # @return [Array<Hash>] Directories to add
62
+ attr_reader :directories
63
+
64
+ # Initialize ISO writer
65
+ #
66
+ # @param output_path [String] Output ISO file path
67
+ # @param options [Hash] Writer options
68
+ # @option options [String] :volume_id Volume label
69
+ # @option options [String] :system_id System identifier
70
+ # @option options [String] :publisher Publisher name
71
+ # @option options [String] :preparer Preparer name
72
+ # @option options [String] :application Application name
73
+ # @option options [Integer] :level ISO 9660 level (1-3)
74
+ # @option options [Boolean] :rock_ridge Enable Rock Ridge
75
+ # @option options [Boolean] :joliet Enable Joliet
76
+ def initialize(output_path, options = {})
77
+ @output_path = output_path
78
+ @options = default_options.merge(options)
79
+
80
+ @volume_id = @options[:volume_id]
81
+ @system_id = @options[:system_id]
82
+ @publisher = @options[:publisher]
83
+ @preparer = @options[:preparer]
84
+ @application = @options[:application]
85
+ @level = @options[:level]
86
+ @rock_ridge = @options[:rock_ridge]
87
+ @joliet = @options[:joliet]
88
+
89
+ @files = []
90
+ @directories = []
91
+ end
92
+
93
+ # Add file to ISO image
94
+ #
95
+ # @param file_path [String] Source file path
96
+ # @param iso_path [String, nil] Path in ISO (defaults to basename)
97
+ # @raise [ArgumentError] if file doesn't exist
98
+ def add_file(file_path, iso_path = nil)
99
+ raise ArgumentError, "File not found: #{file_path}" unless
100
+ File.exist?(file_path)
101
+
102
+ iso_path ||= File.basename(file_path)
103
+
104
+ @files << {
105
+ source: File.expand_path(file_path),
106
+ iso_path: sanitize_path(iso_path),
107
+ stat: File.stat(file_path),
108
+ }
109
+ end
110
+
111
+ # Add directory to ISO image
112
+ #
113
+ # @param dir_path [String] Source directory path
114
+ # @param recursive [Boolean] Include subdirectories
115
+ # @param iso_path [String, nil] Path in ISO (defaults to basename)
116
+ # @raise [ArgumentError] if directory doesn't exist
117
+ def add_directory(dir_path, recursive: true, iso_path: nil)
118
+ raise ArgumentError, "Directory not found: #{dir_path}" unless
119
+ Dir.exist?(dir_path)
120
+
121
+ iso_path ||= File.basename(dir_path)
122
+ iso_path = sanitize_path(iso_path)
123
+
124
+ if recursive
125
+ add_directory_recursive(dir_path, iso_path)
126
+ else
127
+ add_directory_flat(dir_path, iso_path)
128
+ end
129
+ end
130
+
131
+ # Create ISO image
132
+ #
133
+ # @raise [IOError] if write fails
134
+ def write
135
+ File.open(@output_path, "wb") do |io|
136
+ # Build directory structure
137
+ builder = DirectoryBuilder.new(
138
+ @files,
139
+ @directories,
140
+ level: @level,
141
+ rock_ridge: @rock_ridge,
142
+ )
143
+ dir_structure = builder.build
144
+
145
+ # Build volume descriptor
146
+ volume_builder = VolumeBuilder.new(
147
+ volume_id: @volume_id,
148
+ system_id: @system_id,
149
+ publisher: @publisher,
150
+ preparer: @preparer,
151
+ application: @application,
152
+ level: @level,
153
+ rock_ridge: @rock_ridge,
154
+ joliet: @joliet,
155
+ )
156
+
157
+ # Write ISO structure
158
+ write_system_area(io)
159
+ write_volume_descriptors(io, volume_builder, dir_structure)
160
+ write_path_tables(io, dir_structure)
161
+ write_directories(io, dir_structure)
162
+ write_file_data(io)
163
+ end
164
+
165
+ @output_path
166
+ end
167
+
168
+ private
169
+
170
+ # Default writer options
171
+ #
172
+ # @return [Hash] Default options
173
+ def default_options
174
+ {
175
+ volume_id: "OMNIZIP_ISO",
176
+ system_id: "LINUX",
177
+ publisher: "OMNIZIP",
178
+ preparer: "OMNIZIP #{Omnizip::VERSION}",
179
+ application: "OMNIZIP",
180
+ level: 2,
181
+ # Rock Ridge System Use fields and Joliet UCS-2 directory
182
+ # trees are not implemented; advertising either extension
183
+ # makes readers misparse the image (e.g. 7-Zip reads the
184
+ # ASCII names as UCS-2 via the cloned SVD), so both stay
185
+ # off until real implementations land.
186
+ rock_ridge: false,
187
+ joliet: false,
188
+ }
189
+ end
190
+
191
+ # Add directory recursively
192
+ #
193
+ # @param dir_path [String] Source directory
194
+ # @param iso_path [String] ISO path
195
+ def add_directory_recursive(dir_path, iso_path)
196
+ # Add directory itself
197
+ @directories << {
198
+ source: File.expand_path(dir_path),
199
+ iso_path: iso_path,
200
+ stat: File.stat(dir_path),
201
+ directory: true,
202
+ }
203
+
204
+ # Add all contents
205
+ Dir.foreach(dir_path) do |entry|
206
+ next if [".", ".."].include?(entry)
207
+
208
+ source_path = File.join(dir_path, entry)
209
+ target_path = "#{iso_path}/#{entry}"
210
+
211
+ if File.directory?(source_path)
212
+ add_directory_recursive(source_path, target_path)
213
+ else
214
+ add_file(source_path, target_path)
215
+ end
216
+ end
217
+ end
218
+
219
+ # Add directory flat (non-recursive)
220
+ #
221
+ # @param dir_path [String] Source directory
222
+ # @param iso_path [String] ISO path
223
+ def add_directory_flat(dir_path, iso_path)
224
+ @directories << {
225
+ source: File.expand_path(dir_path),
226
+ iso_path: iso_path,
227
+ stat: File.stat(dir_path),
228
+ directory: true,
229
+ }
230
+
231
+ Dir.foreach(dir_path) do |entry|
232
+ next if [".", ".."].include?(entry)
233
+
234
+ source_path = File.join(dir_path, entry)
235
+ next if File.directory?(source_path)
236
+
237
+ add_file(source_path, "#{iso_path}/#{entry}")
238
+ end
239
+ end
240
+
241
+ # Sanitize path for ISO filesystem
242
+ #
243
+ # @param path [String] Input path
244
+ # @return [String] Sanitized path
245
+ def sanitize_path(path)
246
+ # Remove leading/trailing slashes
247
+ path = path.gsub(%r{^/+}, "").gsub(%r{/+$}, "")
248
+
249
+ # Normalize separators
250
+ path.split("/").map do |component|
251
+ sanitize_filename(component)
252
+ end.join("/")
253
+ end
254
+
255
+ # Sanitize filename for ISO level
256
+ #
257
+ # @param name [String] Filename
258
+ # @return [String] Sanitized filename
259
+ def sanitize_filename(name)
260
+ case @level
261
+ when 1
262
+ # Level 1: 8.3 format, A-Z 0-9 _ only
263
+ base = name.upcase.gsub(/[^A-Z0-9_]/, "_")[0, 8]
264
+ ext = ""
265
+ if name.include?(".")
266
+ ext = "." + name.split(".").last.upcase.gsub(/[^A-Z0-9]/, "")[0,
267
+ 3]
268
+ end
269
+ base + ext
270
+ when 2
271
+ # Level 2: Up to 31 chars, more relaxed
272
+ name.gsub(/[^A-Za-z0-9_.-]/, "_")[0, 31]
273
+ else
274
+ # Level 3: No restrictions
275
+ name
276
+ end
277
+ end
278
+
279
+ # Write system area (first 16 sectors)
280
+ #
281
+ # @param io [IO] Output IO
282
+ def write_system_area(io)
283
+ # System area is reserved, write zeros
284
+ io.write("\x00" * (Iso::SECTOR_SIZE * Iso::SYSTEM_AREA_SECTORS))
285
+ end
286
+
287
+ # Write volume descriptors
288
+ #
289
+ # @param io [IO] Output IO
290
+ # @param builder [VolumeBuilder] Volume builder
291
+ # @param dir_structure [Hash] Directory structure
292
+ def write_volume_descriptors(io, builder, dir_structure)
293
+ # Fixed layout: 16 PVD, 17 terminator, 18 path table (L),
294
+ # 19 path table (BE), directory data from sector 22.
295
+ root = dir_structure[:root].merge(
296
+ total_sectors: dir_structure[:total_sectors],
297
+ path_table_size: dir_structure[:path_table_size],
298
+ path_table_location: 18,
299
+ path_table_location_be: 19,
300
+ )
301
+
302
+ # Write primary volume descriptor
303
+ pvd = builder.build_primary(root)
304
+ io.write(pvd)
305
+
306
+ # Write Joliet supplementary descriptor if enabled
307
+ if @joliet
308
+ svd = builder.build_joliet(root)
309
+ io.write(svd)
310
+ end
311
+
312
+ # Write terminator
313
+ terminator = build_terminator
314
+ io.write(terminator)
315
+ end
316
+
317
+ # Build volume descriptor set terminator
318
+ #
319
+ # @return [String] Terminator sector (2048 bytes)
320
+ def build_terminator
321
+ sector = +""
322
+ sector << [Iso::VD_TERMINATOR].pack("C") # Type
323
+ sector << VolumeDescriptor::ISO_IDENTIFIER # "CD001"
324
+ sector << [1].pack("C") # Version
325
+ sector << ("\x00" * (Iso::SECTOR_SIZE - 7))
326
+ sector
327
+ end
328
+
329
+ # Write path tables
330
+ #
331
+ # @param io [IO] Output IO
332
+ # @param dir_structure [Hash] Directory structure
333
+ def write_path_tables(io, dir_structure)
334
+ # Path tables provide quick directory lookup
335
+ # For simplicity, we'll write minimal path tables
336
+
337
+ # Little-endian path table
338
+ path_table = build_path_table(dir_structure[:directories])
339
+ io.write(path_table)
340
+
341
+ # Pad to sector boundary
342
+ padding = Iso::SECTOR_SIZE - (path_table.bytesize % Iso::SECTOR_SIZE)
343
+ io.write("\x00" * padding) if padding < Iso::SECTOR_SIZE
344
+
345
+ # Big-endian path table (required by spec)
346
+ path_table_be = build_path_table(dir_structure[:directories],
347
+ big_endian: true)
348
+ io.write(path_table_be)
349
+
350
+ # Pad to sector boundary
351
+ padding = Iso::SECTOR_SIZE - (path_table_be.bytesize % Iso::SECTOR_SIZE)
352
+ io.write("\x00" * padding) if padding < Iso::SECTOR_SIZE
353
+ end
354
+
355
+ # Build path table
356
+ #
357
+ # @param directories [Array<Hash>] Directory list
358
+ # @param big_endian [Boolean] Use big-endian format
359
+ # @return [String] Path table data
360
+ def build_path_table(directories, big_endian: false)
361
+ table = +""
362
+
363
+ directories.each_with_index do |dir, _idx|
364
+ name = dir[:name]
365
+ parent = dir[:parent_idx] || 1
366
+
367
+ # Name length
368
+ table << [name.bytesize].pack("C")
369
+
370
+ # Extended attribute record length
371
+ table << [0].pack("C")
372
+
373
+ # Location of extent
374
+ pack_format = big_endian ? "N" : "V"
375
+ table << [dir[:location]].pack(pack_format)
376
+
377
+ # Parent directory number (1-based)
378
+ pack_format = big_endian ? "n" : "v"
379
+ table << [parent + 1].pack(pack_format)
380
+
381
+ # Directory name
382
+ table << name
383
+
384
+ # Pad to even length
385
+ table << "\x00" if name.bytesize.odd?
386
+ end
387
+
388
+ table
389
+ end
390
+
391
+ # Write directory records
392
+ #
393
+ # @param io [IO] Output IO
394
+ # @param dir_structure [Hash] Directory structure
395
+ def write_directories(io, dir_structure)
396
+ dir_structure[:directories].each do |dir_info|
397
+ write_directory_record(io, dir_info)
398
+ end
399
+ end
400
+
401
+ # Write single directory record
402
+ #
403
+ # @param io [IO] Output IO
404
+ # @param dir_info [Hash] Directory information
405
+ def write_directory_record(io, dir_info)
406
+ # Seek to directory location
407
+ io.seek(dir_info[:location] * Iso::SECTOR_SIZE)
408
+
409
+ # Write directory entries
410
+ dir_data = build_directory_data(dir_info)
411
+ io.write(dir_data)
412
+
413
+ # Pad to sector boundary
414
+ padding = Iso::SECTOR_SIZE - (dir_data.bytesize % Iso::SECTOR_SIZE)
415
+ io.write("\x00" * padding) if padding < Iso::SECTOR_SIZE
416
+ end
417
+
418
+ # Build directory data with all entries
419
+ #
420
+ # @param dir_info [Hash] Directory information
421
+ # @return [String] Directory record data
422
+ def build_directory_data(dir_info)
423
+ data = +""
424
+
425
+ # Add "." entry (current directory)
426
+ data << build_directory_entry("\x00", dir_info, is_self: true)
427
+
428
+ # Add ".." entry (parent directory)
429
+ parent = dir_info[:parent] || dir_info
430
+ data << build_directory_entry("\x01", parent, is_self: false)
431
+
432
+ # Add child entries
433
+ dir_info[:children].each do |child|
434
+ name = child[:name]
435
+ data << build_directory_entry(name, child, is_self: false)
436
+ end
437
+
438
+ data
439
+ end
440
+
441
+ # Build single directory entry
442
+ #
443
+ # @param name [String] Entry name
444
+ # @param entry_info [Hash] Entry information
445
+ # @param is_self [Boolean] Is this the "." entry
446
+ # @return [String] Directory entry record
447
+ def build_directory_entry(name, entry_info, is_self:)
448
+ record = +""
449
+
450
+ # Extended attribute length (0)
451
+ ext_attr_len = 0
452
+
453
+ # Calculate record length
454
+ name_len = name.bytesize
455
+ padding = name_len.even? ? 1 : 0
456
+ record_len = 33 + name_len + padding
457
+
458
+ # Byte 0: Length of directory record
459
+ record << [record_len].pack("C")
460
+
461
+ # Byte 1: Extended attribute record length
462
+ record << [ext_attr_len].pack("C")
463
+
464
+ # Bytes 2-9: Location of extent (both-endian)
465
+ location = entry_info[:location] || 0
466
+ record << [location].pack("V") # Little-endian
467
+ record << [location].pack("N") # Big-endian
468
+
469
+ # Bytes 10-17: Data length (both-endian)
470
+ data_length = entry_info[:size] || 0
471
+ record << [data_length].pack("V")
472
+ record << [data_length].pack("N")
473
+
474
+ # Bytes 18-24: Recording date and time
475
+ record << encode_record_datetime(entry_info[:mtime] || Time.now)
476
+
477
+ # Byte 25: File flags
478
+ flags = 0
479
+ flags |= Iso::FLAG_DIRECTORY if entry_info[:directory]
480
+ record << [flags].pack("C")
481
+
482
+ # Byte 26: File unit size (0 for non-interleaved)
483
+ record << [0].pack("C")
484
+
485
+ # Byte 27: Interleave gap size
486
+ record << [0].pack("C")
487
+
488
+ # Bytes 28-31: Volume sequence number (both-endian)
489
+ record << [1].pack("v")
490
+ record << [1].pack("n")
491
+
492
+ # Byte 32: Length of file identifier
493
+ record << [name_len].pack("C")
494
+
495
+ # Bytes 33+: File identifier
496
+ record << name
497
+
498
+ # Padding byte if name length is even
499
+ record << "\x00" if name_len.even?
500
+
501
+ record
502
+ end
503
+
504
+ # Encode recording date/time (7-byte format)
505
+ #
506
+ # @param time [Time] Time to encode
507
+ # @return [String] 7-byte encoded time
508
+ def encode_record_datetime(time)
509
+ [
510
+ time.year - 1900, # Years since 1900
511
+ time.month, # Month (1-12)
512
+ time.day, # Day (1-31)
513
+ time.hour, # Hour (0-23)
514
+ time.min, # Minute (0-59)
515
+ time.sec, # Second (0-59)
516
+ 0, # GMT offset (0 = GMT)
517
+ ].pack("C7")
518
+ end
519
+
520
+ # Write file data
521
+ #
522
+ # @param io [IO] Output IO
523
+ def write_file_data(io)
524
+ @files.each do |file_info|
525
+ # Seek to file location
526
+ io.seek(file_info[:location] * Iso::SECTOR_SIZE)
527
+
528
+ # Write file data
529
+ File.open(file_info[:source], "rb") do |src|
530
+ while (data = src.read(Iso::SECTOR_SIZE))
531
+ # Pad to sector boundary
532
+ if data.bytesize < Iso::SECTOR_SIZE
533
+ data += "\x00" * (Iso::SECTOR_SIZE - data.bytesize)
534
+ end
535
+ io.write(data)
536
+ end
537
+ end
538
+ end
539
+ end
540
+ end
541
+ end
542
+ end
543
+ end