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,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Profile
5
+ # Thread-safe registry for compression profiles
6
+ #
7
+ # This class manages both built-in and custom compression profiles,
8
+ # providing a central location for profile registration, lookup, and
9
+ # management.
10
+ class ProfileRegistry
11
+ # Initialize a new profile registry
12
+ def initialize
13
+ @profiles = {}
14
+ @mutex = Mutex.new
15
+ end
16
+
17
+ # Register a profile
18
+ #
19
+ # @param profile [CompressionProfile] Profile to register
20
+ # @raise [ArgumentError] if profile with same name already exists
21
+ # @return [CompressionProfile] The registered profile
22
+ def register(profile)
23
+ unless profile.is_a?(CompressionProfile)
24
+ raise ArgumentError,
25
+ "Profile must be a CompressionProfile instance"
26
+ end
27
+
28
+ @mutex.synchronize do
29
+ if @profiles.key?(profile.name)
30
+ raise ArgumentError,
31
+ "Profile '#{profile.name}' is already registered"
32
+ end
33
+
34
+ @profiles[profile.name] = profile
35
+ end
36
+
37
+ profile
38
+ end
39
+
40
+ # Register a profile, replacing if it exists
41
+ #
42
+ # @param profile [CompressionProfile] Profile to register
43
+ # @return [CompressionProfile] The registered profile
44
+ def register!(profile)
45
+ unless profile.is_a?(CompressionProfile)
46
+ raise ArgumentError,
47
+ "Profile must be a CompressionProfile instance"
48
+ end
49
+
50
+ @mutex.synchronize do
51
+ @profiles[profile.name] = profile
52
+ end
53
+
54
+ profile
55
+ end
56
+
57
+ # Unregister a profile by name
58
+ #
59
+ # @param name [Symbol] Profile name
60
+ # @return [CompressionProfile, nil] The unregistered profile or nil
61
+ def unregister(name)
62
+ @mutex.synchronize do
63
+ @profiles.delete(name)
64
+ end
65
+ end
66
+
67
+ # Get a profile by name
68
+ #
69
+ # @param name [Symbol] Profile name
70
+ # @return [CompressionProfile, nil] Profile or nil if not found
71
+ def get(name)
72
+ @mutex.synchronize do
73
+ @profiles[name]
74
+ end
75
+ end
76
+
77
+ # Check if a profile is registered
78
+ #
79
+ # @param name [Symbol] Profile name
80
+ # @return [Boolean] true if profile exists
81
+ def registered?(name)
82
+ @mutex.synchronize do
83
+ @profiles.key?(name)
84
+ end
85
+ end
86
+
87
+ # Get all registered profile names
88
+ #
89
+ # @return [Array<Symbol>] List of profile names
90
+ def names
91
+ @mutex.synchronize do
92
+ @profiles.keys
93
+ end
94
+ end
95
+
96
+ # Get all registered profiles
97
+ #
98
+ # @return [Array<CompressionProfile>] List of profiles
99
+ def all
100
+ @mutex.synchronize do
101
+ @profiles.values
102
+ end
103
+ end
104
+
105
+ # Find profiles suitable for a MIME type
106
+ #
107
+ # @param mime_type [String] MIME type string
108
+ # @return [Array<CompressionProfile>] Suitable profiles
109
+ def suitable_for(mime_type)
110
+ all.select { |profile| profile.suitable_for?(mime_type) }
111
+ end
112
+
113
+ # Clear all registered profiles
114
+ #
115
+ # @return [void]
116
+ def clear
117
+ @mutex.synchronize do
118
+ @profiles.clear
119
+ end
120
+ end
121
+
122
+ # Get the number of registered profiles
123
+ #
124
+ # @return [Integer] Profile count
125
+ def count
126
+ @mutex.synchronize do
127
+ @profiles.size
128
+ end
129
+ end
130
+
131
+ # Iterate over all profiles
132
+ #
133
+ # @yield [profile] Yields each profile
134
+ # @yieldparam profile [CompressionProfile] A registered profile
135
+ # @return [void]
136
+ # rubocop:disable Naming/BlockForwarding, Style/ArgumentsForwarding -- Ruby 3.0 compatibility
137
+ def each(&block)
138
+ all.each(&block)
139
+ end
140
+ # rubocop:enable Naming/BlockForwarding, Style/ArgumentsForwarding
141
+
142
+ # Get profile information as hash
143
+ #
144
+ # @return [Hash{Symbol => Hash}] Profiles indexed by name
145
+ def to_h
146
+ @mutex.synchronize do
147
+ @profiles.transform_values(&:to_h)
148
+ end
149
+ end
150
+
151
+ # String representation
152
+ #
153
+ # @return [String]
154
+ def inspect
155
+ @mutex.synchronize do
156
+ "#<#{self.class.name} profiles=#{@profiles.keys.join(', ')}>"
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "compression_profile"
4
+ require_relative "../file_type/mime_classifier"
5
+
6
+ module Omnizip
7
+ module Profile
8
+ # Text compression profile
9
+ #
10
+ # Optimized for compressing text files.
11
+ # Uses PPMd7 which excels at text compression through context modeling.
12
+ class TextProfile < CompressionProfile
13
+ # Initialize text profile
14
+ def initialize
15
+ super(
16
+ name: :text,
17
+ algorithm: :ppmd7,
18
+ level: 6,
19
+ filter: nil,
20
+ solid: false,
21
+ description: "Optimized for text files"
22
+ )
23
+ end
24
+
25
+ # Check if this profile is suitable for a MIME type
26
+ #
27
+ # @param mime_type [String] MIME type string
28
+ # @return [Boolean] true if MIME type is text-based
29
+ def suitable_for?(mime_type)
30
+ return true unless mime_type
31
+
32
+ FileType::MimeClassifier.text?(mime_type)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "profile/compression_profile"
4
+ require_relative "profile/profile_registry"
5
+ require_relative "profile/profile_detector"
6
+ require_relative "profile/custom_profile"
7
+ require_relative "profile/fast_profile"
8
+ require_relative "profile/balanced_profile"
9
+ require_relative "profile/maximum_profile"
10
+ require_relative "profile/text_profile"
11
+ require_relative "profile/binary_profile"
12
+ require_relative "profile/archive_profile"
13
+
14
+ module Omnizip
15
+ # Compression profile management
16
+ #
17
+ # This module provides a high-level API for working with compression
18
+ # profiles. Profiles encapsulate compression settings and allow users
19
+ # to easily select optimal compression strategies for different file types.
20
+ module Profile
21
+ class << self
22
+ # Get the global profile registry
23
+ #
24
+ # @return [ProfileRegistry] The global registry
25
+ def registry
26
+ @registry ||= ProfileRegistry.new.tap do |reg|
27
+ register_built_in_profiles(reg)
28
+ end
29
+ end
30
+
31
+ # Get a profile by name
32
+ #
33
+ # @param name [Symbol] Profile name
34
+ # @return [CompressionProfile, nil] The profile or nil
35
+ def get(name)
36
+ registry.get(name)
37
+ end
38
+
39
+ # Define a custom profile
40
+ #
41
+ # @param name [Symbol] Profile name
42
+ # @param base [Symbol, nil] Base profile to extend
43
+ # @yield [builder] Yields a builder for profile configuration
44
+ # @yieldparam builder [CustomProfile::Builder] The profile builder
45
+ # @return [CustomProfile] The created profile
46
+ #
47
+ # @example Define a custom profile
48
+ # Omnizip::Profile.define(:my_profile) do |p|
49
+ # p.algorithm = :lzma2
50
+ # p.level = 7
51
+ # p.filter = :bcj_x86
52
+ # p.solid = true
53
+ # p.description = "My custom profile"
54
+ # end
55
+ #
56
+ # @example Extend an existing profile
57
+ # Omnizip::Profile.define(:my_fast, base: :fast) do |p|
58
+ # p.level = 2
59
+ # p.description = "Slightly better than fast"
60
+ # end
61
+ def define(name, base: nil)
62
+ base_profile = base ? registry.get(base) : nil
63
+ builder = CustomProfile::Builder.new(name, base_profile)
64
+
65
+ yield builder if block_given?
66
+
67
+ builder.valid?
68
+ profile = builder.build
69
+
70
+ registry.register!(profile)
71
+ profile
72
+ end
73
+
74
+ # List all available profile names
75
+ #
76
+ # @return [Array<Symbol>] List of profile names
77
+ def list
78
+ registry.names
79
+ end
80
+
81
+ # Get recommended profile for a file type
82
+ #
83
+ # @param file_type [String, Symbol] MIME type string or category symbol
84
+ # @return [CompressionProfile, nil] Recommended profile
85
+ def for_file_type(file_type)
86
+ # If file_type is a symbol (category), find first suitable profile
87
+ return find_profile_for_category(file_type) if file_type.is_a?(Symbol)
88
+
89
+ # If file_type is a MIME string, find suitable profiles
90
+ if file_type.is_a?(String)
91
+ suitable = registry.suitable_for(file_type)
92
+ return registry.get(:balanced) if suitable.empty?
93
+
94
+ return select_best_profile_for_mime(suitable, file_type)
95
+ end
96
+
97
+ # Default to balanced
98
+ registry.get(:balanced)
99
+ end
100
+
101
+ # Auto-detect optimal profile for a file
102
+ #
103
+ # @param file_path [String] Path to the file
104
+ # @param options [Hash] Detection options
105
+ # @return [CompressionProfile] Detected profile
106
+ def detect(file_path, options = {})
107
+ detector.detect(file_path, options)
108
+ end
109
+
110
+ # Get the profile detector
111
+ #
112
+ # @return [ProfileDetector] The detector instance
113
+ def detector
114
+ @detector ||= ProfileDetector.new(registry)
115
+ end
116
+
117
+ # Reset the global registry (mainly for testing)
118
+ #
119
+ # @return [void]
120
+ def reset!
121
+ @registry = nil
122
+ @detector = nil
123
+ end
124
+
125
+ private
126
+
127
+ # Register all built-in profiles
128
+ #
129
+ # @param registry [ProfileRegistry] Registry to populate
130
+ # @return [void]
131
+ def register_built_in_profiles(registry)
132
+ registry.register(FastProfile.new)
133
+ registry.register(BalancedProfile.new)
134
+ registry.register(MaximumProfile.new)
135
+ registry.register(TextProfile.new)
136
+ registry.register(BinaryProfile.new)
137
+ registry.register(ArchiveProfile.new)
138
+ end
139
+
140
+ # Find profile for a category symbol
141
+ #
142
+ # @param category [Symbol] File category
143
+ # @return [CompressionProfile, nil] Recommended profile
144
+ def find_profile_for_category(category)
145
+ case category
146
+ when :text, :document, :code
147
+ registry.get(:text)
148
+ when :executable
149
+ registry.get(:binary)
150
+ when :archive, :compressed
151
+ registry.get(:archive)
152
+ else
153
+ registry.get(:balanced)
154
+ end
155
+ end
156
+
157
+ # Select best profile from suitable candidates based on MIME type
158
+ #
159
+ # @param profiles [Array<CompressionProfile>] Suitable profiles
160
+ # @param mime_type [String] MIME type string
161
+ # @return [CompressionProfile] Best profile
162
+ def select_best_profile_for_mime(profiles, mime_type)
163
+ require_relative "file_type/mime_classifier"
164
+
165
+ # Determine category from MIME type
166
+ category = FileType::MimeClassifier.profile_category(mime_type)
167
+
168
+ priority = case category
169
+ when :archive
170
+ %i[archive fast balanced]
171
+ when :text
172
+ %i[text balanced]
173
+ when :binary
174
+ %i[binary maximum balanced]
175
+ else
176
+ [:balanced]
177
+ end
178
+
179
+ # Find first profile matching priority
180
+ priority.each do |name|
181
+ profile = profiles.find { |p| p.name == name }
182
+ return profile if profile
183
+ end
184
+
185
+ # Return first suitable profile if none matched priority
186
+ profiles.first
187
+ end
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ class Profiler
5
+ # Profiles memory allocation and retention
6
+ class MemoryProfiler
7
+ def initialize
8
+ @call_counts = Hash.new(0)
9
+ end
10
+
11
+ def profile(operation_name)
12
+ GC.start
13
+ GC.disable
14
+
15
+ gc_stat_before = GC.stat
16
+ objspace_before = ObjectSpace.count_objects
17
+
18
+ yield
19
+
20
+ objspace_after = ObjectSpace.count_objects
21
+ gc_stat_after = GC.stat
22
+
23
+ GC.enable
24
+
25
+ @call_counts[operation_name] += 1
26
+
27
+ # Calculate memory metrics
28
+ total_allocated = gc_stat_after[:total_allocated_objects] -
29
+ gc_stat_before[:total_allocated_objects]
30
+ total_freed = gc_stat_after[:total_freed_objects] -
31
+ gc_stat_before[:total_freed_objects]
32
+
33
+ # Object allocation delta
34
+ objspace_after[:TOTAL]
35
+ objspace_before[:TOTAL]
36
+
37
+ # Estimate memory based on object allocations
38
+ # Average Ruby object is ~40 bytes
39
+ estimated_memory = total_allocated * 40
40
+
41
+ Models::PerformanceResult.new(
42
+ operation_name: operation_name,
43
+ memory_allocated: estimated_memory,
44
+ memory_retained: (total_allocated - total_freed) * 40,
45
+ object_allocations: total_allocated,
46
+ gc_runs: 0,
47
+ call_count: @call_counts[operation_name],
48
+ )
49
+ ensure
50
+ GC.enable
51
+ end
52
+
53
+ def reset!
54
+ @call_counts.clear
55
+ end
56
+
57
+ def call_count(operation_name)
58
+ @call_counts[operation_name]
59
+ end
60
+
61
+ def total_calls
62
+ @call_counts.values.sum
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark"
4
+
5
+ module Omnizip
6
+ class Profiler
7
+ # Profiles method execution time and call counts
8
+ class MethodProfiler
9
+ def initialize
10
+ @call_counts = Hash.new(0)
11
+ end
12
+
13
+ def profile(operation_name)
14
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
15
+ gc_stat_before = GC.stat
16
+
17
+ yield
18
+
19
+ end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
20
+ gc_stat_after = GC.stat
21
+
22
+ @call_counts[operation_name] += 1
23
+
24
+ wall_time = end_time - start_time
25
+ gc_runs = gc_stat_after[:count] - gc_stat_before[:count]
26
+
27
+ Models::PerformanceResult.new(
28
+ operation_name: operation_name,
29
+ total_time: wall_time,
30
+ wall_time: wall_time,
31
+ gc_runs: gc_runs,
32
+ call_count: @call_counts[operation_name],
33
+ )
34
+ end
35
+
36
+ def reset!
37
+ @call_counts.clear
38
+ end
39
+
40
+ def call_count(operation_name)
41
+ @call_counts[operation_name]
42
+ end
43
+
44
+ def total_calls
45
+ @call_counts.values.sum
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fileutils"
5
+
6
+ module Omnizip
7
+ class Profiler
8
+ # Generates formatted profiling reports with optimization recommendations
9
+ class ReportGenerator
10
+ attr_reader :report
11
+
12
+ def initialize(report)
13
+ @report = report
14
+ end
15
+
16
+ # Generate a human-readable text report
17
+ def generate_text_report
18
+ lines = []
19
+ lines << ("=" * 80)
20
+ lines << "PERFORMANCE PROFILING REPORT"
21
+ lines << ("=" * 80)
22
+ lines << "Profile: #{report.profile_name}"
23
+ lines << "Timestamp: #{report.timestamp}"
24
+ lines << ""
25
+
26
+ lines += generate_summary_section
27
+ lines += generate_results_section
28
+ lines += generate_hot_paths_section
29
+ lines += generate_bottlenecks_section
30
+
31
+ lines.join("\n")
32
+ end
33
+
34
+ # Generate a JSON report
35
+ def generate_json_report
36
+ JSON.pretty_generate(report.to_h)
37
+ end
38
+
39
+ # Save report to file
40
+ def save_to_file(filename, format: :text)
41
+ content = case format
42
+ when :text then generate_text_report
43
+ when :json then generate_json_report
44
+ else raise ArgumentError, "Unknown format: #{format}"
45
+ end
46
+
47
+ # Create parent directories if they don't exist
48
+ dir = File.dirname(filename)
49
+ FileUtils.mkdir_p(dir)
50
+
51
+ File.write(filename, content)
52
+ puts "Report saved to #{filename}"
53
+ end
54
+
55
+ # Print report to console
56
+ def print_report
57
+ puts generate_text_report
58
+ end
59
+
60
+ private
61
+
62
+ def generate_summary_section
63
+ lines = []
64
+ lines << ("-" * 80)
65
+ lines << "SUMMARY"
66
+ lines << ("-" * 80)
67
+ lines << format("Total Execution Time: %.3fs",
68
+ report.total_execution_time)
69
+ lines << format("Total Memory Allocated: %s",
70
+ format_bytes(report.total_memory_allocated))
71
+ lines << format("Total GC Runs: %d", report.total_gc_runs)
72
+ lines << format("Operations Profiled: %d", report.results.size)
73
+ lines << ""
74
+ lines
75
+ end
76
+
77
+ def generate_results_section
78
+ return [] if report.results.empty?
79
+
80
+ lines = []
81
+ lines << ("-" * 80)
82
+ lines << "DETAILED RESULTS"
83
+ lines << ("-" * 80)
84
+ lines << "Operation Time (s) Memory Calls"
85
+ lines << ("-" * 80)
86
+
87
+ report.results.sort_by(&:total_time).reverse.each do |result|
88
+ lines << format("%-40s %12.3f %15s %10d",
89
+ truncate(result.operation_name, 40),
90
+ result.total_time || 0.0,
91
+ format_bytes(result.memory_allocated || 0),
92
+ result.call_count || 0)
93
+ end
94
+ lines << ""
95
+ lines
96
+ end
97
+
98
+ def generate_hot_paths_section
99
+ return [] if report.hot_paths.empty?
100
+
101
+ lines = []
102
+ lines << ("-" * 80)
103
+ lines << "HOT PATHS (>10% execution time)"
104
+ lines << ("-" * 80)
105
+
106
+ report.hot_paths.each do |hot_path|
107
+ lines << format(" %s: %.3fs (%.1f%%)",
108
+ hot_path[:operation],
109
+ hot_path[:time],
110
+ hot_path[:percentage])
111
+ end
112
+ lines << ""
113
+ lines
114
+ end
115
+
116
+ def generate_bottlenecks_section
117
+ return [] if report.bottlenecks.empty?
118
+
119
+ lines = []
120
+ lines << ("-" * 80)
121
+ lines << "PERFORMANCE BOTTLENECKS"
122
+ lines << ("-" * 80)
123
+
124
+ report.bottlenecks.group_by { |b| b[:type] }.each do |type, bottlenecks|
125
+ lines << "\n#{type.to_s.upcase} Bottlenecks:"
126
+ bottlenecks.each do |bottleneck|
127
+ lines << format(" [%s] %s",
128
+ bottleneck[:severity].to_s.upcase,
129
+ bottleneck[:operation])
130
+
131
+ case type
132
+ when :memory
133
+ lines << format(" Memory: %s",
134
+ format_bytes(bottleneck[:allocated]))
135
+ when :cpu
136
+ lines << format(" Time: %.3fs", bottleneck[:time])
137
+ when :gc
138
+ lines << format(" GC Pressure: %.2f runs/s",
139
+ bottleneck[:gc_pressure])
140
+ end
141
+ end
142
+ end
143
+ lines << ""
144
+ lines
145
+ end
146
+
147
+ def format_bytes(bytes)
148
+ return "0 B" if bytes.nil? || bytes.zero?
149
+
150
+ units = %w[B KB MB GB]
151
+ size = bytes.to_f
152
+ unit_index = 0
153
+
154
+ while size >= 1024.0 && unit_index < units.size - 1
155
+ size /= 1024.0
156
+ unit_index += 1
157
+ end
158
+
159
+ format("%.2f %s", size, units[unit_index])
160
+ end
161
+
162
+ def truncate(string, max_length)
163
+ return string if string.length <= max_length
164
+
165
+ "#{string[0...(max_length - 3)]}..."
166
+ end
167
+ end
168
+ end
169
+ end