omnizip 0.4.7-arm-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (632) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +293 -0
  5. data/CHANGELOG.md +1647 -0
  6. data/CONTEXT.md +68 -0
  7. data/COPYING +502 -0
  8. data/Gemfile +19 -0
  9. data/LICENSE +12 -0
  10. data/README.adoc +1327 -0
  11. data/Rakefile +15 -0
  12. data/TODO.refactor/00-overview.md +67 -0
  13. data/TODO.refactor/01-registry-base-class.md +81 -0
  14. data/TODO.refactor/02-error-hierarchy.md +57 -0
  15. data/TODO.refactor/03-autoload-entry-point.md +69 -0
  16. data/TODO.refactor/04-filter-base-consolidation.md +49 -0
  17. data/TODO.refactor/05-send-private-methods.md +64 -0
  18. data/TODO.refactor/06-instance-variable-access.md +69 -0
  19. data/TODO.refactor/07-respond-to-replacement.md +237 -0
  20. data/TODO.refactor/08-spec-doubles.md +27 -0
  21. data/TODO.refactor/09-cli-shared-module.md +35 -0
  22. data/TODO.refactor/10-format-detector-ocp.md +34 -0
  23. data/TODO.refactor/11-convenience-decoupling.md +38 -0
  24. data/TODO.refactor/12-thread-safety.md +8 -0
  25. data/TODO.refactor/13-lutaml-model-migration.md +158 -0
  26. data/TODO.refactor/14-add-missing-specs.md +25 -0
  27. data/benchmark/README.md +260 -0
  28. data/benchmark/benchmark_suite.rb +125 -0
  29. data/benchmark/compression_bench.rb +181 -0
  30. data/benchmark/filter_bench.rb +180 -0
  31. data/benchmark/models/benchmark_result.rb +59 -0
  32. data/benchmark/models/comparison_result.rb +69 -0
  33. data/benchmark/profile_suite.rb +167 -0
  34. data/benchmark/reporter.rb +150 -0
  35. data/benchmark/run_benchmarks.rb +66 -0
  36. data/benchmark/test_data.rb +137 -0
  37. data/config/formats/rar3_spec.yml +92 -0
  38. data/config/formats/rar5_spec.yml +102 -0
  39. data/docs/.github/workflows/docs.yml +142 -0
  40. data/docs/.gitignore +21 -0
  41. data/docs/.lychee.toml +67 -0
  42. data/docs/Gemfile +13 -0
  43. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  44. data/docs/README.md +101 -0
  45. data/docs/_config.yml +112 -0
  46. data/docs/assets/logo.svg +1 -0
  47. data/docs/assets/omnizip-logo.pdf +1540 -11
  48. data/docs/comparison/feature-matrix.adoc +694 -0
  49. data/docs/comparison/index.adoc +113 -0
  50. data/docs/comparison/vs-7zip.adoc +309 -0
  51. data/docs/comparison/vs-peazip.adoc +77 -0
  52. data/docs/comparison/vs-rubyzip.adoc +342 -0
  53. data/docs/comparison/vs-winrar.adoc +100 -0
  54. data/docs/compatibility.adoc +579 -0
  55. data/docs/concepts/index.adoc +129 -0
  56. data/docs/developer/architecture.adoc +256 -0
  57. data/docs/developer/contributing.adoc +158 -0
  58. data/docs/developer/index.adoc +25 -0
  59. data/docs/developer/testing.adoc +212 -0
  60. data/docs/getting-started/basic-usage.adoc +263 -0
  61. data/docs/getting-started/index.adoc +42 -0
  62. data/docs/getting-started/installation.adoc +138 -0
  63. data/docs/getting-started/quick-start.adoc +183 -0
  64. data/docs/getting-started/your-first-archive.adoc +219 -0
  65. data/docs/guides/advanced-features/encryption.adoc +277 -0
  66. data/docs/guides/advanced-features/index.adoc +59 -0
  67. data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
  68. data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
  69. data/docs/guides/advanced-features/streaming.adoc +142 -0
  70. data/docs/guides/archive-formats/gzip-format.adoc +105 -0
  71. data/docs/guides/archive-formats/index.adoc +160 -0
  72. data/docs/guides/archive-formats/ole-format.adoc +151 -0
  73. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  74. data/docs/guides/archive-formats/rar5.adoc +521 -0
  75. data/docs/guides/archive-formats/rpm-format.adoc +108 -0
  76. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  77. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  78. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  79. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  80. data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
  81. data/docs/guides/compression-algorithms/deflate.adoc +313 -0
  82. data/docs/guides/compression-algorithms/index.adoc +190 -0
  83. data/docs/guides/compression-algorithms/lzma.adoc +394 -0
  84. data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
  85. data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
  86. data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
  87. data/docs/guides/creating-archives.adoc +348 -0
  88. data/docs/guides/extracting-archives.adoc +53 -0
  89. data/docs/guides/format-conversion.adoc +64 -0
  90. data/docs/guides/index.adoc +49 -0
  91. data/docs/guides/migration-rubyzip.adoc +217 -0
  92. data/docs/guides/parity-archives.adoc +605 -0
  93. data/docs/guides/performance-tuning.adoc +88 -0
  94. data/docs/index.adoc +228 -0
  95. data/docs/lychee.toml +67 -0
  96. data/docs/reference/api/overview.adoc +187 -0
  97. data/docs/reference/cli/compress-command.adoc +114 -0
  98. data/docs/reference/cli/overview.adoc +140 -0
  99. data/docs/reference/index.adoc +26 -0
  100. data/docs/resources/faq.adoc +185 -0
  101. data/docs/resources/quick-reference.adoc +222 -0
  102. data/docs/rust-backend.md +0 -0
  103. data/docs/troubleshooting/index.adoc +207 -0
  104. data/docs/xar_format.md +216 -0
  105. data/examples/api_comparison.rb +205 -0
  106. data/examples/deflate64_example.rb +96 -0
  107. data/examples/par2_demo.rb +121 -0
  108. data/examples/quick_start_native.rb +150 -0
  109. data/examples/quick_start_rubyzip.rb +115 -0
  110. data/examples/rubyzip_compatibility_demo.rb +194 -0
  111. data/exe/omnizip +27 -0
  112. data/lib/omnizip/algorithm.rb +176 -0
  113. data/lib/omnizip/algorithm_registry.rb +65 -0
  114. data/lib/omnizip/algorithms/.keep +0 -0
  115. data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
  116. data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
  117. data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
  118. data/lib/omnizip/algorithms/bzip2.rb +108 -0
  119. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  120. data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
  121. data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
  122. data/lib/omnizip/algorithms/deflate.rb +135 -0
  123. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  124. data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
  125. data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
  126. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
  127. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
  128. data/lib/omnizip/algorithms/deflate64.rb +118 -0
  129. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  130. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  131. data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
  132. data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
  133. data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
  134. data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
  135. data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
  136. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
  137. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
  138. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
  139. data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
  140. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
  141. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  142. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  143. data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
  144. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  145. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
  146. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
  147. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  148. data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
  149. data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
  150. data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
  151. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  152. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
  153. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
  154. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
  155. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
  156. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
  157. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
  158. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  159. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
  160. data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
  161. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
  162. data/lib/omnizip/algorithms/lzma.rb +266 -0
  163. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
  164. data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
  165. data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
  166. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
  167. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  168. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
  169. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  170. data/lib/omnizip/algorithms/lzma2.rb +133 -0
  171. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  172. data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
  173. data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
  174. data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
  175. data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
  176. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  177. data/lib/omnizip/algorithms/ppmd7.rb +146 -0
  178. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  179. data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
  180. data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
  181. data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
  182. data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
  183. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  184. data/lib/omnizip/algorithms/ppmd8.rb +122 -0
  185. data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
  186. data/lib/omnizip/algorithms/registration.rb +28 -0
  187. data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
  188. data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
  189. data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
  190. data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
  191. data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
  192. data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
  193. data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
  194. data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
  195. data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
  196. data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
  197. data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
  198. data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
  199. data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
  200. data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
  201. data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
  202. data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
  203. data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
  204. data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
  205. data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
  206. data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
  207. data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
  208. data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
  209. data/lib/omnizip/algorithms/zstandard.rb +210 -0
  210. data/lib/omnizip/algorithms.rb +35 -0
  211. data/lib/omnizip/archive/builder.rb +48 -0
  212. data/lib/omnizip/archive/reader_session.rb +67 -0
  213. data/lib/omnizip/archive.rb +86 -0
  214. data/lib/omnizip/archive_handler.rb +82 -0
  215. data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
  216. data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
  217. data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
  218. data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
  219. data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
  220. data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
  221. data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
  222. data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
  223. data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
  224. data/lib/omnizip/archive_handlers.rb +18 -0
  225. data/lib/omnizip/backends.rb +160 -0
  226. data/lib/omnizip/buffer/memory_archive.rb +246 -0
  227. data/lib/omnizip/buffer/memory_extractor.rb +234 -0
  228. data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
  229. data/lib/omnizip/buffer.rb +187 -0
  230. data/lib/omnizip/checksum_registry.rb +41 -0
  231. data/lib/omnizip/checksums/crc32.rb +101 -0
  232. data/lib/omnizip/checksums/crc64.rb +102 -0
  233. data/lib/omnizip/checksums/crc_base.rb +158 -0
  234. data/lib/omnizip/checksums/registration.rb +16 -0
  235. data/lib/omnizip/checksums/verifier.rb +130 -0
  236. data/lib/omnizip/checksums.rb +11 -0
  237. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  238. data/lib/omnizip/chunked/reader.rb +78 -0
  239. data/lib/omnizip/chunked/writer.rb +123 -0
  240. data/lib/omnizip/chunked.rb +123 -0
  241. data/lib/omnizip/cli/output_formatter.rb +112 -0
  242. data/lib/omnizip/cli.rb +604 -0
  243. data/lib/omnizip/commands/.keep +0 -0
  244. data/lib/omnizip/commands/archive_create_command.rb +245 -0
  245. data/lib/omnizip/commands/archive_extract_command.rb +231 -0
  246. data/lib/omnizip/commands/archive_list_command.rb +204 -0
  247. data/lib/omnizip/commands/archive_repair_command.rb +129 -0
  248. data/lib/omnizip/commands/archive_verify_command.rb +115 -0
  249. data/lib/omnizip/commands/compress_command.rb +115 -0
  250. data/lib/omnizip/commands/decompress_command.rb +149 -0
  251. data/lib/omnizip/commands/list_command.rb +51 -0
  252. data/lib/omnizip/commands/metadata_command.rb +215 -0
  253. data/lib/omnizip/commands/parity_create_command.rb +114 -0
  254. data/lib/omnizip/commands/parity_repair_command.rb +120 -0
  255. data/lib/omnizip/commands/parity_verify_command.rb +122 -0
  256. data/lib/omnizip/commands/profile_list_command.rb +54 -0
  257. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  258. data/lib/omnizip/commands.rb +21 -0
  259. data/lib/omnizip/convenience.rb +389 -0
  260. data/lib/omnizip/converter/conversion_registry.rb +50 -0
  261. data/lib/omnizip/converter/conversion_strategy.rb +108 -0
  262. data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
  263. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
  264. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
  265. data/lib/omnizip/converter.rb +124 -0
  266. data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
  267. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  268. data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
  269. data/lib/omnizip/crypto/aes256.rb +102 -0
  270. data/lib/omnizip/crypto.rb +11 -0
  271. data/lib/omnizip/entry.rb +44 -0
  272. data/lib/omnizip/error.rb +110 -0
  273. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
  274. data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
  275. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  276. data/lib/omnizip/eta/sample_history.rb +143 -0
  277. data/lib/omnizip/eta/time_estimator.rb +106 -0
  278. data/lib/omnizip/eta.rb +68 -0
  279. data/lib/omnizip/extraction/filter_chain.rb +179 -0
  280. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  281. data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
  282. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  283. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  284. data/lib/omnizip/extraction/selective_extractor.rb +247 -0
  285. data/lib/omnizip/extraction.rb +115 -0
  286. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  287. data/lib/omnizip/file_type.rb +117 -0
  288. data/lib/omnizip/filter.rb +141 -0
  289. data/lib/omnizip/filter_pipeline.rb +108 -0
  290. data/lib/omnizip/filter_registry.rb +113 -0
  291. data/lib/omnizip/filters/bcj.rb +277 -0
  292. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  293. data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
  294. data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
  295. data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
  296. data/lib/omnizip/filters/bcj2.rb +93 -0
  297. data/lib/omnizip/filters/bcj_arm.rb +174 -0
  298. data/lib/omnizip/filters/bcj_arm64.rb +242 -0
  299. data/lib/omnizip/filters/bcj_ia64.rb +194 -0
  300. data/lib/omnizip/filters/bcj_ppc.rb +188 -0
  301. data/lib/omnizip/filters/bcj_sparc.rb +174 -0
  302. data/lib/omnizip/filters/bcj_x86.rb +191 -0
  303. data/lib/omnizip/filters/delta.rb +195 -0
  304. data/lib/omnizip/filters/xz_delta.rb +258 -0
  305. data/lib/omnizip/filters.rb +20 -0
  306. data/lib/omnizip/format_detector.rb +166 -0
  307. data/lib/omnizip/formats/.keep +0 -0
  308. data/lib/omnizip/formats/bzip2_file.rb +159 -0
  309. data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
  310. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  311. data/lib/omnizip/formats/cpio/entry.rb +389 -0
  312. data/lib/omnizip/formats/cpio/reader.rb +194 -0
  313. data/lib/omnizip/formats/cpio/writer.rb +232 -0
  314. data/lib/omnizip/formats/cpio.rb +132 -0
  315. data/lib/omnizip/formats/format_spec_loader.rb +228 -0
  316. data/lib/omnizip/formats/gzip.rb +236 -0
  317. data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
  318. data/lib/omnizip/formats/iso/directory_record.rb +162 -0
  319. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  320. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  321. data/lib/omnizip/formats/iso/reader.rb +194 -0
  322. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  323. data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
  324. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  325. data/lib/omnizip/formats/iso/writer.rb +543 -0
  326. data/lib/omnizip/formats/iso.rb +133 -0
  327. data/lib/omnizip/formats/lzip.rb +161 -0
  328. data/lib/omnizip/formats/lzma_alone.rb +149 -0
  329. data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
  330. data/lib/omnizip/formats/msi/constants.rb +157 -0
  331. data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
  332. data/lib/omnizip/formats/msi/entry.rb +134 -0
  333. data/lib/omnizip/formats/msi/reader.rb +301 -0
  334. data/lib/omnizip/formats/msi/string_pool.rb +246 -0
  335. data/lib/omnizip/formats/msi/table_parser.rb +244 -0
  336. data/lib/omnizip/formats/msi.rb +73 -0
  337. data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
  338. data/lib/omnizip/formats/ole/constants.rb +61 -0
  339. data/lib/omnizip/formats/ole/dirent.rb +439 -0
  340. data/lib/omnizip/formats/ole/header.rb +199 -0
  341. data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
  342. data/lib/omnizip/formats/ole/storage.rb +482 -0
  343. data/lib/omnizip/formats/ole/types/variant.rb +338 -0
  344. data/lib/omnizip/formats/ole.rb +143 -0
  345. data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
  346. data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
  347. data/lib/omnizip/formats/rar/block_parser.rb +282 -0
  348. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  349. data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
  350. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
  351. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
  352. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  353. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  354. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  355. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  356. data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
  357. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
  358. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
  359. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
  360. data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
  361. data/lib/omnizip/formats/rar/compression.rb +17 -0
  362. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  363. data/lib/omnizip/formats/rar/constants.rb +88 -0
  364. data/lib/omnizip/formats/rar/decompressor.rb +316 -0
  365. data/lib/omnizip/formats/rar/external_writer.rb +311 -0
  366. data/lib/omnizip/formats/rar/header.rb +209 -0
  367. data/lib/omnizip/formats/rar/license_validator.rb +111 -0
  368. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  369. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  370. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  371. data/lib/omnizip/formats/rar/models.rb +14 -0
  372. data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
  373. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
  374. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
  375. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  376. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  377. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
  378. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  379. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
  380. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  381. data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
  382. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  383. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  384. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  385. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  386. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  387. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
  388. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  389. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
  390. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
  391. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
  392. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  393. data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
  394. data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
  395. data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
  396. data/lib/omnizip/formats/rar/reader.rb +377 -0
  397. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  398. data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
  399. data/lib/omnizip/formats/rar/writer.rb +437 -0
  400. data/lib/omnizip/formats/rar.rb +193 -0
  401. data/lib/omnizip/formats/rar3/compressor.rb +71 -0
  402. data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
  403. data/lib/omnizip/formats/rar3/reader.rb +107 -0
  404. data/lib/omnizip/formats/rar3/writer.rb +220 -0
  405. data/lib/omnizip/formats/rar3.rb +15 -0
  406. data/lib/omnizip/formats/rar5/compressor.rb +71 -0
  407. data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
  408. data/lib/omnizip/formats/rar5/reader.rb +130 -0
  409. data/lib/omnizip/formats/rar5/writer.rb +65 -0
  410. data/lib/omnizip/formats/rar5.rb +15 -0
  411. data/lib/omnizip/formats/rpm/constants.rb +58 -0
  412. data/lib/omnizip/formats/rpm/entry.rb +106 -0
  413. data/lib/omnizip/formats/rpm/header.rb +106 -0
  414. data/lib/omnizip/formats/rpm/lead.rb +132 -0
  415. data/lib/omnizip/formats/rpm/tag.rb +228 -0
  416. data/lib/omnizip/formats/rpm/writer.rb +652 -0
  417. data/lib/omnizip/formats/rpm.rb +458 -0
  418. data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
  419. data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
  420. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  421. data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
  422. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
  423. data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
  424. data/lib/omnizip/formats/seven_zip/header.rb +102 -0
  425. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
  426. data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
  427. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  428. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
  429. data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
  430. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  431. data/lib/omnizip/formats/seven_zip/models.rb +20 -0
  432. data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
  433. data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
  434. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
  435. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
  436. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  437. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
  438. data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
  439. data/lib/omnizip/formats/seven_zip.rb +179 -0
  440. data/lib/omnizip/formats/tar/constants.rb +73 -0
  441. data/lib/omnizip/formats/tar/entry.rb +98 -0
  442. data/lib/omnizip/formats/tar/header.rb +206 -0
  443. data/lib/omnizip/formats/tar/reader.rb +119 -0
  444. data/lib/omnizip/formats/tar/writer.rb +212 -0
  445. data/lib/omnizip/formats/tar.rb +74 -0
  446. data/lib/omnizip/formats/xar/constants.rb +119 -0
  447. data/lib/omnizip/formats/xar/entry.rb +268 -0
  448. data/lib/omnizip/formats/xar/header.rb +223 -0
  449. data/lib/omnizip/formats/xar/reader.rb +400 -0
  450. data/lib/omnizip/formats/xar/toc.rb +570 -0
  451. data/lib/omnizip/formats/xar/writer.rb +461 -0
  452. data/lib/omnizip/formats/xar.rb +145 -0
  453. data/lib/omnizip/formats/xz/reader.rb +121 -0
  454. data/lib/omnizip/formats/xz/writer.rb +416 -0
  455. data/lib/omnizip/formats/xz.rb +210 -0
  456. data/lib/omnizip/formats/xz_const.rb +49 -0
  457. data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
  458. data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
  459. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  460. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
  461. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  462. data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
  463. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
  464. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
  465. data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
  466. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
  467. data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
  468. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
  469. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  470. data/lib/omnizip/formats/xz_impl.rb +52 -0
  471. data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
  472. data/lib/omnizip/formats/zip/constants.rb +69 -0
  473. data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
  474. data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
  475. data/lib/omnizip/formats/zip/reader.rb +376 -0
  476. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  477. data/lib/omnizip/formats/zip/writer.rb +489 -0
  478. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
  479. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
  480. data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
  481. data/lib/omnizip/formats/zip.rb +50 -0
  482. data/lib/omnizip/formats.rb +29 -0
  483. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  484. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  485. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  486. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  487. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  488. data/lib/omnizip/implementations/base.rb +19 -0
  489. data/lib/omnizip/implementations/rust/archive.rb +93 -0
  490. data/lib/omnizip/implementations/rust/library.rb +221 -0
  491. data/lib/omnizip/implementations/rust.rb +26 -0
  492. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
  493. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
  494. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
  495. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
  496. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
  497. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
  498. data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
  499. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
  500. data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
  501. data/lib/omnizip/implementations/seven_zip.rb +11 -0
  502. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
  503. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
  504. data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
  505. data/lib/omnizip/implementations/xz_utils.rb +10 -0
  506. data/lib/omnizip/implementations.rb +25 -0
  507. data/lib/omnizip/io/buffered_input.rb +147 -0
  508. data/lib/omnizip/io/buffered_output.rb +106 -0
  509. data/lib/omnizip/io/source.rb +143 -0
  510. data/lib/omnizip/io/stream_manager.rb +117 -0
  511. data/lib/omnizip/io.rb +15 -0
  512. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  513. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  514. data/lib/omnizip/link_handler.rb +129 -0
  515. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  516. data/lib/omnizip/metadata/entry_metadata.rb +153 -0
  517. data/lib/omnizip/metadata/metadata_editor.rb +169 -0
  518. data/lib/omnizip/metadata/metadata_registry.rb +71 -0
  519. data/lib/omnizip/metadata/metadata_validator.rb +101 -0
  520. data/lib/omnizip/metadata.rb +58 -0
  521. data/lib/omnizip/models/.keep +0 -0
  522. data/lib/omnizip/models/algorithm_metadata.rb +41 -0
  523. data/lib/omnizip/models/attribute_apply.rb +40 -0
  524. data/lib/omnizip/models/compression_options.rb +53 -0
  525. data/lib/omnizip/models/conversion_options.rb +79 -0
  526. data/lib/omnizip/models/conversion_result.rb +141 -0
  527. data/lib/omnizip/models/eta_result.rb +45 -0
  528. data/lib/omnizip/models/extraction_rule.rb +115 -0
  529. data/lib/omnizip/models/filter_chain.rb +142 -0
  530. data/lib/omnizip/models/filter_config.rb +148 -0
  531. data/lib/omnizip/models/match_result.rb +141 -0
  532. data/lib/omnizip/models/optimization_suggestion.rb +95 -0
  533. data/lib/omnizip/models/parallel_options.rb +116 -0
  534. data/lib/omnizip/models/performance_result.rb +85 -0
  535. data/lib/omnizip/models/profile_report.rb +116 -0
  536. data/lib/omnizip/models/progress_options.rb +39 -0
  537. data/lib/omnizip/models/split_options.rb +116 -0
  538. data/lib/omnizip/optimization_registry.rb +45 -0
  539. data/lib/omnizip/parallel/engine.rb +52 -0
  540. data/lib/omnizip/parallel/job_queue.rb +209 -0
  541. data/lib/omnizip/parallel/job_scheduler.rb +225 -0
  542. data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
  543. data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
  544. data/lib/omnizip/parallel/thread_pool.rb +60 -0
  545. data/lib/omnizip/parallel/worker_pool.rb +227 -0
  546. data/lib/omnizip/parallel.rb +156 -0
  547. data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
  548. data/lib/omnizip/parity/galois16.rb +145 -0
  549. data/lib/omnizip/parity/models/creator_packet.rb +71 -0
  550. data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
  551. data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
  552. data/lib/omnizip/parity/models/main_packet.rb +126 -0
  553. data/lib/omnizip/parity/models/packet.rb +156 -0
  554. data/lib/omnizip/parity/models/packet_registry.rb +102 -0
  555. data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
  556. data/lib/omnizip/parity/models.rb +27 -0
  557. data/lib/omnizip/parity/par2_creator.rb +496 -0
  558. data/lib/omnizip/parity/par2_repairer.rb +409 -0
  559. data/lib/omnizip/parity/par2_verifier.rb +373 -0
  560. data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
  561. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  562. data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
  563. data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
  564. data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
  565. data/lib/omnizip/parity.rb +207 -0
  566. data/lib/omnizip/password/encryption_registry.rb +26 -0
  567. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  568. data/lib/omnizip/password/password_validator.rb +129 -0
  569. data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
  570. data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
  571. data/lib/omnizip/password.rb +88 -0
  572. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  573. data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
  574. data/lib/omnizip/pipe.rb +120 -0
  575. data/lib/omnizip/platform/ntfs_streams.rb +200 -0
  576. data/lib/omnizip/platform.rb +189 -0
  577. data/lib/omnizip/profile/archive_profile.rb +36 -0
  578. data/lib/omnizip/profile/balanced_profile.rb +31 -0
  579. data/lib/omnizip/profile/binary_profile.rb +33 -0
  580. data/lib/omnizip/profile/compression_profile.rb +157 -0
  581. data/lib/omnizip/profile/custom_profile.rb +155 -0
  582. data/lib/omnizip/profile/fast_profile.rb +31 -0
  583. data/lib/omnizip/profile/maximum_profile.rb +31 -0
  584. data/lib/omnizip/profile/profile_detector.rb +108 -0
  585. data/lib/omnizip/profile/profile_registry.rb +160 -0
  586. data/lib/omnizip/profile/text_profile.rb +33 -0
  587. data/lib/omnizip/profile.rb +261 -0
  588. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  589. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  590. data/lib/omnizip/profiler/report_generator.rb +158 -0
  591. data/lib/omnizip/profiler.rb +192 -0
  592. data/lib/omnizip/progress/callback_reporter.rb +34 -0
  593. data/lib/omnizip/progress/console_reporter.rb +59 -0
  594. data/lib/omnizip/progress/log_reporter.rb +89 -0
  595. data/lib/omnizip/progress/operation_progress.rb +118 -0
  596. data/lib/omnizip/progress/progress_bar.rb +156 -0
  597. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  598. data/lib/omnizip/progress/progress_tracker.rb +215 -0
  599. data/lib/omnizip/progress/silent_reporter.rb +22 -0
  600. data/lib/omnizip/progress.rb +131 -0
  601. data/lib/omnizip/registry.rb +111 -0
  602. data/lib/omnizip/rubyzip_compat.rb +61 -0
  603. data/lib/omnizip/temp/safe_extract.rb +124 -0
  604. data/lib/omnizip/temp/temp_file.rb +123 -0
  605. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  606. data/lib/omnizip/temp.rb +184 -0
  607. data/lib/omnizip/version.rb +5 -0
  608. data/lib/omnizip/zip/entry.rb +160 -0
  609. data/lib/omnizip/zip/file.rb +485 -0
  610. data/lib/omnizip/zip/input_stream.rb +270 -0
  611. data/lib/omnizip/zip/output_stream.rb +320 -0
  612. data/lib/omnizip/zip.rb +23 -0
  613. data/lib/omnizip.rb +157 -0
  614. data/lib/tasks/msi_test_files.rake +66 -0
  615. data/lib/tasks/platform_gems.rake +147 -0
  616. data/lib/tasks/rust_backend.rake +48 -0
  617. data/readme-docs/advanced-features.adoc +514 -0
  618. data/readme-docs/api-usage.adoc +445 -0
  619. data/readme-docs/architecture.adoc +450 -0
  620. data/readme-docs/archive-formats.adoc +479 -0
  621. data/readme-docs/cli-usage.adoc +222 -0
  622. data/readme-docs/compression-algorithms.adoc +446 -0
  623. data/readme-docs/compression-profiles.adoc +247 -0
  624. data/readme-docs/encryption-checksums.adoc +328 -0
  625. data/readme-docs/format-converter.adoc +316 -0
  626. data/readme-docs/installation.adoc +228 -0
  627. data/readme-docs/par2-archives.adoc +608 -0
  628. data/readme-docs/performance-profiler.adoc +389 -0
  629. data/readme-docs/preprocessing-filters.adoc +280 -0
  630. data/vendor/libomnizip_ffi.so +0 -0
  631. data/xz-file-format-1.2.1.txt +1174 -0
  632. metadata +768 -0
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Omnizip
6
+ module Formats
7
+ module Rar
8
+ # RAR archive repair functionality
9
+ # Attempts to repair corrupted archives using recovery records
10
+ class ArchiveRepairer
11
+ attr_reader :verifier, :recovery_record, :parity_handler
12
+
13
+ # Repair result
14
+ class RepairResult
15
+ attr_accessor :success, :repaired_files, :unrepaired_files,
16
+ :repaired_blocks, :errors, :output_path
17
+
18
+ def initialize
19
+ @success = false
20
+ @repaired_files = []
21
+ @unrepaired_files = []
22
+ @repaired_blocks = []
23
+ @errors = []
24
+ @output_path = nil
25
+ end
26
+
27
+ # Check if repair was successful
28
+ #
29
+ # @return [Boolean] true if all files repaired
30
+ def success?
31
+ @success && @unrepaired_files.empty?
32
+ end
33
+
34
+ # Get repair summary
35
+ #
36
+ # @return [String] Repair summary
37
+ def summary
38
+ if success?
39
+ "Repair successful: #{@repaired_files.size} files, " \
40
+ "#{@repaired_blocks.size} blocks"
41
+ elsif @repaired_files.any?
42
+ "Partial repair: #{@repaired_files.size} files OK, " \
43
+ "#{@unrepaired_files.size} failed"
44
+ else
45
+ "Repair failed: #{@errors.join(', ')}"
46
+ end
47
+ end
48
+ end
49
+
50
+ # Initialize repairer
51
+ def initialize
52
+ @verifier = nil
53
+ @recovery_record = nil
54
+ @parity_handler = nil
55
+ end
56
+
57
+ # Repair corrupted archive
58
+ #
59
+ # @param input_path [String] Path to corrupted archive
60
+ # @param output_path [String] Path for repaired archive
61
+ # @param options [Hash] Repair options
62
+ # @option options [Boolean] :use_external_rev Use external .rev files
63
+ # @option options [Boolean] :verify_repaired Verify after repair
64
+ # @option options [Boolean] :verbose Enable verbose output
65
+ # @return [RepairResult] Repair results
66
+ def repair(input_path, output_path, options = {})
67
+ result = RepairResult.new
68
+ result.output_path = output_path
69
+
70
+ begin
71
+ # Verify archive first
72
+ @verifier = ArchiveVerifier.new(input_path)
73
+ verification = @verifier.verify(
74
+ use_recovery: true,
75
+ verbose: options[:verbose],
76
+ )
77
+
78
+ unless verification.recovery_available
79
+ result.errors << "No recovery records available"
80
+ return result
81
+ end
82
+
83
+ unless verification.can_repair?
84
+ result.errors << "Corruption not recoverable"
85
+ return result
86
+ end
87
+
88
+ # Perform repair
89
+ @recovery_record = @verifier.recovery_record
90
+ @parity_handler = @verifier.parity_handler
91
+
92
+ perform_repair(input_path, output_path, verification, result,
93
+ options)
94
+
95
+ # Verify repaired archive
96
+ if options[:verify_repaired] && result.success
97
+ verify_repaired_archive(output_path, result)
98
+ end
99
+ rescue StandardError => e
100
+ result.success = false
101
+ result.errors << "Repair error: #{e.message}"
102
+ end
103
+
104
+ result
105
+ end
106
+
107
+ # Attempt quick repair (in-place)
108
+ #
109
+ # @param archive_path [String] Path to archive
110
+ # @param options [Hash] Repair options
111
+ # @return [RepairResult] Repair results
112
+ def quick_repair(archive_path, options = {})
113
+ # Create temporary output
114
+ temp_output = "#{archive_path}.repaired"
115
+
116
+ result = repair(archive_path, temp_output, options)
117
+
118
+ if result.success?
119
+ # Replace original with repaired
120
+ FileUtils.mv(temp_output, archive_path, force: true)
121
+ result.output_path = archive_path
122
+ else
123
+ # Clean up temp file
124
+ FileUtils.rm_f(temp_output)
125
+ end
126
+
127
+ result
128
+ end
129
+
130
+ private
131
+
132
+ # Perform the actual repair
133
+ #
134
+ # @param input_path [String] Input archive path
135
+ # @param output_path [String] Output archive path
136
+ # @param verification [VerificationResult] Verification results
137
+ # @param result [RepairResult] Repair result to update
138
+ # @param options [Hash] Repair options
139
+ def perform_repair(input_path, output_path, verification, result,
140
+ options)
141
+ # Copy archive to output first
142
+ FileUtils.cp(input_path, output_path)
143
+
144
+ # Repair corrupted blocks
145
+ verification.corrupt_blocks.each do |block_index|
146
+ if repair_block(output_path, block_index, options)
147
+ result.repaired_blocks << block_index
148
+ else
149
+ result.errors << "Failed to repair block #{block_index}"
150
+ end
151
+ end
152
+
153
+ # Track repaired files
154
+ verification.corrupted_files.each do |filename|
155
+ if verify_file_in_archive(output_path, filename)
156
+ result.repaired_files << filename
157
+ else
158
+ result.unrepaired_files << filename
159
+ end
160
+ end
161
+
162
+ result.success = result.unrepaired_files.empty?
163
+ end
164
+
165
+ # Repair single block in archive
166
+ #
167
+ # @param archive_path [String] Path to archive
168
+ # @param block_index [Integer] Block to repair
169
+ # @param options [Hash] Repair options
170
+ # @return [Boolean] true if repaired
171
+ def repair_block(archive_path, block_index, options)
172
+ return false unless @parity_handler.can_recover?(block_index)
173
+
174
+ # Recover the block
175
+ recovered_data = @parity_handler.recover_block(archive_path,
176
+ block_index)
177
+ return false unless recovered_data
178
+
179
+ # Write recovered data to archive
180
+ write_block_to_archive(archive_path, block_index, recovered_data)
181
+
182
+ puts "Repaired block #{block_index}" if options[:verbose]
183
+ true
184
+ rescue StandardError => e
185
+ if options[:verbose]
186
+ puts "Failed to repair block #{block_index}: #{e.message}"
187
+ end
188
+ false
189
+ end
190
+
191
+ # Write block data to archive
192
+ #
193
+ # @param archive_path [String] Path to archive
194
+ # @param block_index [Integer] Block index
195
+ # @param data [String] Block data
196
+ def write_block_to_archive(archive_path, block_index, data)
197
+ block_size = @recovery_record.block_size
198
+ offset = block_index * block_size
199
+
200
+ File.open(archive_path, "r+b") do |io|
201
+ io.seek(offset)
202
+ io.write(data)
203
+ end
204
+ end
205
+
206
+ # Verify file in archive
207
+ #
208
+ # @param archive_path [String] Path to archive
209
+ # @param filename [String] File name to verify
210
+ # @return [Boolean] true if file is valid
211
+ def verify_file_in_archive(archive_path, filename)
212
+ reader = Reader.new(archive_path)
213
+ reader.open
214
+
215
+ entry = reader.entries.find { |e| e.name == filename }
216
+ return false unless entry
217
+
218
+ # Verify entry (simplified - would check CRC in full implementation)
219
+ true
220
+ rescue StandardError
221
+ false
222
+ end
223
+
224
+ # Verify repaired archive
225
+ #
226
+ # @param archive_path [String] Path to repaired archive
227
+ # @param result [RepairResult] Repair result to update
228
+ def verify_repaired_archive(archive_path, result)
229
+ verifier = ArchiveVerifier.new(archive_path)
230
+ verification = verifier.verify(use_recovery: false)
231
+
232
+ return if verification.valid?
233
+
234
+ result.success = false
235
+ result.errors << "Repaired archive still has errors"
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Rar
6
+ # RAR archive verification
7
+ # Verifies archive integrity using CRCs and recovery records
8
+ class ArchiveVerifier
9
+ attr_reader :archive_path, :recovery_record, :parity_handler
10
+
11
+ # Verification result
12
+ class VerificationResult
13
+ attr_accessor :valid, :files_total, :files_ok, :files_corrupted,
14
+ :corrupted_files, :recoverable, :corrupt_blocks,
15
+ :recovery_available, :errors
16
+
17
+ def initialize
18
+ @valid = true
19
+ @files_total = 0
20
+ @files_ok = 0
21
+ @files_corrupted = 0
22
+ @corrupted_files = []
23
+ @recoverable = false
24
+ @corrupt_blocks = []
25
+ @recovery_available = false
26
+ @errors = []
27
+ end
28
+
29
+ # Check if archive is valid
30
+ #
31
+ # @return [Boolean] true if valid
32
+ def valid?
33
+ @valid && @files_corrupted.zero?
34
+ end
35
+
36
+ # Check if corruption can be repaired
37
+ #
38
+ # @return [Boolean] true if repairable
39
+ def can_repair?
40
+ @recovery_available && @recoverable
41
+ end
42
+
43
+ # Get summary string
44
+ #
45
+ # @return [String] Verification summary
46
+ def summary
47
+ if valid?
48
+ "Archive OK: #{@files_total} files verified"
49
+ else
50
+ msg = "Archive corrupted: #{@files_corrupted}/#{@files_total} files damaged"
51
+ msg += " (repairable)" if can_repair?
52
+ msg
53
+ end
54
+ end
55
+ end
56
+
57
+ # Initialize verifier
58
+ #
59
+ # @param archive_path [String] Path to RAR archive
60
+ def initialize(archive_path)
61
+ @archive_path = archive_path
62
+ @recovery_record = nil
63
+ @parity_handler = nil
64
+ end
65
+
66
+ # Verify archive integrity
67
+ #
68
+ # @param use_recovery [Boolean] Use recovery records for verification
69
+ # @param verbose [Boolean] Enable verbose output
70
+ # @return [VerificationResult] Verification results
71
+ def verify(use_recovery: true, verbose: false)
72
+ result = VerificationResult.new
73
+
74
+ begin
75
+ # Open and parse archive
76
+ reader = Reader.new(@archive_path)
77
+ reader.open
78
+
79
+ result.files_total = reader.entries.size
80
+
81
+ # Detect recovery records
82
+ detect_recovery_records(reader, result) if use_recovery
83
+
84
+ # Verify each file
85
+ reader.entries.each do |entry|
86
+ file_valid = verify_entry(entry, verbose)
87
+
88
+ if file_valid
89
+ result.files_ok += 1
90
+ else
91
+ result.files_corrupted += 1
92
+ result.corrupted_files << entry.name
93
+ result.valid = false
94
+ end
95
+ end
96
+
97
+ # Check if corruption is recoverable
98
+ if result.files_corrupted.positive? && result.recovery_available
99
+ result.recoverable = check_recoverability(result.corrupt_blocks)
100
+ end
101
+ rescue StandardError => e
102
+ result.valid = false
103
+ result.errors << "Verification failed: #{e.message}"
104
+ end
105
+
106
+ result
107
+ end
108
+
109
+ # Verify single file entry
110
+ #
111
+ # @param entry [Models::RarEntry] Entry to verify
112
+ # @param verbose [Boolean] Print verbose output
113
+ # @return [Boolean] true if valid
114
+ def verify_entry(entry, verbose = false)
115
+ return true if entry.directory?
116
+
117
+ # For now, we rely on the decompressor to verify
118
+ # In a full implementation, we would check CRC32
119
+ valid = verify_entry_crc(entry)
120
+
121
+ puts "#{entry.name}: #{valid ? 'OK' : 'FAILED'}" if verbose
122
+
123
+ valid
124
+ rescue StandardError => e
125
+ puts "#{entry.name}: ERROR (#{e.message})" if verbose
126
+ false
127
+ end
128
+
129
+ # Quick test of archive
130
+ #
131
+ # @return [Boolean] true if archive can be opened
132
+ def quick_test
133
+ Reader.new(@archive_path).open
134
+ true
135
+ rescue StandardError
136
+ false
137
+ end
138
+
139
+ private
140
+
141
+ # Detect recovery records in archive
142
+ #
143
+ # @param reader [Reader] Archive reader
144
+ # @param result [VerificationResult] Result object to update
145
+ def detect_recovery_records(reader, result)
146
+ version = reader.header&.version || 4
147
+
148
+ @recovery_record = RecoveryRecord.new(version)
149
+
150
+ # Check for integrated recovery records
151
+ File.open(@archive_path, "rb") do |io|
152
+ @recovery_record.parse_from_archive(io, reader.archive_info.flags)
153
+ end
154
+
155
+ # Check for external .rev files
156
+ rev_files = @recovery_record.detect_external_files(@archive_path)
157
+ @recovery_record.load_external_files(rev_files) if rev_files.any?
158
+
159
+ result.recovery_available = @recovery_record.available?
160
+
161
+ # Initialize parity handler if recovery available
162
+ return unless result.recovery_available
163
+
164
+ @parity_handler = ParityHandler.new(@recovery_record)
165
+ @parity_handler.load_parity_data(@recovery_record.external_files)
166
+ end
167
+
168
+ # Verify entry CRC
169
+ #
170
+ # @param entry [Models::RarEntry] Entry to verify
171
+ # @return [Boolean] true if CRC matches
172
+ def verify_entry_crc(_entry)
173
+ # This is a placeholder - actual CRC verification would require
174
+ # extracting and checking the file
175
+ # For now, assume OK unless we have specific corruption data
176
+ true
177
+ end
178
+
179
+ # Check if corruption is recoverable
180
+ #
181
+ # @param corrupt_blocks [Array<Integer>] Corrupted block indices
182
+ # @return [Boolean] true if recoverable
183
+ def check_recoverability(corrupt_blocks)
184
+ return false unless @parity_handler
185
+
186
+ # Check if all corrupted blocks can be recovered
187
+ corrupt_blocks.all? { |idx| @parity_handler.can_recover?(idx) }
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,282 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Rar
6
+ # RAR block parser
7
+ # Parses different block types in RAR archives
8
+ class BlockParser
9
+ include Omnizip::Formats::Rar::Constants
10
+
11
+ attr_reader :version
12
+
13
+ # Initialize block parser
14
+ #
15
+ # @param version [Integer] RAR version (4 or 5)
16
+ def initialize(version)
17
+ @version = version
18
+ end
19
+
20
+ # Parse file block and create entry
21
+ #
22
+ # @param io [IO] Input stream
23
+ # @return [Models::RarEntry, nil] Parsed entry or nil
24
+ def parse_file_block(io)
25
+ if @version == 5
26
+ parse_rar5_file_block(io)
27
+ else
28
+ parse_rar4_file_block(io)
29
+ end
30
+ end
31
+
32
+ # Skip to next block
33
+ #
34
+ # @param io [IO] Input stream
35
+ # @param block_size [Integer] Block size to skip
36
+ def skip_block(io, block_size)
37
+ io.read(block_size) if block_size.positive?
38
+ end
39
+
40
+ private
41
+
42
+ # Parse RAR4 file block
43
+ #
44
+ # @param io [IO] Input stream
45
+ # @return [Models::RarEntry, nil] Parsed entry or nil
46
+ def parse_rar4_file_block(io)
47
+ entry = Models::RarEntry.new
48
+ block_start = io.pos
49
+
50
+ # Read block header
51
+ read_uint16(io)
52
+ head_type = io.read(1)&.ord
53
+ return nil unless head_type == BLOCK_FILE
54
+
55
+ head_flags = read_uint16(io)
56
+ head_size = read_uint16(io)
57
+
58
+ # Read file header data
59
+ pack_size = read_uint32(io)
60
+ unpack_size = read_uint32(io)
61
+ host_os = io.read(1)&.ord
62
+ file_crc = read_uint32(io)
63
+ file_time = read_uint32(io)
64
+ unpack_ver = io.read(1)&.ord
65
+ method = io.read(1)&.ord
66
+ name_size = read_uint16(io)
67
+ attr = read_uint32(io)
68
+
69
+ # Read extended sizes if large file
70
+ if head_flags.anybits?(FILE_LARGE)
71
+ high_pack_size = read_uint32(io)
72
+ high_unpack_size = read_uint32(io)
73
+ pack_size |= (high_pack_size << 32)
74
+ unpack_size |= (high_unpack_size << 32)
75
+ end
76
+
77
+ # Sanity bounds: corrupt headers must not drive huge reads.
78
+ # head_size can never exceed the bytes left from the block
79
+ # start, and the name must fit inside the header.
80
+ if head_size > io.size - block_start ||
81
+ name_size + 32 > head_size
82
+ return nil
83
+ end
84
+
85
+ # Read file name
86
+ name_bytes = io.read(name_size)
87
+ entry.name = decode_filename(name_bytes, head_flags)
88
+ # RAR4 archives store DOS-style backslash separators;
89
+ # normalize to forward slashes like unrar on Unix. Scrub
90
+ # first: unicode-flagged names may carry bytes that are not
91
+ # valid UTF-8, and String#tr raises on them under any
92
+ # locale.
93
+ entry.name = entry.name.scrub.tr("\\", "/")
94
+
95
+ # Set entry properties
96
+ entry.size = unpack_size
97
+ entry.compressed_size = pack_size
98
+ entry.crc = file_crc
99
+ entry.host_os = host_os
100
+ entry.method = method
101
+ entry.version = unpack_ver
102
+ entry.flags = head_flags
103
+ entry.attributes = attr
104
+ entry.mtime = dos_time_to_time(file_time)
105
+
106
+ # Set flags. RAR4 directory entries carry the full
107
+ # dictionary mask 0xE0 in HEAD_FLAGS (a directory has no
108
+ # dictionary); the exact match avoids misreading a large
109
+ # dictionary size on files as the marker.
110
+ entry.is_dir = head_flags.allbits?(FILE_DIRECTORY)
111
+ # WinRAR writes directory names with a trailing backslash;
112
+ # normalize it away for host paths.
113
+ entry.name = entry.name.chomp("\\") if entry.is_dir
114
+ entry.encrypted = head_flags.anybits?(FILE_ENCRYPTED)
115
+ entry.split_before = head_flags.anybits?(FILE_SPLIT_BEFORE)
116
+ entry.split_after = head_flags.anybits?(FILE_SPLIT_AFTER)
117
+
118
+ # Skip remaining header data and file data. HEAD_SIZE
119
+ # counts the whole block including the 2-byte HEAD_CRC;
120
+ # consumed so far: 2 (CRC) + 30 (fixed fields) + name, plus
121
+ # 8 more when high-size words were present. Leftover bytes
122
+ # cover salt/extra time fields without interpreting them.
123
+ remaining = head_size - (name_size + 32)
124
+ remaining -= 8 if head_flags.anybits?(FILE_LARGE)
125
+ io.read(remaining) if remaining.positive?
126
+ # Record where the packed data starts so extraction can seek
127
+ # straight to it instead of re-parsing the archive
128
+ entry.data_offset = io.pos
129
+ # Seek past the data: never allocate the packed bytes just
130
+ # to skip them. A corrupt pack_size (bigger than the file)
131
+ # would overflow the seek offset on Linux — clamp to EOF so
132
+ # the entry still lists.
133
+ skip_past(io, pack_size)
134
+
135
+ entry
136
+ end
137
+
138
+ # Parse RAR5 file block
139
+ #
140
+ # @param io [IO] Input stream
141
+ # @return [Models::RarEntry, nil] Parsed entry or nil
142
+ def parse_rar5_file_block(io)
143
+ entry = Models::RarEntry.new
144
+
145
+ # Read block header
146
+ read_uint32(io)
147
+ read_vint(io)
148
+ header_type = read_vint(io)
149
+ return nil unless header_type == RAR5_HEADER_FILE
150
+
151
+ header_flags = read_vint(io)
152
+
153
+ # Optional ExtraAreaSize / DataSize precede the file fields
154
+ extra_size = header_flags.anybits?(RAR5_FLAG_EXTRA_AREA) ? read_vint(io) : 0
155
+ data_size = header_flags.anybits?(RAR5_FLAG_DATA_AREA) ? read_vint(io) : 0
156
+
157
+ # Sanity bounds: corrupt headers must not drive huge reads
158
+ remaining_bytes = io.size - io.pos
159
+ return nil if extra_size > remaining_bytes || data_size > remaining_bytes
160
+
161
+ # Read file header
162
+ file_flags = read_vint(io)
163
+ unpack_size = read_vint(io)
164
+ attr = read_vint(io)
165
+
166
+ # Read modification time if present
167
+ mtime = nil
168
+ mtime = read_uint32(io) if file_flags.anybits?(0x02)
169
+
170
+ # Read CRC if present
171
+ crc = nil
172
+ crc = read_uint32(io) if file_flags.anybits?(0x04)
173
+
174
+ # Read compression info
175
+ read_vint(io)
176
+ host_os = read_vint(io)
177
+ name_length = read_vint(io)
178
+
179
+ # Read file name
180
+ name_bytes = io.read(name_length)
181
+ entry.name = name_bytes.to_s.scrub.force_encoding("UTF-8")
182
+
183
+ # Set entry properties
184
+ entry.size = unpack_size
185
+ entry.compressed_size = data_size
186
+ entry.crc = crc
187
+ entry.host_os = host_os
188
+ entry.flags = file_flags
189
+ entry.attributes = attr
190
+ entry.mtime = Time.at(mtime) if mtime
191
+ entry.is_dir = file_flags.anybits?(RAR5_FLAG_IS_DIR)
192
+ entry.version = 5
193
+
194
+ # Skip extra area, then compressed data; record the data
195
+ # start for direct-seek extraction. The data is seeked past,
196
+ # never read: corrupt sizes must not drive huge allocations.
197
+ io.read(extra_size) if extra_size.positive?
198
+ entry.data_offset = io.pos
199
+ skip_past(io, data_size)
200
+
201
+ entry
202
+ end
203
+
204
+ # Skip forward without allocating: clamp corrupt sizes to EOF
205
+ # so an overflowing seek (EINVAL on Linux) cannot abort the
206
+ # block walk
207
+ def skip_past(io, bytes)
208
+ return if bytes <= 0
209
+
210
+ remaining = io.size - io.pos
211
+ io.seek([bytes, remaining].min, ::IO::SEEK_CUR)
212
+ end
213
+
214
+ # Decode filename from bytes
215
+ #
216
+ # @param bytes [String] Raw filename bytes
217
+ # @param flags [Integer] Block flags
218
+ # @return [String] Decoded filename
219
+ def decode_filename(bytes, flags)
220
+ if flags.nobits?(FILE_UNICODE)
221
+ # ASCII filename
222
+ bytes.force_encoding("ASCII-8BIT")
223
+ else
224
+ # Unicode filename
225
+ bytes.force_encoding("UTF-8")
226
+ end
227
+ end
228
+
229
+ # Convert DOS time to Ruby Time
230
+ #
231
+ # @param dos_time [Integer] DOS time value
232
+ # @return [Time] Ruby time object
233
+ def dos_time_to_time(dos_time)
234
+ sec = (dos_time & 0x1F) * 2
235
+ min = (dos_time >> 5) & 0x3F
236
+ hour = (dos_time >> 11) & 0x1F
237
+ day = (dos_time >> 16) & 0x1F
238
+ month = (dos_time >> 21) & 0x0F
239
+ year = ((dos_time >> 25) & 0x7F) + 1980
240
+
241
+ Time.new(year, month, day, hour, min, sec)
242
+ rescue ArgumentError
243
+ Time.now
244
+ end
245
+
246
+ # Read 16-bit unsigned integer (little-endian)
247
+ def read_uint16(io)
248
+ bytes = io.read(2)
249
+ return 0 unless bytes&.size == 2
250
+
251
+ bytes.unpack1("v")
252
+ end
253
+
254
+ # Read 32-bit unsigned integer (little-endian)
255
+ def read_uint32(io)
256
+ bytes = io.read(4)
257
+ return 0 unless bytes&.size == 4
258
+
259
+ bytes.unpack1("V")
260
+ end
261
+
262
+ # Read variable-length integer (RAR5)
263
+ def read_vint(io)
264
+ result = 0
265
+ shift = 0
266
+
267
+ loop do
268
+ byte = io.read(1)&.ord
269
+ return result unless byte
270
+
271
+ result |= (byte & 0x7F) << shift
272
+ break if byte.nobits?(0x80)
273
+
274
+ shift += 7
275
+ end
276
+
277
+ result
278
+ end
279
+ end
280
+ end
281
+ end
282
+ end