omnizip 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (511) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +754 -0
  5. data/COPYING +502 -0
  6. data/Gemfile +17 -0
  7. data/LICENSE +12 -0
  8. data/README.adoc +1045 -0
  9. data/Rakefile +12 -0
  10. data/benchmark/README.md +260 -0
  11. data/benchmark/benchmark_suite.rb +125 -0
  12. data/benchmark/compression_bench.rb +181 -0
  13. data/benchmark/filter_bench.rb +180 -0
  14. data/benchmark/models/benchmark_result.rb +59 -0
  15. data/benchmark/models/comparison_result.rb +69 -0
  16. data/benchmark/profile_suite.rb +167 -0
  17. data/benchmark/reporter.rb +150 -0
  18. data/benchmark/run_benchmarks.rb +66 -0
  19. data/benchmark/test_data.rb +137 -0
  20. data/config/formats/rar3_spec.yml +91 -0
  21. data/config/formats/rar5_spec.yml +102 -0
  22. data/docs/.github/workflows/docs.yml +142 -0
  23. data/docs/.gitignore +21 -0
  24. data/docs/.lychee.toml +67 -0
  25. data/docs/Gemfile +13 -0
  26. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  27. data/docs/README.md +101 -0
  28. data/docs/_config.yml +112 -0
  29. data/docs/assets/logo.svg +1 -0
  30. data/docs/assets/omnizip-logo.pdf +1540 -11
  31. data/docs/comparison/feature-matrix.adoc +694 -0
  32. data/docs/comparison/index.adoc +113 -0
  33. data/docs/comparison/vs-7zip.adoc +309 -0
  34. data/docs/comparison/vs-peazip.adoc +77 -0
  35. data/docs/comparison/vs-rubyzip.adoc +342 -0
  36. data/docs/comparison/vs-winrar.adoc +100 -0
  37. data/docs/compatibility.adoc +579 -0
  38. data/docs/concepts/index.adoc +129 -0
  39. data/docs/developer/architecture.adoc +256 -0
  40. data/docs/developer/contributing.adoc +158 -0
  41. data/docs/developer/index.adoc +25 -0
  42. data/docs/developer/testing.adoc +212 -0
  43. data/docs/getting-started/basic-usage.adoc +271 -0
  44. data/docs/getting-started/index.adoc +42 -0
  45. data/docs/getting-started/installation.adoc +138 -0
  46. data/docs/getting-started/quick-start.adoc +185 -0
  47. data/docs/getting-started/your-first-archive.adoc +218 -0
  48. data/docs/guides/advanced-features/encryption.adoc +300 -0
  49. data/docs/guides/advanced-features/index.adoc +49 -0
  50. data/docs/guides/advanced-features/parallel-processing.adoc +246 -0
  51. data/docs/guides/advanced-features/progress-tracking.adoc +320 -0
  52. data/docs/guides/advanced-features/streaming.adoc +212 -0
  53. data/docs/guides/archive-formats/gzip-format.adoc +107 -0
  54. data/docs/guides/archive-formats/index.adoc +130 -0
  55. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  56. data/docs/guides/archive-formats/rar5.adoc +521 -0
  57. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  58. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  59. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  60. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  61. data/docs/guides/compression-algorithms/bzip2.adoc +113 -0
  62. data/docs/guides/compression-algorithms/deflate.adoc +319 -0
  63. data/docs/guides/compression-algorithms/index.adoc +190 -0
  64. data/docs/guides/compression-algorithms/lzma.adoc +398 -0
  65. data/docs/guides/compression-algorithms/lzma2.adoc +327 -0
  66. data/docs/guides/compression-algorithms/ppmd.adoc +316 -0
  67. data/docs/guides/compression-algorithms/zstandard.adoc +361 -0
  68. data/docs/guides/creating-archives.adoc +354 -0
  69. data/docs/guides/extracting-archives.adoc +53 -0
  70. data/docs/guides/format-conversion.adoc +64 -0
  71. data/docs/guides/index.adoc +49 -0
  72. data/docs/guides/migration-rubyzip.adoc +217 -0
  73. data/docs/guides/parity-archives.adoc +605 -0
  74. data/docs/guides/performance-tuning.adoc +88 -0
  75. data/docs/index.adoc +218 -0
  76. data/docs/lychee.toml +67 -0
  77. data/docs/reference/api/overview.adoc +188 -0
  78. data/docs/reference/cli/compress-command.adoc +114 -0
  79. data/docs/reference/cli/overview.adoc +140 -0
  80. data/docs/reference/index.adoc +26 -0
  81. data/docs/resources/faq.adoc +185 -0
  82. data/docs/resources/quick-reference.adoc +222 -0
  83. data/docs/troubleshooting/index.adoc +208 -0
  84. data/examples/api_comparison.rb +205 -0
  85. data/examples/deflate64_example.rb +96 -0
  86. data/examples/par2_demo.rb +121 -0
  87. data/examples/quick_start_native.rb +150 -0
  88. data/examples/quick_start_rubyzip.rb +115 -0
  89. data/examples/rubyzip_compatibility_demo.rb +194 -0
  90. data/exe/omnizip +27 -0
  91. data/lib/omnizip/algorithm.rb +130 -0
  92. data/lib/omnizip/algorithm_registry.rb +86 -0
  93. data/lib/omnizip/algorithms/.keep +0 -0
  94. data/lib/omnizip/algorithms/bzip2/bwt.rb +225 -0
  95. data/lib/omnizip/algorithms/bzip2/decoder.rb +193 -0
  96. data/lib/omnizip/algorithms/bzip2/encoder.rb +237 -0
  97. data/lib/omnizip/algorithms/bzip2/huffman.rb +206 -0
  98. data/lib/omnizip/algorithms/bzip2/mtf.rb +101 -0
  99. data/lib/omnizip/algorithms/bzip2/rle.rb +151 -0
  100. data/lib/omnizip/algorithms/bzip2.rb +130 -0
  101. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  102. data/lib/omnizip/algorithms/deflate/decoder.rb +38 -0
  103. data/lib/omnizip/algorithms/deflate/encoder.rb +46 -0
  104. data/lib/omnizip/algorithms/deflate.rb +128 -0
  105. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  106. data/lib/omnizip/algorithms/deflate64/decoder.rb +153 -0
  107. data/lib/omnizip/algorithms/deflate64/encoder.rb +98 -0
  108. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +354 -0
  109. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +142 -0
  110. data/lib/omnizip/algorithms/deflate64.rb +109 -0
  111. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  112. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  113. data/lib/omnizip/algorithms/lzma/decoder.rb +148 -0
  114. data/lib/omnizip/algorithms/lzma/dictionary.rb +69 -0
  115. data/lib/omnizip/algorithms/lzma/distance_coder.rb +415 -0
  116. data/lib/omnizip/algorithms/lzma/encoder.rb +142 -0
  117. data/lib/omnizip/algorithms/lzma/length_coder.rb +260 -0
  118. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +320 -0
  119. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +210 -0
  120. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +341 -0
  121. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +192 -0
  122. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  123. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  124. data/lib/omnizip/algorithms/lzma/match_finder.rb +205 -0
  125. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  126. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +88 -0
  127. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +130 -0
  128. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  129. data/lib/omnizip/algorithms/lzma/range_coder.rb +85 -0
  130. data/lib/omnizip/algorithms/lzma/range_decoder.rb +434 -0
  131. data/lib/omnizip/algorithms/lzma/range_encoder.rb +194 -0
  132. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  133. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +325 -0
  134. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +426 -0
  135. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +645 -0
  136. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +227 -0
  137. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +169 -0
  138. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +261 -0
  139. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  140. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +331 -0
  141. data/lib/omnizip/algorithms/lzma/xz_state.rb +116 -0
  142. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +2055 -0
  143. data/lib/omnizip/algorithms/lzma.rb +238 -0
  144. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +182 -0
  145. data/lib/omnizip/algorithms/lzma2/constants.rb +41 -0
  146. data/lib/omnizip/algorithms/lzma2/encoder.rb +147 -0
  147. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +161 -0
  148. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  149. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +127 -0
  150. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  151. data/lib/omnizip/algorithms/lzma2.rb +141 -0
  152. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  153. data/lib/omnizip/algorithms/ppmd7/context.rb +154 -0
  154. data/lib/omnizip/algorithms/ppmd7/decoder.rb +126 -0
  155. data/lib/omnizip/algorithms/ppmd7/encoder.rb +163 -0
  156. data/lib/omnizip/algorithms/ppmd7/model.rb +248 -0
  157. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  158. data/lib/omnizip/algorithms/ppmd7.rb +116 -0
  159. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  160. data/lib/omnizip/algorithms/ppmd8/context.rb +34 -0
  161. data/lib/omnizip/algorithms/ppmd8/decoder.rb +107 -0
  162. data/lib/omnizip/algorithms/ppmd8/encoder.rb +138 -0
  163. data/lib/omnizip/algorithms/ppmd8/model.rb +250 -0
  164. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  165. data/lib/omnizip/algorithms/ppmd8.rb +82 -0
  166. data/lib/omnizip/algorithms/ppmd_base.rb +138 -0
  167. data/lib/omnizip/algorithms/sevenzip_lzma2.rb +123 -0
  168. data/lib/omnizip/algorithms/xz_lzma2.rb +118 -0
  169. data/lib/omnizip/algorithms/zstandard/constants.rb +25 -0
  170. data/lib/omnizip/algorithms/zstandard/decoder.rb +46 -0
  171. data/lib/omnizip/algorithms/zstandard/encoder.rb +51 -0
  172. data/lib/omnizip/algorithms/zstandard.rb +138 -0
  173. data/lib/omnizip/buffer/memory_archive.rb +251 -0
  174. data/lib/omnizip/buffer/memory_extractor.rb +224 -0
  175. data/lib/omnizip/buffer.rb +176 -0
  176. data/lib/omnizip/checksum_registry.rb +114 -0
  177. data/lib/omnizip/checksums/crc32.rb +100 -0
  178. data/lib/omnizip/checksums/crc64.rb +101 -0
  179. data/lib/omnizip/checksums/crc_base.rb +158 -0
  180. data/lib/omnizip/checksums/verifier.rb +131 -0
  181. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  182. data/lib/omnizip/chunked/reader.rb +78 -0
  183. data/lib/omnizip/chunked/writer.rb +120 -0
  184. data/lib/omnizip/chunked.rb +129 -0
  185. data/lib/omnizip/cli/output_formatter.rb +104 -0
  186. data/lib/omnizip/cli.rb +572 -0
  187. data/lib/omnizip/commands/.keep +0 -0
  188. data/lib/omnizip/commands/archive_create_command.rb +427 -0
  189. data/lib/omnizip/commands/archive_extract_command.rb +272 -0
  190. data/lib/omnizip/commands/archive_list_command.rb +218 -0
  191. data/lib/omnizip/commands/archive_repair_command.rb +131 -0
  192. data/lib/omnizip/commands/archive_verify_command.rb +117 -0
  193. data/lib/omnizip/commands/compress_command.rb +117 -0
  194. data/lib/omnizip/commands/decompress_command.rb +120 -0
  195. data/lib/omnizip/commands/list_command.rb +53 -0
  196. data/lib/omnizip/commands/metadata_command.rb +153 -0
  197. data/lib/omnizip/commands/parity_create_command.rb +122 -0
  198. data/lib/omnizip/commands/parity_repair_command.rb +122 -0
  199. data/lib/omnizip/commands/parity_verify_command.rb +124 -0
  200. data/lib/omnizip/commands/profile_list_command.rb +56 -0
  201. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  202. data/lib/omnizip/convenience.rb +359 -0
  203. data/lib/omnizip/converter/conversion_registry.rb +49 -0
  204. data/lib/omnizip/converter/conversion_strategy.rb +121 -0
  205. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +97 -0
  206. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +112 -0
  207. data/lib/omnizip/converter.rb +105 -0
  208. data/lib/omnizip/crypto/aes256/cipher.rb +100 -0
  209. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  210. data/lib/omnizip/crypto/aes256/key_derivation.rb +101 -0
  211. data/lib/omnizip/crypto/aes256.rb +102 -0
  212. data/lib/omnizip/error.rb +106 -0
  213. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +98 -0
  214. data/lib/omnizip/eta/moving_average_estimator.rb +99 -0
  215. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  216. data/lib/omnizip/eta/sample_history.rb +143 -0
  217. data/lib/omnizip/eta/time_estimator.rb +106 -0
  218. data/lib/omnizip/eta.rb +63 -0
  219. data/lib/omnizip/extraction/filter_chain.rb +177 -0
  220. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  221. data/lib/omnizip/extraction/pattern_matcher.rb +70 -0
  222. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  223. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  224. data/lib/omnizip/extraction/selective_extractor.rb +240 -0
  225. data/lib/omnizip/extraction.rb +111 -0
  226. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  227. data/lib/omnizip/file_type.rb +113 -0
  228. data/lib/omnizip/filter.rb +139 -0
  229. data/lib/omnizip/filter_pipeline.rb +108 -0
  230. data/lib/omnizip/filter_registry.rb +166 -0
  231. data/lib/omnizip/filters/bcj.rb +279 -0
  232. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  233. data/lib/omnizip/filters/bcj2/decoder.rb +200 -0
  234. data/lib/omnizip/filters/bcj2/encoder.rb +61 -0
  235. data/lib/omnizip/filters/bcj2/stream_data.rb +93 -0
  236. data/lib/omnizip/filters/bcj2.rb +99 -0
  237. data/lib/omnizip/filters/bcj_arm.rb +176 -0
  238. data/lib/omnizip/filters/bcj_arm64.rb +244 -0
  239. data/lib/omnizip/filters/bcj_ia64.rb +196 -0
  240. data/lib/omnizip/filters/bcj_ppc.rb +190 -0
  241. data/lib/omnizip/filters/bcj_sparc.rb +176 -0
  242. data/lib/omnizip/filters/bcj_x86.rb +193 -0
  243. data/lib/omnizip/filters/delta.rb +196 -0
  244. data/lib/omnizip/filters/filter_base.rb +72 -0
  245. data/lib/omnizip/filters/registry.rb +123 -0
  246. data/lib/omnizip/filters/xz_delta.rb +258 -0
  247. data/lib/omnizip/format_detector.rb +162 -0
  248. data/lib/omnizip/format_registry.rb +59 -0
  249. data/lib/omnizip/formats/.keep +0 -0
  250. data/lib/omnizip/formats/bzip2_file.rb +172 -0
  251. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  252. data/lib/omnizip/formats/cpio/entry.rb +385 -0
  253. data/lib/omnizip/formats/cpio/reader.rb +196 -0
  254. data/lib/omnizip/formats/cpio/writer.rb +234 -0
  255. data/lib/omnizip/formats/cpio.rb +140 -0
  256. data/lib/omnizip/formats/format_spec_loader.rb +230 -0
  257. data/lib/omnizip/formats/gzip.rb +238 -0
  258. data/lib/omnizip/formats/iso/directory_builder.rb +297 -0
  259. data/lib/omnizip/formats/iso/directory_record.rb +152 -0
  260. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  261. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  262. data/lib/omnizip/formats/iso/reader.rb +197 -0
  263. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  264. data/lib/omnizip/formats/iso/volume_builder.rb +320 -0
  265. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  266. data/lib/omnizip/formats/iso/writer.rb +530 -0
  267. data/lib/omnizip/formats/iso.rb +140 -0
  268. data/lib/omnizip/formats/lzip.rb +175 -0
  269. data/lib/omnizip/formats/lzma_alone.rb +171 -0
  270. data/lib/omnizip/formats/rar/archive_repairer.rb +243 -0
  271. data/lib/omnizip/formats/rar/archive_verifier.rb +195 -0
  272. data/lib/omnizip/formats/rar/block_parser.rb +243 -0
  273. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  274. data/lib/omnizip/formats/rar/compression/dispatcher.rb +217 -0
  275. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +216 -0
  276. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +158 -0
  277. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  278. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  279. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  280. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  281. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +105 -0
  282. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +219 -0
  283. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +262 -0
  284. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  285. data/lib/omnizip/formats/rar/constants.rb +82 -0
  286. data/lib/omnizip/formats/rar/decompressor.rb +238 -0
  287. data/lib/omnizip/formats/rar/external_writer.rb +312 -0
  288. data/lib/omnizip/formats/rar/header.rb +192 -0
  289. data/lib/omnizip/formats/rar/license_validator.rb +109 -0
  290. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  291. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  292. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  293. data/lib/omnizip/formats/rar/parity_handler.rb +292 -0
  294. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +202 -0
  295. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +578 -0
  296. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  297. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  298. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +97 -0
  299. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  300. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +166 -0
  301. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  302. data/lib/omnizip/formats/rar/rar5/header.rb +187 -0
  303. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  304. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  305. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  306. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  307. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  308. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +264 -0
  309. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  310. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +194 -0
  311. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +109 -0
  312. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +142 -0
  313. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  314. data/lib/omnizip/formats/rar/rar5/vint.rb +65 -0
  315. data/lib/omnizip/formats/rar/rar5/writer.rb +466 -0
  316. data/lib/omnizip/formats/rar/rar_format_base.rb +241 -0
  317. data/lib/omnizip/formats/rar/reader.rb +366 -0
  318. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  319. data/lib/omnizip/formats/rar/volume_manager.rb +168 -0
  320. data/lib/omnizip/formats/rar/writer.rb +431 -0
  321. data/lib/omnizip/formats/rar.rb +205 -0
  322. data/lib/omnizip/formats/rar3/compressor.rb +73 -0
  323. data/lib/omnizip/formats/rar3/decompressor.rb +66 -0
  324. data/lib/omnizip/formats/rar3/reader.rb +386 -0
  325. data/lib/omnizip/formats/rar3/writer.rb +219 -0
  326. data/lib/omnizip/formats/rar5/compressor.rb +73 -0
  327. data/lib/omnizip/formats/rar5/decompressor.rb +66 -0
  328. data/lib/omnizip/formats/rar5/reader.rb +342 -0
  329. data/lib/omnizip/formats/rar5/writer.rb +214 -0
  330. data/lib/omnizip/formats/seven_zip/coder_chain.rb +150 -0
  331. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  332. data/lib/omnizip/formats/seven_zip/encoded_header.rb +114 -0
  333. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +142 -0
  334. data/lib/omnizip/formats/seven_zip/file_collector.rb +144 -0
  335. data/lib/omnizip/formats/seven_zip/header.rb +106 -0
  336. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +134 -0
  337. data/lib/omnizip/formats/seven_zip/header_writer.rb +466 -0
  338. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  339. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +58 -0
  340. data/lib/omnizip/formats/seven_zip/models/folder.rb +69 -0
  341. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  342. data/lib/omnizip/formats/seven_zip/parser.rb +660 -0
  343. data/lib/omnizip/formats/seven_zip/reader.rb +458 -0
  344. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +632 -0
  345. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +315 -0
  346. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  347. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +162 -0
  348. data/lib/omnizip/formats/seven_zip/writer.rb +740 -0
  349. data/lib/omnizip/formats/seven_zip.rb +93 -0
  350. data/lib/omnizip/formats/tar/constants.rb +73 -0
  351. data/lib/omnizip/formats/tar/entry.rb +94 -0
  352. data/lib/omnizip/formats/tar/header.rb +168 -0
  353. data/lib/omnizip/formats/tar/reader.rb +121 -0
  354. data/lib/omnizip/formats/tar/writer.rb +216 -0
  355. data/lib/omnizip/formats/tar.rb +84 -0
  356. data/lib/omnizip/formats/xz/reader.rb +116 -0
  357. data/lib/omnizip/formats/xz.rb +237 -0
  358. data/lib/omnizip/formats/xz_impl/block_decoder.rb +754 -0
  359. data/lib/omnizip/formats/xz_impl/block_encoder.rb +306 -0
  360. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  361. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +186 -0
  362. data/lib/omnizip/formats/xz_impl/constants.rb +49 -0
  363. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  364. data/lib/omnizip/formats/xz_impl/index_encoder.rb +122 -0
  365. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +468 -0
  366. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +99 -0
  367. data/lib/omnizip/formats/xz_impl/stream_footer.rb +81 -0
  368. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +117 -0
  369. data/lib/omnizip/formats/xz_impl/stream_header.rb +55 -0
  370. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +108 -0
  371. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  372. data/lib/omnizip/formats/xz_impl/writer.rb +421 -0
  373. data/lib/omnizip/formats/zip/central_directory_header.rb +195 -0
  374. data/lib/omnizip/formats/zip/constants.rb +69 -0
  375. data/lib/omnizip/formats/zip/end_of_central_directory.rb +133 -0
  376. data/lib/omnizip/formats/zip/local_file_header.rb +138 -0
  377. data/lib/omnizip/formats/zip/reader.rb +250 -0
  378. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  379. data/lib/omnizip/formats/zip/writer.rb +375 -0
  380. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +104 -0
  381. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +66 -0
  382. data/lib/omnizip/formats/zip/zip64_extra_field.rb +114 -0
  383. data/lib/omnizip/formats/zip.rb +50 -0
  384. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  385. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  386. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  387. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  388. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  389. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +421 -0
  390. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +465 -0
  391. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +288 -0
  392. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +200 -0
  393. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +197 -0
  394. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +141 -0
  395. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +519 -0
  396. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +723 -0
  397. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +750 -0
  398. data/lib/omnizip/io/buffered_input.rb +146 -0
  399. data/lib/omnizip/io/buffered_output.rb +105 -0
  400. data/lib/omnizip/io/stream_manager.rb +115 -0
  401. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  402. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  403. data/lib/omnizip/link_handler.rb +124 -0
  404. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  405. data/lib/omnizip/metadata/entry_metadata.rb +146 -0
  406. data/lib/omnizip/metadata/metadata_editor.rb +171 -0
  407. data/lib/omnizip/metadata/metadata_registry.rb +64 -0
  408. data/lib/omnizip/metadata/metadata_validator.rb +99 -0
  409. data/lib/omnizip/metadata.rb +57 -0
  410. data/lib/omnizip/models/.keep +0 -0
  411. data/lib/omnizip/models/algorithm_metadata.rb +73 -0
  412. data/lib/omnizip/models/compression_options.rb +71 -0
  413. data/lib/omnizip/models/conversion_options.rb +87 -0
  414. data/lib/omnizip/models/conversion_result.rb +135 -0
  415. data/lib/omnizip/models/eta_result.rb +46 -0
  416. data/lib/omnizip/models/extraction_rule.rb +115 -0
  417. data/lib/omnizip/models/filter_chain.rb +144 -0
  418. data/lib/omnizip/models/filter_config.rb +183 -0
  419. data/lib/omnizip/models/match_result.rb +124 -0
  420. data/lib/omnizip/models/optimization_suggestion.rb +91 -0
  421. data/lib/omnizip/models/parallel_options.rb +104 -0
  422. data/lib/omnizip/models/performance_result.rb +79 -0
  423. data/lib/omnizip/models/profile_report.rb +82 -0
  424. data/lib/omnizip/models/progress_options.rb +38 -0
  425. data/lib/omnizip/models/split_options.rb +116 -0
  426. data/lib/omnizip/optimization_registry.rb +81 -0
  427. data/lib/omnizip/parallel/job_queue.rb +209 -0
  428. data/lib/omnizip/parallel/job_scheduler.rb +203 -0
  429. data/lib/omnizip/parallel/parallel_compressor.rb +347 -0
  430. data/lib/omnizip/parallel/parallel_extractor.rb +329 -0
  431. data/lib/omnizip/parallel/worker_pool.rb +223 -0
  432. data/lib/omnizip/parallel.rb +149 -0
  433. data/lib/omnizip/parity/chunked_block_processor.rb +196 -0
  434. data/lib/omnizip/parity/galois16.rb +145 -0
  435. data/lib/omnizip/parity/models/creator_packet.rb +73 -0
  436. data/lib/omnizip/parity/models/file_description_packet.rb +133 -0
  437. data/lib/omnizip/parity/models/ifsc_packet.rb +123 -0
  438. data/lib/omnizip/parity/models/main_packet.rb +128 -0
  439. data/lib/omnizip/parity/models/packet.rb +156 -0
  440. data/lib/omnizip/parity/models/packet_registry.rb +109 -0
  441. data/lib/omnizip/parity/models/recovery_slice_packet.rb +78 -0
  442. data/lib/omnizip/parity/par2_creator.rb +531 -0
  443. data/lib/omnizip/parity/par2_repairer.rb +407 -0
  444. data/lib/omnizip/parity/par2_verifier.rb +364 -0
  445. data/lib/omnizip/parity/par2cmdline_algorithm.rb +110 -0
  446. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  447. data/lib/omnizip/parity/reed_solomon_decoder.rb +266 -0
  448. data/lib/omnizip/parity/reed_solomon_encoder.rb +111 -0
  449. data/lib/omnizip/parity/reed_solomon_matrix.rb +342 -0
  450. data/lib/omnizip/parity.rb +186 -0
  451. data/lib/omnizip/password/encryption_registry.rb +65 -0
  452. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  453. data/lib/omnizip/password/password_validator.rb +129 -0
  454. data/lib/omnizip/password/winzip_aes_strategy.rb +192 -0
  455. data/lib/omnizip/password/zip_crypto_strategy.rb +141 -0
  456. data/lib/omnizip/password.rb +87 -0
  457. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  458. data/lib/omnizip/pipe/stream_decompressor.rb +174 -0
  459. data/lib/omnizip/pipe.rb +121 -0
  460. data/lib/omnizip/platform/ntfs_streams.rb +201 -0
  461. data/lib/omnizip/platform.rb +189 -0
  462. data/lib/omnizip/profile/archive_profile.rb +39 -0
  463. data/lib/omnizip/profile/balanced_profile.rb +33 -0
  464. data/lib/omnizip/profile/binary_profile.rb +36 -0
  465. data/lib/omnizip/profile/compression_profile.rb +158 -0
  466. data/lib/omnizip/profile/custom_profile.rb +157 -0
  467. data/lib/omnizip/profile/fast_profile.rb +33 -0
  468. data/lib/omnizip/profile/maximum_profile.rb +33 -0
  469. data/lib/omnizip/profile/profile_detector.rb +110 -0
  470. data/lib/omnizip/profile/profile_registry.rb +161 -0
  471. data/lib/omnizip/profile/text_profile.rb +36 -0
  472. data/lib/omnizip/profile.rb +190 -0
  473. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  474. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  475. data/lib/omnizip/profiler/report_generator.rb +169 -0
  476. data/lib/omnizip/profiler.rb +204 -0
  477. data/lib/omnizip/progress/callback_reporter.rb +36 -0
  478. data/lib/omnizip/progress/console_reporter.rb +62 -0
  479. data/lib/omnizip/progress/log_reporter.rb +91 -0
  480. data/lib/omnizip/progress/operation_progress.rb +118 -0
  481. data/lib/omnizip/progress/progress_bar.rb +156 -0
  482. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  483. data/lib/omnizip/progress/progress_tracker.rb +190 -0
  484. data/lib/omnizip/progress/silent_reporter.rb +24 -0
  485. data/lib/omnizip/progress.rb +127 -0
  486. data/lib/omnizip/rubyzip_compat.rb +63 -0
  487. data/lib/omnizip/temp/safe_extract.rb +168 -0
  488. data/lib/omnizip/temp/temp_file.rb +124 -0
  489. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  490. data/lib/omnizip/temp.rb +181 -0
  491. data/lib/omnizip/version.rb +5 -0
  492. data/lib/omnizip/zip/entry.rb +156 -0
  493. data/lib/omnizip/zip/file.rb +485 -0
  494. data/lib/omnizip/zip/input_stream.rb +273 -0
  495. data/lib/omnizip/zip/output_stream.rb +324 -0
  496. data/lib/omnizip.rb +156 -0
  497. data/readme-docs/advanced-features.adoc +515 -0
  498. data/readme-docs/api-usage.adoc +444 -0
  499. data/readme-docs/architecture.adoc +449 -0
  500. data/readme-docs/archive-formats.adoc +479 -0
  501. data/readme-docs/cli-usage.adoc +222 -0
  502. data/readme-docs/compression-algorithms.adoc +442 -0
  503. data/readme-docs/compression-profiles.adoc +247 -0
  504. data/readme-docs/encryption-checksums.adoc +328 -0
  505. data/readme-docs/format-converter.adoc +325 -0
  506. data/readme-docs/installation.adoc +228 -0
  507. data/readme-docs/par2-archives.adoc +608 -0
  508. data/readme-docs/performance-profiler.adoc +389 -0
  509. data/readme-docs/preprocessing-filters.adoc +280 -0
  510. data/xz-file-format-1.2.1.txt +1174 -0
  511. metadata +617 -0
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "conversion_strategy"
4
+
5
+ module Omnizip
6
+ module Converter
7
+ # Convert ZIP archives to 7-Zip format
8
+ class ZipToSevenZipStrategy < ConversionStrategy
9
+ # Perform ZIP to 7z conversion
10
+ # @return [ConversionResult] Conversion result
11
+ def convert
12
+ start_time = Time.now
13
+ entry_count = 0
14
+
15
+ require_relative "../zip/file"
16
+ require_relative "../formats/seven_zip"
17
+
18
+ # Open source ZIP archive
19
+ Omnizip::Zip::File.open(source_path) do |zip|
20
+ # Collect all entries and their data
21
+ entries_data = collect_entries(zip)
22
+ entry_count = entries_data.size
23
+
24
+ # Create target 7z archive
25
+ create_seven_zip(entries_data)
26
+ end
27
+
28
+ create_result(start_time, entry_count)
29
+ end
30
+
31
+ # Get source format
32
+ # @return [Symbol] Source format (:zip)
33
+ def source_format
34
+ :zip
35
+ end
36
+
37
+ # Get target format
38
+ # @return [Symbol] Target format (:seven_zip)
39
+ def target_format
40
+ :seven_zip
41
+ end
42
+
43
+ # Check if can convert
44
+ # @param source [String] Source file
45
+ # @param target [String] Target file
46
+ # @return [Boolean] True if can convert
47
+ def self.can_convert?(source, target)
48
+ source.end_with?(".zip") && target.end_with?(".7z")
49
+ end
50
+
51
+ private
52
+
53
+ def collect_entries(zip)
54
+ entries = []
55
+
56
+ zip.entries.each do |entry|
57
+ data = {
58
+ name: entry.name,
59
+ directory: entry.directory?,
60
+ mtime: entry.time,
61
+ content: nil,
62
+ }
63
+
64
+ unless entry.directory?
65
+ data[:content] = zip.get_input_stream(entry)
66
+
67
+ if options.preserve_metadata && entry.unix_perms.positive?
68
+ data[:unix_perms] = entry.unix_perms
69
+ end
70
+ end
71
+
72
+ entries << data
73
+ end
74
+
75
+ entries
76
+ end
77
+
78
+ def create_seven_zip(entries)
79
+ writer = Omnizip::Formats::SevenZip::Writer.new(target_path)
80
+
81
+ # Set compression options
82
+ compression = options.compression || :lzma2
83
+ level = options.compression_level || 5
84
+ options.solid.nil? || options.solid
85
+
86
+ # Add each entry
87
+ entries.each do |entry_data|
88
+ if entry_data[:directory]
89
+ # 7z doesn't have explicit directory entries
90
+ # Directories are implied by file paths
91
+ next
92
+ end
93
+
94
+ writer.add_data(
95
+ entry_data[:name],
96
+ entry_data[:content],
97
+ algorithm: compression,
98
+ level: level,
99
+ )
100
+ end
101
+
102
+ # Apply filter if specified
103
+ if options.filter
104
+ add_warning("Filters not yet supported in 7z conversion")
105
+ end
106
+
107
+ # Write the archive
108
+ writer.write
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "models/conversion_options"
4
+ require_relative "models/conversion_result"
5
+ require_relative "converter/conversion_strategy"
6
+ require_relative "converter/zip_to_seven_zip_strategy"
7
+ require_relative "converter/seven_zip_to_zip_strategy"
8
+ require_relative "converter/conversion_registry"
9
+
10
+ module Omnizip
11
+ # Archive format conversion module
12
+ # Provides conversion between different archive formats
13
+ module Converter
14
+ class << self
15
+ # Convert archive from one format to another
16
+ # @param source_path [String] Source archive path
17
+ # @param target_path [String] Target archive path
18
+ # @param options [Hash, ConversionOptions] Conversion options
19
+ # @return [ConversionResult] Conversion result
20
+ def convert(source_path, target_path, **options)
21
+ # Find appropriate strategy first
22
+ strategy_class = ConversionRegistry.find_strategy(source_path,
23
+ target_path)
24
+ unless strategy_class
25
+ raise ArgumentError, "No conversion strategy available for " \
26
+ "#{source_path} -> #{target_path}"
27
+ end
28
+
29
+ # Then validate input files
30
+ unless File.exist?(source_path)
31
+ raise Errno::ENOENT, "Source file not found: #{source_path}"
32
+ end
33
+
34
+ # Create options object
35
+ opts = options.is_a?(Models::ConversionOptions) ? options : create_options(**options)
36
+ opts.validate
37
+
38
+ # Perform conversion
39
+ strategy = strategy_class.new(source_path, target_path, opts)
40
+ result = strategy.convert
41
+
42
+ # Delete source if requested
43
+ File.delete(source_path) if opts.delete_source && File.exist?(source_path)
44
+
45
+ result
46
+ end
47
+
48
+ # Convert with explicit options object
49
+ # @param source_path [String] Source archive path
50
+ # @param target_path [String] Target archive path
51
+ # @param options [ConversionOptions] Conversion options
52
+ # @return [ConversionResult] Conversion result
53
+ def convert_with_options(source_path, target_path, options)
54
+ convert(source_path, target_path, options)
55
+ end
56
+
57
+ # Check if conversion is supported
58
+ # @param source_path [String] Source archive path
59
+ # @param target_path [String] Target archive path
60
+ # @return [Boolean] True if conversion is supported
61
+ def supported?(source_path, target_path)
62
+ ConversionRegistry.supported?(source_path, target_path)
63
+ end
64
+
65
+ # Get available conversion strategies
66
+ # @return [Array<Class>] List of strategy classes
67
+ def strategies
68
+ ConversionRegistry.strategies
69
+ end
70
+
71
+ # Batch convert multiple archives
72
+ # @param sources [Array<String>] Source file paths
73
+ # @param target_format [Symbol] Target format (:zip or :seven_zip)
74
+ # @param options [Hash] Conversion options
75
+ # @yield [result] Optional block called for each conversion
76
+ # @return [Array<ConversionResult>] Conversion results
77
+ def batch_convert(sources, target_format: :seven_zip, **options, &block)
78
+ results = []
79
+
80
+ sources.each do |source|
81
+ target = generate_target_path(source, target_format)
82
+ result = convert(source, target, target_format: target_format,
83
+ **options)
84
+ results << result
85
+ yield(result) if block
86
+ end
87
+
88
+ results
89
+ end
90
+
91
+ private
92
+
93
+ def create_options(**options)
94
+ Models::ConversionOptions.new(**options)
95
+ end
96
+
97
+ def generate_target_path(source, target_format)
98
+ base = File.basename(source, File.extname(source))
99
+ dir = File.dirname(source)
100
+ ext = target_format == :seven_zip ? ".7z" : ".zip"
101
+ File.join(dir, base + ext)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 Ribose Inc.
4
+
5
+ require "openssl"
6
+ require_relative "constants"
7
+
8
+ module Omnizip
9
+ module Crypto
10
+ class Aes256
11
+ # AES-256-CBC cipher operations
12
+ #
13
+ # Wraps OpenSSL's AES-256-CBC implementation with proper
14
+ # padding and error handling for 7-Zip compatibility.
15
+ class Cipher
16
+ include Constants
17
+
18
+ attr_reader :key, :iv
19
+
20
+ # Initialize cipher with key and IV
21
+ #
22
+ # @param key [String] 32-byte AES-256 key
23
+ # @param iv [String] 16-byte initialization vector
24
+ def initialize(key, iv)
25
+ validate_key_iv(key, iv)
26
+ @key = key
27
+ @iv = iv
28
+ end
29
+
30
+ # Encrypt data using AES-256-CBC
31
+ #
32
+ # @param plaintext [String] Data to encrypt
33
+ # @return [String] Encrypted data
34
+ def encrypt(plaintext)
35
+ cipher = create_cipher(:encrypt)
36
+
37
+ # Handle empty data - just call final() for padding
38
+ if plaintext.empty?
39
+ return cipher.final
40
+ end
41
+
42
+ result = cipher.update(plaintext)
43
+ result << cipher.final
44
+
45
+ result
46
+ end
47
+
48
+ # Decrypt data using AES-256-CBC
49
+ #
50
+ # @param ciphertext [String] Encrypted data
51
+ # @return [String] Decrypted data
52
+ def decrypt(ciphertext)
53
+ cipher = create_cipher(:decrypt)
54
+
55
+ # Handle empty or very small ciphertext
56
+ if ciphertext.empty?
57
+ return ""
58
+ end
59
+
60
+ result = cipher.update(ciphertext)
61
+ result << cipher.final
62
+
63
+ result
64
+ end
65
+
66
+ private
67
+
68
+ # Validate key and IV parameters
69
+ #
70
+ # @param key [String] Key to validate
71
+ # @param iv [String] IV to validate
72
+ # @return [void]
73
+ # @raise [ArgumentError] If key or IV invalid
74
+ def validate_key_iv(key, iv)
75
+ if key.bytesize != KEY_SIZE
76
+ raise ArgumentError,
77
+ "Key must be #{KEY_SIZE} bytes"
78
+ end
79
+ return unless iv.bytesize != IV_SIZE
80
+
81
+ raise ArgumentError,
82
+ "IV must be #{IV_SIZE} bytes"
83
+ end
84
+
85
+ # Create OpenSSL cipher instance
86
+ #
87
+ # @param mode [Symbol] :encrypt or :decrypt
88
+ # @return [OpenSSL::Cipher] Configured cipher
89
+ def create_cipher(mode)
90
+ cipher = OpenSSL::Cipher.new("AES-256-CBC")
91
+ cipher.send(mode) # Call encrypt or decrypt first
92
+ cipher.key = @key # Then set key
93
+ cipher.iv = @iv # Then set IV
94
+ cipher.padding = 1 # PKCS7 padding
95
+ cipher
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 Ribose Inc.
4
+
5
+ module Omnizip
6
+ module Crypto
7
+ class Aes256
8
+ # Constants for AES-256 encryption in 7-Zip format
9
+ module Constants
10
+ # Key size for AES-256 (32 bytes = 256 bits)
11
+ KEY_SIZE = 32
12
+
13
+ # Maximum salt size (16 bytes)
14
+ SALT_SIZE_MAX = 16
15
+ SALT_SIZE = 16
16
+
17
+ # IV size (16 bytes = AES block size)
18
+ IV_SIZE = 16
19
+ BLOCK_SIZE = 16
20
+
21
+ # Default number of SHA-256 cycles (2^19 = 524288)
22
+ DEFAULT_CYCLES_POWER = 19
23
+ MIN_CYCLES_POWER = 0
24
+ MAX_CYCLES_POWER = 24
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 Ribose Inc.
4
+
5
+ require "digest/sha2"
6
+ require_relative "constants"
7
+
8
+ module Omnizip
9
+ module Crypto
10
+ class Aes256
11
+ # 7-Zip password-based key derivation
12
+ #
13
+ # Uses SHA-256 iterative hashing to derive encryption keys
14
+ # from passwords. The number of iterations is 2^cycles_power.
15
+ class KeyDerivation
16
+ include Constants
17
+
18
+ # Derive AES-256 key from password
19
+ #
20
+ # This implements 7-Zip's key derivation:
21
+ # 1. Concatenate salt and password
22
+ # 2. Hash with SHA-256 for 2^cycles_power iterations
23
+ # 3. Extract first 32 bytes as key
24
+ #
25
+ # @param password [String] User password
26
+ # @param salt [String] Random salt
27
+ # @param cycles_power [Integer] Power of 2 for iterations
28
+ # @return [String] 32-byte AES-256 key
29
+ def self.derive_key(password, salt, cycles_power = DEFAULT_CYCLES_POWER)
30
+ validate_inputs(password, salt, cycles_power)
31
+
32
+ # Calculate number of iterations
33
+ num_cycles = 1 << cycles_power
34
+
35
+ # Initial input: salt + password (in UTF-16LE for 7-Zip compat)
36
+ # Force binary encoding to make concatenation work
37
+ encoded_password = encode_password(password).force_encoding(Encoding::BINARY)
38
+ input = salt.dup.force_encoding(Encoding::BINARY) + encoded_password
39
+
40
+ # Iterative SHA-256 hashing
41
+ key = perform_hashing(input, num_cycles)
42
+
43
+ # Return first 32 bytes
44
+ key[0, KEY_SIZE]
45
+ end
46
+
47
+ # Validate key derivation inputs
48
+ #
49
+ # @param password [String] Password to validate
50
+ # @param salt [String] Salt to validate
51
+ # @param cycles_power [Integer] Cycles power to validate
52
+ # @return [void]
53
+ # @raise [ArgumentError] If inputs are invalid
54
+ def self.validate_inputs(password, salt, cycles_power)
55
+ if password.nil? || password.empty?
56
+ raise ArgumentError,
57
+ "Password cannot be empty"
58
+ end
59
+ if salt.bytesize != SALT_SIZE
60
+ raise ArgumentError,
61
+ "Salt must be #{SALT_SIZE} bytes"
62
+ end
63
+
64
+ return if cycles_power.between?(MIN_CYCLES_POWER, MAX_CYCLES_POWER)
65
+
66
+ raise ArgumentError,
67
+ "Cycles power must be between #{MIN_CYCLES_POWER} and #{MAX_CYCLES_POWER}"
68
+ end
69
+
70
+ # Encode password to UTF-16LE (7-Zip format)
71
+ #
72
+ # @param password [String] Password in any encoding
73
+ # @return [String] UTF-16LE encoded password
74
+ def self.encode_password(password)
75
+ password.encode(Encoding::UTF_16LE)
76
+ end
77
+
78
+ # Perform iterative SHA-256 hashing
79
+ #
80
+ # @param input [String] Initial input (salt + password)
81
+ # @param num_cycles [Integer] Number of hash iterations
82
+ # @return [String] Final hash result
83
+ def self.perform_hashing(input, num_cycles)
84
+ digest = Digest::SHA256.new
85
+ result = input
86
+
87
+ num_cycles.times do
88
+ digest.reset
89
+ digest << result
90
+ result = digest.digest
91
+ end
92
+
93
+ result
94
+ end
95
+
96
+ private_class_method :validate_inputs, :encode_password,
97
+ :perform_hashing
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 Ribose Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a
6
+ # copy of this software and associated documentation files (the "Software"),
7
+ # to deal in the Software without restriction, including without limitation
8
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ # and/or sell copies of the Software, and to permit persons to whom the
10
+ # Software is furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
+ # DEALINGS IN THE SOFTWARE.
22
+
23
+ require "openssl"
24
+ require "digest/sha2"
25
+ require_relative "aes256/constants"
26
+ require_relative "aes256/key_derivation"
27
+ require_relative "aes256/cipher"
28
+
29
+ module Omnizip
30
+ module Crypto
31
+ # AES-256 encryption for 7-Zip archives
32
+ #
33
+ # Implements 7-Zip's AES-256-CBC encryption with:
34
+ # - Password-based key derivation (SHA-256)
35
+ # - Configurable salt and cycles
36
+ # - CBC mode with IV
37
+ #
38
+ # This follows 7-Zip's encryption specification.
39
+ class Aes256
40
+ include Constants
41
+
42
+ # Encrypt data with AES-256
43
+ #
44
+ # @param data [String] Data to encrypt
45
+ # @param password [String] Encryption password
46
+ # @param options [Hash] Encryption options
47
+ # @option options [Integer] :num_cycles_power Power of 2 for key
48
+ # derivation iterations
49
+ # @option options [String] :salt Random salt (auto-generated if nil)
50
+ # @option options [String] :iv Initialization vector
51
+ # (auto-generated if nil)
52
+ # @return [Hash] Encrypted data with metadata
53
+ def self.encrypt(data, password, options = {})
54
+ salt = options[:salt] || generate_salt
55
+ iv = options[:iv] || generate_iv
56
+ cycles_power = options[:num_cycles_power] || DEFAULT_CYCLES_POWER
57
+
58
+ key = KeyDerivation.derive_key(password, salt, cycles_power)
59
+ cipher = Cipher.new(key, iv)
60
+
61
+ encrypted_data = cipher.encrypt(data)
62
+
63
+ {
64
+ data: encrypted_data,
65
+ salt: salt,
66
+ iv: iv,
67
+ cycles_power: cycles_power,
68
+ }
69
+ end
70
+
71
+ # Decrypt data with AES-256
72
+ #
73
+ # @param encrypted_data [String] Encrypted data
74
+ # @param password [String] Decryption password
75
+ # @param salt [String] Salt used during encryption
76
+ # @param iv [String] IV used during encryption
77
+ # @param cycles_power [Integer] Cycles power used during encryption
78
+ # @return [String] Decrypted data
79
+ def self.decrypt(encrypted_data, password, salt, iv, cycles_power)
80
+ key = KeyDerivation.derive_key(password, salt, cycles_power)
81
+ cipher = Cipher.new(key, iv)
82
+
83
+ cipher.decrypt(encrypted_data)
84
+ end
85
+
86
+ # Generate random salt
87
+ #
88
+ # @param size [Integer] Salt size in bytes (default 16)
89
+ # @return [String] Random salt
90
+ def self.generate_salt(size = SALT_SIZE)
91
+ OpenSSL::Random.random_bytes(size)
92
+ end
93
+
94
+ # Generate random IV
95
+ #
96
+ # @return [String] Random IV
97
+ def self.generate_iv
98
+ OpenSSL::Random.random_bytes(IV_SIZE)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 Ribose Inc.
4
+
5
+ module Omnizip
6
+ # Base error class for all Omnizip errors
7
+ class Error < StandardError
8
+ end
9
+
10
+ # Error raised when compression fails
11
+ class CompressionError < Error
12
+ end
13
+
14
+ # Error raised when decompression fails
15
+ class DecompressionError < Error
16
+ end
17
+
18
+ # Error raised when an algorithm is not found
19
+ class AlgorithmNotFoundError < Error
20
+ end
21
+
22
+ # Error raised when an unknown algorithm is requested
23
+ class UnknownAlgorithmError < Error
24
+ end
25
+
26
+ # Error raised when a format is not supported
27
+ class UnsupportedFormatError < Error
28
+ end
29
+
30
+ # Error raised when format parsing fails
31
+ class FormatError < Error
32
+ end
33
+
34
+ # Error raised when archive is invalid
35
+ class InvalidArchiveError < Error
36
+ end
37
+
38
+ # Error raised when I/O operations fail
39
+ class IOError < Error
40
+ end
41
+
42
+ # Error raised when checksum validation fails
43
+ class ChecksumError < Error
44
+ end
45
+
46
+ # Error raised when optimization strategy is not found
47
+ class OptimizationNotFound < Error
48
+ end
49
+
50
+ # Error raised when progress tracking fails
51
+ class ProgressError < Error
52
+ end
53
+
54
+ # Error raised when ETA calculation fails
55
+ class ETAError < Error
56
+ end
57
+
58
+ # Error raised when RAR write is attempted without license
59
+ class NotLicensedError < Error
60
+ def initialize(message = default_message)
61
+ super
62
+ end
63
+
64
+ private
65
+
66
+ def default_message
67
+ <<~MSG
68
+ RAR creation requires a licensed copy of WinRAR.
69
+
70
+ To use RAR creation:
71
+ 1. Purchase a WinRAR license from https://www.rarlab.com/
72
+ 2. Install WinRAR on your system
73
+ 3. Confirm license ownership when prompted
74
+
75
+ Alternatively, use 7z format which provides similar compression
76
+ with no licensing restrictions:
77
+
78
+ Omnizip::Formats::SevenZip.create('archive.7z') do |sz|
79
+ sz.add_directory('files/')
80
+ end
81
+ MSG
82
+ end
83
+ end
84
+
85
+ # Error raised when RAR executable is not found
86
+ class RarNotAvailableError < Error
87
+ def initialize(message = default_message)
88
+ super
89
+ end
90
+
91
+ private
92
+
93
+ def default_message
94
+ <<~MSG
95
+ WinRAR executable not found.
96
+
97
+ Please install WinRAR:
98
+ - Windows: Download from https://www.rarlab.com/
99
+ - Linux: Install 'rar' package (requires license)
100
+ - macOS: Install via Homebrew: brew install rar (requires license)
101
+
102
+ After installation, ensure 'rar' or 'Rar.exe' is in your PATH.
103
+ MSG
104
+ end
105
+ end
106
+ end