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,204 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "models/performance_result"
4
+ require_relative "models/profile_report"
5
+ require_relative "models/optimization_suggestion"
6
+
7
+ module Omnizip
8
+ # Main profiler interface using Strategy pattern for different profiling approaches
9
+ class Profiler
10
+ attr_reader :report, :enabled
11
+
12
+ def initialize(profile_name: "default", enabled: true)
13
+ @profile_name = profile_name
14
+ @enabled = enabled
15
+ @report = Models::ProfileReport.new(profile_name: profile_name)
16
+ @profilers = {}
17
+ end
18
+
19
+ # Register a profiler strategy
20
+ def register_profiler(name, profiler)
21
+ @profilers[name] = profiler
22
+ end
23
+
24
+ # Profile a block of code with the specified profiler strategy
25
+ def profile(operation_name, profiler_type: :method, &block)
26
+ return yield unless enabled
27
+
28
+ profiler = @profilers[profiler_type]
29
+ unless profiler
30
+ raise ArgumentError,
31
+ "Unknown profiler type: #{profiler_type}"
32
+ end
33
+
34
+ result = profiler.profile(operation_name, &block)
35
+ @report.add_result(result)
36
+ result
37
+ end
38
+
39
+ # Profile a method call with automatic naming
40
+ def profile_method(object, method_name, *args, profiler_type: :method,
41
+ **kwargs)
42
+ operation_name = "#{object.class}##{method_name}"
43
+ profile(operation_name, profiler_type: profiler_type) do
44
+ object.public_send(method_name, *args, **kwargs)
45
+ end
46
+ end
47
+
48
+ # Analyze collected results and identify hot paths
49
+ def analyze_hot_paths(threshold_percentage: 10.0)
50
+ total_time = report.total_execution_time
51
+ return [] if total_time.zero?
52
+
53
+ threshold_time = total_time * (threshold_percentage / 100.0)
54
+
55
+ hot_operations = report.results.select do |result|
56
+ result.total_time && result.total_time >= threshold_time
57
+ end
58
+
59
+ hot_operations.each do |op|
60
+ @report.add_hot_path(
61
+ operation: op.operation_name,
62
+ time: op.total_time,
63
+ percentage: (op.total_time / total_time) * 100,
64
+ )
65
+ end
66
+
67
+ hot_operations
68
+ end
69
+
70
+ # Identify performance bottlenecks
71
+ def identify_bottlenecks
72
+ bottlenecks = []
73
+
74
+ # Memory bottlenecks
75
+ memory_intensive = report.memory_intensive_operations(limit: 3)
76
+ memory_intensive.each do |op|
77
+ bottlenecks << {
78
+ type: :memory,
79
+ operation: op.operation_name,
80
+ allocated: op.memory_allocated,
81
+ severity: calculate_memory_severity(op),
82
+ }
83
+ @report.add_bottleneck(bottlenecks.last)
84
+ end
85
+
86
+ # CPU bottlenecks
87
+ cpu_intensive = report.slowest_operations(limit: 3)
88
+ cpu_intensive.each do |op|
89
+ bottlenecks << {
90
+ type: :cpu,
91
+ operation: op.operation_name,
92
+ time: op.total_time,
93
+ severity: calculate_cpu_severity(op),
94
+ }
95
+ @report.add_bottleneck(bottlenecks.last)
96
+ end
97
+
98
+ # GC pressure bottlenecks
99
+ high_gc = report.results.select do |r|
100
+ r.gc_pressure && r.gc_pressure > 1.0
101
+ end
102
+ high_gc.each do |op|
103
+ bottlenecks << {
104
+ type: :gc,
105
+ operation: op.operation_name,
106
+ gc_pressure: op.gc_pressure,
107
+ severity: :high,
108
+ }
109
+ @report.add_bottleneck(bottlenecks.last)
110
+ end
111
+
112
+ bottlenecks
113
+ end
114
+
115
+ # Generate optimization suggestions based on profiling data
116
+ def generate_suggestions
117
+ # Analyze hot paths for optimization opportunities
118
+ suggestions = analyze_hot_paths.map do |hot_op|
119
+ Models::OptimizationSuggestion.new(
120
+ title: "Optimize hot path: #{hot_op.operation_name}",
121
+ description: "Operation consuming #{hot_op.total_time}s " \
122
+ "(#{((hot_op.total_time / report.total_execution_time) * 100).round(1)}% of total time)",
123
+ severity: :high,
124
+ category: :hotpath,
125
+ impact_estimate: hot_op.total_time / report.total_execution_time,
126
+ related_operations: [hot_op.operation_name],
127
+ metrics: { time: hot_op.total_time },
128
+ )
129
+ end
130
+
131
+ # Analyze memory usage
132
+ report.memory_intensive_operations(limit: 3).each do |mem_op|
133
+ next unless mem_op.memory_allocated > 1_000_000 # > 1MB
134
+
135
+ suggestions << Models::OptimizationSuggestion.new(
136
+ title: "Reduce memory allocation: #{mem_op.operation_name}",
137
+ description: "Operation allocating #{format_bytes(mem_op.memory_allocated)}",
138
+ severity: calculate_memory_severity(mem_op),
139
+ category: :memory,
140
+ impact_estimate: mem_op.memory_allocated / report.total_memory_allocated.to_f,
141
+ related_operations: [mem_op.operation_name],
142
+ metrics: { memory_allocated: mem_op.memory_allocated },
143
+ )
144
+ end
145
+
146
+ suggestions.sort_by(&:priority_score).reverse
147
+ end
148
+
149
+ # Enable profiling
150
+ def enable!
151
+ @enabled = true
152
+ end
153
+
154
+ # Disable profiling
155
+ def disable!
156
+ @enabled = false
157
+ end
158
+
159
+ # Reset profiler state
160
+ def reset!
161
+ @report = Models::ProfileReport.new(profile_name: @profile_name)
162
+ end
163
+
164
+ private
165
+
166
+ def calculate_memory_severity(operation)
167
+ return :low unless operation.memory_allocated
168
+
169
+ mb = operation.memory_allocated / (1024.0 * 1024.0)
170
+ case mb
171
+ when 0...1 then :low
172
+ when 1...10 then :medium
173
+ when 10...50 then :high
174
+ else :critical
175
+ end
176
+ end
177
+
178
+ def calculate_cpu_severity(operation)
179
+ return :low unless operation.total_time
180
+
181
+ case operation.total_time
182
+ when 0...0.1 then :low
183
+ when 0.1...1.0 then :medium
184
+ when 1.0...5.0 then :high
185
+ else :critical
186
+ end
187
+ end
188
+
189
+ def format_bytes(bytes)
190
+ return "0 B" if bytes.zero?
191
+
192
+ units = %w[B KB MB GB]
193
+ size = bytes.to_f
194
+ unit_index = 0
195
+
196
+ while size >= 1024.0 && unit_index < units.size - 1
197
+ size /= 1024.0
198
+ unit_index += 1
199
+ end
200
+
201
+ format("%.2f %s", size, units[unit_index])
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (C) 2025 Ribose Inc.
5
+ #
6
+
7
+ require_relative "progress_reporter"
8
+
9
+ module Omnizip
10
+ module Progress
11
+ # Progress reporter that calls a user-provided Ruby block.
12
+ #
13
+ # This reporter allows users to provide custom callbacks for
14
+ # progress updates, enabling integration with web frameworks,
15
+ # GUI applications, or custom logging systems.
16
+ class CallbackReporter < ProgressReporter
17
+ attr_reader :callback
18
+
19
+ # Initialize a new callback reporter
20
+ #
21
+ # @param callback [Proc] Block to call with progress updates
22
+ # @yield [progress] Yields progress tracker to the block
23
+ def initialize(&callback)
24
+ super()
25
+ @callback = callback || proc { |_| }
26
+ end
27
+
28
+ # Report progress by calling the callback
29
+ #
30
+ # @param progress [ProgressTracker] Progress tracker with current state
31
+ def report(progress)
32
+ callback.call(progress)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (C) 2025 Ribose Inc.
5
+ #
6
+
7
+ require_relative "progress_reporter"
8
+ require_relative "progress_bar"
9
+
10
+ module Omnizip
11
+ module Progress
12
+ # Progress reporter that displays a progress bar in the console.
13
+ #
14
+ # This reporter uses ProgressBar to render a visual progress bar
15
+ # in the terminal, with automatic TTY detection and color support.
16
+ class ConsoleReporter < ProgressReporter
17
+ attr_reader :progress_bar, :output
18
+
19
+ # Initialize a new console reporter
20
+ #
21
+ # @param output [IO] Output stream (default: $stdout)
22
+ # @param width [Integer] Bar width (auto-detect if nil)
23
+ # @param use_color [Boolean] Enable color output
24
+ def initialize(output: $stdout, width: nil, use_color: true)
25
+ super()
26
+ @output = output
27
+ @progress_bar = ProgressBar.new(width: width, use_color: use_color)
28
+ @started = false
29
+ end
30
+
31
+ # Report progress to console
32
+ #
33
+ # @param progress [ProgressTracker] Progress tracker with current state
34
+ def report(progress)
35
+ return unless output.tty?
36
+
37
+ @started = true
38
+ output.print progress_bar.render(progress)
39
+ output.flush
40
+ end
41
+
42
+ # Called when operation starts
43
+ #
44
+ # @param _progress [ProgressTracker] Progress tracker
45
+ def start(_progress)
46
+ @started = false
47
+ end
48
+
49
+ # Called when operation completes
50
+ #
51
+ # @param _progress [ProgressTracker] Progress tracker
52
+ def finish(_progress)
53
+ return unless output.tty? && @started
54
+
55
+ # Clear the progress bar and print newline
56
+ output.print progress_bar.clear
57
+ output.puts
58
+ output.flush
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (C) 2025 Ribose Inc.
5
+ #
6
+
7
+ require_relative "progress_reporter"
8
+
9
+ module Omnizip
10
+ module Progress
11
+ # Progress reporter that writes to a log file.
12
+ #
13
+ # This reporter writes timestamped progress updates to a log file,
14
+ # useful for debugging, auditing, or monitoring long-running operations.
15
+ class LogReporter < ProgressReporter
16
+ attr_reader :log_file, :verbose
17
+
18
+ # Initialize a new log reporter
19
+ #
20
+ # @param log_file [String, IO] Log file path or IO object
21
+ # @param verbose [Boolean] Include detailed information
22
+ def initialize(log_file:, verbose: false)
23
+ super()
24
+ @log_file = log_file.is_a?(String) ? File.open(log_file, "a") : log_file
25
+ @verbose = verbose
26
+ @owns_file = log_file.is_a?(String)
27
+ end
28
+
29
+ # Report progress to log file
30
+ #
31
+ # @param progress [ProgressTracker] Progress tracker with current state
32
+ def report(progress)
33
+ timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
34
+
35
+ if verbose
36
+ log_file.puts format(
37
+ "[%s] Progress: %.1f%% (%d/%d files, %d/%d bytes) - %s - %s - ETA: %s",
38
+ timestamp,
39
+ progress.percentage,
40
+ progress.files_processed,
41
+ progress.operation_progress.total_files,
42
+ progress.bytes_processed,
43
+ progress.operation_progress.total_bytes,
44
+ progress.current_file || "unknown",
45
+ progress.rate_formatted,
46
+ progress.eta_formatted,
47
+ )
48
+ else
49
+ log_file.puts format(
50
+ "[%s] Progress: %.1f%% - %s",
51
+ timestamp,
52
+ progress.percentage,
53
+ progress.current_file || "processing",
54
+ )
55
+ end
56
+
57
+ log_file.flush
58
+ end
59
+
60
+ # Called when operation starts
61
+ #
62
+ # @param progress [ProgressTracker] Progress tracker
63
+ def start(progress)
64
+ timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
65
+ log_file.puts format(
66
+ "[%s] Started: %d files, %d bytes",
67
+ timestamp,
68
+ progress.operation_progress.total_files,
69
+ progress.operation_progress.total_bytes,
70
+ )
71
+ log_file.flush
72
+ end
73
+
74
+ # Called when operation completes
75
+ #
76
+ # @param progress [ProgressTracker] Progress tracker
77
+ def finish(progress)
78
+ timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S")
79
+ log_file.puts format(
80
+ "[%s] Completed in %.2fs",
81
+ timestamp,
82
+ progress.elapsed_seconds,
83
+ )
84
+ log_file.flush
85
+
86
+ # Close file if we opened it
87
+ log_file.close if @owns_file
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (C) 2025 Ribose Inc.
5
+ #
6
+
7
+ module Omnizip
8
+ module Progress
9
+ # Represents the current state of an operation's progress.
10
+ #
11
+ # This class stores all data about the current progress of an operation,
12
+ # including file counts, byte counts, current file being processed,
13
+ # and calculated percentages.
14
+ class OperationProgress
15
+ attr_reader :total_files, :total_bytes, :files_done, :bytes_done,
16
+ :current_file, :start_time
17
+
18
+ # Initialize a new operation progress tracker
19
+ #
20
+ # @param total_files [Integer] Total number of files to process
21
+ # @param total_bytes [Integer] Total bytes to process
22
+ def initialize(total_files:, total_bytes:)
23
+ @total_files = total_files
24
+ @total_bytes = total_bytes
25
+ @files_done = 0
26
+ @bytes_done = 0
27
+ @current_file = nil
28
+ @start_time = Time.now
29
+ end
30
+
31
+ # Update progress with new values
32
+ #
33
+ # @param files [Integer] Number of files completed
34
+ # @param bytes [Integer] Number of bytes processed
35
+ # @param current_file [String] Name of file currently processing
36
+ def update(files:, bytes:, current_file: nil)
37
+ @files_done = files
38
+ @bytes_done = bytes
39
+ @current_file = current_file
40
+ end
41
+
42
+ # Calculate overall percentage complete
43
+ #
44
+ # @return [Float] Percentage complete (0.0-100.0)
45
+ def percentage
46
+ return 0.0 if total_bytes.zero?
47
+
48
+ (bytes_done.to_f / total_bytes * 100.0).round(1)
49
+ end
50
+
51
+ # Calculate percentage of files complete
52
+ #
53
+ # @return [Float] Percentage of files complete (0.0-100.0)
54
+ def files_percent
55
+ return 0.0 if total_files.zero?
56
+
57
+ (files_done.to_f / total_files * 100.0).round(1)
58
+ end
59
+
60
+ # Calculate percentage of bytes complete
61
+ #
62
+ # @return [Float] Percentage of bytes complete (0.0-100.0)
63
+ def bytes_percent
64
+ return 0.0 if total_bytes.zero?
65
+
66
+ (bytes_done.to_f / total_bytes * 100.0).round(1)
67
+ end
68
+
69
+ # Get elapsed time in seconds
70
+ #
71
+ # @return [Float] Seconds elapsed since start
72
+ def elapsed_seconds
73
+ Time.now - start_time
74
+ end
75
+
76
+ # Get remaining bytes to process
77
+ #
78
+ # @return [Integer] Bytes remaining
79
+ def remaining_bytes
80
+ total_bytes - bytes_done
81
+ end
82
+
83
+ # Get remaining files to process
84
+ #
85
+ # @return [Integer] Files remaining
86
+ def remaining_files
87
+ total_files - files_done
88
+ end
89
+
90
+ # Check if operation is complete
91
+ #
92
+ # @return [Boolean] true if all files and bytes processed
93
+ def complete?
94
+ files_done >= total_files && bytes_done >= total_bytes
95
+ end
96
+
97
+ # Get progress as hash for serialization
98
+ #
99
+ # @return [Hash] Progress data
100
+ def to_h
101
+ {
102
+ total_files: total_files,
103
+ total_bytes: total_bytes,
104
+ files_done: files_done,
105
+ bytes_done: bytes_done,
106
+ current_file: current_file,
107
+ percentage: percentage,
108
+ files_percent: files_percent,
109
+ bytes_percent: bytes_percent,
110
+ elapsed_seconds: elapsed_seconds,
111
+ remaining_bytes: remaining_bytes,
112
+ remaining_files: remaining_files,
113
+ complete: complete?,
114
+ }
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (C) 2025 Ribose Inc.
5
+ #
6
+
7
+ module Omnizip
8
+ module Progress
9
+ # Visual progress bar for terminal output.
10
+ #
11
+ # This class renders a progress bar with percentage, file counts,
12
+ # rate, and ETA information. It supports color output and automatic
13
+ # width detection.
14
+ class ProgressBar
15
+ attr_reader :width, :use_color
16
+
17
+ # Initialize a new progress bar
18
+ #
19
+ # @param width [Integer] Bar width in characters (auto-detect if nil)
20
+ # @param use_color [Boolean] Enable color output
21
+ def initialize(width: nil, use_color: true)
22
+ @width = width || detect_terminal_width
23
+ @use_color = use_color && color_supported?
24
+ end
25
+
26
+ # Render progress bar string
27
+ #
28
+ # @param progress [ProgressTracker] Progress tracker
29
+ # @return [String] Formatted progress bar
30
+ def render(progress)
31
+ bar = build_bar(progress.percentage)
32
+ info = build_info(progress)
33
+
34
+ "\r#{bar} #{info}"
35
+ end
36
+
37
+ # Clear the progress bar line
38
+ #
39
+ # @return [String] Clear string
40
+ def clear
41
+ "\r#{' ' * width}\r"
42
+ end
43
+
44
+ private
45
+
46
+ # Build the progress bar component
47
+ #
48
+ # @param percentage [Float] Completion percentage (0.0-100.0)
49
+ # @return [String] Progress bar string
50
+ def build_bar(percentage)
51
+ bar_width = 20
52
+ filled = ((percentage / 100.0) * bar_width).round
53
+ empty = bar_width - filled
54
+
55
+ bar = "[#{'=' * filled}#{'>' if filled.positive?}#{' ' * [empty - 1,
56
+ 0].max}]"
57
+
58
+ if use_color
59
+ colorize(bar, :green)
60
+ else
61
+ bar
62
+ end
63
+ end
64
+
65
+ # Build the info component (percentage, files, rate, ETA)
66
+ #
67
+ # @param progress [ProgressTracker] Progress tracker
68
+ # @return [String] Info string
69
+ def build_info(progress)
70
+ parts = []
71
+
72
+ # Percentage
73
+ parts << format("%3.0f%%", progress.percentage)
74
+
75
+ # File count
76
+ parts << format(
77
+ "(%d/%d files)",
78
+ progress.files_processed,
79
+ progress.operation_progress.total_files,
80
+ )
81
+
82
+ # Current file (truncate if too long)
83
+ if progress.current_file
84
+ filename = truncate_filename(progress.current_file, 30)
85
+ parts << filename
86
+ end
87
+
88
+ # Rate
89
+ parts << progress.rate_formatted if progress.rate_bps.positive?
90
+
91
+ # ETA
92
+ eta = progress.eta_formatted
93
+ parts << "ETA: #{eta}" unless eta == "calculating..."
94
+
95
+ parts.join(" - ")
96
+ end
97
+
98
+ # Truncate filename to fit width
99
+ #
100
+ # @param filename [String] Filename to truncate
101
+ # @param max_length [Integer] Maximum length
102
+ # @return [String] Truncated filename
103
+ def truncate_filename(filename, max_length)
104
+ return filename if filename.length <= max_length
105
+
106
+ "...#{filename[(-max_length + 3)..]}"
107
+ end
108
+
109
+ # Detect terminal width
110
+ #
111
+ # @return [Integer] Terminal width in characters
112
+ def detect_terminal_width
113
+ if ENV["COLUMNS"]
114
+ ENV["COLUMNS"].to_i
115
+ elsif $stdout.tty?
116
+ begin
117
+ require "io/console"
118
+ $stdout.winsize[1]
119
+ rescue LoadError, NoMethodError
120
+ 80 # Default fallback
121
+ end
122
+ else
123
+ 80
124
+ end
125
+ end
126
+
127
+ # Check if terminal supports color
128
+ #
129
+ # @return [Boolean] true if color is supported
130
+ def color_supported?
131
+ return false unless $stdout.tty?
132
+ return false if ENV["TERM"] == "dumb"
133
+
134
+ true
135
+ end
136
+
137
+ # Colorize string with ANSI color codes
138
+ #
139
+ # @param text [String] Text to colorize
140
+ # @param color [Symbol] Color name (:green, :yellow, :red, etc.)
141
+ # @return [String] Colorized string
142
+ def colorize(text, color)
143
+ color_codes = {
144
+ green: 32,
145
+ yellow: 33,
146
+ red: 31,
147
+ blue: 34,
148
+ cyan: 36,
149
+ }
150
+
151
+ code = color_codes[color] || 0
152
+ "\e[#{code}m#{text}\e[0m"
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (C) 2025 Ribose Inc.
5
+ #
6
+
7
+ module Omnizip
8
+ module Progress
9
+ # Abstract base class for progress reporters.
10
+ #
11
+ # This class defines the interface for progress reporting strategies.
12
+ # Subclasses implement specific reporting mechanisms (console, callback,
13
+ # log file, etc.).
14
+ #
15
+ # @abstract Subclass and override {#report} to implement a reporter
16
+ class ProgressReporter
17
+ # Report progress to the output mechanism
18
+ #
19
+ # @param progress [ProgressTracker] Progress tracker with current state
20
+ # @raise [NotImplementedError] if not implemented by subclass
21
+ def report(progress)
22
+ raise NotImplementedError, "#{self.class} must implement #report"
23
+ end
24
+
25
+ # Called when operation starts (optional hook)
26
+ #
27
+ # @param progress [ProgressTracker] Progress tracker
28
+ def start(progress)
29
+ # Optional hook for subclasses
30
+ end
31
+
32
+ # Called when operation completes (optional hook)
33
+ #
34
+ # @param progress [ProgressTracker] Progress tracker
35
+ def finish(progress)
36
+ # Optional hook for subclasses
37
+ end
38
+ end
39
+ end
40
+ end