omnizip 0.4.7-arm-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (632) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +293 -0
  5. data/CHANGELOG.md +1647 -0
  6. data/CONTEXT.md +68 -0
  7. data/COPYING +502 -0
  8. data/Gemfile +19 -0
  9. data/LICENSE +12 -0
  10. data/README.adoc +1327 -0
  11. data/Rakefile +15 -0
  12. data/TODO.refactor/00-overview.md +67 -0
  13. data/TODO.refactor/01-registry-base-class.md +81 -0
  14. data/TODO.refactor/02-error-hierarchy.md +57 -0
  15. data/TODO.refactor/03-autoload-entry-point.md +69 -0
  16. data/TODO.refactor/04-filter-base-consolidation.md +49 -0
  17. data/TODO.refactor/05-send-private-methods.md +64 -0
  18. data/TODO.refactor/06-instance-variable-access.md +69 -0
  19. data/TODO.refactor/07-respond-to-replacement.md +237 -0
  20. data/TODO.refactor/08-spec-doubles.md +27 -0
  21. data/TODO.refactor/09-cli-shared-module.md +35 -0
  22. data/TODO.refactor/10-format-detector-ocp.md +34 -0
  23. data/TODO.refactor/11-convenience-decoupling.md +38 -0
  24. data/TODO.refactor/12-thread-safety.md +8 -0
  25. data/TODO.refactor/13-lutaml-model-migration.md +158 -0
  26. data/TODO.refactor/14-add-missing-specs.md +25 -0
  27. data/benchmark/README.md +260 -0
  28. data/benchmark/benchmark_suite.rb +125 -0
  29. data/benchmark/compression_bench.rb +181 -0
  30. data/benchmark/filter_bench.rb +180 -0
  31. data/benchmark/models/benchmark_result.rb +59 -0
  32. data/benchmark/models/comparison_result.rb +69 -0
  33. data/benchmark/profile_suite.rb +167 -0
  34. data/benchmark/reporter.rb +150 -0
  35. data/benchmark/run_benchmarks.rb +66 -0
  36. data/benchmark/test_data.rb +137 -0
  37. data/config/formats/rar3_spec.yml +92 -0
  38. data/config/formats/rar5_spec.yml +102 -0
  39. data/docs/.github/workflows/docs.yml +142 -0
  40. data/docs/.gitignore +21 -0
  41. data/docs/.lychee.toml +67 -0
  42. data/docs/Gemfile +13 -0
  43. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  44. data/docs/README.md +101 -0
  45. data/docs/_config.yml +112 -0
  46. data/docs/assets/logo.svg +1 -0
  47. data/docs/assets/omnizip-logo.pdf +1540 -11
  48. data/docs/comparison/feature-matrix.adoc +694 -0
  49. data/docs/comparison/index.adoc +113 -0
  50. data/docs/comparison/vs-7zip.adoc +309 -0
  51. data/docs/comparison/vs-peazip.adoc +77 -0
  52. data/docs/comparison/vs-rubyzip.adoc +342 -0
  53. data/docs/comparison/vs-winrar.adoc +100 -0
  54. data/docs/compatibility.adoc +579 -0
  55. data/docs/concepts/index.adoc +129 -0
  56. data/docs/developer/architecture.adoc +256 -0
  57. data/docs/developer/contributing.adoc +158 -0
  58. data/docs/developer/index.adoc +25 -0
  59. data/docs/developer/testing.adoc +212 -0
  60. data/docs/getting-started/basic-usage.adoc +263 -0
  61. data/docs/getting-started/index.adoc +42 -0
  62. data/docs/getting-started/installation.adoc +138 -0
  63. data/docs/getting-started/quick-start.adoc +183 -0
  64. data/docs/getting-started/your-first-archive.adoc +219 -0
  65. data/docs/guides/advanced-features/encryption.adoc +277 -0
  66. data/docs/guides/advanced-features/index.adoc +59 -0
  67. data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
  68. data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
  69. data/docs/guides/advanced-features/streaming.adoc +142 -0
  70. data/docs/guides/archive-formats/gzip-format.adoc +105 -0
  71. data/docs/guides/archive-formats/index.adoc +160 -0
  72. data/docs/guides/archive-formats/ole-format.adoc +151 -0
  73. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  74. data/docs/guides/archive-formats/rar5.adoc +521 -0
  75. data/docs/guides/archive-formats/rpm-format.adoc +108 -0
  76. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  77. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  78. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  79. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  80. data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
  81. data/docs/guides/compression-algorithms/deflate.adoc +313 -0
  82. data/docs/guides/compression-algorithms/index.adoc +190 -0
  83. data/docs/guides/compression-algorithms/lzma.adoc +394 -0
  84. data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
  85. data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
  86. data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
  87. data/docs/guides/creating-archives.adoc +348 -0
  88. data/docs/guides/extracting-archives.adoc +53 -0
  89. data/docs/guides/format-conversion.adoc +64 -0
  90. data/docs/guides/index.adoc +49 -0
  91. data/docs/guides/migration-rubyzip.adoc +217 -0
  92. data/docs/guides/parity-archives.adoc +605 -0
  93. data/docs/guides/performance-tuning.adoc +88 -0
  94. data/docs/index.adoc +228 -0
  95. data/docs/lychee.toml +67 -0
  96. data/docs/reference/api/overview.adoc +187 -0
  97. data/docs/reference/cli/compress-command.adoc +114 -0
  98. data/docs/reference/cli/overview.adoc +140 -0
  99. data/docs/reference/index.adoc +26 -0
  100. data/docs/resources/faq.adoc +185 -0
  101. data/docs/resources/quick-reference.adoc +222 -0
  102. data/docs/rust-backend.md +0 -0
  103. data/docs/troubleshooting/index.adoc +207 -0
  104. data/docs/xar_format.md +216 -0
  105. data/examples/api_comparison.rb +205 -0
  106. data/examples/deflate64_example.rb +96 -0
  107. data/examples/par2_demo.rb +121 -0
  108. data/examples/quick_start_native.rb +150 -0
  109. data/examples/quick_start_rubyzip.rb +115 -0
  110. data/examples/rubyzip_compatibility_demo.rb +194 -0
  111. data/exe/omnizip +27 -0
  112. data/lib/omnizip/algorithm.rb +176 -0
  113. data/lib/omnizip/algorithm_registry.rb +65 -0
  114. data/lib/omnizip/algorithms/.keep +0 -0
  115. data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
  116. data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
  117. data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
  118. data/lib/omnizip/algorithms/bzip2.rb +108 -0
  119. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  120. data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
  121. data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
  122. data/lib/omnizip/algorithms/deflate.rb +135 -0
  123. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  124. data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
  125. data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
  126. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
  127. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
  128. data/lib/omnizip/algorithms/deflate64.rb +118 -0
  129. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  130. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  131. data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
  132. data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
  133. data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
  134. data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
  135. data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
  136. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
  137. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
  138. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
  139. data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
  140. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
  141. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  142. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  143. data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
  144. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  145. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
  146. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
  147. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  148. data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
  149. data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
  150. data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
  151. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  152. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
  153. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
  154. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
  155. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
  156. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
  157. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
  158. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  159. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
  160. data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
  161. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
  162. data/lib/omnizip/algorithms/lzma.rb +266 -0
  163. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
  164. data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
  165. data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
  166. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
  167. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  168. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
  169. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  170. data/lib/omnizip/algorithms/lzma2.rb +133 -0
  171. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  172. data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
  173. data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
  174. data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
  175. data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
  176. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  177. data/lib/omnizip/algorithms/ppmd7.rb +146 -0
  178. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  179. data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
  180. data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
  181. data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
  182. data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
  183. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  184. data/lib/omnizip/algorithms/ppmd8.rb +122 -0
  185. data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
  186. data/lib/omnizip/algorithms/registration.rb +28 -0
  187. data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
  188. data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
  189. data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
  190. data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
  191. data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
  192. data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
  193. data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
  194. data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
  195. data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
  196. data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
  197. data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
  198. data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
  199. data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
  200. data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
  201. data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
  202. data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
  203. data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
  204. data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
  205. data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
  206. data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
  207. data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
  208. data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
  209. data/lib/omnizip/algorithms/zstandard.rb +210 -0
  210. data/lib/omnizip/algorithms.rb +35 -0
  211. data/lib/omnizip/archive/builder.rb +48 -0
  212. data/lib/omnizip/archive/reader_session.rb +67 -0
  213. data/lib/omnizip/archive.rb +86 -0
  214. data/lib/omnizip/archive_handler.rb +82 -0
  215. data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
  216. data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
  217. data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
  218. data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
  219. data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
  220. data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
  221. data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
  222. data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
  223. data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
  224. data/lib/omnizip/archive_handlers.rb +18 -0
  225. data/lib/omnizip/backends.rb +160 -0
  226. data/lib/omnizip/buffer/memory_archive.rb +246 -0
  227. data/lib/omnizip/buffer/memory_extractor.rb +234 -0
  228. data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
  229. data/lib/omnizip/buffer.rb +187 -0
  230. data/lib/omnizip/checksum_registry.rb +41 -0
  231. data/lib/omnizip/checksums/crc32.rb +101 -0
  232. data/lib/omnizip/checksums/crc64.rb +102 -0
  233. data/lib/omnizip/checksums/crc_base.rb +158 -0
  234. data/lib/omnizip/checksums/registration.rb +16 -0
  235. data/lib/omnizip/checksums/verifier.rb +130 -0
  236. data/lib/omnizip/checksums.rb +11 -0
  237. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  238. data/lib/omnizip/chunked/reader.rb +78 -0
  239. data/lib/omnizip/chunked/writer.rb +123 -0
  240. data/lib/omnizip/chunked.rb +123 -0
  241. data/lib/omnizip/cli/output_formatter.rb +112 -0
  242. data/lib/omnizip/cli.rb +604 -0
  243. data/lib/omnizip/commands/.keep +0 -0
  244. data/lib/omnizip/commands/archive_create_command.rb +245 -0
  245. data/lib/omnizip/commands/archive_extract_command.rb +231 -0
  246. data/lib/omnizip/commands/archive_list_command.rb +204 -0
  247. data/lib/omnizip/commands/archive_repair_command.rb +129 -0
  248. data/lib/omnizip/commands/archive_verify_command.rb +115 -0
  249. data/lib/omnizip/commands/compress_command.rb +115 -0
  250. data/lib/omnizip/commands/decompress_command.rb +149 -0
  251. data/lib/omnizip/commands/list_command.rb +51 -0
  252. data/lib/omnizip/commands/metadata_command.rb +215 -0
  253. data/lib/omnizip/commands/parity_create_command.rb +114 -0
  254. data/lib/omnizip/commands/parity_repair_command.rb +120 -0
  255. data/lib/omnizip/commands/parity_verify_command.rb +122 -0
  256. data/lib/omnizip/commands/profile_list_command.rb +54 -0
  257. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  258. data/lib/omnizip/commands.rb +21 -0
  259. data/lib/omnizip/convenience.rb +389 -0
  260. data/lib/omnizip/converter/conversion_registry.rb +50 -0
  261. data/lib/omnizip/converter/conversion_strategy.rb +108 -0
  262. data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
  263. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
  264. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
  265. data/lib/omnizip/converter.rb +124 -0
  266. data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
  267. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  268. data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
  269. data/lib/omnizip/crypto/aes256.rb +102 -0
  270. data/lib/omnizip/crypto.rb +11 -0
  271. data/lib/omnizip/entry.rb +44 -0
  272. data/lib/omnizip/error.rb +110 -0
  273. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
  274. data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
  275. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  276. data/lib/omnizip/eta/sample_history.rb +143 -0
  277. data/lib/omnizip/eta/time_estimator.rb +106 -0
  278. data/lib/omnizip/eta.rb +68 -0
  279. data/lib/omnizip/extraction/filter_chain.rb +179 -0
  280. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  281. data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
  282. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  283. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  284. data/lib/omnizip/extraction/selective_extractor.rb +247 -0
  285. data/lib/omnizip/extraction.rb +115 -0
  286. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  287. data/lib/omnizip/file_type.rb +117 -0
  288. data/lib/omnizip/filter.rb +141 -0
  289. data/lib/omnizip/filter_pipeline.rb +108 -0
  290. data/lib/omnizip/filter_registry.rb +113 -0
  291. data/lib/omnizip/filters/bcj.rb +277 -0
  292. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  293. data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
  294. data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
  295. data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
  296. data/lib/omnizip/filters/bcj2.rb +93 -0
  297. data/lib/omnizip/filters/bcj_arm.rb +174 -0
  298. data/lib/omnizip/filters/bcj_arm64.rb +242 -0
  299. data/lib/omnizip/filters/bcj_ia64.rb +194 -0
  300. data/lib/omnizip/filters/bcj_ppc.rb +188 -0
  301. data/lib/omnizip/filters/bcj_sparc.rb +174 -0
  302. data/lib/omnizip/filters/bcj_x86.rb +191 -0
  303. data/lib/omnizip/filters/delta.rb +195 -0
  304. data/lib/omnizip/filters/xz_delta.rb +258 -0
  305. data/lib/omnizip/filters.rb +20 -0
  306. data/lib/omnizip/format_detector.rb +166 -0
  307. data/lib/omnizip/formats/.keep +0 -0
  308. data/lib/omnizip/formats/bzip2_file.rb +159 -0
  309. data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
  310. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  311. data/lib/omnizip/formats/cpio/entry.rb +389 -0
  312. data/lib/omnizip/formats/cpio/reader.rb +194 -0
  313. data/lib/omnizip/formats/cpio/writer.rb +232 -0
  314. data/lib/omnizip/formats/cpio.rb +132 -0
  315. data/lib/omnizip/formats/format_spec_loader.rb +228 -0
  316. data/lib/omnizip/formats/gzip.rb +236 -0
  317. data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
  318. data/lib/omnizip/formats/iso/directory_record.rb +162 -0
  319. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  320. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  321. data/lib/omnizip/formats/iso/reader.rb +194 -0
  322. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  323. data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
  324. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  325. data/lib/omnizip/formats/iso/writer.rb +543 -0
  326. data/lib/omnizip/formats/iso.rb +133 -0
  327. data/lib/omnizip/formats/lzip.rb +161 -0
  328. data/lib/omnizip/formats/lzma_alone.rb +149 -0
  329. data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
  330. data/lib/omnizip/formats/msi/constants.rb +157 -0
  331. data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
  332. data/lib/omnizip/formats/msi/entry.rb +134 -0
  333. data/lib/omnizip/formats/msi/reader.rb +301 -0
  334. data/lib/omnizip/formats/msi/string_pool.rb +246 -0
  335. data/lib/omnizip/formats/msi/table_parser.rb +244 -0
  336. data/lib/omnizip/formats/msi.rb +73 -0
  337. data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
  338. data/lib/omnizip/formats/ole/constants.rb +61 -0
  339. data/lib/omnizip/formats/ole/dirent.rb +439 -0
  340. data/lib/omnizip/formats/ole/header.rb +199 -0
  341. data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
  342. data/lib/omnizip/formats/ole/storage.rb +482 -0
  343. data/lib/omnizip/formats/ole/types/variant.rb +338 -0
  344. data/lib/omnizip/formats/ole.rb +143 -0
  345. data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
  346. data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
  347. data/lib/omnizip/formats/rar/block_parser.rb +282 -0
  348. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  349. data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
  350. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
  351. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
  352. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  353. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  354. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  355. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  356. data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
  357. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
  358. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
  359. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
  360. data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
  361. data/lib/omnizip/formats/rar/compression.rb +17 -0
  362. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  363. data/lib/omnizip/formats/rar/constants.rb +88 -0
  364. data/lib/omnizip/formats/rar/decompressor.rb +316 -0
  365. data/lib/omnizip/formats/rar/external_writer.rb +311 -0
  366. data/lib/omnizip/formats/rar/header.rb +209 -0
  367. data/lib/omnizip/formats/rar/license_validator.rb +111 -0
  368. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  369. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  370. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  371. data/lib/omnizip/formats/rar/models.rb +14 -0
  372. data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
  373. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
  374. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
  375. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  376. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  377. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
  378. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  379. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
  380. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  381. data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
  382. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  383. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  384. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  385. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  386. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  387. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
  388. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  389. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
  390. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
  391. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
  392. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  393. data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
  394. data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
  395. data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
  396. data/lib/omnizip/formats/rar/reader.rb +377 -0
  397. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  398. data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
  399. data/lib/omnizip/formats/rar/writer.rb +437 -0
  400. data/lib/omnizip/formats/rar.rb +193 -0
  401. data/lib/omnizip/formats/rar3/compressor.rb +71 -0
  402. data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
  403. data/lib/omnizip/formats/rar3/reader.rb +107 -0
  404. data/lib/omnizip/formats/rar3/writer.rb +220 -0
  405. data/lib/omnizip/formats/rar3.rb +15 -0
  406. data/lib/omnizip/formats/rar5/compressor.rb +71 -0
  407. data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
  408. data/lib/omnizip/formats/rar5/reader.rb +130 -0
  409. data/lib/omnizip/formats/rar5/writer.rb +65 -0
  410. data/lib/omnizip/formats/rar5.rb +15 -0
  411. data/lib/omnizip/formats/rpm/constants.rb +58 -0
  412. data/lib/omnizip/formats/rpm/entry.rb +106 -0
  413. data/lib/omnizip/formats/rpm/header.rb +106 -0
  414. data/lib/omnizip/formats/rpm/lead.rb +132 -0
  415. data/lib/omnizip/formats/rpm/tag.rb +228 -0
  416. data/lib/omnizip/formats/rpm/writer.rb +652 -0
  417. data/lib/omnizip/formats/rpm.rb +458 -0
  418. data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
  419. data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
  420. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  421. data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
  422. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
  423. data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
  424. data/lib/omnizip/formats/seven_zip/header.rb +102 -0
  425. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
  426. data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
  427. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  428. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
  429. data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
  430. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  431. data/lib/omnizip/formats/seven_zip/models.rb +20 -0
  432. data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
  433. data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
  434. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
  435. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
  436. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  437. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
  438. data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
  439. data/lib/omnizip/formats/seven_zip.rb +179 -0
  440. data/lib/omnizip/formats/tar/constants.rb +73 -0
  441. data/lib/omnizip/formats/tar/entry.rb +98 -0
  442. data/lib/omnizip/formats/tar/header.rb +206 -0
  443. data/lib/omnizip/formats/tar/reader.rb +119 -0
  444. data/lib/omnizip/formats/tar/writer.rb +212 -0
  445. data/lib/omnizip/formats/tar.rb +74 -0
  446. data/lib/omnizip/formats/xar/constants.rb +119 -0
  447. data/lib/omnizip/formats/xar/entry.rb +268 -0
  448. data/lib/omnizip/formats/xar/header.rb +223 -0
  449. data/lib/omnizip/formats/xar/reader.rb +400 -0
  450. data/lib/omnizip/formats/xar/toc.rb +570 -0
  451. data/lib/omnizip/formats/xar/writer.rb +461 -0
  452. data/lib/omnizip/formats/xar.rb +145 -0
  453. data/lib/omnizip/formats/xz/reader.rb +121 -0
  454. data/lib/omnizip/formats/xz/writer.rb +416 -0
  455. data/lib/omnizip/formats/xz.rb +210 -0
  456. data/lib/omnizip/formats/xz_const.rb +49 -0
  457. data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
  458. data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
  459. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  460. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
  461. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  462. data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
  463. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
  464. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
  465. data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
  466. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
  467. data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
  468. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
  469. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  470. data/lib/omnizip/formats/xz_impl.rb +52 -0
  471. data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
  472. data/lib/omnizip/formats/zip/constants.rb +69 -0
  473. data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
  474. data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
  475. data/lib/omnizip/formats/zip/reader.rb +376 -0
  476. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  477. data/lib/omnizip/formats/zip/writer.rb +489 -0
  478. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
  479. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
  480. data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
  481. data/lib/omnizip/formats/zip.rb +50 -0
  482. data/lib/omnizip/formats.rb +29 -0
  483. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  484. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  485. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  486. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  487. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  488. data/lib/omnizip/implementations/base.rb +19 -0
  489. data/lib/omnizip/implementations/rust/archive.rb +93 -0
  490. data/lib/omnizip/implementations/rust/library.rb +221 -0
  491. data/lib/omnizip/implementations/rust.rb +26 -0
  492. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
  493. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
  494. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
  495. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
  496. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
  497. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
  498. data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
  499. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
  500. data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
  501. data/lib/omnizip/implementations/seven_zip.rb +11 -0
  502. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
  503. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
  504. data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
  505. data/lib/omnizip/implementations/xz_utils.rb +10 -0
  506. data/lib/omnizip/implementations.rb +25 -0
  507. data/lib/omnizip/io/buffered_input.rb +147 -0
  508. data/lib/omnizip/io/buffered_output.rb +106 -0
  509. data/lib/omnizip/io/source.rb +143 -0
  510. data/lib/omnizip/io/stream_manager.rb +117 -0
  511. data/lib/omnizip/io.rb +15 -0
  512. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  513. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  514. data/lib/omnizip/link_handler.rb +129 -0
  515. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  516. data/lib/omnizip/metadata/entry_metadata.rb +153 -0
  517. data/lib/omnizip/metadata/metadata_editor.rb +169 -0
  518. data/lib/omnizip/metadata/metadata_registry.rb +71 -0
  519. data/lib/omnizip/metadata/metadata_validator.rb +101 -0
  520. data/lib/omnizip/metadata.rb +58 -0
  521. data/lib/omnizip/models/.keep +0 -0
  522. data/lib/omnizip/models/algorithm_metadata.rb +41 -0
  523. data/lib/omnizip/models/attribute_apply.rb +40 -0
  524. data/lib/omnizip/models/compression_options.rb +53 -0
  525. data/lib/omnizip/models/conversion_options.rb +79 -0
  526. data/lib/omnizip/models/conversion_result.rb +141 -0
  527. data/lib/omnizip/models/eta_result.rb +45 -0
  528. data/lib/omnizip/models/extraction_rule.rb +115 -0
  529. data/lib/omnizip/models/filter_chain.rb +142 -0
  530. data/lib/omnizip/models/filter_config.rb +148 -0
  531. data/lib/omnizip/models/match_result.rb +141 -0
  532. data/lib/omnizip/models/optimization_suggestion.rb +95 -0
  533. data/lib/omnizip/models/parallel_options.rb +116 -0
  534. data/lib/omnizip/models/performance_result.rb +85 -0
  535. data/lib/omnizip/models/profile_report.rb +116 -0
  536. data/lib/omnizip/models/progress_options.rb +39 -0
  537. data/lib/omnizip/models/split_options.rb +116 -0
  538. data/lib/omnizip/optimization_registry.rb +45 -0
  539. data/lib/omnizip/parallel/engine.rb +52 -0
  540. data/lib/omnizip/parallel/job_queue.rb +209 -0
  541. data/lib/omnizip/parallel/job_scheduler.rb +225 -0
  542. data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
  543. data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
  544. data/lib/omnizip/parallel/thread_pool.rb +60 -0
  545. data/lib/omnizip/parallel/worker_pool.rb +227 -0
  546. data/lib/omnizip/parallel.rb +156 -0
  547. data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
  548. data/lib/omnizip/parity/galois16.rb +145 -0
  549. data/lib/omnizip/parity/models/creator_packet.rb +71 -0
  550. data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
  551. data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
  552. data/lib/omnizip/parity/models/main_packet.rb +126 -0
  553. data/lib/omnizip/parity/models/packet.rb +156 -0
  554. data/lib/omnizip/parity/models/packet_registry.rb +102 -0
  555. data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
  556. data/lib/omnizip/parity/models.rb +27 -0
  557. data/lib/omnizip/parity/par2_creator.rb +496 -0
  558. data/lib/omnizip/parity/par2_repairer.rb +409 -0
  559. data/lib/omnizip/parity/par2_verifier.rb +373 -0
  560. data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
  561. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  562. data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
  563. data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
  564. data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
  565. data/lib/omnizip/parity.rb +207 -0
  566. data/lib/omnizip/password/encryption_registry.rb +26 -0
  567. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  568. data/lib/omnizip/password/password_validator.rb +129 -0
  569. data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
  570. data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
  571. data/lib/omnizip/password.rb +88 -0
  572. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  573. data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
  574. data/lib/omnizip/pipe.rb +120 -0
  575. data/lib/omnizip/platform/ntfs_streams.rb +200 -0
  576. data/lib/omnizip/platform.rb +189 -0
  577. data/lib/omnizip/profile/archive_profile.rb +36 -0
  578. data/lib/omnizip/profile/balanced_profile.rb +31 -0
  579. data/lib/omnizip/profile/binary_profile.rb +33 -0
  580. data/lib/omnizip/profile/compression_profile.rb +157 -0
  581. data/lib/omnizip/profile/custom_profile.rb +155 -0
  582. data/lib/omnizip/profile/fast_profile.rb +31 -0
  583. data/lib/omnizip/profile/maximum_profile.rb +31 -0
  584. data/lib/omnizip/profile/profile_detector.rb +108 -0
  585. data/lib/omnizip/profile/profile_registry.rb +160 -0
  586. data/lib/omnizip/profile/text_profile.rb +33 -0
  587. data/lib/omnizip/profile.rb +261 -0
  588. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  589. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  590. data/lib/omnizip/profiler/report_generator.rb +158 -0
  591. data/lib/omnizip/profiler.rb +192 -0
  592. data/lib/omnizip/progress/callback_reporter.rb +34 -0
  593. data/lib/omnizip/progress/console_reporter.rb +59 -0
  594. data/lib/omnizip/progress/log_reporter.rb +89 -0
  595. data/lib/omnizip/progress/operation_progress.rb +118 -0
  596. data/lib/omnizip/progress/progress_bar.rb +156 -0
  597. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  598. data/lib/omnizip/progress/progress_tracker.rb +215 -0
  599. data/lib/omnizip/progress/silent_reporter.rb +22 -0
  600. data/lib/omnizip/progress.rb +131 -0
  601. data/lib/omnizip/registry.rb +111 -0
  602. data/lib/omnizip/rubyzip_compat.rb +61 -0
  603. data/lib/omnizip/temp/safe_extract.rb +124 -0
  604. data/lib/omnizip/temp/temp_file.rb +123 -0
  605. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  606. data/lib/omnizip/temp.rb +184 -0
  607. data/lib/omnizip/version.rb +5 -0
  608. data/lib/omnizip/zip/entry.rb +160 -0
  609. data/lib/omnizip/zip/file.rb +485 -0
  610. data/lib/omnizip/zip/input_stream.rb +270 -0
  611. data/lib/omnizip/zip/output_stream.rb +320 -0
  612. data/lib/omnizip/zip.rb +23 -0
  613. data/lib/omnizip.rb +157 -0
  614. data/lib/tasks/msi_test_files.rake +66 -0
  615. data/lib/tasks/platform_gems.rake +147 -0
  616. data/lib/tasks/rust_backend.rake +48 -0
  617. data/readme-docs/advanced-features.adoc +514 -0
  618. data/readme-docs/api-usage.adoc +445 -0
  619. data/readme-docs/architecture.adoc +450 -0
  620. data/readme-docs/archive-formats.adoc +479 -0
  621. data/readme-docs/cli-usage.adoc +222 -0
  622. data/readme-docs/compression-algorithms.adoc +446 -0
  623. data/readme-docs/compression-profiles.adoc +247 -0
  624. data/readme-docs/encryption-checksums.adoc +328 -0
  625. data/readme-docs/format-converter.adoc +316 -0
  626. data/readme-docs/installation.adoc +228 -0
  627. data/readme-docs/par2-archives.adoc +608 -0
  628. data/readme-docs/performance-profiler.adoc +389 -0
  629. data/readme-docs/preprocessing-filters.adoc +280 -0
  630. data/vendor/libomnizip_ffi.so +0 -0
  631. data/xz-file-format-1.2.1.txt +1174 -0
  632. metadata +768 -0
