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,260 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Rar
6
+ module Rar5
7
+ module MultiVolume
8
+ # Volume manager for multi-volume archive creation
9
+ #
10
+ # This class coordinates the creation of multi-volume RAR5 archives
11
+ # by managing volume splitting, file distribution, and volume writing.
12
+ #
13
+ # @example Create multi-volume archive
14
+ # manager = VolumeManager.new('archive.rar',
15
+ # max_volume_size: 10 * 1024 * 1024, # 10 MB
16
+ # compression: :lzma,
17
+ # level: 5
18
+ # )
19
+ # manager.add_file('large_file.dat')
20
+ # manager.create_volumes
21
+ class VolumeManager
22
+ # @return [String] Base archive path
23
+ attr_reader :base_path
24
+
25
+ # @return [VolumeOptions] Volume options
26
+ attr_reader :volume_options
27
+
28
+ # @return [Hash] Compression options
29
+ attr_reader :compression_options
30
+
31
+ # @return [Array<Hash>] Files to archive
32
+ attr_reader :files
33
+
34
+ # Initialize volume manager
35
+ #
36
+ # @param base_path [String] Base archive path (e.g., "archive.rar")
37
+ # @param options [Hash] Options
38
+ # @option options [Integer] :max_volume_size Maximum volume size in bytes
39
+ # @option options [String] :volume_naming Naming pattern ("part", "volume", "numeric")
40
+ # @option options [Symbol] :compression Compression method (:store, :lzma)
41
+ # @option options [Integer] :level Compression level (1-5)
42
+ # @option options [Boolean] :include_mtime Include modification time
43
+ # @option options [Boolean] :include_crc32 Include CRC32
44
+ def initialize(base_path, options = {})
45
+ @base_path = base_path
46
+ @volume_options = Models::VolumeOptions.new(
47
+ max_volume_size: options[:max_volume_size] || 104_857_600,
48
+ volume_naming: options[:volume_naming] || "part",
49
+ )
50
+ @volume_options.validate!
51
+
52
+ @compression_options = {
53
+ compression: options[:compression] || :store,
54
+ level: options[:level] || 3,
55
+ include_mtime: options[:include_mtime] || false,
56
+ include_crc32: options[:include_crc32] || false,
57
+ }
58
+
59
+ @files = []
60
+ end
61
+
62
+ # Add file to archive
63
+ #
64
+ # @param input_path [String] Path to file on disk
65
+ # @param archive_path [String, nil] Path within archive
66
+ # @return [void]
67
+ def add_file(input_path, archive_path = nil)
68
+ unless File.exist?(input_path)
69
+ raise ArgumentError,
70
+ "File not found: #{input_path}"
71
+ end
72
+
73
+ archive_path ||= File.basename(input_path)
74
+
75
+ @files << {
76
+ input: input_path,
77
+ archive: archive_path,
78
+ mtime: File.mtime(input_path),
79
+ stat: File.stat(input_path),
80
+ size: File.size(input_path),
81
+ }
82
+ end
83
+
84
+ # Add directory recursively
85
+ #
86
+ # @param dir_path [String] Directory path
87
+ # @param base_path [String, nil] Base path for relative names
88
+ # @return [void]
89
+ def add_directory(dir_path, base_path = nil)
90
+ base_path ||= dir_path
91
+
92
+ Dir.glob(File.join(dir_path, "**", "*")).each do |path|
93
+ next unless File.file?(path)
94
+
95
+ relative_path = path.sub(
96
+ /^#{Regexp.escape(base_path)}#{File::SEPARATOR}?/, ""
97
+ )
98
+ add_file(path, relative_path)
99
+ end
100
+ end
101
+
102
+ # Create multi-volume archives
103
+ #
104
+ # @return [Array<String>] Paths to created volume files
105
+ def create_volumes
106
+ # Prepare file entries with compression
107
+ prepared_files = prepare_files
108
+
109
+ # Calculate file distribution across volumes
110
+ splitter = VolumeSplitter.new(max_volume_size: @volume_options.max_volume_size)
111
+ distribution = splitter.calculate_file_distribution(prepared_files)
112
+
113
+ # Create each volume
114
+ volume_paths = []
115
+ distribution.each_with_index do |file_indices, volume_idx|
116
+ volume_number = volume_idx + 1
117
+ is_last = (volume_idx == distribution.size - 1)
118
+
119
+ volume_path = VolumeWriter.volume_filename(
120
+ @base_path,
121
+ volume_number,
122
+ naming: @volume_options.volume_naming,
123
+ )
124
+
125
+ write_volume(volume_path, volume_number, file_indices,
126
+ prepared_files, is_last)
127
+ volume_paths << volume_path
128
+ end
129
+
130
+ volume_paths
131
+ end
132
+
133
+ # Check if archive needs splitting
134
+ #
135
+ # @return [Boolean] true if multi-volume needed
136
+ def needs_splitting?
137
+ total_size = estimate_total_size
138
+ VolumeSplitter.needs_splitting?(total_size,
139
+ @volume_options.max_volume_size)
140
+ end
141
+
142
+ private
143
+
144
+ # Prepare files with compression and metadata
145
+ #
146
+ # @return [Array<Hash>] Prepared file information
147
+ def prepare_files
148
+ @files.map do |file|
149
+ # Read and compress file data
150
+ data = File.binread(file[:input])
151
+ compression_method = select_compression_method(data)
152
+ compressed_data = compress_data(data, compression_method)
153
+
154
+ # Calculate CRC32 if needed
155
+ use_crc32 = @compression_options[:include_crc32] && compression_method == Compression::Store::METHOD
156
+ file_crc32 = use_crc32 ? CRC32.calculate(data) : nil
157
+
158
+ # Create file header
159
+ header = FileHeader.new(
160
+ filename: file[:archive],
161
+ file_size: data.bytesize,
162
+ compressed_size: compressed_data.bytesize,
163
+ compression_method: compression_method,
164
+ mtime: @compression_options[:include_mtime] ? file[:mtime] : nil,
165
+ crc32: file_crc32,
166
+ )
167
+
168
+ # Estimate header size (approximate)
169
+ header_data = header.encode
170
+ header_size = header_data.bytesize
171
+
172
+ {
173
+ file: file,
174
+ header: header,
175
+ header_size: header_size,
176
+ compressed_data: compressed_data,
177
+ compressed_size: compressed_data.bytesize,
178
+ }
179
+ end
180
+ end
181
+
182
+ # Write single volume file
183
+ #
184
+ # @param volume_path [String] Volume file path
185
+ # @param volume_number [Integer] Volume number (1-based)
186
+ # @param file_indices [Array<Integer>] File indices to include
187
+ # @param prepared_files [Array<Hash>] All prepared files
188
+ # @param is_last [Boolean] Is this the last volume?
189
+ # @return [void]
190
+ def write_volume(volume_path, volume_number, file_indices,
191
+ prepared_files, is_last)
192
+ writer = VolumeWriter.new(volume_path,
193
+ volume_number: volume_number, is_last: is_last)
194
+
195
+ writer.write do |vol|
196
+ vol.write_signature
197
+ vol.write_main_header
198
+
199
+ file_indices.each do |idx|
200
+ prepared = prepared_files[idx]
201
+ vol.write_file_data(prepared[:header],
202
+ prepared[:compressed_data])
203
+ end
204
+
205
+ vol.write_end_header
206
+ end
207
+ end
208
+
209
+ # Select compression method
210
+ #
211
+ # @param data [String] File data
212
+ # @return [Integer] Compression method ID
213
+ def select_compression_method(data)
214
+ case @compression_options[:compression]
215
+ when :store
216
+ Compression::Store::METHOD
217
+ when :lzma
218
+ level = @compression_options[:level] || 3
219
+ Compression::Lzma.method_id(level)
220
+ when :auto
221
+ if data.bytesize < 1024
222
+ Compression::Store::METHOD
223
+ else
224
+ level = @compression_options[:level] || 3
225
+ Compression::Lzma.method_id(level)
226
+ end
227
+ else
228
+ Compression::Store::METHOD
229
+ end
230
+ end
231
+
232
+ # Compress data
233
+ #
234
+ # @param data [String] Data to compress
235
+ # @param method [Integer] Compression method ID
236
+ # @return [String] Compressed data
237
+ def compress_data(data, method)
238
+ if method == Compression::Store::METHOD
239
+ Compression::Store.compress(data)
240
+ else
241
+ level = method.clamp(1, 5)
242
+ Compression::Lzma.compress(data, level: level)
243
+ end
244
+ end
245
+
246
+ # Estimate total archive size
247
+ #
248
+ # @return [Integer] Estimated size in bytes
249
+ def estimate_total_size
250
+ # Rough estimate: sum of file sizes + overhead
251
+ file_sizes = @files.sum { |f| f[:size] }
252
+ overhead = 1024 * @files.size # Header overhead per file
253
+ file_sizes + overhead
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Rar
6
+ module Rar5
7
+ module MultiVolume
8
+ # Volume splitter for multi-volume archives
9
+ #
10
+ # This class handles splitting compressed data streams across
11
+ # multiple volumes while respecting size boundaries and file atomicity.
12
+ #
13
+ # @example Split data across volumes
14
+ # splitter = VolumeSplitter.new(max_volume_size: 10_485_760)
15
+ # splitter.start_volume(1)
16
+ # splitter.write_to_current_volume(file1_data)
17
+ # if !splitter.can_fit_in_current_volume?(file2_data.bytesize)
18
+ # splitter.finalize_volume
19
+ # splitter.start_volume(2)
20
+ # end
21
+ class VolumeSplitter
22
+ # @return [Integer] Maximum size per volume in bytes
23
+ attr_reader :max_volume_size
24
+
25
+ # @return [Integer] Current volume number (1-based)
26
+ attr_reader :current_volume_number
27
+
28
+ # @return [Integer] Bytes written to current volume
29
+ attr_reader :current_volume_bytes
30
+
31
+ # @return [Array<Hash>] Volume metadata
32
+ attr_reader :volumes
33
+
34
+ # Minimum space reserved for headers (signature + main + end headers)
35
+ HEADER_OVERHEAD = 1024
36
+
37
+ # Initialize volume splitter
38
+ #
39
+ # @param max_volume_size [Integer] Maximum size per volume in bytes
40
+ def initialize(max_volume_size:)
41
+ @max_volume_size = max_volume_size
42
+ @current_volume_number = 0
43
+ @current_volume_bytes = 0
44
+ @current_volume_data = []
45
+ @volumes = []
46
+ end
47
+
48
+ # Start a new volume
49
+ #
50
+ # @param volume_number [Integer] Volume number (1-based)
51
+ # @return [void]
52
+ def start_volume(volume_number)
53
+ @current_volume_number = volume_number
54
+ @current_volume_bytes = HEADER_OVERHEAD # Reserve space for headers
55
+ @current_volume_data = []
56
+ end
57
+
58
+ # Check if data can fit in current volume
59
+ #
60
+ # @param data_size [Integer] Size of data to write
61
+ # @return [Boolean] true if data fits, false if new volume needed
62
+ def can_fit_in_current_volume?(data_size)
63
+ (@current_volume_bytes + data_size) <= @max_volume_size
64
+ end
65
+
66
+ # Get remaining space in current volume
67
+ #
68
+ # @return [Integer] Bytes available
69
+ def remaining_space
70
+ @max_volume_size - @current_volume_bytes
71
+ end
72
+
73
+ # Write data to current volume
74
+ #
75
+ # @param data [String] Data to write
76
+ # @return [void]
77
+ # @raise [RuntimeError] if no volume is active
78
+ # @raise [RuntimeError] if data doesn't fit
79
+ def write_to_current_volume(data)
80
+ raise Omnizip::CompressionError, "No active volume" if @current_volume_number.zero?
81
+ raise Omnizip::CompressionError, "Data doesn't fit in current volume" unless can_fit_in_current_volume?(data.bytesize)
82
+
83
+ @current_volume_data << data
84
+ @current_volume_bytes += data.bytesize
85
+ end
86
+
87
+ # Finalize current volume
88
+ #
89
+ # @return [Hash] Volume metadata
90
+ def finalize_volume
91
+ volume_info = {
92
+ number: @current_volume_number,
93
+ size: @current_volume_bytes,
94
+ data: @current_volume_data.join,
95
+ }
96
+
97
+ @volumes << volume_info
98
+ volume_info
99
+ end
100
+
101
+ # Calculate optimal file distribution across volumes
102
+ #
103
+ # This method determines how to distribute files across volumes
104
+ # to minimize volume count while respecting atomicity.
105
+ #
106
+ # @param files [Array<Hash>] File information with :compressed_size
107
+ # @return [Array<Array<Integer>>] Volume assignments (file indices per volume)
108
+ def calculate_file_distribution(files)
109
+ distribution = []
110
+ current_volume_files = []
111
+ current_volume_used = HEADER_OVERHEAD
112
+
113
+ files.each_with_index do |file, idx|
114
+ file_size = file[:compressed_size] + file[:header_size]
115
+
116
+ # Check if file fits in current volume
117
+ if (current_volume_used + file_size) <= @max_volume_size
118
+ current_volume_files << idx
119
+ current_volume_used += file_size
120
+ else
121
+ # Start new volume
122
+ distribution << current_volume_files unless current_volume_files.empty?
123
+ current_volume_files = [idx]
124
+ current_volume_used = HEADER_OVERHEAD + file_size
125
+
126
+ # Check if single file exceeds volume size
127
+ if current_volume_used > @max_volume_size
128
+ # File must span multiple volumes (not implemented yet)
129
+ # For now, just place it in its own volume
130
+ distribution << [idx]
131
+ current_volume_files = []
132
+ current_volume_used = HEADER_OVERHEAD
133
+ end
134
+ end
135
+ end
136
+
137
+ # Add final volume if not empty
138
+ distribution << current_volume_files unless current_volume_files.empty?
139
+
140
+ distribution
141
+ end
142
+
143
+ # Check if archive needs splitting
144
+ #
145
+ # @param total_size [Integer] Total archive size
146
+ # @return [Boolean] true if splitting needed
147
+ def self.needs_splitting?(total_size, max_volume_size)
148
+ total_size > max_volume_size
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Rar
6
+ module Rar5
7
+ module MultiVolume
8
+ # Volume writer for multi-volume archives
9
+ #
10
+ # This class writes individual .rar volume files with proper
11
+ # RAR5 headers and volume-specific flags.
12
+ #
13
+ # @example Write a volume
14
+ # writer = VolumeWriter.new('archive.part1.rar', volume_number: 1, is_last: false)
15
+ # writer.write_signature
16
+ # writer.write_main_header
17
+ # writer.write_file_data(file_header, compressed_data)
18
+ # writer.write_end_header
19
+ # writer.close
20
+ class VolumeWriter
21
+ # Main ARCHIVE flags (spec): 0x0001 volume,
22
+ # 0x0002 volume number field present
23
+ VOLUME_ARCHIVE_FLAG = MainHeader::ARCHIVE_FLAG_VOLUME
24
+ VOLUME_NUMBER_FLAG = MainHeader::ARCHIVE_FLAG_VOLUME_NUMBER
25
+
26
+ # End header flags
27
+ VOLUME_END_FLAG = 0x0001 # Not the last volume (more volumes follow)
28
+
29
+ # @return [String] Volume file path
30
+ attr_reader :path
31
+
32
+ # @return [Integer] Volume number (1-based)
33
+ attr_reader :volume_number
34
+
35
+ # @return [Boolean] Is this the last volume?
36
+ attr_reader :is_last
37
+
38
+ # @return [IO] File handle
39
+ attr_reader :io
40
+
41
+ # Initialize volume writer
42
+ #
43
+ # @param path [String] Output volume file path
44
+ # @param volume_number [Integer] Volume number (1-based)
45
+ # @param is_last [Boolean] Is this the last volume?
46
+ def initialize(path, volume_number:, is_last: false)
47
+ @path = path
48
+ @volume_number = volume_number
49
+ @is_last = is_last
50
+ @io = nil
51
+ end
52
+
53
+ # Open volume file for writing
54
+ #
55
+ # @return [void]
56
+ def open
57
+ @io = File.open(@path, "wb")
58
+ end
59
+
60
+ # Close volume file
61
+ #
62
+ # @return [void]
63
+ def close
64
+ @io&.close
65
+ @io = nil
66
+ end
67
+
68
+ # Write with automatic open/close
69
+ #
70
+ # @yield [writer] Yields self for writing operations
71
+ # @return [void]
72
+ def write
73
+ open
74
+ yield self
75
+ ensure
76
+ close
77
+ end
78
+
79
+ # Write RAR5 signature
80
+ #
81
+ # @return [void]
82
+ def write_signature
83
+ raise Omnizip::IOError, "Volume not open" unless @io
84
+
85
+ # RAR5 signature: "Rar!\x1A\x07\x01\x00"
86
+ signature = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01,
87
+ 0x00].pack("C*")
88
+ @io.write(signature)
89
+ end
90
+
91
+ # Write Main header with volume flags
92
+ #
93
+ # @return [void]
94
+ def write_main_header
95
+ raise Omnizip::IOError, "Volume not open" unless @io
96
+
97
+ # Archive flags: every volume declares 0x0001; volumes
98
+ # after the first also carry the volume number field
99
+ # (spec: number is N-1, absent on the first volume).
100
+ archive_flags = VOLUME_ARCHIVE_FLAG
101
+ volume_number = nil
102
+ if @volume_number > 1
103
+ archive_flags |= VOLUME_NUMBER_FLAG
104
+ volume_number = @volume_number - 1
105
+ end
106
+
107
+ @io.write(MainHeader.new(archive_flags: archive_flags,
108
+ volume_number: volume_number).encode)
109
+ end
110
+
111
+ # Write file data (header + compressed data)
112
+ #
113
+ # @param file_header [FileHeader] File header
114
+ # @param compressed_data [String] Compressed file data
115
+ # @return [void]
116
+ def write_file_data(file_header, compressed_data)
117
+ raise Omnizip::IOError, "Volume not open" unless @io
118
+
119
+ @io.write(file_header.encode)
120
+ @io.write(compressed_data)
121
+ end
122
+
123
+ # Write End header with volume flags
124
+ #
125
+ # @return [void]
126
+ def write_end_header
127
+ raise Omnizip::IOError, "Volume not open" unless @io
128
+
129
+ # End-of-archive flags: 0x0001 marks a volume with more
130
+ # volumes following; the last volume ends with 0.
131
+ end_flags = @is_last ? 0 : VOLUME_END_FLAG
132
+ @io.write(EndHeader.new(end_flags: end_flags).encode)
133
+ end
134
+
135
+ # Generate volume filename from base name
136
+ #
137
+ # @param base_path [String] Base archive path (e.g., "archive.rar")
138
+ # @param volume_number [Integer] Volume number (1-based)
139
+ # @param naming [String] Naming pattern ("part" or "volume")
140
+ # @return [String] Volume filename (e.g., "archive.part1.rar")
141
+ def self.volume_filename(base_path, volume_number, naming: "part")
142
+ dir = File.dirname(base_path)
143
+ basename = File.basename(base_path, ".*")
144
+ ext = File.extname(base_path)
145
+
146
+ volume_name = case naming
147
+ when "part"
148
+ "#{basename}.part#{volume_number}#{ext}"
149
+ when "volume"
150
+ "#{basename}.vol#{volume_number}#{ext}"
151
+ when "numeric"
152
+ # Simple numeric suffix: archive.rar, archive.r00, archive.r01, etc.
153
+ if volume_number == 1
154
+ "#{basename}#{ext}"
155
+ else
156
+ # Volume 2 => r00, Volume 3 => r01, etc.
157
+ "#{basename}.r#{format('%02d',
158
+ volume_number - 2)}"
159
+ end
160
+ else
161
+ "#{basename}.part#{volume_number}#{ext}"
162
+ end
163
+
164
+ # Handle relative vs absolute paths
165
+ if dir == "."
166
+ volume_name
167
+ else
168
+ File.join(dir, volume_name)
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Omnizip
6
+ module Formats
7
+ module Rar
8
+ module Rar5
9
+ module Solid
10
+ # Solid LZMA encoder with persistent dictionary
11
+ #
12
+ # This encoder maintains LZMA dictionary state across multiple files,
13
+ # allowing later files to reference data from earlier files. This is
14
+ # the core technique behind solid compression's improved ratios.
15
+ #
16
+ # Unlike normal compression where each file is independent, solid
17
+ # compression treats all files as one continuous stream, maximizing
18
+ # dictionary-based compression efficiency.
19
+ #
20
+ # @example Compress multiple files in solid mode
21
+ # encoder = SolidEncoder.new(level: 5)
22
+ # compressed = encoder.compress_stream(concatenated_data)
23
+ class SolidEncoder
24
+ # @return [Integer] Compression level (1-5)
25
+ attr_reader :level
26
+
27
+ # @return [Hash] LZMA options
28
+ attr_reader :lzma_options
29
+
30
+ # Initialize solid encoder
31
+ #
32
+ # @param options [Hash] Encoder options
33
+ # @option options [Integer] :level Compression level (1-5, default: 3)
34
+ def initialize(options = {})
35
+ @level = options[:level] || 3
36
+ @lzma_options = build_lzma_options(@level)
37
+ end
38
+
39
+ # Compress data with persistent dictionary
40
+ #
41
+ # @param data [String] Data to compress (concatenated files)
42
+ # @return [String] Compressed data
43
+ def compress_stream(data)
44
+ input = StringIO.new(data)
45
+ output = StringIO.new
46
+ output.set_encoding(Encoding::BINARY)
47
+
48
+ # Create LZMA encoder
49
+ lzma = Algorithms::LZMA.new
50
+
51
+ # Compress entire stream at once (maintains dictionary)
52
+ lzma.compress(input, output, @lzma_options)
53
+
54
+ output.string
55
+ end
56
+
57
+ # Decompress solid stream
58
+ #
59
+ # @param data [String] Compressed data
60
+ # @return [String] Decompressed data
61
+ def decompress_stream(data)
62
+ input = StringIO.new(data)
63
+ output = StringIO.new
64
+ output.set_encoding(Encoding::BINARY)
65
+
66
+ lzma = Algorithms::LZMA.new
67
+ lzma.decompress(input, output)
68
+
69
+ output.string
70
+ end
71
+
72
+ # Build LZMA options for solid compression
73
+ #
74
+ # Solid compression benefits from larger dictionaries since
75
+ # we're compressing more data at once.
76
+ #
77
+ # @param level [Integer] RAR5 compression level (1-5)
78
+ # @return [LzmaOptions] LZMA encoder options
79
+ def build_lzma_options(level)
80
+ # Use larger dictionaries for solid mode
81
+ # This allows better cross-file references
82
+ dict_size = 1 << case level
83
+ when 1 then 20 # 1 MB (fastest)
84
+ when 2 then 22 # 4 MB (fast)
85
+ when 3 then 24 # 16 MB (normal)
86
+ when 4 then 25 # 32 MB (good)
87
+ when 5 then 26 # 64 MB (best)
88
+ else 24 # default: 16 MB
89
+ end
90
+
91
+ LzmaOptions.new(level, dict_size)
92
+ end
93
+
94
+ # Simple options class for LZMA parameters
95
+ class LzmaOptions
96
+ attr_reader :level, :dict_size
97
+
98
+ def initialize(level, dict_size)
99
+ @level = level
100
+ @dict_size = dict_size
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end