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,266 @@
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
+ # LZMA (Lempel-Ziv-Markov chain Algorithm) compression
26
+ #
27
+ # LZMA is a lossless data compression algorithm that combines
28
+ # Lempel-Ziv dictionary compression with range coding (a form
29
+ # of arithmetic coding). It achieves high compression ratios
30
+ # by using adaptive probability models.
31
+ #
32
+ # This implementation uses:
33
+ # - LZ77 match finder for finding duplicate sequences
34
+ # - Range coding for probability-based encoding
35
+ # - Adaptive bit models that adjust based on input data
36
+ # - State machine for compression context tracking
37
+ #
38
+ # The algorithm operates by:
39
+ # 1. Finding matches using LZ77 dictionary compression
40
+ # 2. Encoding decisions using range coder with probability models
41
+ # 3. Maintaining state for optimal compression
42
+ class LZMA < Algorithm
43
+ # Nested classes - autoloaded
44
+ autoload :Constants, "omnizip/algorithms/lzma/constants"
45
+ autoload :BitModel, "omnizip/algorithms/lzma/bit_model"
46
+ autoload :ProbabilityModels, "omnizip/algorithms/lzma/probability_models"
47
+ autoload :XZRangeEncoder, "omnizip/algorithms/lzma/xz_range_encoder"
48
+ autoload :Dictionary, "omnizip/algorithms/lzma/dictionary"
49
+ autoload :LZMAState, "omnizip/algorithms/lzma/lzma_state"
50
+ autoload :RangeCoder, "omnizip/algorithms/lzma/range_coder"
51
+ autoload :RangeEncoder, "omnizip/algorithms/lzma/range_encoder"
52
+ autoload :RangeDecoder, "omnizip/algorithms/lzma/range_decoder"
53
+ autoload :Match, "omnizip/algorithms/lzma/match"
54
+ autoload :MatchFinder, "omnizip/algorithms/lzma/match_finder"
55
+ autoload :OptimalEncoder, "omnizip/algorithms/lzma/optimal_encoder"
56
+ autoload :State, "omnizip/algorithms/lzma/state"
57
+ autoload :XzState, "omnizip/algorithms/lzma/xz_state"
58
+ autoload :XzProbabilityModels,
59
+ "omnizip/algorithms/lzma/xz_probability_models"
60
+ autoload :XzPriceCalculator, "omnizip/algorithms/lzma/xz_price_calculator"
61
+ autoload :XzMatchFinderAdapter,
62
+ "omnizip/algorithms/lzma/xz_match_finder_adapter"
63
+ autoload :LengthCoder, "omnizip/algorithms/lzma/length_coder"
64
+ autoload :DistanceCoder, "omnizip/algorithms/lzma/distance_coder"
65
+ autoload :LiteralEncoder, "omnizip/algorithms/lzma/literal_encoder"
66
+ autoload :LiteralDecoder, "omnizip/algorithms/lzma/literal_decoder"
67
+ autoload :MatchFinderConfig, "omnizip/algorithms/lzma/match_finder_config"
68
+ autoload :MatchFinderFactory,
69
+ "omnizip/algorithms/lzma/match_finder_factory"
70
+ autoload :XzEncoder, "omnizip/algorithms/lzma/xz_encoder"
71
+ autoload :XzEncoderFast, "omnizip/algorithms/lzma/xz_encoder_fast"
72
+ autoload :XzBufferedRangeEncoder,
73
+ "omnizip/algorithms/lzma/xz_buffered_range_encoder"
74
+ autoload :XzRangeEncoderExact,
75
+ "omnizip/algorithms/lzma/xz_range_encoder_exact"
76
+ autoload :XzRangeEncoder, "omnizip/algorithms/lzma/xz_range_encoder_exact"
77
+ autoload :Encoder, "omnizip/algorithms/lzma/encoder"
78
+ autoload :Decoder, "omnizip/algorithms/lzma/decoder"
79
+ autoload :LzmaAloneDecoder, "omnizip/algorithms/lzma/lzma_alone_decoder"
80
+ autoload :LzipDecoder, "omnizip/algorithms/lzma/lzip_decoder"
81
+ autoload :Lzma1Encoder, "omnizip/algorithms/lzma/lzma1_encoder"
82
+
83
+ # Cross-namespace dependencies - autoloaded
84
+ autoload :Crc32, "omnizip/checksums/crc32"
85
+ autoload :SevenZipLzmaEncoder,
86
+ "omnizip/implementations/seven_zip/lzma/encoder"
87
+ autoload :SevenZipMatchFinder,
88
+ "omnizip/implementations/seven_zip/lzma/match_finder"
89
+
90
+ # Initialize the LZMA algorithm with options
91
+ #
92
+ # @param options [Hash] Algorithm options
93
+ # @option options [Integer] :lc Literal context bits (default: 3)
94
+ # @option options [Integer] :lp Literal position bits (default: 0)
95
+ # @option options [Integer] :pb Position bits (default: 2)
96
+ # @option options [Integer] :dict_size Dictionary size (default: 4MB)
97
+ # @option options [Boolean] :lzma2_mode Raw LZMA mode (no header, for 7-Zip)
98
+ def initialize(options = {})
99
+ super()
100
+ @lc = options[:lc] || 3
101
+ @lp = options[:lp] || 0
102
+ @pb = options[:pb] || 2
103
+ @dict_size = options[:dict_size] || (4 * 1024 * 1024) # 4 MB default
104
+ @lzma2_mode = options[:lzma2_mode]
105
+ @uncompressed_size = options[:uncompressed_size] || options[:size]
106
+ end
107
+
108
+ # Get algorithm metadata
109
+ #
110
+ # @return [AlgorithmMetadata] Algorithm information
111
+ def self.metadata
112
+ Models::AlgorithmMetadata.new.tap do |meta|
113
+ meta.name = "lzma"
114
+ meta.description = "LZMA compression using range coding " \
115
+ "and dictionary compression"
116
+ meta.version = "1.0.0"
117
+ end
118
+ end
119
+
120
+ # Compress data using LZMA algorithm
121
+ #
122
+ # @param input_stream [IO] Input stream to compress
123
+ # @param output_stream [IO] Output stream for compressed data
124
+ # @param options [Models::CompressionOptions] Compression options
125
+ # @return [void]
126
+ def compress(input_stream, output_stream, options = nil)
127
+ input_data = input_stream.read
128
+ encoder = Encoder.new(output_stream, build_encoder_options(options))
129
+ encoder.encode_stream(input_data)
130
+ end
131
+
132
+ # Decompress LZMA-compressed data
133
+ #
134
+ # @param input_stream [IO] Input stream of compressed data
135
+ # @param output_stream [IO] Output stream for decompressed data
136
+ # @param options [Models::CompressionOptions, Hash] Decompression options
137
+ # @return [IO] The output_stream (for chaining)
138
+ def decompress(input_stream, output_stream, options = nil)
139
+ # Set binary encoding on output stream for proper byte handling
140
+ output_stream.set_encoding(Encoding::BINARY)
141
+
142
+ # Build decoder options, merging with instance variables as fallbacks
143
+ decoder_opts = build_decoder_options(options)
144
+ if @lzma2_mode && !decoder_opts.key?(:lzma2_mode)
145
+ decoder_opts[:lzma2_mode] =
146
+ @lzma2_mode
147
+ end
148
+ decoder_opts[:lc] = @lc if @lc && !decoder_opts.key?(:lc)
149
+ decoder_opts[:lp] = @lp if @lp && !decoder_opts.key?(:lp)
150
+ decoder_opts[:pb] = @pb if @pb && !decoder_opts.key?(:pb)
151
+ if @dict_size && !decoder_opts.key?(:dict_size)
152
+ decoder_opts[:dict_size] =
153
+ @dict_size
154
+ end
155
+ if @uncompressed_size && !decoder_opts.key?(:uncompressed_size)
156
+ decoder_opts[:uncompressed_size] =
157
+ @uncompressed_size
158
+ end
159
+ # allowed: options is a public parameter; the body needs #key? and #[]
160
+ decoder_opts[:uncompressed_size] ||= options[:size] if options.respond_to?(:key?) && options.key?(:size)
161
+
162
+ decoder = Decoder.new(input_stream, decoder_opts)
163
+ decoder.decode_stream(output_stream)
164
+ output_stream
165
+ end
166
+
167
+ private
168
+
169
+ # Build encoder options from compression options
170
+ #
171
+ # @param options [Models::CompressionOptions, Hash, nil] Compression opts
172
+ # @return [Hash] Encoder options
173
+ def build_encoder_options(options)
174
+ return {} if options.nil?
175
+
176
+ opts = {}
177
+
178
+ # Handle Hash-like options
179
+ # allowed: options is a public parameter; the body needs #[] and #key?
180
+ if options.respond_to?(:[])
181
+ opts[:lc] = options[:lc] if options[:lc]
182
+ opts[:lp] = options[:lp] if options[:lp]
183
+ opts[:pb] = options[:pb] if options[:pb]
184
+ opts[:dict_size] = options[:dict_size] if options[:dict_size]
185
+ opts[:write_size] = options[:write_size] if options.key?(:write_size)
186
+ if options.key?(:sdk_compatible)
187
+ opts[:sdk_compatible] =
188
+ options[:sdk_compatible]
189
+ end
190
+ if options.key?(:xz_compatible)
191
+ opts[:xz_compatible] =
192
+ options[:xz_compatible]
193
+ end
194
+ opts[:raw_mode] = options[:raw_mode] if options.key?(:raw_mode)
195
+ end
196
+
197
+ # Handle level from both Hash and CompressionOptions
198
+ # Models::CompressionOptions and SolidEncoder::LzmaOptions both expose
199
+ # #level and share no ancestor; converting needs them unified first.
200
+ # allowed: type check deferred, not feature detection
201
+ level = if options.respond_to?(:level)
202
+ options.level
203
+ # allowed: reader-style options are handled above; this arm needs #[]
204
+ elsif options.respond_to?(:[])
205
+ options[:level]
206
+ end
207
+ level ||= 5
208
+
209
+ opts[:dict_size] ||= dictionary_size_for_level(level)
210
+
211
+ opts
212
+ end
213
+
214
+ # Build decoder options from decompression options
215
+ #
216
+ # @param options [Models::CompressionOptions, Hash, nil] Decompression opts
217
+ # @return [Hash] Decoder options
218
+ def build_decoder_options(options)
219
+ return {} if options.nil?
220
+
221
+ # Handle case where options is an Integer (uncompressed size) instead of Hash
222
+ return {} if options.is_a?(Integer)
223
+
224
+ opts = {}
225
+
226
+ # Handle Hash-like options - pass through all decoder-relevant options
227
+ # allowed: options is a public parameter; the body needs #key? and #[]
228
+ if options.respond_to?(:key?)
229
+ if options.key?(:sdk_compatible)
230
+ opts[:sdk_compatible] =
231
+ options[:sdk_compatible]
232
+ end
233
+ opts[:lzma2_mode] = options[:lzma2_mode] if options.key?(:lzma2_mode)
234
+ opts[:lc] = options[:lc] if options.key?(:lc)
235
+ opts[:lp] = options[:lp] if options.key?(:lp)
236
+ opts[:pb] = options[:pb] if options.key?(:pb)
237
+ opts[:dict_size] = options[:dict_size] if options.key?(:dict_size)
238
+ if options.key?(:uncompressed_size)
239
+ opts[:uncompressed_size] =
240
+ options[:uncompressed_size]
241
+ end
242
+ opts[:size] = options[:size] if options.key?(:size)
243
+ end
244
+
245
+ opts
246
+ end
247
+
248
+ # Get dictionary size based on compression level
249
+ #
250
+ # @param level [Integer] Compression level (0-9)
251
+ # @return [Integer] Dictionary size in bytes
252
+ def dictionary_size_for_level(level)
253
+ 1 << case level
254
+ when 0..1 then 16 # 64KB
255
+ when 2..3 then 20 # 1MB
256
+ when 4..5 then 22 # 4MB
257
+ when 6..7 then 23 # 8MB
258
+ else 24 # 16MB
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ # Register the LZMA algorithm
266
+ Omnizip::AlgorithmRegistry.register(:lzma, Omnizip::Algorithms::LZMA)
@@ -0,0 +1,180 @@
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 LZMA2
26
+ # LZMA2 Chunk Manager - handles chunk boundaries and decisions
27
+ #
28
+ # This class is responsible for:
29
+ # - Splitting data into chunks of appropriate size
30
+ # - Deciding whether to compress or store each chunk uncompressed
31
+ # - Managing chunk buffering
32
+ # - Providing thread safety infrastructure (for future use)
33
+ #
34
+ # The chunk manager implements intelligent compression decisions
35
+ # based on compression ratio thresholds.
36
+ #
37
+ # IMPORTANT: LZMA2 format limits uncompressed chunk size to 65536 bytes
38
+ # due to 2-byte size encoding. This manager enforces that limit.
39
+ class ChunkManager
40
+ include Constants
41
+
42
+ attr_reader :chunk_size
43
+
44
+ # Maximum bytes per chunk (LZMA2 spec limit)
45
+ MAX_CHUNK_BYTES = UNCOMPRESSED_SIZE_MAX + 1 # 65536 bytes
46
+
47
+ # Chunk data model
48
+ #
49
+ # Represents a single chunk of data with its metadata
50
+ class Chunk
51
+ attr_reader :data, :compressed_data, :is_compressed
52
+
53
+ # Initialize a chunk
54
+ #
55
+ # @param data [String] Uncompressed chunk data
56
+ def initialize(data)
57
+ @data = data
58
+ @compressed_data = nil
59
+ @is_compressed = false
60
+ end
61
+
62
+ # Set compressed data
63
+ #
64
+ # @param compressed [String] Compressed data
65
+ # @return [void]
66
+ def compressed_data=(compressed)
67
+ @compressed_data = compressed
68
+ @is_compressed = true
69
+ end
70
+
71
+ # Get the data to write (compressed or uncompressed)
72
+ #
73
+ # @return [String] Data to write
74
+ def output_data
75
+ @is_compressed ? @compressed_data : @data
76
+ end
77
+
78
+ # Get size of output data
79
+ #
80
+ # @return [Integer] Size in bytes
81
+ def output_size
82
+ output_data.bytesize
83
+ end
84
+
85
+ # Get uncompressed size
86
+ #
87
+ # @return [Integer] Size in bytes
88
+ def uncompressed_size
89
+ @data.bytesize
90
+ end
91
+ end
92
+
93
+ # Initialize chunk manager
94
+ #
95
+ # @param chunk_size [Integer] Desired chunk size
96
+ def initialize(chunk_size = CHUNK_SIZE_DEFAULT)
97
+ @chunk_size = validate_chunk_size(chunk_size)
98
+ # Enforce LZMA2 format limit
99
+ @effective_chunk_size = [@chunk_size, MAX_CHUNK_BYTES].min
100
+ end
101
+
102
+ # Split data into chunks
103
+ #
104
+ # @param data [String] Data to split
105
+ # @return [Array<Chunk>] Array of chunks
106
+ def create_chunks(data)
107
+ chunks = []
108
+ pos = 0
109
+
110
+ while pos < data.bytesize
111
+ chunk_data = data.byteslice(pos, @effective_chunk_size)
112
+ chunks << Chunk.new(chunk_data)
113
+ pos += @effective_chunk_size
114
+ end
115
+
116
+ chunks
117
+ end
118
+
119
+ # Decide if chunk should be compressed
120
+ #
121
+ # Makes decision based on compression ratio threshold.
122
+ # If compressed size is not significantly smaller than
123
+ # uncompressed size, store uncompressed.
124
+ #
125
+ # @param chunk [Chunk] Chunk with compressed data set
126
+ # @return [Boolean] True if should use compression
127
+ def should_compress?(chunk)
128
+ return false unless chunk.compressed_data
129
+
130
+ # Calculate compression ratio
131
+ ratio = chunk.output_size.to_f / chunk.uncompressed_size
132
+
133
+ # Only use compression if ratio is below threshold
134
+ ratio < COMPRESSION_THRESHOLD
135
+ end
136
+
137
+ # Decide if chunk is last chunk
138
+ #
139
+ # @param chunk_index [Integer] Current chunk index
140
+ # @param total_chunks [Integer] Total number of chunks
141
+ # @return [Boolean] True if last chunk
142
+ def last_chunk?(chunk_index, total_chunks)
143
+ chunk_index == total_chunks - 1
144
+ end
145
+
146
+ # Calculate optimal chunk size for data
147
+ #
148
+ # This method can be used to dynamically adjust chunk size
149
+ # based on data characteristics (future enhancement).
150
+ #
151
+ # @param data_size [Integer] Total data size
152
+ # @return [Integer] Optimal chunk size
153
+ def optimal_chunk_size(data_size)
154
+ # For now, use effective chunk size
155
+ # Future: could adjust based on data size
156
+ return @effective_chunk_size if data_size <= @effective_chunk_size * 2
157
+
158
+ # For larger data, might want larger chunks (up to max)
159
+ [@effective_chunk_size * 2, MAX_CHUNK_BYTES].min
160
+ end
161
+
162
+ private
163
+
164
+ # Validate chunk size
165
+ #
166
+ # @param size [Integer] Chunk size to validate
167
+ # @return [Integer] Validated size
168
+ # @raise [ArgumentError] If size is invalid
169
+ def validate_chunk_size(size)
170
+ unless size.between?(CHUNK_SIZE_MIN, CHUNK_SIZE_MAX)
171
+ raise ArgumentError,
172
+ "Chunk size must be between #{CHUNK_SIZE_MIN} " \
173
+ "and #{CHUNK_SIZE_MAX}"
174
+ end
175
+ size
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Algorithms
5
+ # LZMA2 Format Constants (from XZ Utils specification)
6
+ module LZMA2Const
7
+ # Maximum size of compressed data per chunk (excluding headers)
8
+ CHUNK_MAX = 65536 # 64 KB
9
+
10
+ # Maximum size of uncompressed data per chunk
11
+ # Limited by 16-bit size field in LZMA2 header (stores size-1)
12
+ # Max value is 0xFFFF + 1 = 65536 bytes
13
+ UNCOMPRESSED_MAX = 65536 # 64 KB
14
+
15
+ # Maximum size of LZMA2 chunk header
16
+ HEADER_MAX = 6
17
+
18
+ # Size of uncompressed chunk header
19
+ HEADER_UNCOMPRESSED = 3
20
+
21
+ # Control byte values
22
+ CONTROL_END = 0x00 # End of stream marker
23
+ CONTROL_UNCOMPRESSED_RESET = 0x01 # Uncompressed with dict reset
24
+ CONTROL_UNCOMPRESSED = 0x02 # Uncompressed without reset
25
+ CONTROL_LZMA_MIN = 0x80 # Minimum LZMA control byte
26
+
27
+ # Control byte flags (for LZMA chunks)
28
+ FLAG_UNCOMPRESSED_SIZE = 0x80 # Base flag for LZMA chunks
29
+ FLAG_RESET_STATE = 0x20 # Reset LZMA state
30
+ FLAG_RESET_PROPERTIES = 0x40 # Reset properties + state
31
+ FLAG_RESET_DICT = 0x60 # Reset dict + properties + state
32
+
33
+ # Dictionary size encoding constants
34
+ DICT_SIZE_MIN = 4096 # 4 KB minimum
35
+ DICT_SIZE_MAX = 0xFFFFFFFF # 4 GB maximum
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Omnizip
6
+ module Algorithms
7
+ # LZMA2 encoder - delegates to XzLZMA2Encoder
8
+ #
9
+ # This class provides a backward-compatible API that delegates to the
10
+ # complete XzLZMA2Encoder implementation ported from XZ Utils.
11
+ #
12
+ # Based on XZ Utils lzma2_encoder.c
13
+ class LZMA2Encoder
14
+ attr_reader :dict_size, :lc, :lp, :pb
15
+
16
+ # Initialize the encoder
17
+ #
18
+ # @param dict_size [Integer] Dictionary size (default: 8MB)
19
+ # @param lc [Integer] Literal context bits (default: 3)
20
+ # @param lp [Integer] Literal position bits (default: 0)
21
+ # @param pb [Integer] Position bits (default: 2)
22
+ # @param standalone [Boolean] If true, write property byte for
23
+ # standalone LZMA2 files (default: false)
24
+ def initialize(
25
+ dict_size: 8 * 1024 * 1024,
26
+ lc: 3,
27
+ lp: 0,
28
+ pb: 2,
29
+ standalone: false,
30
+ **
31
+ )
32
+ @dict_size = dict_size
33
+ @lc = lc
34
+ @lp = lp
35
+ @pb = pb
36
+ @standalone = standalone
37
+
38
+ # Create the SimpleLZMA2Encoder (uses working XzEncoder internally)
39
+ @encoder = LZMA2::SimpleLZMA2Encoder.new(
40
+ dict_size: dict_size,
41
+ lc: lc,
42
+ lp: lp,
43
+ pb: pb,
44
+ standalone: standalone,
45
+ )
46
+ end
47
+
48
+ # Encode data into LZMA2 format
49
+ #
50
+ # @param input [String] Input data to compress
51
+ # @return [String] LZMA2 compressed data
52
+ def encode(input)
53
+ @encoder.encode(input)
54
+ end
55
+
56
+ # Compress data from input stream to output stream
57
+ # This method provides compatibility with the AlgorithmRegistry interface
58
+ #
59
+ # @param input_io [IO] Input stream to read from
60
+ # @param output_io [IO] Output stream to write to
61
+ # @param level [Integer] Compression level (not used, kept for compatibility)
62
+ # @return [Integer] Number of bytes written
63
+ def compress(input_io, output_io, _level = nil)
64
+ input_data = input_io.read
65
+ compressed = encode(input_data)
66
+ output_io.write(compressed)
67
+ compressed.bytesize
68
+ end
69
+
70
+ # Decompress data from input stream to output stream
71
+ # This method provides compatibility with the AlgorithmRegistry interface
72
+ #
73
+ # @param input_io [IO] Input stream to read from
74
+ # @param output_io [IO] Output stream to write to
75
+ # @param size [Integer] Expected uncompressed size (optional)
76
+ # @return [Integer] Number of bytes written
77
+ def decompress(input_io, output_io, _size = nil)
78
+ # Check if this is being called for 7-Zip format (raw LZMA2 stream)
79
+ # 7-Zip stores LZMA2 without a property byte
80
+ # We can detect this by checking if input_io is a StringIO (which is used
81
+ # by StreamDecompressor for 7-Zip format)
82
+ raw_mode = input_io.is_a?(StringIO)
83
+
84
+ # Create a decoder instance
85
+ decoder = LZMA2::Decoder.new(input_io, raw_mode: raw_mode)
86
+
87
+ # For raw_mode (7-Zip format), we need to provide dict_size
88
+ # Use default 8MB if not specified
89
+ if raw_mode
90
+ # Re-create decoder with dict_size option
91
+ decoder = LZMA2::Decoder.new(input_io,
92
+ raw_mode: true,
93
+ dict_size: @dict_size)
94
+ end
95
+
96
+ # Decode the stream
97
+ result = decoder.decode_stream
98
+
99
+ # Write to output
100
+ output_io.write(result)
101
+
102
+ result.bytesize
103
+ end
104
+
105
+ # Encode dictionary size for LZMA2 properties
106
+ # Returns a single byte encoding the dictionary size
107
+ #
108
+ # @param dict_size [Integer] Dictionary size to encode
109
+ # @return [Integer] Encoded dictionary size byte
110
+ def self.encode_dict_size(dict_size)
111
+ # LZMA2 dictionary size encoding (XZ Utils format)
112
+ # Byte value d encodes dictionary size as:
113
+ # If d < 40: size = 2^((d/2) + 12) (for even d)
114
+ # or size = 3 * 2^((d-1)/2 + 11) (for odd d)
115
+ # If d == 40: size = 0xFFFFFFFF (4GB - 1)
116
+
117
+ # Clamp to valid range
118
+ d = [dict_size, LZMA2Const::DICT_SIZE_MIN].max
119
+
120
+ # For 8MB (8 * 1024 * 1024 = 8388608 = 2^23):
121
+ # We want: 2^((d/2) + 12) = 2^23
122
+ # So: (d/2) + 12 = 23
123
+ # Therefore: d/2 = 11, d = 22
124
+
125
+ # Calculate log2 of dict_size
126
+ log2_size = 0
127
+ temp = d
128
+ while temp > 1
129
+ log2_size += 1
130
+ temp >>= 1
131
+ end
132
+
133
+ # Encoding formula for power-of-2 sizes:
134
+ # d = 2 * (log2_size - 12)
135
+ if d == (1 << log2_size)
136
+ # Exact power of 2
137
+ [(log2_size - 12) * 2, 40].min
138
+ else
139
+ # Between 2^n and 2^n + 2^(n-1), use odd encoding
140
+ [((log2_size - 12) * 2) + 1, 40].min
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end