@@ -0,0 +1,350 @@
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 Zstandard
26
+ # Sequences section decoder (RFC 8878 §3.1.1.3.2) and the LZ77
27
+ # executor (§3.1.2).
28
+ #
29
+ # Decoding follows the C reference ZSTD_decodeSequence:
30
+ #
31
+ # - State initialization order: LL, OF, ML.
32
+ # - Per sequence: resolve the offset first (reading its extra
33
+ # bits and updating the repeat-offset slots), then read the ML
34
+ # extra bits, then the LL extra bits.
35
+ # - State updates (non-last sequences) in order LL, ML, OF.
36
+ class SequencesDecoder
37
+ include Constants
38
+
39
+ Sequence = Struct.new(:literal_length, :match_length, :offset)
40
+
41
+ # @return [Array<Sequence>]
42
+ attr_reader :sequences
43
+
44
+ # @return [Hash] FSE tables for the next block's Repeat mode
45
+ attr_reader :fse_tables
46
+
47
+ # Decode the sequences section at the head of `input`.
48
+ #
49
+ # @param input [String]
50
+ # @param previous_tables [Hash] tables carried from the previous
51
+ # compressed block (:ll, :ml, :of entries)
52
+ # @param executor [SequenceExecutor] repeat-offset state,
53
+ # updated in place while decoding
54
+ # @return [SequencesDecoder]
55
+ def self.decode(input, previous_tables = {}, executor = nil)
56
+ new(input, previous_tables, executor || SequenceExecutor.new).decode_section
57
+ end
58
+
59
+ def initialize(input, previous_tables, executor)
60
+ @input = input
61
+ @previous_tables = previous_tables
62
+ @executor = executor
63
+ @sequences = []
64
+ @fse_tables = {}
65
+ end
66
+
67
+ # rubocop:disable Metrics/MethodLength
68
+ # rubocop:disable Metrics/AbcSize
69
+ def decode_section
70
+ num_sequences, offset = read_sequence_count
71
+ return self if num_sequences.zero?
72
+
73
+ if @input.bytesize <= offset
74
+ raise Omnizip::DecompressionError,
75
+ "truncated sequences section: missing modes byte"
76
+ end
77
+ # rubocop:enable Metrics/AbcSize
78
+
79
+ modes = @input.getbyte(offset)
80
+ ll_mode = (modes >> 6) & 0x03
81
+ of_mode = (modes >> 4) & 0x03
82
+ ml_mode = (modes >> 2) & 0x03
83
+
84
+ cursor = offset + 1
85
+ @ll_table, cursor = build_table(ll_mode, :ll,
86
+ PREDEFINED_LL_DISTRIBUTION,
87
+ LITERALS_LENGTH_ACCURACY_LOG, cursor)
88
+ @of_table, cursor = build_table(of_mode, :of,
89
+ PREDEFINED_OFFSET_DISTRIBUTION,
90
+ OFFSET_ACCURACY_LOG, cursor)
91
+ @ml_table, cursor = build_table(ml_mode, :ml,
92
+ PREDEFINED_ML_DISTRIBUTION,
93
+ MATCH_LENGTH_ACCURACY_LOG, cursor)
94
+
95
+ decode_sequences(num_sequences, @input.byteslice(cursor..))
96
+ self
97
+ end
98
+ # rubocop:enable Metrics/AbcSize
99
+ # rubocop:enable Metrics/MethodLength
100
+
101
+ private
102
+
103
+ # Sequence count: 1-3 bytes (RFC 8878 §3.1.1.3.2.1).
104
+ # rubocop:disable Metrics/AbcSize
105
+ def read_sequence_count
106
+ b0 = @input.getbyte(0)
107
+ if b0 < 0x80
108
+ [b0, 1]
109
+ elsif b0 == 0xFF
110
+ if @input.bytesize < 3
111
+ raise Omnizip::DecompressionError,
112
+ "truncated 3-byte sequence count"
113
+ end
114
+ # rubocop:enable Metrics/AbcSize
115
+
116
+ [@input.byteslice(1, 2).unpack1("v") + 0x7F00, 3]
117
+ else
118
+ if @input.bytesize < 2
119
+ raise Omnizip::DecompressionError,
120
+ "truncated 2-byte sequence count"
121
+ end
122
+
123
+ [((b0 - 0x80) << 8) + @input.getbyte(1), 2]
124
+ end
125
+ end
126
+
127
+ # Build the table for one symbol type. Returns [table, new_cursor].
128
+ # rubocop:disable Metrics/AbcSize
129
+ def build_table(mode, type, predef_distribution, predef_log, cursor)
130
+ table = case mode
131
+ when MODE_PREDEFINED
132
+ FSE::Table.build_predefined(predef_distribution.to_a,
133
+ predef_log)
134
+ when MODE_RLE
135
+ if cursor >= @input.bytesize
136
+ raise Omnizip::DecompressionError,
137
+ "RLE mode: missing symbol byte"
138
+ end
139
+ # rubocop:enable Metrics/AbcSize
140
+
141
+ symbol = @input.getbyte(cursor)
142
+ limit = { ll: LITERAL_LENGTH_TABLE.length,
143
+ ml: MATCH_LENGTH_TABLE.length,
144
+ of: OF_BASE.length }[type]
145
+ if symbol >= limit
146
+ raise Omnizip::DecompressionError,
147
+ "RLE symbol #{symbol} out of range for #{type}"
148
+ end
149
+
150
+ FSE::Table.build_rle(symbol, 0)
151
+ when MODE_FSE
152
+ tbl, consumed = FSE.read_table(@input.byteslice(cursor..))
153
+ attach_code_values(tbl, type)
154
+ @fse_tables[type] = tbl
155
+ return [tbl, cursor + consumed]
156
+ when MODE_REPEAT
157
+ prev = @previous_tables[type]
158
+ if prev.nil?
159
+ raise Omnizip::DecompressionError,
160
+ "repeat mode for #{type} without a previous table"
161
+ end
162
+
163
+ return [prev, cursor]
164
+ else
165
+ raise Omnizip::DecompressionError,
166
+ "invalid sequence mode #{mode}"
167
+ end
168
+
169
+ attach_code_values(table, type)
170
+ @fse_tables[type] = table
171
+ cursor2 = mode == MODE_RLE ? cursor + 1 : cursor
172
+ [table, cursor2]
173
+ end
174
+
175
+ # Annotate each FSE state with the (base, extra_bits) of the LL /
176
+ # ML / OF code its symbol maps to, following the C reference's
177
+ # precomputed seqSymbol layout.
178
+ # rubocop:disable Metrics/AbcSize
179
+ def attach_code_values(table, type)
180
+ case type
181
+ when :ll
182
+ table.states.each do |st|
183
+ base, bits = LITERAL_LENGTH_TABLE[st.symbol] || [0, 0]
184
+ st.base_val = base
185
+ st.nb_add_bits = bits
186
+ end
187
+ # rubocop:enable Metrics/AbcSize
188
+ when :ml
189
+ table.states.each do |st|
190
+ base, bits = MATCH_LENGTH_TABLE[st.symbol] || [0, 0]
191
+ st.base_val = base
192
+ st.nb_add_bits = bits
193
+ end
194
+ when :of
195
+ table.states.each do |st|
196
+ st.base_val = OF_BASE[st.symbol] || 0
197
+ st.nb_add_bits = OF_BITS[st.symbol] || 0
198
+ end
199
+ end
200
+ end
201
+
202
+ # rubocop:disable Metrics/MethodLength
203
+ # rubocop:disable Metrics/AbcSize
204
+ def decode_sequences(count, bitstream_bytes)
205
+ bs = FSE::BitStream.new(bitstream_bytes)
206
+
207
+ ll_tbl = @ll_table
208
+ of_tbl = @of_table
209
+ ml_tbl = @ml_table
210
+ ll_state = bs.read_bits(ll_tbl.accuracy_log)
211
+ bs.reload
212
+ of_state = bs.read_bits(of_tbl.accuracy_log)
213
+ bs.reload
214
+ ml_state = bs.read_bits(ml_tbl.accuracy_log)
215
+ bs.reload
216
+
217
+ count.times do |seq_idx|
218
+ is_last = seq_idx == count - 1
219
+
220
+ ll_e = ll_tbl[ll_state]
221
+ of_e = of_tbl[of_state]
222
+ ml_e = ml_tbl[ml_state]
223
+
224
+ ll0 = ll_e.base_val.zero?
225
+ offset = @executor.resolve_offset(of_e, ll0, bs)
226
+ match_length = ml_e.base_val + bs.read_bits(ml_e.nb_add_bits)
227
+ literal_length = ll_e.base_val + bs.read_bits(ll_e.nb_add_bits)
228
+
229
+ unless is_last
230
+ ll_state = ll_e.baseline + bs.read_bits(ll_e.num_bits)
231
+ ml_state = ml_e.baseline + bs.read_bits(ml_e.num_bits)
232
+ of_state = of_e.baseline + bs.read_bits(of_e.num_bits)
233
+ bs.reload
234
+ end
235
+ # rubocop:enable Metrics/AbcSize
236
+
237
+ @sequences << Sequence.new(literal_length, match_length, offset)
238
+ end
239
+ end
240
+ # rubocop:enable Metrics/MethodLength
241
+ end
242
+
243
+ # Stateful LZ77 sequence executor (RFC 8878 §3.1.2). Tracks the
244
+ # three repeat-offset slots across the frame; the slots are
245
+ # updated while decoding each sequence's offset.
246
+ class SequenceExecutor
247
+ include Constants
248
+
249
+ # @return [Array<Integer>] repeat offsets, most recent first
250
+ attr_reader :repeat_offsets
251
+
252
+ def initialize
253
+ @repeat_offsets = DEFAULT_REPEAT_OFFSETS.dup
254
+ end
255
+
256
+ # Reset to the frame defaults [1, 4, 8].
257
+ def reset
258
+ @repeat_offsets = DEFAULT_REPEAT_OFFSETS.dup
259
+ end
260
+
261
+ # Resolve a sequence offset (C reference semantics).
262
+ #
263
+ # Offset codes 0 and 1 address the repeat slots; the exact
264
+ # behaviour depends on ll0 (whether the sequence emits no
265
+ # literals). Codes >= 2 carry a real distance:
266
+ # distance = OF_BASE[code] + read(code bits).
267
+ #
268
+ # @param of_e [FSE::State] offset table entry for this sequence
269
+ # @param ll0 [Boolean] literal length is zero
270
+ # @param bs [FSE::BitStream]
271
+ # @return [Integer] resolved byte distance
272
+ # rubocop:disable Metrics/AbcSize
273
+ def resolve_offset(of_e, ll0, bs)
274
+ of_bits = of_e.nb_add_bits
275
+ prev = @repeat_offsets
276
+
277
+ if of_bits > 1
278
+ offset = of_e.base_val + bs.read_bits(of_bits)
279
+ prev[2] = prev[1]
280
+ prev[1] = prev[0]
281
+ prev[0] = offset
282
+ offset
283
+ elsif of_bits.zero?
284
+ offset = prev[ll0 ? 1 : 0]
285
+ if ll0
286
+ prev[1] = prev[0]
287
+ prev[0] = offset
288
+ end
289
+ # rubocop:enable Metrics/AbcSize
290
+ offset
291
+ else
292
+ # of_bits == 1: the "rep3-1" special family.
293
+ selector = of_e.base_val + (ll0 ? 1 : 0) + bs.read_bits(1)
294
+ temp = case selector
295
+ when 1 then prev[1]
296
+ when 3 then prev[0] - 1
297
+ else prev[2]
298
+ end
299
+ if temp.zero?
300
+ raise Omnizip::DecompressionError,
301
+ "repeat offset 1 - 1 evaluated to 0 (corrupt stream)"
302
+ end
303
+
304
+ prev[2] = prev[1] unless selector == 1
305
+ prev[1] = prev[0]
306
+ prev[0] = temp
307
+ temp
308
+ end
309
+ end
310
+
311
+ # Execute decoded sequences against the literal buffer,
312
+ # appending to output and returning the produced bytes.
313
+ #
314
+ # @param literals [String]
315
+ # @param sequences [Array<SequencesDecoder::Sequence>]
316
+ # @param output [String] accumulator (frame output so far)
317
+ # @return [String] the block's output
318
+ # rubocop:disable Metrics/AbcSize
319
+ def execute(literals, sequences, output)
320
+ lit_pos = 0
321
+ block_start = output.bytesize
322
+
323
+ sequences.each do |seq|
324
+ ll = seq.literal_length
325
+ if ll.positive?
326
+ take = [ll, literals.bytesize - lit_pos].min
327
+ output << literals.byteslice(lit_pos, take)
328
+ lit_pos += take
329
+ end
330
+ # rubocop:enable Metrics/AbcSize
331
+
332
+ distance = seq.offset
333
+ if distance.zero? || distance > output.bytesize
334
+ raise Omnizip::DecompressionError,
335
+ "match distance #{distance} exceeds decoded output " \
336
+ "length #{output.bytesize}"
337
+ end
338
+
339
+ ml = seq.match_length
340
+ src_start = output.bytesize - distance
341
+ ml.times { |i| output << output.getbyte(src_start + (i % distance)) }
342
+ end
343
+
344
+ output << literals.byteslice(lit_pos..) if lit_pos < literals.bytesize
345
+ output.byteslice(block_start..)
346
+ end
347
+ end
348
+ end
349
+ end
350
+ end
@@ -0,0 +1,333 @@
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 Zstandard
26
+ # Sequences section encoder (RFC 8878 §3.1.1.3.2; port of the
27
+ # omnizip-rs encoder/sequences.rs, from zstd_compress_sequences.c).
28
+ #
29
+ # Encodes the match finder's sequences with three FSE states
30
+ # (LL, OF, ML) into the reverse bitstream, choosing Predefined or
31
+ # FSE_Compressed tables per symbol type. Repeat offsets use the
32
+ # offBase 0/1/2 short codes exactly as the decoder resolves
33
+ # them.
34
+ module SequencesEncoder
35
+ include Constants
36
+
37
+ MODE_PREDEFINED = 0
38
+ MODE_FSE = 2
39
+
40
+ # Slack favoring Predefined tables (the payload estimate is
41
+ # entropy-approximate; marginal FSE wins on small streams are
42
+ # noise and lose in practice).
43
+ FSE_SLACK_BITS = 24
44
+
45
+ module_function
46
+
47
+ # Encode the sequences section for `seq_store`.
48
+ #
49
+ # @param seq_store [MatchFinder::SeqStore]
50
+ # @param initial_reps [Array<Integer>] wire repeat offsets the
51
+ # decoder holds before this block
52
+ # @return [Array(String, Array<Integer>)] the section bytes and
53
+ # the wire rep state after this block
54
+ # rubocop:disable Metrics/MethodLength
55
+ # rubocop:disable-next Metrics/AbcSize
56
+ def encode_section(seq_store, initial_reps)
57
+ nb_seq = seq_store.sequences.length
58
+ out = write_sequence_count(nb_seq)
59
+ return [out, initial_reps] if nb_seq.zero?
60
+
61
+ ll_codes, ml_codes, of_codes, ll_extras, ml_extras, off_bases,
62
+ wire_reps = compute_codes(seq_store, initial_reps)
63
+
64
+ ll_count = Array.new(LITERAL_LENGTH_TABLE.length, 0)
65
+ ml_count = Array.new(MATCH_LENGTH_TABLE.length, 0)
66
+ of_count = Array.new(32, 0)
67
+ ll_max = count_symbols(ll_codes, ll_count)
68
+ ml_max = count_symbols(ml_codes, ml_count)
69
+ of_max = count_symbols(of_codes, of_count)
70
+
71
+ ll_choice = choose_table_mode(ll_count, ll_max,
72
+ PREDEFINED_LL_DISTRIBUTION, 6, 35, 9,
73
+ nb_seq)
74
+ of_choice = choose_table_mode(of_count, of_max,
75
+ PREDEFINED_OFFSET_DISTRIBUTION, 5, 28,
76
+ 8, nb_seq)
77
+ ml_choice = choose_table_mode(ml_count, ml_max,
78
+ PREDEFINED_ML_DISTRIBUTION, 6, 52, 9,
79
+ nb_seq)
80
+
81
+ modes = (ll_choice[:mode] << 6) | (of_choice[:mode] << 4) |
82
+ (ml_choice[:mode] << 2)
83
+ out << modes.chr
84
+
85
+ if ll_choice[:mode] == MODE_FSE
86
+ out << FSE::Encoder.new(ll_choice[:norm], ll_choice[:table_log],
87
+ ll_max).write_ncount
88
+ end
89
+ if of_choice[:mode] == MODE_FSE
90
+ out << FSE::Encoder.new(of_choice[:norm], of_choice[:table_log],
91
+ of_max).write_ncount
92
+ end
93
+ if ml_choice[:mode] == MODE_FSE
94
+ out << FSE::Encoder.new(ml_choice[:norm], ml_choice[:table_log],
95
+ ml_max).write_ncount
96
+ end
97
+
98
+ ll_ctable = table_for(ll_choice)
99
+ of_ctable = table_for(of_choice)
100
+ ml_ctable = table_for(ml_choice)
101
+
102
+ out << encode_sequences_bitstream(
103
+ ll_codes, ml_codes, of_codes, ll_extras, ml_extras, off_bases,
104
+ ll_ctable, ml_ctable, of_ctable
105
+ )
106
+
107
+ [out, wire_reps]
108
+ end
109
+ # rubocop:enable Metrics/MethodLength
110
+
111
+ # Compute per-sequence codes and extras, tracking the WIRE rep
112
+ # state exactly as the decoder's resolve_offset does (this is
113
+ # the state the next block must carry, not the match finder's).
114
+ #
115
+ # rubocop:disable Metrics/MethodLength
116
+ # rubocop:disable-next Metrics/AbcSize
117
+ def compute_codes(seq_store, initial_reps)
118
+ ll_codes = []
119
+ ml_codes = []
120
+ of_codes = []
121
+ ll_extras = []
122
+ ml_extras = []
123
+ off_bases = []
124
+ reps = initial_reps.dup
125
+
126
+ seq_store.sequences.each do |seq|
127
+ ll_c, ll_e = ll_code(seq.literal_length)
128
+ ml_c, ml_e = ml_code(seq.match_length)
129
+ ll0 = seq.literal_length.zero?
130
+
131
+ ob = if !ll0 && seq.offset == reps[0]
132
+ 1 # rep1: decoder uses prev[0], no rotation
133
+ elsif ll0 && seq.offset == reps[1]
134
+ used = reps[1] # decoder swaps prev[0]/prev[1]
135
+ reps[1] = reps[0]
136
+ reps[0] = used
137
+ 1
138
+ elsif seq.offset == reps[2] && seq.offset > 3
139
+ used = reps[2] # rep3: decoder shifts prev[2] to front
140
+ reps[2] = reps[1]
141
+ reps[1] = reps[0]
142
+ reps[0] = used
143
+ ll0 ? 2 : 3
144
+ else
145
+ reps[2] = reps[1]
146
+ reps[1] = reps[0]
147
+ reps[0] = seq.offset
148
+ seq.offset + 3
149
+ end
150
+
151
+ ll_codes << ll_c
152
+ ml_codes << ml_c
153
+ of_codes << [ob.bit_length - 1, 31].min
154
+ ll_extras << ll_e
155
+ ml_extras << ml_e
156
+ off_bases << ob
157
+ end
158
+
159
+ [ll_codes, ml_codes, of_codes, ll_extras, ml_extras, off_bases,
160
+ reps]
161
+ end
162
+ # rubocop:enable Metrics/MethodLength
163
+
164
+ # LL code for a literal length: (code, extra value).
165
+ def ll_code(lit_len)
166
+ code = LITERAL_LENGTH_TABLE.length - 1
167
+ while code.positive? && LITERAL_LENGTH_TABLE[code][0] > lit_len
168
+ code -= 1
169
+ end
170
+ [code, lit_len - LITERAL_LENGTH_TABLE[code][0]]
171
+ end
172
+
173
+ # ML code for a match length: (code, extra value).
174
+ def ml_code(match_len)
175
+ code = MATCH_LENGTH_TABLE.length - 1
176
+ while code.positive? && MATCH_LENGTH_TABLE[code][0] > match_len
177
+ code -= 1
178
+ end
179
+ [code, match_len - MATCH_LENGTH_TABLE[code][0]]
180
+ end
181
+
182
+ def count_symbols(codes, count)
183
+ max_sym = 0
184
+ codes.each do |c|
185
+ count[c] += 1
186
+ max_sym = c if c > max_sym
187
+ end
188
+ max_sym
189
+ end
190
+
191
+ # Choose Predefined vs FSE_Compressed for one symbol type.
192
+ #
193
+ # rubocop:disable Metrics/MethodLength
194
+ # rubocop:disable-next Metrics/AbcSize
195
+ def choose_table_mode(count, max_sym, default_norm, default_log,
196
+ default_max_sym, accuracy_cap, total)
197
+ predefined_viable = (0..max_sym).all? do |s|
198
+ count[s].zero? ||
199
+ (s < default_norm.length && default_norm[s] != 0)
200
+ end
201
+
202
+ opt_log = FSE::Encoder.optimal_table_log(accuracy_cap, total,
203
+ max_sym)
204
+ custom_norm = FSE::Encoder.normalize_count(
205
+ opt_log, count, total, max_sym, use_low_prob: false
206
+ )
207
+
208
+ fse_norm = if custom_norm.empty?
209
+ single = Array.new(max_sym + 1, 0)
210
+ single[max_sym] = 1 << opt_log
211
+ single
212
+ else
213
+ custom_norm
214
+ end
215
+
216
+ unless predefined_viable
217
+ return { mode: MODE_FSE, norm: fse_norm, table_log: opt_log,
218
+ max_sym: max_sym }
219
+ end
220
+
221
+ predef_bits = estimate_cost(count, default_norm, default_log,
222
+ max_sym)
223
+ fse_bits = estimate_cost(count, fse_norm, opt_log, max_sym) +
224
+ (8 * ncount_size(fse_norm, max_sym, opt_log))
225
+
226
+ if fse_bits + FSE_SLACK_BITS < predef_bits
227
+ { mode: MODE_FSE, norm: fse_norm, table_log: opt_log,
228
+ max_sym: max_sym }
229
+ else
230
+ { mode: MODE_PREDEFINED, norm: default_norm.to_a,
231
+ table_log: default_log, max_sym: default_max_sym }
232
+ end
233
+ end
234
+ # rubocop:enable Metrics/MethodLength
235
+
236
+ # Estimated payload cost in bits for a distribution.
237
+ def estimate_cost(count, norm, table_log, max_sym)
238
+ table_size = 1 << table_log
239
+ total_bits = 0
240
+ (0..max_sym).each do |s|
241
+ next if count[s].zero?
242
+
243
+ n = s < norm.length ? norm[s] : 0
244
+ prob = if n.positive?
245
+ n
246
+ elsif n == -1
247
+ 1
248
+ else
249
+ table_size
250
+ end
251
+ total_bits += (count[s] * Math.log(table_size.to_f / prob, 2))
252
+ .round
253
+ end
254
+ total_bits
255
+ end
256
+
257
+ def table_for(choice)
258
+ FSE::Encoder.new(choice[:norm], choice[:table_log], choice[:max_sym])
259
+ end
260
+
261
+ # Exact size of the NCount header a distribution would write.
262
+ def ncount_size(norm, max_sym, table_log)
263
+ FSE::Encoder.new(norm, table_log, max_sym).write_ncount.bytesize
264
+ rescue Omnizip::CompressionError
265
+ Float::INFINITY
266
+ end
267
+
268
+ # Sequence count, 1-3 bytes (RFC 8878 §3.1.1.3.2.1).
269
+ def write_sequence_count(nb_seq)
270
+ if nb_seq < 128
271
+ [nb_seq].pack("C")
272
+ elsif nb_seq < 0x7F00
273
+ [128 + (nb_seq >> 8), nb_seq & 0xFF].pack("CC")
274
+ else
275
+ v = nb_seq - 0x7F00
276
+ [0xFF, v & 0xFF, (v >> 8) & 0xFF].pack("C*")
277
+ end
278
+ end
279
+
280
+ # The reverse-order three-state FSE bitstream (port of the
281
+ # Rust encode_sequences_bitstream). The decoder reads states
282
+ # LL, OF, ML first and consumes extras OF, ML, LL per
283
+ # sequence, so the encoder initializes from the LAST sequence
284
+ # and walks backwards.
285
+ #
286
+ # rubocop:disable Metrics/MethodLength
287
+ # rubocop:disable-next Metrics/AbcSize
288
+ def encode_sequences_bitstream(ll_codes, ml_codes, of_codes,
289
+ ll_extras, ml_extras, off_bases,
290
+ ll_ctable, ml_ctable, of_ctable)
291
+ nb_seq = ll_codes.length
292
+ bitc = FSE::Encoder::BitCStream.new
293
+
294
+ state_ml = FSE::Encoder::CState.init2(ml_ctable, ml_codes[nb_seq - 1])
295
+ state_of = FSE::Encoder::CState.init2(of_ctable, of_codes[nb_seq - 1])
296
+ state_ll = FSE::Encoder::CState.init2(ll_ctable, ll_codes[nb_seq - 1])
297
+
298
+ last = nb_seq - 1
299
+ bitc.add_bits(ll_extras[last],
300
+ LITERAL_LENGTH_TABLE[ll_codes[last]][1])
301
+ bitc.flush
302
+ bitc.add_bits(ml_extras[last],
303
+ MATCH_LENGTH_TABLE[ml_codes[last]][1])
304
+ bitc.flush
305
+ bitc.add_bits(off_bases[last], of_codes[last])
306
+ bitc.flush
307
+
308
+ (nb_seq - 2).downto(0) do |n|
309
+ state_of.encode(bitc, of_ctable, of_codes[n])
310
+ state_ml.encode(bitc, ml_ctable, ml_codes[n])
311
+ bitc.flush
312
+ state_ll.encode(bitc, ll_ctable, ll_codes[n])
313
+ bitc.flush
314
+
315
+ bitc.add_bits(ll_extras[n],
316
+ LITERAL_LENGTH_TABLE[ll_codes[n]][1])
317
+ bitc.add_bits(ml_extras[n],
318
+ MATCH_LENGTH_TABLE[ml_codes[n]][1])
319
+ bitc.flush
320
+ bitc.add_bits(off_bases[n], of_codes[n])
321
+ bitc.flush
322
+ end
323
+
324
+ state_ml.flush(bitc)
325
+ state_of.flush(bitc)
326
+ state_ll.flush(bitc)
327
+ bitc.close
328
+ end
329
+ # rubocop:enable Metrics/MethodLength
330
+ end
331
+ end
332
+ end
333
+ end