omnizip 0.4.7-x86_64-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,640 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (C) 2025 Ribose Inc.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a
6
+ # copy of this software and associated documentation files (the "Software"),
7
+ # to deal in the Software without restriction, including without limitation
8
+ # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ # and/or sell copies of the Software, and to permit persons to whom the
10
+ # Software is furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
+ # DEALINGS IN THE SOFTWARE.
22
+
23
+ module Omnizip
24
+ module Algorithms
25
+ class LZMA < Algorithm
26
+ # XZ Utils-compatible fast mode encoder
27
+ #
28
+ # Implements greedy heuristics from lzma_encoder_optimum_fast.c.
29
+ # Uses 1-position lookahead to decide between literals and matches.
30
+ # No price calculation - relies on simple heuristics for speed.
31
+ #
32
+ # Based on: xz/src/liblzma/lzma/lzma_encoder_optimum_fast.c
33
+ class XzEncoderFast
34
+ include Constants
35
+
36
+ # Number of rep distances (REPS constant)
37
+ REPS = 4
38
+
39
+ # Literal marker (matches XZ Utils UINT32_MAX)
40
+ LITERAL_MARKER = 0xFFFFFFFF
41
+
42
+ attr_reader :reps
43
+
44
+ # Return bytes needed for decoding (excludes flush padding)
45
+ #
46
+ # For LZMA2: returns pre-flush position (excludes 5-byte flush padding)
47
+ # For regular LZMA: returns full output size
48
+ #
49
+ # @return [Integer] Number of bytes decoder will consume
50
+ def bytes_for_decode
51
+ @encoder.bytes_for_decode
52
+ end
53
+
54
+ # Initialize fast mode encoder
55
+ #
56
+ # @param mf [XzMatchFinderAdapter] Match finder
57
+ # @param encoder [XzBufferedRangeEncoder] Range encoder
58
+ # @param models [XzProbabilityModels] Probability models
59
+ # @param state [XzState] LZMA state machine
60
+ # @param nice_len [Integer] Nice match length (default 32)
61
+ # @param lc [Integer] Literal context bits (default 3)
62
+ # @param lp [Integer] Literal position bits (default 0)
63
+ # @param pb [Integer] Position bits (default 2)
64
+ def initialize(mf, encoder, models, state, nice_len: 32, lc: 3, lp: 0,
65
+ pb: 2)
66
+ @mf = mf
67
+ @encoder = encoder
68
+ @models = models
69
+ @state = state
70
+ @nice_len = nice_len
71
+ @lc = lc
72
+ @lp = lp
73
+ @pb = pb
74
+
75
+ # Rep distances (last 4 match distances)
76
+ # Initialize to 0 to prevent false matches before first normal match
77
+ @reps = [0, 0, 0, 0]
78
+
79
+ # Lookahead cache (for read_ahead == 1 optimization)
80
+ @read_ahead = 0
81
+ @longest_match_length = 0
82
+ @matches_count = 0
83
+ @cached_matches = []
84
+
85
+ # Track previous byte for literal context
86
+ @prev_byte = 0
87
+ end
88
+
89
+ # Find best match at current position using fast mode heuristics
90
+ #
91
+ # Returns (back, len) where:
92
+ # - back = LITERAL_MARKER, len = 1: encode literal
93
+ # - back = 0..3, len >= 2: rep match (use reps[back])
94
+ # - back >= 4, len >= 2: normal match (distance = back - 4)
95
+ #
96
+ # @return [Array<Integer, Integer>] [back, len]
97
+ def find_best_match
98
+ # Get matches (use cached if lookahead was done)
99
+ if @read_ahead.zero?
100
+ len_main = @mf.find_matches
101
+ matches_count = @mf.matches.size
102
+ else
103
+ # Use cached matches from previous lookahead
104
+ len_main = @longest_match_length
105
+ matches_count = @matches_count
106
+ @read_ahead = 0
107
+ end
108
+
109
+ buf_avail = [@mf.available + 1, MATCH_LEN_MAX].min
110
+
111
+ # Not enough input for match
112
+ return [LITERAL_MARKER, 1] if buf_avail < 2
113
+
114
+ # Check rep matches
115
+ rep_len, rep_index = check_rep_matches(buf_avail)
116
+
117
+ # Found long rep match - return immediately
118
+ if rep_len >= @nice_len
119
+ # Don't skip here - main loop handles it
120
+ return [rep_index, rep_len]
121
+ end
122
+
123
+ # Found long normal match - return immediately
124
+ if len_main >= @nice_len
125
+ back_main = @mf.matches.last.dist - 1 + REPS # Convert to 0-based then add REPS offset
126
+ # Don't skip here - main loop handles it
127
+ return [back_main, len_main]
128
+ end
129
+
130
+ # Select best normal match using heuristics
131
+ back_main = 0
132
+ if len_main >= 2
133
+ back_main = @mf.matches.last.dist
134
+
135
+ # Apply change_pair heuristic: prefer closer distances
136
+ while matches_count > 1 &&
137
+ len_main == @mf.matches[matches_count - 2].len + 1
138
+ prev_dist = @mf.matches[matches_count - 2].dist
139
+ break unless change_pair?(prev_dist, back_main)
140
+
141
+ matches_count -= 1
142
+ len_main = @mf.matches[matches_count - 1].len
143
+ back_main = @mf.matches[matches_count - 1].dist
144
+ end
145
+
146
+ # Reject short matches with far distances
147
+ len_main = 1 if len_main == 2 && back_main >= 0x80
148
+ end
149
+
150
+ # Compare rep vs normal match
151
+ # Prefer rep match if:
152
+ # - rep_len + 1 >= len_main, OR
153
+ # - rep_len + 2 >= len_main AND back_main > 512, OR
154
+ # - rep_len + 3 >= len_main AND back_main > 32768
155
+ if (rep_len >= 2) && ((rep_len + 1 >= len_main) ||
156
+ (rep_len + 2 >= len_main && back_main > (1 << 9)) ||
157
+ (rep_len + 3 >= len_main && back_main > (1 << 15)))
158
+ # Don't skip here - main loop handles it
159
+ return [rep_index, rep_len]
160
+ end
161
+
162
+ # No good match found
163
+ return [LITERAL_MARKER, 1] if len_main < 2 || buf_avail <= 2
164
+
165
+ # Lookahead: check next position for better match
166
+ @longest_match_length = @mf.find_matches
167
+ @matches_count = @mf.matches.size
168
+ @read_ahead = 1
169
+
170
+ if @longest_match_length >= 2
171
+ new_dist = @mf.matches.last.dist
172
+
173
+ # Encode literal if next position has better match
174
+ if (@longest_match_length >= len_main && new_dist < back_main) ||
175
+ (@longest_match_length == len_main + 1 && !change_pair?(
176
+ back_main, new_dist
177
+ )) ||
178
+ (@longest_match_length > len_main + 1) ||
179
+ (len_main.between?(3, @longest_match_length + 1) &&
180
+ change_pair?(new_dist, back_main))
181
+ return [LITERAL_MARKER, 1]
182
+ end
183
+ end
184
+
185
+ # Check reps at next position (after lookahead)
186
+ # Skip if all distances are 0 (uninitialized - before first normal match)
187
+ unless @reps.all?(0)
188
+ limit = [2, len_main - 1].max
189
+ @reps.each do |rep_dist|
190
+ if memcmp_at_offset(1, rep_dist, limit)
191
+ return [LITERAL_MARKER, 1]
192
+ end
193
+ end
194
+ end
195
+
196
+ # Encode best normal match
197
+ # Don't skip here - main loop handles it
198
+ # back_main contains raw 1-based distance, convert to back value
199
+ [back_main - 1 + REPS, len_main] # Convert to 0-based then add REPS offset
200
+ end
201
+
202
+ # Update rep distances after encoding match
203
+ #
204
+ # @param distance [Integer] Match distance (0-based)
205
+ def update_reps_match(distance)
206
+ @reps = [distance, @reps[0], @reps[1], @reps[2]]
207
+ end
208
+
209
+ # Update rep distances after encoding rep match
210
+ #
211
+ # @param rep_index [Integer] Rep index (0-3)
212
+ def update_reps_rep(rep_index)
213
+ rep_dist = @reps[rep_index]
214
+ @reps.delete_at(rep_index)
215
+ @reps.unshift(rep_dist)
216
+ end
217
+
218
+ # Encode literal symbol
219
+ #
220
+ # @param symbol [Integer] Byte value to encode
221
+ def encode_literal(symbol)
222
+ pos_state = @mf.pos & ((1 << @pb) - 1)
223
+
224
+ # Encode is_match bit (0 for literal)
225
+ prob_is_match = @models.is_match[@state.value][pos_state]
226
+ @encoder.queue_bit(prob_is_match, 0)
227
+
228
+ # Get literal subcoder BASE index (XZ Utils literal_subcoder macro)
229
+ # The subcoder is a flat array of 768 probability models
230
+ literal_base = get_literal_base(@mf.pos, @prev_byte)
231
+
232
+ if @state.literal_state?
233
+ # Normal literal (8-bit tree)
234
+ encode_normal_literal(literal_base, symbol)
235
+ else
236
+ # Matched literal (compare with match byte at rep0)
237
+ match_byte = @mf.get_byte(-@reps[0]) # reps[0] is 0-based offset
238
+ encode_matched_literal(literal_base, match_byte, symbol)
239
+ end
240
+
241
+ # Update state and prev_byte
242
+ @state.update_literal
243
+ @prev_byte = symbol
244
+ end
245
+
246
+ # Encode rep match
247
+ #
248
+ # @param rep_index [Integer] Rep index (0-3)
249
+ # @param length [Integer] Match length (>= 2)
250
+ def encode_rep_match(rep_index, length)
251
+ pos_state = @mf.pos & ((1 << @pb) - 1)
252
+
253
+ # Encode is_match bit (1 for match)
254
+ prob_is_match = @models.is_match[@state.value][pos_state]
255
+ @encoder.queue_bit(prob_is_match, 1)
256
+
257
+ # Encode is_rep bit (1 for rep)
258
+ prob_is_rep = @models.is_rep[@state.value]
259
+ @encoder.queue_bit(prob_is_rep, 1)
260
+
261
+ prob_is_rep0 = @models.is_rep0[@state.value]
262
+ case rep_index
263
+ when 0
264
+ # rep0
265
+ @encoder.queue_bit(prob_is_rep0, 0) # FIX: 0 means "yes, use rep0"
266
+
267
+ prob_is_rep0_long = @models.is_rep0_long[@state.value][pos_state]
268
+ if length == 1
269
+ # Short rep (1 byte)
270
+ @encoder.queue_bit(prob_is_rep0_long, 0)
271
+ @state.update_short_rep
272
+ else
273
+ # Long rep0
274
+ @encoder.queue_bit(prob_is_rep0_long, 1)
275
+ encode_rep_length(length, pos_state)
276
+ @state.update_long_rep
277
+ end
278
+ when 1
279
+ # rep1
280
+ @encoder.queue_bit(prob_is_rep0, 1)
281
+ prob_is_rep1 = @models.is_rep1[@state.value]
282
+ @encoder.queue_bit(prob_is_rep1, 0) # FIX: 0 means "yes, use rep1"
283
+ encode_rep_length(length, pos_state)
284
+ @state.update_long_rep
285
+ when 2
286
+ # rep2
287
+ @encoder.queue_bit(prob_is_rep0, 1)
288
+ prob_is_rep1 = @models.is_rep1[@state.value]
289
+ @encoder.queue_bit(prob_is_rep1, 1)
290
+ prob_is_rep2 = @models.is_rep2[@state.value]
291
+ @encoder.queue_bit(prob_is_rep2, 0) # FIX: 0 means "yes, use rep2"
292
+ encode_rep_length(length, pos_state)
293
+ @state.update_long_rep
294
+ else
295
+ # rep3
296
+ @encoder.queue_bit(prob_is_rep0, 1)
297
+ prob_is_rep1 = @models.is_rep1[@state.value]
298
+ @encoder.queue_bit(prob_is_rep1, 1)
299
+ prob_is_rep2 = @models.is_rep2[@state.value]
300
+ @encoder.queue_bit(prob_is_rep2, 1)
301
+ encode_rep_length(length, pos_state)
302
+ @state.update_long_rep
303
+ end
304
+
305
+ # Update prev_byte (last byte of match)
306
+ @prev_byte = @mf.get_byte(length - 1)
307
+ end
308
+
309
+ # Encode normal match
310
+ #
311
+ # @param distance [Integer] Match distance (0-based)
312
+ # @param length [Integer] Match length (>= 2)
313
+ def encode_normal_match(distance, length)
314
+ pos_state = @mf.pos & ((1 << @pb) - 1)
315
+
316
+ # Encode is_match bit (1 for match)
317
+ prob_is_match = @models.is_match[@state.value][pos_state]
318
+ @encoder.queue_bit(prob_is_match, 1)
319
+
320
+ # Encode is_rep bit (0 for normal match)
321
+ prob_is_rep = @models.is_rep[@state.value]
322
+ @encoder.queue_bit(prob_is_rep, 0)
323
+
324
+ # Encode length
325
+ encode_match_length(length, pos_state)
326
+
327
+ # Encode distance
328
+ encode_distance(distance, length)
329
+
330
+ # Update state and prev_byte
331
+ @state.update_match
332
+ @prev_byte = @mf.get_byte(length - 1)
333
+ end
334
+
335
+ private
336
+
337
+ # Check all rep matches at current position
338
+ #
339
+ # @param buf_avail [Integer] Bytes available
340
+ # @return [Array<Integer, Integer>] [best_rep_len, best_rep_index]
341
+ def check_rep_matches(buf_avail)
342
+ rep_len = 0
343
+ rep_index = 0
344
+
345
+ # Guard: Skip rep matching if all distances are 0 (uninitialized)
346
+ # This prevents false matches before the first normal match
347
+ return [0, 0] if @reps.all?(0)
348
+
349
+ @reps.each_with_index do |rep_dist, i|
350
+ # Skip rep distances of 0 (same position, invalid)
351
+ next if rep_dist.zero?
352
+
353
+ # Check first 2 bytes (MATCH_LEN_MIN)
354
+ next unless matches_at_distance?(rep_dist, MATCH_LEN_MIN)
355
+
356
+ # Calculate full match length
357
+ len = calculate_match_length(rep_dist, buf_avail)
358
+
359
+ if len > rep_len
360
+ rep_len = len
361
+ rep_index = i
362
+ end
363
+ end
364
+
365
+ [rep_len, rep_index]
366
+ end
367
+
368
+ # Check if first n bytes match at given distance
369
+ #
370
+ # @param distance [Integer] Distance to check (0-based: 0=same pos, 1=1 byte back)
371
+ # @param n [Integer] Number of bytes to check
372
+ # @return [Boolean] True if matches
373
+ def matches_at_distance?(distance, n)
374
+ return false if @mf.pos < distance
375
+
376
+ n.times do |i|
377
+ curr = @mf.get_byte(i)
378
+ prev = @mf.get_byte(i - distance)
379
+ return false if curr != prev
380
+ end
381
+
382
+ true
383
+ end
384
+
385
+ # Calculate match length at given distance
386
+ #
387
+ # @param distance [Integer] Distance (0-based: 0=same pos, 1=1 byte back)
388
+ # @param max_len [Integer] Maximum length to check
389
+ # @return [Integer] Match length
390
+ def calculate_match_length(distance, max_len)
391
+ return 0 if @mf.pos < distance
392
+
393
+ len = 0
394
+
395
+ while len < max_len
396
+ curr = @mf.get_byte(len)
397
+ prev = @mf.get_byte(len - distance)
398
+ break if curr != prev
399
+
400
+ len += 1
401
+ end
402
+
403
+ len
404
+ end
405
+
406
+ # Compare bytes at offset with bytes at distance
407
+ #
408
+ # Used for checking reps after lookahead.
409
+ #
410
+ # @param offset [Integer] Offset from current position
411
+ # @param distance [Integer] Distance to check (1-based)
412
+ # @param limit [Integer] Number of bytes to compare
413
+ # @return [Boolean] True if all bytes match
414
+ def memcmp_at_offset(offset, distance, limit)
415
+ limit.times do |i|
416
+ curr = @mf.get_byte(offset + i)
417
+ prev = @mf.get_byte(offset + i - distance)
418
+ return false if curr != prev
419
+ end
420
+
421
+ true
422
+ end
423
+
424
+ # Apply change_pair heuristic
425
+ #
426
+ # Prefer closer distances if far distance is much larger.
427
+ #
428
+ # @param small_dist [Integer] Smaller distance
429
+ # @param big_dist [Integer] Larger distance
430
+ # @return [Boolean] True if should change to smaller distance
431
+ def change_pair?(small_dist, big_dist)
432
+ (big_dist >> 7) > small_dist
433
+ end
434
+
435
+ # Get literal subcoder BASE index
436
+ #
437
+ # Ported from XZ Utils literal_subcoder() macro in lzma_common.h
438
+ # Returns the base index into the flat literal models array
439
+ # Each subcoder has 768 probability models (0x300)
440
+ #
441
+ # @param pos [Integer] Current position
442
+ # @param prev_byte [Integer] Previous byte
443
+ # @return [Integer] Base index into @models.literal array
444
+ def get_literal_base(pos, prev_byte)
445
+ # literal_mask = (UINT32_C(0x100) << (lp)) - (UINT32_C(0x100) >> (lc))
446
+ literal_mask = (0x100 << @lp) - (0x100 >> @lc)
447
+
448
+ # ((((pos) << 8) + (prev_byte)) & (literal_mask)) << (lc)
449
+ context = (((pos << 8) + prev_byte) & literal_mask) << @lc
450
+
451
+ # 3 * context (each subcoder has 768 models, indexed as 3 * context + offset)
452
+ 3 * context
453
+ end
454
+
455
+ # Encode normal literal (8-bit tree)
456
+ #
457
+ # @param literal_base [Integer] Base index into literal models array
458
+ # @param symbol [Integer] Byte value
459
+ def encode_normal_literal(literal_base, symbol)
460
+ context = 1
461
+ 8.downto(1) do |i|
462
+ bit = (symbol >> (i - 1)) & 1
463
+ @encoder.queue_bit(@models.literal[literal_base + context], bit)
464
+ context = (context << 1) | bit
465
+ end
466
+ end
467
+
468
+ # Encode matched literal (compare with match byte)
469
+ #
470
+ # @param literal_base [Integer] Base index into literal models array
471
+ # @param match_byte [Integer] Byte at match position
472
+ # @param symbol [Integer] Byte value to encode
473
+ def encode_matched_literal(literal_base, match_byte, symbol)
474
+ offset = 0x100
475
+ symbol += 0x100 # Start symbol at 256 (XZ Utils algorithm)
476
+
477
+ # Loop until symbol reaches 0x10000 (65536)
478
+ while symbol < 0x10000
479
+ match_byte <<= 1
480
+ match_bit = match_byte & offset
481
+ subcoder_index = offset + match_bit + (symbol >> 8)
482
+ bit = (symbol >> 7) & 1
483
+
484
+ @encoder.queue_bit(@models.literal[literal_base + subcoder_index],
485
+ bit)
486
+
487
+ symbol <<= 1
488
+ offset &= ~(match_byte ^ symbol)
489
+ end
490
+ end
491
+
492
+ # Encode rep match length
493
+ #
494
+ # @param length [Integer] Match length (>= 2)
495
+ # @param pos_state [Integer] Position state
496
+ def encode_rep_length(length, pos_state)
497
+ encode_length(@models.rep_len_encoder, length, pos_state)
498
+ end
499
+
500
+ # Encode normal match length
501
+ #
502
+ # @param length [Integer] Match length (>= 2)
503
+ # @param pos_state [Integer] Position state
504
+ def encode_match_length(length, pos_state)
505
+ encode_length(@models.match_len_encoder, length, pos_state)
506
+ end
507
+
508
+ # Encode length using length encoder
509
+ #
510
+ # @param len_encoder [LengthEncoder] Length encoder
511
+ # @param length [Integer] Match length (2-273)
512
+ # @param pos_state [Integer] Position state
513
+ def encode_length(len_encoder, length, pos_state)
514
+ len = length - MATCH_LEN_MIN
515
+
516
+ if len < LEN_LOW_SYMBOLS
517
+ # Low: 0-7
518
+ @encoder.queue_bit(len_encoder.choice, 0)
519
+ encode_bittree(len_encoder.low[pos_state], NUM_LEN_LOW_BITS, len)
520
+ elsif len < LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS
521
+ # Mid: 8-15
522
+ @encoder.queue_bit(len_encoder.choice, 1)
523
+ @encoder.queue_bit(len_encoder.choice2, 0)
524
+ encode_bittree(len_encoder.mid[pos_state], NUM_LEN_MID_BITS,
525
+ len - LEN_LOW_SYMBOLS)
526
+ else
527
+ # High: 16-271
528
+ @encoder.queue_bit(len_encoder.choice, 1)
529
+ @encoder.queue_bit(len_encoder.choice2, 1)
530
+ encode_bittree(len_encoder.high, NUM_LEN_HIGH_BITS,
531
+ len - LEN_LOW_SYMBOLS - LEN_MID_SYMBOLS)
532
+ end
533
+ end
534
+
535
+ # Encode distance
536
+ #
537
+ # @param distance [Integer] Distance (0-based)
538
+ # @param length [Integer] Match length
539
+ def encode_distance(distance, length)
540
+ dist_slot = get_dist_slot(distance)
541
+ len_state = get_len_to_pos_state(length)
542
+
543
+ # Encode distance slot
544
+ encode_bittree(@models.dist_slot[len_state], NUM_DIST_SLOT_BITS,
545
+ dist_slot)
546
+
547
+ # Encode distance footer
548
+ if dist_slot >= START_POS_MODEL_INDEX
549
+ footer_bits = (dist_slot >> 1) - 1
550
+ base = (2 | (dist_slot & 1)) << footer_bits
551
+ dist_reduced = distance - base
552
+
553
+ if dist_slot < END_POS_MODEL_INDEX
554
+ # Use probability models
555
+ encode_bittree_reverse(@models.dist_special, dist_reduced,
556
+ footer_bits, base - dist_slot)
557
+ else
558
+ # Direct bits + alignment
559
+ direct_bits = footer_bits - DIST_ALIGN_BITS
560
+ @encoder.queue_direct_bits(dist_reduced >> DIST_ALIGN_BITS,
561
+ direct_bits)
562
+ encode_bittree_reverse(@models.dist_align, dist_reduced & ((1 << DIST_ALIGN_BITS) - 1),
563
+ DIST_ALIGN_BITS, 0)
564
+ end
565
+ end
566
+ end
567
+
568
+ # Encode bittree (MSB first)
569
+ #
570
+ # @param probs [Array<BitModel>] Probability models
571
+ # @param num_bits [Integer] Number of bits
572
+ # @param value [Integer] Value to encode
573
+ def encode_bittree(probs, num_bits, value)
574
+ context = 1
575
+ num_bits.downto(1) do |i|
576
+ bit = (value >> (i - 1)) & 1
577
+ @encoder.queue_bit(probs[context], bit)
578
+ context = (context << 1) | bit
579
+ end
580
+ end
581
+
582
+ # Encode bittree in reverse (LSB first)
583
+ #
584
+ # @param probs [Array<BitModel>] Probability models
585
+ # @param value [Integer] Value to encode
586
+ # @param num_bits [Integer] Number of bits
587
+ # @param offset [Integer] Probability array offset
588
+ def encode_bittree_reverse(probs, value, num_bits, offset)
589
+ context = 1
590
+ num_bits.times do |i|
591
+ bit = (value >> i) & 1
592
+ @encoder.queue_bit(probs[offset + context], bit)
593
+ context = (context << 1) | bit
594
+ end
595
+ end
596
+
597
+ # Get distance slot for distance
598
+ #
599
+ # @param distance [Integer] Distance (0-based)
600
+ # @return [Integer] Distance slot (0-63)
601
+ def get_dist_slot(distance)
602
+ if distance < NUM_FULL_DISTANCES
603
+ # Use precomputed table for small distances
604
+ distance < 4 ? distance : fast_pos_small(distance)
605
+ else
606
+ # Formula for large distances
607
+ fast_pos_large(distance)
608
+ end
609
+ end
610
+
611
+ # Fast position calculation for small distances
612
+ def fast_pos_small(distance)
613
+ # Simplified slot calculation
614
+ slot = 0
615
+ dist = distance
616
+ while dist > 3
617
+ dist >>= 1
618
+ slot += 2
619
+ end
620
+ slot + dist
621
+ end
622
+
623
+ # Fast position calculation for large distances
624
+ def fast_pos_large(distance)
625
+ slot = fast_pos_small(distance >> 6)
626
+ slot + 12
627
+ end
628
+
629
+ # Map length to position state
630
+ #
631
+ # @param length [Integer] Match length
632
+ # @return [Integer] Position state (0-3)
633
+ def get_len_to_pos_state(length)
634
+ len = length - MATCH_LEN_MIN
635
+ len < NUM_LEN_TO_POS_STATES ? len : NUM_LEN_TO_POS_STATES - 1
636
+ end
637
+ end
638
+ end
639
+ end
640
+ end