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,572 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (C) 2024 Ribose Inc.
5
+ #
6
+ # This file is part of Omnizip.
7
+ #
8
+ # Omnizip is a pure Ruby port of 7-Zip compression algorithms.
9
+ # Based on the 7-Zip LZMA SDK by Igor Pavlov.
10
+ #
11
+ # This library is free software; you can redistribute it and/or
12
+ # modify it under the terms of the GNU Lesser General Public
13
+ # License as published by the Free Software Foundation; either
14
+ # version 2.1 of the License, or (at your option) any later version.
15
+ #
16
+ # See the COPYING file for the complete text of the license.
17
+ #
18
+
19
+ require "thor"
20
+ require_relative "commands/compress_command"
21
+ require_relative "commands/decompress_command"
22
+ require_relative "commands/list_command"
23
+ require_relative "commands/archive_create_command"
24
+ require_relative "commands/archive_extract_command"
25
+ require_relative "commands/archive_list_command"
26
+ require_relative "commands/profile_list_command"
27
+ require_relative "commands/profile_show_command"
28
+ require_relative "commands/metadata_command"
29
+ require_relative "commands/archive_verify_command"
30
+ require_relative "commands/archive_repair_command"
31
+ require_relative "cli/output_formatter"
32
+
33
+ module Omnizip
34
+ # Profile commands subcommand group
35
+ class ProfileCommands < Thor
36
+ class << self
37
+ def exit_on_failure?
38
+ true
39
+ end
40
+ end
41
+
42
+ desc "list", "List available compression profiles"
43
+ long_desc <<~DESC
44
+ List all available compression profiles with their descriptions.
45
+
46
+ Examples:
47
+
48
+ $ omnizip profile list
49
+
50
+ $ omnizip profile list --verbose
51
+ DESC
52
+ option :verbose, type: :boolean, default: false,
53
+ aliases: "-v",
54
+ desc: "Show detailed information"
55
+ def list
56
+ Omnizip::Commands::ProfileListCommand.new(options).run
57
+ rescue StandardError => e
58
+ handle_error(e)
59
+ end
60
+
61
+ desc "show PROFILE", "Show profile details"
62
+ long_desc <<~DESC
63
+ Show detailed information about a specific compression profile.
64
+
65
+ PROFILE is the name of the profile to show.
66
+
67
+ Examples:
68
+
69
+ $ omnizip profile show maximum
70
+
71
+ $ omnizip profile show fast
72
+ DESC
73
+ def show(profile_name)
74
+ Omnizip::Commands::ProfileShowCommand.new(options).run(profile_name)
75
+ rescue StandardError => e
76
+ handle_error(e)
77
+ end
78
+
79
+ private
80
+
81
+ def handle_error(error)
82
+ warn Omnizip::CliOutputFormatter.format_error(error)
83
+ exit 1
84
+ end
85
+ end
86
+
87
+ # Archive commands subcommand group
88
+ class ArchiveCommands < Thor
89
+ class << self
90
+ def exit_on_failure?
91
+ true
92
+ end
93
+ end
94
+
95
+ desc "create OUTPUT INPUT...", "Create .7z or .rar archive"
96
+ long_desc <<~DESC
97
+ Create a .7z or .rar archive from files and directories.
98
+
99
+ OUTPUT is the path to the archive to create (.7z or .rar extension).
100
+ INPUT can be one or more files or directories to archive.
101
+
102
+ For split archives, OUTPUT should end with .001 (e.g., backup.7z.001).
103
+
104
+ RAR5 archives are created using pure Ruby (no external tools needed).
105
+ RAR5 currently supports individual files only (not directories).
106
+
107
+ Examples:
108
+
109
+ $ omnizip archive create archive.7z file1.txt file2.txt
110
+
111
+ $ omnizip archive create archive.7z dir/ --algorithm lzma2 \\
112
+ --level 9
113
+
114
+ $ omnizip archive create archive.7z file.txt --no-solid \\
115
+ --filters bcj_x86
116
+
117
+ $ omnizip archive create backup.7z.001 large_data/ --volume-size 100M
118
+
119
+ $ omnizip archive create backup.7z.001 files/ --volume-size 4.7GB
120
+
121
+ $ omnizip archive create archive.rar file1.txt file2.txt
122
+
123
+ $ omnizip archive create archive.rar data.txt --rar-compression lzma \\
124
+ --level 5 --include-mtime --include-crc32
125
+
126
+ $ omnizip archive create secure.rar data.txt --rar-compression lzma \\
127
+ --level 5 --password "SecurePass123!" --kdf-iterations 262144
128
+
129
+ $ omnizip archive create backup.rar files/ --rar-compression lzma \\
130
+ --level 5 --solid --multi-volume --volume-size 100M
131
+
132
+ $ omnizip archive create critical.rar data/ --rar-compression lzma \\
133
+ --level 5 --password "Secure2025!" --recovery --recovery-percent 10
134
+ DESC
135
+ option :format, type: :string,
136
+ desc: "Archive format (7z or rar, default: auto-detect from extension)"
137
+ option :profile, type: :string,
138
+ desc: "Compression profile (fast, balanced, maximum, text, binary, archive, auto)"
139
+ option :algorithm, type: :string, default: "lzma2",
140
+ desc: "Compression algorithm for 7z (lzma, lzma2, ppmd7, bzip2)"
141
+ option :level, type: :numeric, default: 5,
142
+ desc: "Compression level (1-9 for 7z, 1-5 for RAR5)"
143
+ option :solid, type: :boolean, default: true,
144
+ desc: "Use solid compression (default: true for 7z, false for RAR)"
145
+ option :filters, type: :string,
146
+ desc: "Filter chain for 7z (e.g., bcj_x86,delta)"
147
+ option :volume_size, type: :string,
148
+ desc: "Volume size for split archives (e.g., 100M, 650MB, 4.7GB)"
149
+ option :password, type: :string,
150
+ desc: "Password for encryption (7z: header encryption, RAR5: AES-256-CBC)"
151
+ option :encrypt_headers, type: :boolean, default: false,
152
+ desc: "Encrypt archive headers (7z only, hides filenames)"
153
+ option :preserve_ntfs_streams, type: :boolean, default: false,
154
+ desc: "Preserve NTFS alternate data streams (Windows only, 7z only)"
155
+ option :rar_version, type: :numeric, default: 5,
156
+ desc: "RAR version (4 or 5, default: 5 for pure Ruby)"
157
+ option :rar_compression, type: :string, default: "store",
158
+ desc: "RAR compression method (store, lzma, auto)"
159
+ option :include_mtime, type: :boolean, default: false,
160
+ desc: "Include modification time in RAR5 file headers"
161
+ option :include_crc32, type: :boolean, default: false,
162
+ desc: "Include CRC32 checksum in RAR5 file headers"
163
+ option :multi_volume, type: :boolean, default: false,
164
+ desc: "Create multi-volume RAR5 archive (requires --volume-size)"
165
+ option :volume_naming, type: :string, default: "part",
166
+ desc: "Volume naming pattern for RAR5 (part, volume, numeric)"
167
+ option :kdf_iterations, type: :numeric, default: 262_144,
168
+ desc: "PBKDF2 iterations for RAR5 encryption (65536-1048576, default: 262144)"
169
+ option :recovery, type: :boolean, default: false,
170
+ desc: "Generate PAR2 recovery records for RAR5"
171
+ option :recovery_percent, type: :numeric, default: 5,
172
+ desc: "PAR2 redundancy percentage for RAR5 (0-100, default: 5)"
173
+ option :verbose, type: :boolean, default: false,
174
+ aliases: "-v",
175
+ desc: "Enable verbose output"
176
+ def create(output, *inputs)
177
+ Omnizip::Commands::ArchiveCreateCommand.new(options).run(output, *inputs)
178
+ rescue StandardError => e
179
+ handle_error(e)
180
+ end
181
+
182
+ desc "extract ARCHIVE [OUTPUT_DIR]", "Extract archive"
183
+ long_desc <<~DESC
184
+ Extract a .7z, .zip, or .rar archive to a directory.
185
+
186
+ ARCHIVE is the path to the archive to extract.
187
+ OUTPUT_DIR is the directory to extract to (default: current directory).
188
+
189
+ Pattern extraction options allow selective extraction of files.
190
+
191
+ Examples:
192
+
193
+ $ omnizip archive extract archive.zip
194
+
195
+ $ omnizip archive extract archive.zip output/ --verbose
196
+
197
+ $ omnizip archive extract archive.zip output/ --pattern '**/*.txt'
198
+
199
+ $ omnizip archive extract archive.zip output/ \\
200
+ --pattern '*.txt' --pattern '*.md'
201
+
202
+ $ omnizip archive extract archive.zip output/ \\
203
+ --pattern '**/*' --exclude '**/*.tmp' --exclude '**/test/**'
204
+
205
+ $ omnizip archive extract archive.zip output/ \\
206
+ --regex '\\.log$'
207
+
208
+ $ omnizip archive extract archive.zip output/ \\
209
+ --pattern 'src/**/*.rb' --flatten
210
+ DESC
211
+ option :verbose, type: :boolean, default: false,
212
+ aliases: "-v",
213
+ desc: "Enable verbose output"
214
+ option :pattern, type: :array,
215
+ desc: "Include pattern(s) for selective extraction"
216
+ option :exclude, type: :array,
217
+ desc: "Exclude pattern(s) for selective extraction"
218
+ option :regex, type: :string,
219
+ desc: "Regular expression pattern for selective extraction"
220
+ option :flatten, type: :boolean, default: false,
221
+ desc: "Extract all files to output root (ignore paths)"
222
+ option :count, type: :boolean, default: false,
223
+ desc: "Count matches without extracting"
224
+ def extract(archive, output_dir = nil)
225
+ Omnizip::Commands::ArchiveExtractCommand.new(options).run(archive,
226
+ output_dir)
227
+ rescue StandardError => e
228
+ handle_error(e)
229
+ end
230
+
231
+ desc "list ARCHIVE", "List archive contents"
232
+ long_desc <<~DESC
233
+ List the contents of a .7z, .zip, or .rar archive.
234
+
235
+ ARCHIVE is the path to the archive to list.
236
+
237
+ Pattern filtering options allow listing only matching files.
238
+
239
+ Examples:
240
+
241
+ $ omnizip archive list archive.zip
242
+
243
+ $ omnizip archive list archive.zip --verbose
244
+
245
+ $ omnizip archive list archive.zip --pattern '**/*.rb'
246
+
247
+ $ omnizip archive list archive.zip --pattern '*.txt' --count
248
+ DESC
249
+ option :verbose, type: :boolean, default: false,
250
+ aliases: "-v",
251
+ desc: "Enable verbose output"
252
+ option :pattern, type: :array,
253
+ desc: "Include pattern(s) for filtering"
254
+ option :exclude, type: :array,
255
+ desc: "Exclude pattern(s) for filtering"
256
+ option :count, type: :boolean, default: false,
257
+ desc: "Show count of matches"
258
+ def list(archive)
259
+ Omnizip::Commands::ArchiveListCommand.new(options).run(archive)
260
+ rescue StandardError => e
261
+ handle_error(e)
262
+ end
263
+
264
+ desc "metadata ARCHIVE [PATTERN]", "View or edit archive metadata"
265
+ long_desc <<~DESC
266
+ View or edit metadata for archives and entries.
267
+
268
+ ARCHIVE is the path to the archive.
269
+ PATTERN is an optional entry name or glob pattern.
270
+
271
+ Examples:
272
+
273
+ # View archive metadata
274
+ $ omnizip archive metadata archive.zip --show
275
+
276
+ # View entry metadata
277
+ $ omnizip archive metadata archive.zip file.txt --show
278
+
279
+ # Set archive comment
280
+ $ omnizip archive metadata archive.zip --comment "My backup"
281
+
282
+ # Set entry comment
283
+ $ omnizip archive metadata archive.zip file.txt --comment "Important"
284
+
285
+ # Set modification time
286
+ $ omnizip archive metadata archive.zip file.txt --set-mtime now
287
+
288
+ # Set permissions
289
+ $ omnizip archive metadata archive.zip '*.rb' --chmod 755
290
+ DESC
291
+ option :show, type: :boolean, default: false,
292
+ desc: "Show metadata (read-only)"
293
+ option :comment, type: :string,
294
+ desc: "Set comment"
295
+ option :set_mtime, type: :string,
296
+ desc: "Set modification time (e.g., 'now', '2024-01-01')"
297
+ option :chmod, type: :string,
298
+ desc: "Set Unix permissions (e.g., '755', '0644')"
299
+ option :set_attribute, type: :string,
300
+ desc: "Set attribute flag (readonly, hidden, system, archive)"
301
+ option :verbose, type: :boolean, default: false,
302
+ aliases: "-v",
303
+ desc: "Enable verbose output"
304
+ def metadata(archive, pattern = nil)
305
+ Omnizip::Commands::MetadataCommand.new(options).run(archive, pattern)
306
+ rescue StandardError => e
307
+ handle_error(e)
308
+ end
309
+
310
+ private
311
+
312
+ def handle_error(error)
313
+ warn Omnizip::CliOutputFormatter.format_error(error)
314
+ exit 1
315
+ end
316
+ end
317
+
318
+ # Command-line interface for Omnizip.
319
+ #
320
+ # Provides Thor-based CLI commands for compressing and decompressing
321
+ # files using various compression algorithms.
322
+ class Cli < Thor
323
+ class << self
324
+ def exit_on_failure?
325
+ true
326
+ end
327
+ end
328
+
329
+ desc "compress INPUT OUTPUT", "Compress a file or stream"
330
+ long_desc <<~DESC
331
+ Compress INPUT file and write the result to OUTPUT file.
332
+
333
+ Use '-' for INPUT to read from stdin or OUTPUT to write to stdout.
334
+ This enables Unix pipeline integration for streaming workflows.
335
+
336
+ The compression algorithm and level can be specified with options.
337
+ By default, LZMA compression is used with level 5.
338
+
339
+ Examples:
340
+
341
+ $ omnizip compress input.txt output.lzma
342
+
343
+ $ omnizip compress input.txt output.lzma --level 9 --verbose
344
+
345
+ $ cat input.txt | omnizip compress - output.zip --format zip
346
+
347
+ $ omnizip compress input.txt - --format zip > output.zip
348
+
349
+ $ cat data.txt | omnizip compress - - --format zip > out.zip
350
+ DESC
351
+ option :algorithm, type: :string, default: "lzma",
352
+ desc: "Compression algorithm to use"
353
+ option :format, type: :string, default: nil,
354
+ desc: "Archive format (zip, 7z) - enables pipe mode"
355
+ option :level, type: :numeric, default: 5,
356
+ desc: "Compression level (1-9)"
357
+ option :entry_name, type: :string, default: nil,
358
+ desc: "Entry name in archive (pipe mode only)"
359
+ option :verbose, type: :boolean, default: false,
360
+ aliases: "-v",
361
+ desc: "Enable verbose output"
362
+ def compress(input, output)
363
+ # Pipe mode: use streaming compression
364
+ if Omnizip::Pipe.stdin?(input) || Omnizip::Pipe.stdout?(output)
365
+ compress_pipe(input, output)
366
+ else
367
+ Commands::CompressCommand.new(options).run(input, output)
368
+ end
369
+ rescue StandardError => e
370
+ handle_error(e)
371
+ end
372
+
373
+ desc "decompress INPUT OUTPUT", "Decompress a file or stream"
374
+ long_desc <<~DESC
375
+ Decompress INPUT file and write the result to OUTPUT file or directory.
376
+
377
+ Use '-' for INPUT to read from stdin. If OUTPUT is a directory,
378
+ extracts all files. If OUTPUT is '-', streams first file to stdout.
379
+
380
+ The algorithm will be auto-detected from the compressed file,
381
+ or can be explicitly specified with the --algorithm option.
382
+
383
+ Examples:
384
+
385
+ $ omnizip decompress output.lzma restored.txt
386
+
387
+ $ omnizip decompress output.lzma restored.txt --verbose
388
+
389
+ $ cat archive.zip | omnizip decompress - extracted/
390
+
391
+ $ omnizip decompress - - < archive.zip > output.txt
392
+
393
+ $ cat archive.zip | omnizip decompress - extracted/ --verbose
394
+ DESC
395
+ option :algorithm, type: :string,
396
+ desc: "Decompression algorithm (auto-detect if omitted)"
397
+ option :verbose, type: :boolean, default: false,
398
+ aliases: "-v",
399
+ desc: "Enable verbose output"
400
+ def decompress(input, output)
401
+ # Pipe mode: use streaming decompression
402
+ if Omnizip::Pipe.stdin?(input) || Omnizip::Pipe.stdout?(output)
403
+ decompress_pipe(input, output)
404
+ else
405
+ Commands::DecompressCommand.new(options).run(input, output)
406
+ end
407
+ rescue StandardError => e
408
+ handle_error(e)
409
+ end
410
+
411
+ desc "list", "List available compression algorithms"
412
+ long_desc <<~DESC
413
+ List all registered compression algorithms with their metadata.
414
+
415
+ Displays algorithm name, description, and version information.
416
+
417
+ Example:
418
+
419
+ $ omnizip list
420
+ DESC
421
+ option :verbose, type: :boolean, default: false,
422
+ aliases: "-v",
423
+ desc: "Enable verbose output"
424
+ def list
425
+ Commands::ListCommand.new(options).run
426
+ rescue StandardError => e
427
+ handle_error(e)
428
+ end
429
+
430
+ desc "version", "Display version information"
431
+ def version
432
+ puts "Omnizip v#{Omnizip::VERSION}"
433
+ puts "Pure Ruby implementation of LZMA compression"
434
+ end
435
+
436
+ desc "profile SUBCOMMAND ...ARGS", "Manage compression profiles"
437
+ subcommand "profile", ProfileCommands
438
+
439
+ desc "archive SUBCOMMAND ...ARGS", "Manage .7z archives"
440
+ subcommand "archive", ArchiveCommands
441
+ desc "convert SOURCE TARGET", "Convert archive between formats"
442
+ long_desc <<~DESC
443
+ Convert an archive from one format to another.
444
+
445
+ SOURCE is the path to the source archive (ZIP, 7z, or RAR).
446
+ TARGET is the path to the target archive (ZIP or 7z).
447
+ Note: RAR can only be a source (read-only), not a target.
448
+
449
+ Examples:
450
+
451
+ $ omnizip convert archive.zip archive.7z
452
+
453
+ $ omnizip convert archive.7z backup.zip
454
+
455
+ $ omnizip convert archive.zip archive.7z --compression lzma2 --level 9
456
+
457
+ $ omnizip convert archive.zip archive.7z --no-solid
458
+ DESC
459
+ option :compression, type: :string,
460
+ desc: "Compression algorithm (lzma, lzma2, ppmd7, bzip2)"
461
+ option :level, type: :numeric, default: 5,
462
+ desc: "Compression level (1-9)"
463
+ option :filter, type: :string,
464
+ desc: "Filter to apply (bcj-x86, delta, etc.)"
465
+ option :solid, type: :boolean, default: true,
466
+ desc: "Use solid compression for 7z (default: true)"
467
+ option :preserve_metadata, type: :boolean, default: true,
468
+ desc: "Preserve metadata (default: true)"
469
+ option :delete_source, type: :boolean, default: false,
470
+ desc: "Delete source after conversion"
471
+ option :verbose, type: :boolean, default: false,
472
+ aliases: "-v",
473
+ desc: "Enable verbose output"
474
+ def convert(source, target)
475
+ require_relative "converter"
476
+
477
+ puts "Converting #{source} to #{target}..." if options[:verbose]
478
+
479
+ result = Omnizip::Converter.convert(
480
+ source,
481
+ target,
482
+ compression: options[:compression]&.to_sym,
483
+ compression_level: options[:level],
484
+ filter: options[:filter]&.to_sym,
485
+ solid: options[:solid],
486
+ preserve_metadata: options[:preserve_metadata],
487
+ delete_source: options[:delete_source],
488
+ )
489
+
490
+ puts "Conversion complete!"
491
+ puts "Source: #{result.source_path} (#{format_bytes(result.source_size)})"
492
+ puts "Target: #{result.target_path} (#{format_bytes(result.target_size)})"
493
+ puts "Size change: #{result.size_reduction.round(1)}%"
494
+ puts "Duration: #{result.duration.round(2)}s"
495
+ puts "Entries: #{result.entry_count}"
496
+
497
+ if result.warnings?
498
+ puts "\nWarnings:"
499
+ result.warnings.each { |w| puts " - #{w}" }
500
+ end
501
+ rescue StandardError => e
502
+ handle_error(e)
503
+ end
504
+
505
+ map %w[-v --version] => :version
506
+
507
+ private
508
+
509
+ def compress_pipe(input, output)
510
+ input_io = input == "-" ? $stdin : File.open(input, "rb")
511
+ output_io = output == "-" ? $stdout : File.open(output, "wb")
512
+
513
+ format = (options[:format] || :zip).to_sym
514
+ compression = options[:algorithm]&.to_sym
515
+ entry_name = options[:entry_name] || File.basename(input == "-" ? "stream.dat" : input)
516
+
517
+ if options[:verbose]
518
+ warn "Compressing from #{input == '-' ? 'stdin' : input} to #{output == '-' ? 'stdout' : output}"
519
+ warn "Format: #{format}, Entry: #{entry_name}"
520
+ end
521
+
522
+ Omnizip::Pipe.compress(
523
+ input_io,
524
+ output_io,
525
+ format: format,
526
+ compression: compression,
527
+ entry_name: entry_name,
528
+ level: options[:level],
529
+ )
530
+
531
+ warn "Compression complete" if options[:verbose]
532
+ ensure
533
+ input_io.close if input_io && input != "-"
534
+ output_io.close if output_io && output != "-"
535
+ end
536
+
537
+ def decompress_pipe(input, output)
538
+ input_io = input == "-" ? $stdin : File.open(input, "rb")
539
+
540
+ if options[:verbose]
541
+ warn "Decompressing from #{input == '-' ? 'stdin' : input}"
542
+ end
543
+
544
+ if output == "-"
545
+ # Stream to stdout
546
+ Omnizip::Pipe.decompress(input_io, output: $stdout)
547
+ else
548
+ # Extract to directory
549
+ Omnizip::Pipe.decompress(input_io, output_dir: output)
550
+ end
551
+
552
+ warn "Decompression complete" if options[:verbose]
553
+ ensure
554
+ input_io.close if input_io && input != "-"
555
+ end
556
+
557
+ def handle_error(error)
558
+ warn CliOutputFormatter.format_error(error)
559
+ exit 1
560
+ end
561
+
562
+ def format_bytes(bytes)
563
+ return "0 B" if bytes.zero?
564
+
565
+ units = %w[B KB MB GB TB]
566
+ exp = (Math.log(bytes) / Math.log(1024)).to_i
567
+ exp = [exp, units.size - 1].min
568
+
569
+ "%.1f %s" % [bytes.to_f / (1024**exp), units[exp]]
570
+ end
571
+ end
572
+ end
File without changes