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,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ # Byte-level codec backend resolution — THE tier switch
5
+ # (TODO.ref-parity/62). Both paths share the algorithm classes'
6
+ # IO plumbing; only the byte core swaps.
7
+ #
8
+ # Policy:
9
+ # OMNIZIP_BACKEND=ruby force pure Ruby everywhere
10
+ # OMNIZIP_BACKEND=rust require the Rust library (raises when absent)
11
+ # OMNIZIP_BACKEND=auto (default) Rust for directions marked
12
+ # safe, Ruby otherwise, whenever the
13
+ # cdylib is loadable
14
+ #
15
+ # Safety marks (owner guidance 2026-09-19: some Ruby cores are
16
+ # LESS accurate than the Rust ports — be careful which tier is
17
+ # trusted for what):
18
+ # - decompress -> :rust by default. Decode is output-invariant
19
+ # AND the Rust decoders carry fixes the Ruby cores lack;
20
+ # disagreements are treated as Ruby-side accuracy findings
21
+ # (see the cross-tier differential spec), not coin flips.
22
+ # - compress -> :ruby by default. Byte-stability for content
23
+ # addressing (DropId dedup assumes identical frames); the
24
+ # Rust encoders produce DIFFERENT valid streams (probed:
25
+ # bzip2 L6, Ruby 906 B vs Rust 874 B). OMNIZIP_BACKEND=rust
26
+ # opts into Rust encode where correctness-of-ratio is wanted
27
+ # over frame stability.
28
+ module Backends
29
+ # Codecs whose Rust encoder is BYTE-IDENTICAL to the pure-Ruby
30
+ # 2026-09-20 policy flip (owner directive): RUST IS THE AUTHORITY
31
+ # — its encoders/decoders are the ports validated against the
32
+ # reference C/C++ implementations (bzip2, xz/liblzma, zstd,
33
+ # libdeflate), and they are determinism-contracted (same input +
34
+ # level => same bytes on every machine). :auto therefore routes
35
+ # BOTH directions through Rust whenever the cdylib loads; encode
36
+ # falls back to the Ruby core on any Rust error, so :auto is
37
+ # never worse than pure Ruby. The pure-Ruby cores remain the
38
+ # portable fallback and the OMNIZIP_BACKEND=ruby escape hatch.
39
+ RUST_AUTHORITATIVE = true
40
+
41
+ # usize::MAX — the FFI's "caller does not know the plaintext
42
+ # size" sentinel (streaming decode contract).
43
+ UNKNOWN_LENGTH = 0xFFFF_FFFF_FFFF_FFFF
44
+
45
+ class << self
46
+ def for(codec, _direction)
47
+ mode = ENV.fetch("OMNIZIP_BACKEND", "auto")
48
+
49
+ return backend_rust if mode == "rust"
50
+ return backend_ruby if mode == "ruby"
51
+
52
+ return backend_ruby unless Implementations::Rust::Library.available?
53
+ return backend_ruby unless Implementations::Rust::Library.supports?(codec)
54
+
55
+ backend_rust
56
+ end
57
+
58
+ # Compress through the tier-selected backend. The block is
59
+ # the pure-Ruby core — evaluated ONLY on the Ruby path, so
60
+ # the accelerated path never pays for it. A Rust encode error
61
+ # falls back to the Ruby core (auto is never worse than pure
62
+ # Ruby); only the forced `rust` mode propagates.
63
+ def compress(codec, data, level, &ruby_core)
64
+ backend = Backends.for(codec, :encode)
65
+ return yield if backend == RubyBackend
66
+
67
+ begin
68
+ backend.compress(codec, data, level)
69
+ rescue Implementations::Rust::Error => e
70
+ raise if ENV.fetch("OMNIZIP_BACKEND", "auto") == "rust"
71
+
72
+ warn "omnizip: rust #{codec} encode failed (#{e.message}); using ruby" if ENV["OMNIZIP_BACKEND_DEBUG"]
73
+ yield
74
+ end
75
+ end
76
+
77
+ # Decompress through the tier-selected backend (output-
78
+ # invariant: :auto prefers Rust whenever loadable). A Rust
79
+ # failure falls back to the Ruby core — the Ruby readers are
80
+ # the tolerant superset (legacy container variants, malformed
81
+ # inputs they historically accept), so :auto must never be
82
+ # WORSE than pure Ruby. Only the forced `rust` mode propagates.
83
+ def decompress(codec, data, expected_len, &ruby_core)
84
+ backend = Backends.for(codec, :decode)
85
+ return yield if backend == RubyBackend
86
+
87
+ begin
88
+ backend.decompress(codec, data, expected_len)
89
+ rescue Implementations::Rust::Error => e
90
+ raise if ENV.fetch("OMNIZIP_BACKEND", "auto") == "rust"
91
+
92
+ warn "omnizip: rust #{codec} decode failed (#{e.message}); using ruby" if ENV["OMNIZIP_BACKEND_DEBUG"]
93
+ yield
94
+ end
95
+ end
96
+
97
+ # Whole-archive tier helpers: nil means "Rust unavailable or
98
+ # entry not found — caller falls back to the Ruby reader".
99
+ def archive_entry_names(path)
100
+ Omnizip::Implementations::Rust::Archive.open(File.binread(path)) { |a| return a.entry_names }
101
+ rescue Omnizip::Implementations::Rust::Archive::LibraryMissing, Omnizip::Implementations::Rust::Error, StandardError
102
+ nil
103
+ end
104
+
105
+ # rubocop:disable-next Lint/ReturnInVoidContext
106
+ def archive_read_entry(path, entry_name)
107
+ Omnizip::Implementations::Rust::Archive.open(File.binread(path)) do |a|
108
+ idx = a.entry_names.index(entry_name)
109
+ return nil if idx.nil?
110
+
111
+ return a.read_entry(idx)
112
+ end
113
+ rescue Omnizip::Implementations::Rust::Archive::LibraryMissing, Omnizip::Implementations::Rust::Error, StandardError
114
+ nil
115
+ end
116
+
117
+ private
118
+
119
+ def backend_rust
120
+ RustBackend
121
+ end
122
+
123
+ def backend_ruby
124
+ RubyBackend
125
+ end
126
+ end
127
+
128
+ # The pure-Ruby path: a no-op backend — callers fall back to
129
+ # their own in-tree cores, which ARE the reference. Kept as an
130
+ # object for symmetry with the Rust side.
131
+ module RubyBackend
132
+ module_function
133
+
134
+ # :nocov:
135
+ def compress(codec, _data, _level)
136
+ raise Error, "#{codec}: ruby core not wired through Backends (call it directly)"
137
+ end
138
+
139
+ def decompress(codec, _data, _expected_len)
140
+ raise Error, "#{codec}: ruby core not wired through Backends (call it directly)"
141
+ end
142
+ # :nocov:
143
+ end
144
+
145
+ # The Rust-accelerated path over the Fiddle handle.
146
+ module RustBackend
147
+ module_function
148
+
149
+ def compress(codec, data, level)
150
+ Implementations::Rust::Library.instance.compress(codec, data, level)
151
+ end
152
+
153
+ def decompress(codec, data, expected_len)
154
+ Implementations::Rust::Library.instance.decompress(codec, data, expected_len)
155
+ end
156
+ end
157
+
158
+ class Error < StandardError; end
159
+ end
160
+ end
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Buffer
5
+ # Wrapper for in-memory archive operations
6
+ #
7
+ # Provides unified interface for adding entries to and reading entries
8
+ # from archives stored in memory (StringIO). Works with both OutputStream
9
+ # (for creating) and InputStream (for reading).
10
+ #
11
+ # @example Creating an archive
12
+ # writer = Formats::Zip::Writer.new(nil)
13
+ # archive = MemoryArchive.new(writer, :zip)
14
+ # archive.add('file.txt', 'content')
15
+ # writer.write_to_io(buffer)
16
+ #
17
+ # @example Reading an archive
18
+ # archive = MemoryArchive.new(Formats::Zip::Reader.new(path), :zip)
19
+ # archive.each_entry do |entry|
20
+ # puts entry.name
21
+ # end
22
+ class MemoryArchive
23
+ attr_reader :format, :stream
24
+
25
+ # Initialize memory archive wrapper
26
+ #
27
+ # @param stream [Formats::Zip::Writer, Formats::Zip::Reader]
28
+ # Native writer (write mode) or reader (read mode)
29
+ # @param format [Symbol] Archive format (:zip)
30
+ def initialize(stream, format)
31
+ @stream = stream
32
+ @format = format
33
+ @entries_cache = nil
34
+ end
35
+
36
+ # Add file from memory (write mode only)
37
+ #
38
+ # @param name [String] Entry name (path within archive)
39
+ # @param data [String] Entry content
40
+ # @param options [Hash] Entry options
41
+ # @option options [Time] :time Modification time (default: now)
42
+ # @option options [String] :comment Entry comment
43
+ # @option options [Symbol] :compression Compression method
44
+ # (:store, :deflate)
45
+ # @option options [Integer] :level Compression level (1-9)
46
+ # @return [self] For method chaining
47
+ #
48
+ # @example Add multiple files
49
+ # archive.add('file1.txt', 'content1')
50
+ # .add('file2.txt', 'content2')
51
+ # .add('dir/', '') # Directory entry
52
+ #
53
+ # @raise [RuntimeError] If stream is not an OutputStream
54
+ def add(name, data, **options)
55
+ ensure_write_mode!
56
+
57
+ if name.end_with?("/") && data.to_s.empty?
58
+ stream.add_directory(name)
59
+ else
60
+ method = if options[:compression] == :store
61
+ Formats::Zip::Constants::COMPRESSION_STORE
62
+ end
63
+ stream.add_data(name, data, nil, compression_method: method)
64
+ end
65
+
66
+ self
67
+ end
68
+
69
+ # Add data with block (write mode only)
70
+ #
71
+ # @param name [String] Entry name
72
+ # @param options [Hash] Entry options
73
+ # @yield Block that returns content
74
+ # @yieldreturn [String] Entry content
75
+ # @return [self] For method chaining
76
+ #
77
+ # @example Add with block
78
+ # archive.add_data('file.txt') { File.read('source.txt') }
79
+ def add_data(name, **options)
80
+ ensure_write_mode!
81
+ data = yield
82
+ add(name, data, **options)
83
+ end
84
+
85
+ # Iterate entries (read mode only)
86
+ #
87
+ # @yield [entry] Block called for each entry
88
+ # @yieldparam entry [Entry] Archive entry
89
+ # @return [void]
90
+ #
91
+ # @example Process all entries
92
+ # archive.each_entry do |entry|
93
+ # puts "#{entry.name}: #{entry.size} bytes"
94
+ # content = entry.read unless entry.directory?
95
+ # end
96
+ #
97
+ # @raise [RuntimeError] If stream is not an InputStream
98
+ def each_entry
99
+ ensure_read_mode!
100
+
101
+ stream.entries.each do |zip_entry|
102
+ yield(Entry.new(zip_entry, stream))
103
+ end
104
+ end
105
+
106
+ # Extract all entries to memory (read mode only)
107
+ #
108
+ # @return [Hash<String, String>] Filename => content mapping
109
+ #
110
+ # @example Extract all
111
+ # files = archive.extract_all_to_memory
112
+ # files.each { |name, content| puts "#{name}: #{content.size}" }
113
+ def extract_all_to_memory
114
+ ensure_read_mode!
115
+
116
+ result = {}
117
+ each_entry do |entry|
118
+ result[entry.name] = entry.read unless entry.directory?
119
+ end
120
+ result
121
+ end
122
+
123
+ # Get underlying buffer as string (write mode only)
124
+ #
125
+ # @return [String] Complete archive as binary string
126
+ #
127
+ # @example Get archive data
128
+ # archive_data = archive.to_s
129
+ # File.binwrite('output.zip', archive_data)
130
+ #
131
+ # @raise [RuntimeError] If stream is not an OutputStream
132
+ def to_s
133
+ ensure_write_mode!
134
+
135
+ # The buffer is owned by Buffer.create; this method should be
136
+ # called on the StringIO it returns instead.
137
+ raise NotImplementedError,
138
+ "Use Buffer.create return value instead"
139
+ end
140
+
141
+ # Entry wrapper with read capability
142
+ #
143
+ # Wraps underlying ZIP entry to provide consistent interface
144
+ # for reading entry data from the stream.
145
+ class Entry
146
+ attr_reader :name, :size, :compressed_size, :time, :comment
147
+
148
+ # Initialize entry wrapper
149
+ #
150
+ # @param entry [Formats::Zip::CentralDirectoryHeader] entry
151
+ # @param reader [Formats::Zip::Reader] Native archive reader
152
+ def initialize(entry, reader)
153
+ @entry = entry
154
+ @reader = reader
155
+ @name = entry.filename
156
+ @size = entry.uncompressed_size
157
+ @compressed_size = entry.compressed_size
158
+ @time = entry.time
159
+ @comment = entry.comment.to_s
160
+ @directory = entry.directory?
161
+ @content = nil
162
+ @pos = 0
163
+ end
164
+
165
+ # Read entry content
166
+ #
167
+ # @param size [Integer, nil] Number of bytes to read (nil for all)
168
+ # @return [String, nil] Entry data or nil if EOF
169
+ #
170
+ # @example Read entire entry
171
+ # content = entry.read
172
+ #
173
+ # @example Read in chunks
174
+ # while (chunk = entry.read(8192))
175
+ # process_chunk(chunk)
176
+ # end
177
+ def read(size = nil)
178
+ # IO-like streaming semantics: successive reads return
179
+ # successive chunks, nil at end-of-content. Callers like
180
+ # Pipe::StreamDecompressor loop on this — a read that
181
+ # always returns data would loop forever.
182
+ @content ||= @reader.read_entry(@name)
183
+ return nil if @pos >= @content.bytesize
184
+
185
+ chunk = if size
186
+ @content.byteslice(@pos, size)
187
+ else
188
+ @content.byteslice(@pos, @content.bytesize - @pos)
189
+ end
190
+ @pos += chunk.bytesize
191
+ chunk
192
+ end
193
+
194
+ # Check if entry is a directory
195
+ #
196
+ # @return [Boolean] True if directory entry
197
+ def directory?
198
+ @directory
199
+ end
200
+
201
+ # Check if entry is a file
202
+ #
203
+ # @return [Boolean] True if file entry
204
+ def file?
205
+ !@directory
206
+ end
207
+
208
+ # Get compression method
209
+ #
210
+ # @return [Symbol] Compression method (:store, :deflate, etc.)
211
+ def compression_method
212
+ @entry.compression_method
213
+ end
214
+
215
+ # Get CRC32 checksum
216
+ #
217
+ # @return [Integer] CRC32 value
218
+ def crc32
219
+ @entry.crc32
220
+ end
221
+ end
222
+
223
+ private
224
+
225
+ # Ensure stream is in write mode (native Writer)
226
+ #
227
+ # @raise [Omnizip::IOError] If not in write mode
228
+ def ensure_write_mode!
229
+ return if stream.is_a?(Omnizip::Formats::Zip::Writer)
230
+
231
+ raise Omnizip::IOError,
232
+ "Operation requires write mode (Formats::Zip::Writer)"
233
+ end
234
+
235
+ # Ensure stream is in read mode (native Reader)
236
+ #
237
+ # @raise [Omnizip::IOError] If not in read mode
238
+ def ensure_read_mode!
239
+ return if stream.is_a?(Omnizip::Formats::Zip::Reader)
240
+
241
+ raise Omnizip::IOError,
242
+ "Operation requires read mode (Formats::Zip::Reader)"
243
+ end
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require "tmpdir"
5
+
6
+ module Omnizip
7
+ module Buffer
8
+ # Extract archive contents to memory
9
+ #
10
+ # Provides efficient extraction of archive entries to Hash without
11
+ # loading all files at once. Uses lazy evaluation where possible.
12
+ #
13
+ # @example Extract all files
14
+ # extractor = MemoryExtractor.new(zip_data)
15
+ # files = extractor.extract_all
16
+ # # => {"file1.txt" => "content1", "file2.txt" => "content2"}
17
+ #
18
+ # @example Extract single file
19
+ # extractor = MemoryExtractor.new(zip_data)
20
+ # content = extractor.extract_entry('file1.txt')
21
+ # # => "content1"
22
+ class MemoryExtractor
23
+ attr_reader :format
24
+
25
+ # Initialize extractor
26
+ #
27
+ # @param data [String, StringIO] Archive data
28
+ # @param format [Symbol, nil] Archive format (auto-detected if nil)
29
+ #
30
+ # @example Create extractor
31
+ # extractor = MemoryExtractor.new(zip_data)
32
+ # extractor = MemoryExtractor.new(zip_buffer, format: :zip)
33
+ def initialize(data, format: nil)
34
+ @buffer = data.is_a?(StringIO) ? data : StringIO.new(data.b)
35
+ @format = format || detect_format
36
+ @extracted_cache = {}
37
+ end
38
+
39
+ # Extract all entries to Hash
40
+ #
41
+ # @return [Hash<String, String>] Filename => content mapping
42
+ #
43
+ # @example Extract everything
44
+ # files = extractor.extract_all
45
+ # files.keys # => ["file1.txt", "file2.txt", "dir/file3.txt"]
46
+ def extract_all
47
+ result = {}
48
+
49
+ case @format
50
+ when :zip
51
+ extract_all_zip(result)
52
+ when :seven_zip, :"7z"
53
+ extract_all_seven_zip(result)
54
+ else
55
+ raise ArgumentError, "Unsupported format: #{@format}"
56
+ end
57
+
58
+ result
59
+ end
60
+
61
+ # Extract single entry by name
62
+ #
63
+ # @param name [String] Entry name to extract
64
+ # @return [String, nil] Entry content or nil if not found
65
+ #
66
+ # @example Extract specific file
67
+ # content = extractor.extract_entry('readme.txt')
68
+ # # => "Hello World"
69
+ def extract_entry(name)
70
+ # Check cache first
71
+ return @extracted_cache[name] if @extracted_cache.key?(name)
72
+
73
+ # Extract from archive
74
+ content = nil
75
+
76
+ case @format
77
+ when :zip
78
+ content = extract_entry_zip(name)
79
+ when :seven_zip, :"7z"
80
+ content = extract_entry_seven_zip(name)
81
+ else
82
+ raise ArgumentError, "Unsupported format: #{@format}"
83
+ end
84
+
85
+ # Cache the result
86
+ @extracted_cache[name] = content if content
87
+ content
88
+ end
89
+
90
+ # List all entry names without extracting
91
+ #
92
+ # @return [Array<String>] Entry names
93
+ #
94
+ # @example List files
95
+ # extractor.list_entries
96
+ # # => ["file1.txt", "dir/", "dir/file2.txt"]
97
+ def list_entries
98
+ names = []
99
+
100
+ case @format
101
+ when :zip
102
+ list_entries_zip(names)
103
+ when :seven_zip, :"7z"
104
+ SevenZipBridge.open(@buffer) { |archive| names.concat(archive.entry_names) }
105
+ else
106
+ raise ArgumentError, "Unsupported format: #{@format}"
107
+ end
108
+
109
+ names
110
+ end
111
+
112
+ # Check if entry exists in archive
113
+ #
114
+ # @param name [String] Entry name
115
+ # @return [Boolean] True if entry exists
116
+ #
117
+ # @example Check existence
118
+ # extractor.entry_exists?('file.txt') # => true
119
+ def entry_exists?(name)
120
+ list_entries.include?(name)
121
+ end
122
+
123
+ # Get total number of entries
124
+ #
125
+ # @return [Integer] Number of entries
126
+ def entry_count
127
+ list_entries.size
128
+ end
129
+
130
+ # Extract entries matching pattern
131
+ #
132
+ # @param pattern [Regexp, String] Pattern to match
133
+ # @return [Hash<String, String>] Matching entries
134
+ #
135
+ # @example Extract by pattern
136
+ # extractor.extract_matching(/\.txt$/)
137
+ # # => {"file1.txt" => "content1", "file2.txt" => "content2"}
138
+ def extract_matching(pattern)
139
+ pattern = Regexp.new(pattern) if pattern.is_a?(String)
140
+ result = {}
141
+
142
+ list_entries.each do |name|
143
+ next unless name&.match?(pattern)
144
+ next if name.end_with?("/") # Skip directories
145
+
146
+ content = extract_entry(name)
147
+ result[name] = content if content
148
+ end
149
+
150
+ result
151
+ end
152
+
153
+ private
154
+
155
+ # Delegate to the shared buffer-side sniffer
156
+ #
157
+ # @return [Symbol] Detected format
158
+ # @raise [Omnizip::FormatError] If format cannot be detected
159
+ def detect_format
160
+ Omnizip::Buffer.detect_format(@buffer)
161
+ end
162
+
163
+ # The native ZIP reader parses from a path; spill the buffer to
164
+ # a temporary file and yield a reader over it.
165
+ def with_zip_reader
166
+ @buffer.rewind
167
+ Dir.mktmpdir("omnizip_extractor_zip") do |tmp|
168
+ path = File.join(tmp, "buffer.zip")
169
+ File.binwrite(path, @buffer.read)
170
+ yield Omnizip::Formats::Zip::Reader.new(path)
171
+ end
172
+ end
173
+
174
+ # Extract all entries from ZIP through the native reader
175
+ #
176
+ # @param result [Hash] Hash to populate with entries
177
+ def extract_all_zip(result)
178
+ with_zip_reader do |reader|
179
+ reader.entries.each do |entry|
180
+ next if entry.directory?
181
+
182
+ content = reader.read_entry(entry.filename)
183
+ result[entry.filename] = content
184
+ @extracted_cache[entry.filename] = content
185
+ end
186
+ end
187
+ end
188
+
189
+ # Extract every file entry from 7z
190
+ #
191
+ # @param result [Hash] Hash to populate with entries
192
+ def extract_all_seven_zip(result)
193
+ @buffer.rewind
194
+ SevenZipBridge.open(@buffer) do |archive|
195
+ archive.extract_all_to_memory.each do |name, content|
196
+ result[name] = content
197
+ @extracted_cache[name] = content
198
+ end
199
+ end
200
+ end
201
+
202
+ # Extract single entry from 7z
203
+ #
204
+ # @param name [String] Entry name
205
+ # @return [String, nil] Entry content or nil if not found
206
+ def extract_entry_seven_zip(name)
207
+ @buffer.rewind
208
+ SevenZipBridge.open(@buffer) do |archive|
209
+ archive.read_entry(name)
210
+ end
211
+ end
212
+
213
+ # Extract single entry from ZIP through the native reader
214
+ #
215
+ # @param name [String] Entry name
216
+ # @return [String, nil] Entry content or nil if not found
217
+ def extract_entry_zip(name)
218
+ with_zip_reader do |reader|
219
+ entry = reader.entries.find { |e| e.filename == name }
220
+ reader.read_entry(name) if entry && !entry.directory?
221
+ end
222
+ end
223
+
224
+ # List all entry names from ZIP through the native reader
225
+ #
226
+ # @param names [Array] Array to populate with names
227
+ def list_entries_zip(names)
228
+ with_zip_reader do |reader|
229
+ reader.entries.each { |entry| names << entry.filename }
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end