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,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Omnizip
6
+ module Parallel
7
+ # Parallel extraction coordinator using Fractor
8
+ #
9
+ # Manages parallel extraction of files from an archive.
10
+ # Distributes extraction work across multiple workers and
11
+ # writes files to disk in a thread-safe manner.
12
+ #
13
+ # @example Extract archive in parallel
14
+ # extractor = Omnizip::Parallel::ParallelExtractor.new(threads: 4)
15
+ # extractor.extract('backup.zip', 'output/')
16
+ #
17
+ # @example With options
18
+ # options = Omnizip::Models::ParallelOptions.new
19
+ # options.threads = 8
20
+ # extractor = Omnizip::Parallel::ParallelExtractor.new(options)
21
+ # extractor.extract('backup.zip', 'output/')
22
+ class ParallelExtractor
23
+ # @return [Omnizip::Models::ParallelOptions] parallel options
24
+ attr_reader :options
25
+
26
+ # @return [Hash] extraction statistics
27
+ attr_reader :stats
28
+
29
+ # Initialize parallel extractor
30
+ #
31
+ # @param options [Omnizip::Models::ParallelOptions, Hash] parallel options
32
+ # @param threads [Integer] number of threads (overrides options)
33
+ def initialize(options = nil, threads: nil)
34
+ @options = case options
35
+ when Omnizip::Models::ParallelOptions
36
+ options.dup
37
+ when Hash
38
+ Omnizip::Models::ParallelOptions.new.apply(options)
39
+ else
40
+ Omnizip::Models::ParallelOptions.new
41
+ end
42
+
43
+ @options.threads = threads if threads
44
+ @options.validate_options!
45
+
46
+ @stats = {
47
+ files_extracted: 0,
48
+ bytes_extracted: 0,
49
+ start_time: nil,
50
+ end_time: nil,
51
+ }
52
+
53
+ @write_mutex = Mutex.new
54
+ end
55
+
56
+ # Extract archive to directory in parallel
57
+ #
58
+ # @param archive [String] archive path
59
+ # @param dest [String] destination directory
60
+ # @param options [Hash] extraction options
61
+ # @option options [Boolean] :overwrite overwrite existing files
62
+ # @option options [Proc] :progress progress callback
63
+ # @return [Array<String>] extracted file paths
64
+ def extract(archive, dest, **options)
65
+ unless ::File.exist?(archive)
66
+ raise Errno::ENOENT,
67
+ "Archive not found: #{archive}"
68
+ end
69
+
70
+ overwrite = options.fetch(:overwrite, false)
71
+ options[:progress]
72
+
73
+ @stats[:start_time] = Time.now
74
+
75
+ # Read archive to get entries
76
+ entries = read_archive_entries(archive)
77
+
78
+ # Create destination directory
79
+ FileUtils.mkdir_p(dest)
80
+
81
+ # Create job queue
82
+ job_queue = JobQueue.new(max_size: @options.queue_size)
83
+
84
+ # Schedule jobs
85
+ entries.each do |entry|
86
+ job_queue.push_with_size(
87
+ file: entry.filename,
88
+ size: safe_entry_size(entry),
89
+ data: { entry_name: entry.filename },
90
+ )
91
+ end
92
+
93
+ # Create work items from jobs, largest first
94
+ work_items = []
95
+ until job_queue.empty?
96
+ job = job_queue.pop(timeout: 0.1)
97
+ break unless job
98
+
99
+ work_items << job.data[:entry_name]
100
+ end
101
+
102
+ # Threads, not Ractors: Omnizip's autoloads and Proc-holding
103
+ # codec constants cannot cross Ractor boundaries on Ruby <= 3.3
104
+ pool = ThreadPool.new(size: @options.threads)
105
+ raw_results, raw_errors = pool.map(work_items) do |entry_name|
106
+ process_entry(archive, dest, entry_name)
107
+ end
108
+
109
+ # Handle errors (raw_errors holds nil for every item that
110
+ # succeeded — zip+compact would keep those pairs)
111
+ failure_pairs = raw_errors.each_with_index.filter_map do |error, index|
112
+ [work_items[index], error] if error
113
+ end
114
+ unless failure_pairs.empty?
115
+ error_msgs = failure_pairs.map { |name, e| "#{name}: #{e.message}" }
116
+ .join("\n")
117
+ raise Omnizip::DecompressionError, "Extraction errors:\n#{error_msgs}"
118
+ end
119
+
120
+ results = raw_results
121
+
122
+ # Write files to disk (thread-safe)
123
+ extracted_paths = write_extracted_files(results, overwrite: overwrite)
124
+
125
+ @stats[:end_time] = Time.now
126
+ @stats[:files_extracted] = results.size
127
+
128
+ extracted_paths
129
+ end
130
+
131
+ # Get extraction statistics
132
+ #
133
+ # @return [Hash] statistics
134
+ def statistics
135
+ duration = if @stats[:start_time] && @stats[:end_time]
136
+ @stats[:end_time] - @stats[:start_time]
137
+ else
138
+ 0
139
+ end
140
+
141
+ @stats.merge(
142
+ duration: duration,
143
+ throughput_mbps: calculate_throughput(duration),
144
+ )
145
+ end
146
+
147
+ private
148
+
149
+ # Decompress one entry in a worker thread. Each worker opens
150
+ # the archive independently — its own file handle per thread.
151
+ def process_entry(archive_path, dest_dir, entry_name)
152
+ entry = Omnizip::Formats::Zip::Reader.new(archive_path)
153
+ .entries.find { |e| e.filename == entry_name }
154
+ raise Errno::ENOENT, "Entry not found: #{entry_name}" unless entry
155
+
156
+ {
157
+ entry_name: entry_name,
158
+ dest_path: ::File.join(dest_dir, entry_name),
159
+ data: entry.directory? ? "" : read_entry_data(archive_path, entry_name),
160
+ directory: entry.directory?,
161
+ unix_perms: entry.unix_permissions.to_i,
162
+ }
163
+ end
164
+
165
+ def read_entry_data(archive_path, entry_name)
166
+ Omnizip::Formats::Zip::Reader.new(archive_path)
167
+ .read_entry(entry_name)
168
+ end
169
+
170
+ def safe_entry_size(entry)
171
+ entry.uncompressed_size.to_i
172
+ end
173
+
174
+ # Read archive entries through the native reader
175
+ #
176
+ # @param archive_path [String] archive path
177
+ # @return [Array<CentralDirectoryHeader>] array of entries
178
+ def read_archive_entries(archive_path)
179
+ Omnizip::Formats::Zip::Reader.new(archive_path).entries
180
+ end
181
+
182
+ # Write extracted files to disk
183
+ #
184
+ # @param results [Array] extraction results
185
+ # @param overwrite [Boolean] overwrite existing files
186
+ # @return [Array<String>] extracted file paths
187
+ def write_extracted_files(results, overwrite: false)
188
+ extracted_paths = []
189
+
190
+ results.each do |result|
191
+ next unless result
192
+
193
+ dest_path = result[:dest_path]
194
+
195
+ # Thread-safe file writing
196
+ @write_mutex.synchronize do
197
+ if result[:directory]
198
+ # mkdir_p is idempotent — a file entry may already have
199
+ # created this directory as its parent
200
+ FileUtils.mkdir_p(dest_path)
201
+ extracted_paths << dest_path
202
+ next
203
+ end
204
+
205
+ # Check if file exists
206
+ if ::File.exist?(dest_path) && !overwrite
207
+ raise Errno::EEXIST, "File exists: #{dest_path}"
208
+ end
209
+
210
+ FileUtils.mkdir_p(::File.dirname(dest_path))
211
+ ::File.binwrite(dest_path, result[:data])
212
+
213
+ # Set permissions if Unix
214
+ if result[:unix_perms].positive?
215
+ ::File.chmod(result[:unix_perms] & 0o777, dest_path)
216
+ end
217
+
218
+ @stats[:bytes_extracted] += result[:data].bytesize
219
+
220
+ extracted_paths << dest_path
221
+ end
222
+ end
223
+
224
+ extracted_paths
225
+ end
226
+
227
+ # Calculate throughput in MB/s
228
+ #
229
+ # @param duration [Float] duration in seconds
230
+ # @return [Float] throughput in MB/s
231
+ def calculate_throughput(duration)
232
+ return 0.0 if duration.zero?
233
+
234
+ (@stats[:bytes_extracted].to_f / (1024 * 1024)) / duration
235
+ end
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string: true
2
+
3
+ module Omnizip
4
+ module Parallel
5
+ # Bounded thread pool for library work.
6
+ #
7
+ # Unlike the Fractor pool, threads share the VM state — Ractor
8
+ # workers cannot trigger Omnizip's autoloads or touch Proc-holding
9
+ # codec constants on Ruby <= 3.3 ("require by autoload on
10
+ # non-main Ractor is not supported"). Decompression itself still
11
+ # parallelizes: the zlib/bzip2 C extensions release the GVL.
12
+ class ThreadPool
13
+ # @return [Integer] number of worker threads
14
+ attr_reader :size
15
+
16
+ # Initialize the pool
17
+ #
18
+ # @param size [Integer] worker thread count (at least 1)
19
+ def initialize(size:)
20
+ @size = [size.to_i, 1].max
21
+ end
22
+
23
+ # Run +block+ for every item, at most +size+ at a time, and
24
+ # return a pair of parallel arrays: results (nil where an item
25
+ # raised) and errors (nil where it succeeded). Item order is
26
+ # preserved in both arrays.
27
+ #
28
+ # @param items [Array] work items
29
+ # @yieldparam item [Object] one work item
30
+ # @return [Array<Array, Array>]
31
+ def map(items)
32
+ results = Array.new(items.size)
33
+ errors = Array.new(items.size)
34
+ queue = Queue.new
35
+ items.each_with_index { |item, index| queue << [item, index] }
36
+
37
+ threads = Array.new(@size) do
38
+ Thread.new do
39
+ loop do
40
+ begin
41
+ item, index = queue.pop(true)
42
+ rescue ThreadError
43
+ break
44
+ end
45
+
46
+ begin
47
+ results[index] = yield(item)
48
+ rescue StandardError => e
49
+ errors[index] = e
50
+ end
51
+ end
52
+ end
53
+ end
54
+ threads.each(&:join)
55
+
56
+ [results, errors]
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fractor"
4
+
5
+ module Omnizip
6
+ module Parallel
7
+ # Worker pool wrapper for Fractor-based parallel processing
8
+ #
9
+ # Manages a pool of Fractor workers for parallel compression/extraction.
10
+ # Handles job distribution, result collection, and graceful shutdown.
11
+ #
12
+ # @example Create and use worker pool
13
+ # pool = Omnizip::Parallel::WorkerPool.new(
14
+ # worker_class: CompressionWorker,
15
+ # num_workers: 4
16
+ # )
17
+ # pool.start
18
+ # pool.submit(work_item)
19
+ # results = pool.results
20
+ # pool.shutdown
21
+ class WorkerPool
22
+ # @return [Fractor::Supervisor] underlying Fractor supervisor
23
+ attr_reader :supervisor
24
+
25
+ # @return [Array] collected results
26
+ attr_reader :results
27
+
28
+ # @return [Array] collected errors
29
+ attr_reader :errors
30
+
31
+ # @return [Boolean] whether pool is running
32
+ attr_reader :running
33
+
34
+ # Initialize worker pool
35
+ #
36
+ # @param worker_class [Class] Fractor::Worker subclass
37
+ # @param num_workers [Integer] number of worker threads
38
+ # @param continuous [Boolean] continuous mode for long-running tasks
39
+ def initialize(worker_class:, num_workers: nil, continuous: false)
40
+ @worker_class = worker_class
41
+ @num_workers = num_workers || detect_cpu_count
42
+ @continuous = continuous
43
+ @supervisor = nil
44
+ @results = []
45
+ @errors = []
46
+ @running = false
47
+ @result_mutex = Mutex.new
48
+ @work_queue = nil
49
+ end
50
+
51
+ # Start the worker pool
52
+ #
53
+ # @return [void]
54
+ def start
55
+ return if @running
56
+
57
+ # Create Fractor supervisor with worker pool configuration
58
+ @supervisor = Fractor::Supervisor.new(
59
+ worker_pools: [
60
+ {
61
+ worker_class: @worker_class,
62
+ num_workers: @num_workers,
63
+ },
64
+ ],
65
+ continuous_mode: @continuous,
66
+ )
67
+
68
+ # For continuous mode, set up work queue
69
+ if @continuous
70
+ @work_queue = Fractor::WorkQueue.new
71
+ @work_queue.register_with_supervisor(@supervisor)
72
+ end
73
+
74
+ @running = true
75
+
76
+ # Start supervisor in background thread for continuous mode
77
+ if @continuous
78
+ @supervisor_thread = Thread.new do
79
+ @supervisor.run
80
+ rescue StandardError => e
81
+ @result_mutex.synchronize do
82
+ @errors << { error: e, message: "Supervisor error: #{e.message}" }
83
+ end
84
+ end
85
+ else
86
+ # For batch mode, don't start yet - wait for work items
87
+ @supervisor.start_workers
88
+ end
89
+ end
90
+
91
+ # Submit work item to the pool
92
+ #
93
+ # @param work [Fractor::Work] work item to process
94
+ # @return [void]
95
+ def submit(work)
96
+ raise Omnizip::IOError, "Worker pool not started" unless @running
97
+
98
+ if @continuous
99
+ # In continuous mode, add to work queue
100
+ @work_queue << work
101
+ else
102
+ # In batch mode, add to supervisor
103
+ @supervisor.add_work_item(work)
104
+ end
105
+ end
106
+
107
+ # Submit multiple work items
108
+ #
109
+ # @param works [Array<Fractor::Work>] array of work items
110
+ # @return [void]
111
+ def submit_batch(works)
112
+ works.each { |work| submit(work) }
113
+ end
114
+
115
+ # Run the pool in batch mode and wait for completion
116
+ #
117
+ # @return [void]
118
+ def run
119
+ raise Omnizip::IOError, "Can only run in batch mode" if @continuous
120
+ raise Omnizip::IOError, "Worker pool not started" unless @running
121
+
122
+ @supervisor.run
123
+
124
+ # Collect results
125
+ collect_results
126
+ end
127
+
128
+ # Shutdown the worker pool
129
+ #
130
+ # @param timeout [Numeric] timeout in seconds
131
+ # @return [void]
132
+ def shutdown(timeout: 30)
133
+ return unless @running
134
+
135
+ # Stop in BOTH modes: batch worker Ractors otherwise linger
136
+ # in Ractor.receive for the life of the process, burning CPU
137
+ # after the batch completes
138
+ @supervisor&.stop
139
+
140
+ if @continuous
141
+ @supervisor_thread&.join(timeout)
142
+ end
143
+
144
+ # Collect final results
145
+ collect_results
146
+
147
+ @running = false
148
+ end
149
+
150
+ # Get successful results
151
+ #
152
+ # @return [Array] array of successful results
153
+ def successful_results
154
+ @result_mutex.synchronize { @results.dup }
155
+ end
156
+
157
+ # Get failed results
158
+ #
159
+ # @return [Array] array of errors
160
+ def failed_results
161
+ @result_mutex.synchronize { @errors.dup }
162
+ end
163
+
164
+ # Get pool statistics
165
+ #
166
+ # @return [Hash] statistics hash
167
+ def stats
168
+ return {} unless @supervisor
169
+
170
+ {
171
+ workers: @num_workers,
172
+ running: @running,
173
+ continuous: @continuous,
174
+ results: @results.size,
175
+ errors: @errors.size,
176
+ total_processed: @results.size + @errors.size,
177
+ }
178
+ end
179
+
180
+ # Check if pool has completed all work
181
+ #
182
+ # @return [Boolean] true if complete
183
+ def complete?
184
+ return false if @continuous
185
+ return false unless @supervisor
186
+
187
+ # In batch mode, check if all work is processed
188
+ result_aggregator = @supervisor.results
189
+ result_aggregator && !@supervisor.work_queue.empty?
190
+ end
191
+
192
+ private
193
+
194
+ # Collect results from supervisor
195
+ #
196
+ # @return [void]
197
+ def collect_results
198
+ return unless @supervisor
199
+
200
+ result_aggregator = @supervisor.results
201
+ return unless result_aggregator
202
+
203
+ @result_mutex.synchronize do
204
+ # Collect successful results
205
+ result_aggregator.results.each do |work_result|
206
+ @results << work_result
207
+ end
208
+
209
+ # Collect errors
210
+ result_aggregator.errors.each do |error_result|
211
+ @errors << error_result
212
+ end
213
+ end
214
+ end
215
+
216
+ # Detect number of available CPU cores
217
+ #
218
+ # @return [Integer] number of CPUs
219
+ def detect_cpu_count
220
+ require "etc"
221
+ Etc.nprocessors
222
+ rescue StandardError
223
+ 4 # fallback
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ # Parallel processing module for multi-threaded compression/extraction
5
+ #
6
+ # Leverages Fractor for parallel processing to utilize multi-core CPUs.
7
+ # Provides high-level APIs for parallel compression and extraction operations.
8
+ #
9
+ # @example Auto-detect CPU count and compress in parallel
10
+ # Omnizip::Parallel.compress_directory('files/', 'backup.zip')
11
+ #
12
+ # @example Custom thread count
13
+ # Omnizip::Parallel.compress_directory('files/', 'backup.zip', threads: 8)
14
+ #
15
+ # @example Parallel extraction
16
+ # Omnizip::Parallel.extract_archive('large.zip', 'output/', threads: 4)
17
+ #
18
+ # @example Configure globally
19
+ # Omnizip::Parallel.configure do |config|
20
+ # config.default_threads = 8
21
+ # config.queue_size = 100
22
+ # config.load_balancing = :dynamic
23
+ # end
24
+ module Parallel
25
+ # Nested classes - autoloaded
26
+ autoload :JobQueue, "omnizip/parallel/job_queue"
27
+ autoload :JobScheduler, "omnizip/parallel/job_scheduler"
28
+ autoload :WorkerPool, "omnizip/parallel/worker_pool"
29
+ autoload :Engine, "omnizip/parallel/engine"
30
+ autoload :ParallelCompressor, "omnizip/parallel/parallel_compressor"
31
+ autoload :ParallelExtractor, "omnizip/parallel/parallel_extractor"
32
+ autoload :ThreadPool, "omnizip/parallel/thread_pool"
33
+
34
+ class << self
35
+ # Global configuration
36
+ attr_accessor :config
37
+
38
+ # Configure parallel processing globally
39
+ #
40
+ # @yield [config] Configuration block
41
+ # @yieldparam config [Omnizip::Models::ParallelOptions] configuration object
42
+ # @return [void]
43
+ #
44
+ # @example
45
+ # Omnizip::Parallel.configure do |config|
46
+ # config.threads = 8
47
+ # config.queue_size = 100
48
+ # config.strategy = :dynamic
49
+ # end
50
+ def configure
51
+ @config ||= Omnizip::Models::ParallelOptions.new
52
+ yield @config if block_given?
53
+ @config.validate_options!
54
+ @config
55
+ end
56
+
57
+ # Compress directory in parallel
58
+ #
59
+ # @param dir [String] directory path
60
+ # @param output [String] output archive path
61
+ # @param options [Hash] compression options
62
+ # @option options [Integer] :threads number of threads
63
+ # @option options [Symbol] :compression compression method
64
+ # @option options [Integer] :level compression level
65
+ # @option options [Boolean] :recursive include subdirectories
66
+ # @option options [Proc] :progress progress callback
67
+ # @return [String] path to created archive
68
+ #
69
+ # @example
70
+ # Omnizip::Parallel.compress_directory('files/', 'backup.zip')
71
+ # Omnizip::Parallel.compress_directory('files/', 'backup.zip', threads: 8)
72
+ def compress_directory(dir, output, **options)
73
+ threads = options.delete(:threads) || @config&.threads
74
+
75
+ compressor = ParallelCompressor.new(@config, threads: threads)
76
+ result = compressor.compress(dir, output, **options)
77
+
78
+ # Print stats if verbose
79
+ if options[:verbose] || @config&.verbose
80
+ stats = compressor.statistics
81
+ print_stats("Compression", stats)
82
+ end
83
+
84
+ result
85
+ end
86
+
87
+ # Extract archive in parallel
88
+ #
89
+ # @param archive [String] archive path
90
+ # @param dest [String] destination directory
91
+ # @param options [Hash] extraction options
92
+ # @option options [Integer] :threads number of threads
93
+ # @option options [Boolean] :overwrite overwrite existing files
94
+ # @option options [Proc] :progress progress callback
95
+ # @return [Array<String>] extracted file paths
96
+ #
97
+ # @example
98
+ # Omnizip::Parallel.extract_archive('large.zip', 'output/')
99
+ # Omnizip::Parallel.extract_archive('large.zip', 'output/', threads: 4)
100
+ def extract_archive(archive, dest, **options)
101
+ threads = options.delete(:threads) || @config&.threads
102
+
103
+ extractor = ParallelExtractor.new(@config, threads: threads)
104
+ result = extractor.extract(archive, dest, **options)
105
+
106
+ # Print stats if verbose
107
+ if options[:verbose] || @config&.verbose
108
+ stats = extractor.statistics
109
+ print_stats("Extraction", stats)
110
+ end
111
+
112
+ result
113
+ end
114
+
115
+ # Get default configuration
116
+ #
117
+ # @return [Omnizip::Models::ParallelOptions] configuration
118
+ def default_config
119
+ @default_config ||= Omnizip::Models::ParallelOptions.new
120
+ end
121
+
122
+ # Reset configuration to defaults
123
+ #
124
+ # @return [void]
125
+ def reset_config
126
+ @config = Omnizip::Models::ParallelOptions.new
127
+ end
128
+
129
+ private
130
+
131
+ # Print statistics
132
+ #
133
+ # @param operation [String] operation name
134
+ # @param stats [Hash] statistics hash
135
+ def print_stats(operation, stats)
136
+ puts "\n=== #{operation} Statistics ==="
137
+ puts "Files processed: #{stats[:files_processed] || stats[:files_extracted] || 0}"
138
+ puts "Duration: #{'%.2f' % stats[:duration]}s"
139
+ puts "Throughput: #{'%.2f' % stats[:throughput_mbps]} MB/s"
140
+
141
+ if stats[:compression_ratio]
142
+ puts "Compression ratio: #{'%.2f' % stats[:compression_ratio]}%"
143
+ end
144
+
145
+ puts "================================\n"
146
+ end
147
+ end
148
+
149
+ # Initialize default configuration
150
+ def self.setup_default_config
151
+ @config = Omnizip::Models::ParallelOptions.new
152
+ end
153
+
154
+ setup_default_config
155
+ end
156
+ end