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,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require_relative "../algorithms/lzma"
5
+ require_relative "../format_registry"
6
+
7
+ module Omnizip
8
+ module Formats
9
+ #
10
+ # LZIP (.lz) compression format
11
+ #
12
+ # Lzip is a file compression format that uses LZMA compression with a
13
+ # simple container format. It was created as an alternative to the
14
+ # legacy .lzma format with better integrity checking.
15
+ #
16
+ # This is DIFFERENT from both XZ and .lzma (LZMA_Alone) formats:
17
+ # - XZ (.xz): Container format with stream header/footer/index, LZMA2 compression
18
+ # - LZIP (.lz): Standalone format with "LZIP" magic and CRC32 footer, LZMA1 compression
19
+ # - LZMA_Alone (.lzma): Legacy standalone format with properties byte, LZMA1 compression
20
+ #
21
+ # Format structure:
22
+ # - Header (6 bytes):
23
+ # - Magic bytes: "LZIP" (0x4C 0x5A 0x49 0x50)
24
+ # - Version (1 byte): 0 or 1
25
+ # - Dictionary size (1 byte): encoded format
26
+ # - LZMA1 compressed stream (with fixed LC=3, LP=0, PB=2)
27
+ # - Footer:
28
+ # - Version 0 (12 bytes): CRC32 (4) + Uncompressed size (8)
29
+ # - Version 1 (20 bytes): CRC32 (4) + Uncompressed size (8) + Member size (8)
30
+ #
31
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/common/lzip_decoder.c
32
+ #
33
+ module Lzip
34
+ # Lzip magic bytes: "LZIP" in ASCII
35
+ # Reference: lzip_decoder.c:106
36
+ MAGIC = [0x4C, 0x5A, 0x49, 0x50].pack("C*")
37
+
38
+ # Fixed LC/LP/PB values for lzip format
39
+ # Reference: lzip_decoder.c:23-26
40
+ LZIP_LC = 3
41
+ LZIP_LP = 0
42
+ LZIP_PB = 2
43
+
44
+ # Minimum and maximum dictionary sizes (in bytes)
45
+ # Reference: lzip_decoder.c:197-198
46
+ MIN_DICT_SIZE = 4096 # 4 KiB
47
+ MAX_DICT_SIZE = (512 << 20) # 512 MiB
48
+
49
+ class << self
50
+ # Compress a file with LZIP
51
+ #
52
+ # @param input_path [String] Input file path
53
+ # @param output_path [String] Output LZIP file path
54
+ # @param options [Hash] Compression options
55
+ # @option options [Integer] :level Compression level (0-9, default: 6)
56
+ # @option options [Integer] :dict_size Dictionary size (default: auto from level)
57
+ # @option options [Integer] :version LZIP version (0 or 1, default: 1)
58
+ def compress(input_path, output_path, options = {})
59
+ input_data = File.binread(input_path)
60
+
61
+ File.open(output_path, "wb") do |output|
62
+ compress_stream(
63
+ StringIO.new(input_data),
64
+ output,
65
+ options,
66
+ )
67
+ end
68
+ end
69
+
70
+ # Decompress LZIP data
71
+ #
72
+ # @param input [String, IO] Input data, file path, or IO object
73
+ # @param output [String, IO, nil] Output file path or IO object
74
+ # @param options [Hash] Options
75
+ # @option options [Boolean] :ignore_check If true, skip CRC32 verification (default: false)
76
+ # @option options [Boolean] :concatenated If true, decode concatenated .lz members (default: false)
77
+ # @return [String, nil] Decompressed data (if output is nil)
78
+ def decompress(input, output = nil, options = {})
79
+ # Handle raw data string vs file path vs IO object
80
+ data = if input.respond_to?(:read)
81
+ # Already an IO object
82
+ input.read
83
+ elsif input.is_a?(String)
84
+ # Could be file path or raw data
85
+ if !input.include?("\0") && File.exist?(input)
86
+ File.binread(input)
87
+ else
88
+ input.b
89
+ end
90
+ else
91
+ raise ArgumentError,
92
+ "Input must be a String or IO object"
93
+ end
94
+
95
+ # Decode using LzipDecoder
96
+ require_relative "../algorithms/lzma/lzip_decoder"
97
+ decoder = Omnizip::Algorithms::LZMA::LzipDecoder.new(
98
+ StringIO.new(data),
99
+ options,
100
+ )
101
+ result = decoder.decode_stream
102
+
103
+ if output
104
+ if output.respond_to?(:write)
105
+ output.write(result)
106
+ else
107
+ File.binwrite(output, result)
108
+ end
109
+ else
110
+ result
111
+ end
112
+ end
113
+
114
+ # Decode LZIP data (alias for decompress with no output)
115
+ #
116
+ # @param input [String, IO] Input LZIP data or file path
117
+ # @return [String] Decompressed data
118
+ def decode(input)
119
+ decompress(input)
120
+ end
121
+
122
+ # Compress data stream with LZIP
123
+ #
124
+ # @param input_io [IO] Input stream
125
+ # @param output_io [IO] Output stream
126
+ # @param options [Hash] Compression options
127
+ def compress_stream(input_io, _output_io, _options = {})
128
+ input_io.read
129
+
130
+ # TODO: Implement LZIP encoder
131
+ raise NotImplementedError,
132
+ "LZIP encoding not yet implemented. Use decompression only."
133
+ end
134
+
135
+ # Decompress LZIP stream
136
+ #
137
+ # @param input_io [IO] Input stream
138
+ # @param output_io [IO] Output stream
139
+ # @param options [Hash] Options
140
+ # @return [Hash] Metadata (version, dict_size, member_size)
141
+ def decompress_stream(input_io, output_io, options = {})
142
+ require_relative "../algorithms/lzma/lzip_decoder"
143
+ decoder = Omnizip::Algorithms::LZMA::LzipDecoder.new(input_io, options)
144
+ result = decoder.decode_stream
145
+
146
+ output_io.write(result)
147
+
148
+ # Return metadata
149
+ {
150
+ version: decoder.instance_variable_get(:@version),
151
+ dict_size: decoder.instance_variable_get(:@dict_size),
152
+ member_size: decoder.instance_variable_get(:@member_size),
153
+ }
154
+ end
155
+
156
+ # Register LZIP format when loaded
157
+ def register!
158
+ FormatRegistry.register(".lz", Omnizip::Formats::Lzip)
159
+ FormatRegistry.register(".lzip", Omnizip::Formats::Lzip)
160
+ end
161
+
162
+ # Detect if data is LZIP format
163
+ #
164
+ # @param data [String] Data to check
165
+ # @return [Boolean] true if data has LZIP magic bytes
166
+ def lzip_file?(data)
167
+ data.start_with?(MAGIC)
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ # Auto-register on load
175
+ Omnizip::Formats::Lzip.register!
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require_relative "../algorithms/lzma"
5
+ require_relative "../format_registry"
6
+
7
+ module Omnizip
8
+ module Formats
9
+ #
10
+ # LZMA_Alone (.lzma) compression format
11
+ #
12
+ # This is the legacy LZMA_Alone format used by LZMA Utils 4.32.x.
13
+ # It is DIFFERENT from both XZ and LZIP formats:
14
+ # - XZ (.xz): Container format with stream header/footer/index, LZMA2 compression
15
+ # - LZIP (.lz): Standalone format with "LZIP" magic and CRC32 footer, LZMA1 compression
16
+ # - LZMA_Alone (.lzma): Legacy standalone format with properties byte, LZMA1 compression
17
+ #
18
+ # Format structure:
19
+ # - Properties (1 byte): encodes lc, lp, pb values
20
+ # - Dictionary size (4 bytes, little-endian)
21
+ # - Uncompressed size (8 bytes, little-endian, UINT64_MAX = unknown)
22
+ # - LZMA1 compressed stream (no footer, no CRC32)
23
+ #
24
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/common/alone_decoder.c
25
+ #
26
+ module LzmaAlone
27
+ # Maximum valid uncompressed size (256 GiB)
28
+ # From alone_decoder.c:118
29
+ MAX_UNCOMPRESSED_SIZE = (1 << 38)
30
+
31
+ # Property byte validation limits
32
+ # From lzma_decoder.c:1218
33
+ MAX_PROPERTY_BYTE = (((4 * 5) + 4) * 9) + 8 # = 233
34
+
35
+ # Value indicating unknown uncompressed size
36
+ UINT64_MAX = (1 << 64) - 1
37
+
38
+ class << self
39
+ # Compress a file with LZMA_Alone format
40
+ #
41
+ # @param input_path [String] Input file path
42
+ # @param output_path [String] Output LZMA_Alone file path
43
+ # @param options [Hash] Compression options
44
+ # @option options [Integer] :lc Literal context bits (0-8, default: 3)
45
+ # @option options [Integer] :lp Literal position bits (0-4, default: 0)
46
+ # @option options [Integer] :pb Position bits (0-4, default: 2)
47
+ # @option options [Integer] :dict_size Dictionary size (default: 8MB)
48
+ # @option options [Integer] :uncompressed_size Explicit uncompressed size (default: unknown)
49
+ def compress(input_path, output_path, options = {})
50
+ input_data = File.binread(input_path)
51
+
52
+ File.open(output_path, "wb") do |output|
53
+ compress_stream(
54
+ StringIO.new(input_data),
55
+ output,
56
+ options,
57
+ )
58
+ end
59
+ end
60
+
61
+ # Decompress LZMA_Alone data
62
+ #
63
+ # @param input [String, IO] Input data, file path, or IO object
64
+ # @param output [String, IO, nil] Output file path or IO object
65
+ # @param options [Hash] Options
66
+ # @option options [Boolean] :picky If true, reject files unlikely to be .lzma (default: false)
67
+ # @return [String, nil] Decompressed data (if output is nil)
68
+ def decompress(input, output = nil, options = {})
69
+ # Handle raw data string vs file path
70
+ data = if input.respond_to?(:read)
71
+ input.read
72
+ elsif input.is_a?(String)
73
+ if !input.include?("\0") && File.exist?(input)
74
+ File.binread(input)
75
+ else
76
+ input.b
77
+ end
78
+ else
79
+ raise ArgumentError,
80
+ "Input must be a String or IO object"
81
+ end
82
+
83
+ # Decode using LzmaAloneDecoder
84
+ require_relative "../algorithms/lzma/lzma_alone_decoder"
85
+ decoder = Omnizip::Algorithms::LZMA::LzmaAloneDecoder.new(
86
+ StringIO.new(data),
87
+ options,
88
+ )
89
+ result = decoder.decode_stream
90
+
91
+ if output
92
+ if output.respond_to?(:write)
93
+ output.write(result)
94
+ else
95
+ File.binwrite(output, result)
96
+ end
97
+ else
98
+ result
99
+ end
100
+ end
101
+
102
+ # Decode LZMA_Alone data (alias for decompress with no output)
103
+ #
104
+ # @param input [String, IO] Input LZMA_Alone data or file path
105
+ # @return [String] Decompressed data
106
+ def decode(input)
107
+ decompress(input)
108
+ end
109
+
110
+ # Compress data stream with LZMA_Alone format
111
+ #
112
+ # @param input_io [IO] Input stream
113
+ # @param output_io [IO] Output stream
114
+ # @param options [Hash] Compression options
115
+ def compress_stream(input_io, output_io, options = {})
116
+ input_data = input_io.read
117
+
118
+ # Get encoding parameters
119
+ lc = options[:lc] || 3
120
+ lp = options[:lp] || 0
121
+ pb = options[:pb] || 2
122
+ dict_size = options[:dict_size] || (8 * 1024 * 1024)
123
+ uncompressed_size = options[:uncompressed_size] || input_data.bytesize
124
+
125
+ # Encode properties byte
126
+ prop_byte = (((pb * 5) + lp) * 9) + lc
127
+
128
+ # Write header
129
+ output_io.write([prop_byte].pack("C"))
130
+ output_io.write([dict_size].pack("V"))
131
+ output_io.write([uncompressed_size].pack("Q<"))
132
+
133
+ # TODO: Implement LZMA1 encoder
134
+ raise NotImplementedError,
135
+ "LZMA_Alone encoding not yet implemented. Use decompression only."
136
+ end
137
+
138
+ # Decompress LZMA_Alone stream
139
+ #
140
+ # @param input_io [IO] Input stream
141
+ # @param output_io [IO] Output stream
142
+ # @param options [Hash] Options
143
+ # @return [Hash] Metadata (lc, lp, pb, dict_size, uncompressed_size)
144
+ def decompress_stream(input_io, output_io, options = {})
145
+ require_relative "../algorithms/lzma/lzma_alone_decoder"
146
+ decoder = Omnizip::Algorithms::LZMA::LzmaAloneDecoder.new(input_io, options)
147
+ result = decoder.decode_stream
148
+
149
+ output_io.write(result)
150
+
151
+ # Return metadata
152
+ {
153
+ lc: decoder.instance_variable_get(:@lc),
154
+ lp: decoder.instance_variable_get(:@lp),
155
+ pb: decoder.instance_variable_get(:@pb),
156
+ dict_size: decoder.instance_variable_get(:@dict_size),
157
+ uncompressed_size: decoder.instance_variable_get(:@uncompressed_size),
158
+ }
159
+ end
160
+
161
+ # Register LZMA_Alone format when loaded
162
+ def register!
163
+ FormatRegistry.register(".lzma", Omnizip::Formats::LzmaAlone)
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ # Auto-register on load
171
+ Omnizip::Formats::LzmaAlone.register!
@@ -0,0 +1,243 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "archive_verifier"
4
+ require_relative "recovery_record"
5
+ require_relative "parity_handler"
6
+ require "fileutils"
7
+
8
+ module Omnizip
9
+ module Formats
10
+ module Rar
11
+ # RAR archive repair functionality
12
+ # Attempts to repair corrupted archives using recovery records
13
+ class ArchiveRepairer
14
+ attr_reader :verifier, :recovery_record, :parity_handler
15
+
16
+ # Repair result
17
+ class RepairResult
18
+ attr_accessor :success, :repaired_files, :unrepaired_files,
19
+ :repaired_blocks, :errors, :output_path
20
+
21
+ def initialize
22
+ @success = false
23
+ @repaired_files = []
24
+ @unrepaired_files = []
25
+ @repaired_blocks = []
26
+ @errors = []
27
+ @output_path = nil
28
+ end
29
+
30
+ # Check if repair was successful
31
+ #
32
+ # @return [Boolean] true if all files repaired
33
+ def success?
34
+ @success && @unrepaired_files.empty?
35
+ end
36
+
37
+ # Get repair summary
38
+ #
39
+ # @return [String] Repair summary
40
+ def summary
41
+ if success?
42
+ "Repair successful: #{@repaired_files.size} files, " \
43
+ "#{@repaired_blocks.size} blocks"
44
+ elsif @repaired_files.any?
45
+ "Partial repair: #{@repaired_files.size} files OK, " \
46
+ "#{@unrepaired_files.size} failed"
47
+ else
48
+ "Repair failed: #{@errors.join(', ')}"
49
+ end
50
+ end
51
+ end
52
+
53
+ # Initialize repairer
54
+ def initialize
55
+ @verifier = nil
56
+ @recovery_record = nil
57
+ @parity_handler = nil
58
+ end
59
+
60
+ # Repair corrupted archive
61
+ #
62
+ # @param input_path [String] Path to corrupted archive
63
+ # @param output_path [String] Path for repaired archive
64
+ # @param options [Hash] Repair options
65
+ # @option options [Boolean] :use_external_rev Use external .rev files
66
+ # @option options [Boolean] :verify_repaired Verify after repair
67
+ # @option options [Boolean] :verbose Enable verbose output
68
+ # @return [RepairResult] Repair results
69
+ def repair(input_path, output_path, options = {})
70
+ result = RepairResult.new
71
+ result.output_path = output_path
72
+
73
+ begin
74
+ # Verify archive first
75
+ @verifier = ArchiveVerifier.new(input_path)
76
+ verification = @verifier.verify(
77
+ use_recovery: true,
78
+ verbose: options[:verbose],
79
+ )
80
+
81
+ unless verification.recovery_available
82
+ result.errors << "No recovery records available"
83
+ return result
84
+ end
85
+
86
+ unless verification.can_repair?
87
+ result.errors << "Corruption not recoverable"
88
+ return result
89
+ end
90
+
91
+ # Perform repair
92
+ @recovery_record = @verifier.recovery_record
93
+ @parity_handler = @verifier.parity_handler
94
+
95
+ perform_repair(input_path, output_path, verification, result,
96
+ options)
97
+
98
+ # Verify repaired archive
99
+ if options[:verify_repaired] && result.success
100
+ verify_repaired_archive(output_path, result)
101
+ end
102
+ rescue StandardError => e
103
+ result.success = false
104
+ result.errors << "Repair error: #{e.message}"
105
+ end
106
+
107
+ result
108
+ end
109
+
110
+ # Attempt quick repair (in-place)
111
+ #
112
+ # @param archive_path [String] Path to archive
113
+ # @param options [Hash] Repair options
114
+ # @return [RepairResult] Repair results
115
+ def quick_repair(archive_path, options = {})
116
+ # Create temporary output
117
+ temp_output = "#{archive_path}.repaired"
118
+
119
+ result = repair(archive_path, temp_output, options)
120
+
121
+ if result.success?
122
+ # Replace original with repaired
123
+ FileUtils.mv(temp_output, archive_path, force: true)
124
+ result.output_path = archive_path
125
+ else
126
+ # Clean up temp file
127
+ FileUtils.rm_f(temp_output)
128
+ end
129
+
130
+ result
131
+ end
132
+
133
+ private
134
+
135
+ # Perform the actual repair
136
+ #
137
+ # @param input_path [String] Input archive path
138
+ # @param output_path [String] Output archive path
139
+ # @param verification [VerificationResult] Verification results
140
+ # @param result [RepairResult] Repair result to update
141
+ # @param options [Hash] Repair options
142
+ def perform_repair(input_path, output_path, verification, result,
143
+ options)
144
+ # Copy archive to output first
145
+ FileUtils.cp(input_path, output_path)
146
+
147
+ # Repair corrupted blocks
148
+ verification.corrupt_blocks.each do |block_index|
149
+ if repair_block(output_path, block_index, options)
150
+ result.repaired_blocks << block_index
151
+ else
152
+ result.errors << "Failed to repair block #{block_index}"
153
+ end
154
+ end
155
+
156
+ # Track repaired files
157
+ verification.corrupted_files.each do |filename|
158
+ if verify_file_in_archive(output_path, filename)
159
+ result.repaired_files << filename
160
+ else
161
+ result.unrepaired_files << filename
162
+ end
163
+ end
164
+
165
+ result.success = result.unrepaired_files.empty?
166
+ end
167
+
168
+ # Repair single block in archive
169
+ #
170
+ # @param archive_path [String] Path to archive
171
+ # @param block_index [Integer] Block to repair
172
+ # @param options [Hash] Repair options
173
+ # @return [Boolean] true if repaired
174
+ def repair_block(archive_path, block_index, options)
175
+ return false unless @parity_handler.can_recover?(block_index)
176
+
177
+ # Recover the block
178
+ recovered_data = @parity_handler.recover_block(archive_path,
179
+ block_index)
180
+ return false unless recovered_data
181
+
182
+ # Write recovered data to archive
183
+ write_block_to_archive(archive_path, block_index, recovered_data)
184
+
185
+ puts "Repaired block #{block_index}" if options[:verbose]
186
+ true
187
+ rescue StandardError => e
188
+ if options[:verbose]
189
+ puts "Failed to repair block #{block_index}: #{e.message}"
190
+ end
191
+ false
192
+ end
193
+
194
+ # Write block data to archive
195
+ #
196
+ # @param archive_path [String] Path to archive
197
+ # @param block_index [Integer] Block index
198
+ # @param data [String] Block data
199
+ def write_block_to_archive(archive_path, block_index, data)
200
+ block_size = @recovery_record.block_size
201
+ offset = block_index * block_size
202
+
203
+ File.open(archive_path, "r+b") do |io|
204
+ io.seek(offset)
205
+ io.write(data)
206
+ end
207
+ end
208
+
209
+ # Verify file in archive
210
+ #
211
+ # @param archive_path [String] Path to archive
212
+ # @param filename [String] File name to verify
213
+ # @return [Boolean] true if file is valid
214
+ def verify_file_in_archive(archive_path, filename)
215
+ reader = Reader.new(archive_path)
216
+ reader.open
217
+
218
+ entry = reader.entries.find { |e| e.name == filename }
219
+ return false unless entry
220
+
221
+ # Verify entry (simplified - would check CRC in full implementation)
222
+ true
223
+ rescue StandardError
224
+ false
225
+ end
226
+
227
+ # Verify repaired archive
228
+ #
229
+ # @param archive_path [String] Path to repaired archive
230
+ # @param result [RepairResult] Repair result to update
231
+ def verify_repaired_archive(archive_path, result)
232
+ verifier = ArchiveVerifier.new(archive_path)
233
+ verification = verifier.verify(use_recovery: false)
234
+
235
+ return if verification.valid?
236
+
237
+ result.success = false
238
+ result.errors << "Repaired archive still has errors"
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end