omnizip 0.4.7-aarch64-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,547 @@
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
+ require "stringio"
24
+
25
+ module Omnizip
26
+ module Implementations
27
+ module XZUtils
28
+ module LZMA2
29
+ # XZ Utils LZMA2 decoder implementation.
30
+ #
31
+ # This is the original Decoder moved from algorithms/lzma2/decoder.rb
32
+ # to the new namespace structure.
33
+ class Decoder
34
+ include Omnizip::Algorithms::LZMA2Const
35
+
36
+ attr_reader :dict_size
37
+
38
+ # Initialize the decoder
39
+ #
40
+ # @param input [IO] Input stream of compressed data
41
+ # @param options [Hash] Decoding options
42
+ # @option options [Boolean] :raw_mode If true, skip property byte reading (for XZ format)
43
+ # @option options [Integer] :dict_size Dictionary size to use (required for raw_mode)
44
+ def initialize(input, options = {})
45
+ @input = input
46
+ @options = options
47
+ @raw_mode = options[:raw_mode] || false
48
+
49
+ if @raw_mode
50
+ # In raw_mode (XZ format), property byte is provided by caller
51
+ # Only dict_size comes from the XZ filter properties
52
+ @dict_size = options[:dict_size] || (8 * 1024 * 1024)
53
+ @properties = Omnizip::Algorithms::LZMA2::Properties.new(@dict_size)
54
+ else
55
+ read_property_byte
56
+ end
57
+ end
58
+
59
+ # Decode a compressed stream
60
+ #
61
+ # XZ Utils pattern (lzma2_decoder.c):
62
+ # - LZMA decoder is created ONCE and reused across all chunks
63
+ # - State (dictionary, probability models) persists between chunks
64
+ # - Reset only when control byte indicates new properties (control >= 0xC0)
65
+ #
66
+ # @return [String] Decompressed data
67
+ def decode_stream
68
+ output_io = StringIO.new
69
+ output_io.set_encoding("ASCII-8BIT")
70
+
71
+ # XZ Utils pattern: Create LZMA decoder ONCE (lzma2_decoder_init)
72
+ # The decoder will be reused across all chunks
73
+ @lzma_decoder = nil
74
+ @need_properties = true # First LZMA chunk needs properties (XZ Utils line 45)
75
+ @need_dictionary_reset = true # First chunk must reset dictionary (XZ Utils line 43)
76
+
77
+ chunk_num = 0
78
+ loop do
79
+ control = read_control_byte
80
+
81
+ break if control == CONTROL_END
82
+
83
+ # XZ Utils pattern (lzma2_decoder.c:75-82):
84
+ # Dictionary reset is needed if control >= 0xE0 or control == 1
85
+ # If dictionary reset is needed but control doesn't do it, error
86
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:75-82
87
+ if control >= 0xE0 || control == CONTROL_UNCOMPRESSED_RESET
88
+ @need_properties = true
89
+ @need_dictionary_reset = true
90
+ elsif @need_dictionary_reset
91
+ raise Omnizip::FormatError,
92
+ "LZMA2 dictionary reset required but not performed (control=0x#{control.to_s(16).upcase})"
93
+ end
94
+
95
+ # XZ Utils pattern (lzma2_decoder.c:121-126):
96
+ # Clear dictionary reset flag. The actual dict_reset is handled
97
+ # by the LZMA decoder when processing the chunk data.
98
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:121-127
99
+ if @need_dictionary_reset
100
+ @need_dictionary_reset = false
101
+ end
102
+
103
+ # XZ Utils pattern (lzma2_decoder.c:84-110):
104
+ # For LZMA chunks (control >= 0x80), validate properties requirements
105
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:98-99
106
+ if control >= 0x80
107
+ if control >= 0xC0
108
+ # New properties present - properties will be read below
109
+ @need_properties = false
110
+ elsif @need_properties
111
+ # LZMA chunk without properties but properties are needed
112
+ # This happens after dictionary reset when next chunk must have properties
113
+ raise Omnizip::FormatError,
114
+ "LZMA2 properties required but not provided (control=0x#{control.to_s(16).upcase})"
115
+ end
116
+ end
117
+
118
+ chunk_data = decode_chunk(control, chunk_num)
119
+
120
+ # XZ Utils pattern: Uncompressed chunks ALWAYS produce output
121
+ # Dictionary reset chunks (control == 1) initialize the dictionary
122
+ # with the chunk data, then the dictionary is flushed to output
123
+ # So we should NEVER skip output for valid chunks
124
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:121-127
125
+ output_io.write(chunk_data)
126
+ chunk_num += 1
127
+ end
128
+
129
+ output_io.string.force_encoding("ASCII-8BIT")
130
+ end
131
+
132
+ private
133
+
134
+ # Read and parse LZMA2 property byte
135
+ #
136
+ # @return [void]
137
+ # @raise [Omnizip::FormatError] If property byte is invalid
138
+ def read_property_byte
139
+ prop_byte = @input.getbyte
140
+ raise Omnizip::FormatError, "Invalid LZMA2 header" if prop_byte.nil?
141
+
142
+ @properties = Omnizip::Algorithms::LZMA2::Properties.from_byte(prop_byte)
143
+ @dict_size = @properties.actual_dict_size
144
+ end
145
+
146
+ # Read control byte
147
+ #
148
+ # @return [Integer] Control byte value
149
+ # @raise [Omnizip::IOError] If stream ends unexpectedly
150
+ def read_control_byte
151
+ byte = @input.getbyte
152
+ raise Omnizip::IOError, "Unexpected end of stream" if byte.nil?
153
+
154
+ byte
155
+ end
156
+
157
+ # Decode chunk based on control byte
158
+ #
159
+ # XZ Utils pattern (lzma2_decoder.c:75-102):
160
+ # - control >= 0xE0 or control == 1: Dictionary reset + properties needed
161
+ # - control >= 0xC0: State reset + properties
162
+ # - control >= 0xA0: State reset only
163
+ # - control >= 0x80: LZMA chunk (no reset)
164
+ # - control == 0x01 or 0x02: Uncompressed chunk
165
+ # - control > 2 and < 0x80: INVALID (LZMA2_DATA_ERROR)
166
+ #
167
+ # @param control [Integer] Control byte
168
+ # @param chunk_num [Integer] Chunk sequence number
169
+ # @return [String] Decoded chunk data
170
+ def decode_chunk(control, chunk_num)
171
+ # XZ Utils pattern (lzma2_decoder.c:138-140):
172
+ # Invalid control values: control > 2 and < 0x80 are invalid
173
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/lzma/lzma2_decoder.c:138-140
174
+ if control > 2 && control < 0x80
175
+ raise Omnizip::FormatError,
176
+ "Invalid LZMA2 control byte: 0x#{control.to_s(16).upcase} " \
177
+ "(valid ranges: 0x00-0x02, 0x80-0xFF)"
178
+ end
179
+
180
+ if uncompressed_chunk?(control)
181
+ decode_uncompressed_chunk(control)
182
+ else
183
+ decode_compressed_chunk(control, chunk_num)
184
+ end
185
+ end
186
+
187
+ # Check if control byte indicates uncompressed chunk
188
+ #
189
+ # @param control [Integer] Control byte
190
+ # @return [Boolean] True if uncompressed
191
+ def uncompressed_chunk?(control)
192
+ [CONTROL_UNCOMPRESSED_RESET,
193
+ CONTROL_UNCOMPRESSED].include?(control)
194
+ end
195
+
196
+ # Decode uncompressed chunk
197
+ #
198
+ # XZ Utils pattern (lzma2_decoder.c:193-200):
199
+ # - Copy from input to the dictionary as is using dict_write()
200
+ # - This ensures subsequent compressed chunks can reference the data
201
+ # - If LZMA decoder exists, add data to dictionary directly
202
+ # - If LZMA decoder doesn't exist, store data in @uncompressed_buffer
203
+ #
204
+ # @param control [Integer] Control byte
205
+ # @return [String] Uncompressed data
206
+ def decode_uncompressed_chunk(_control)
207
+ # Read uncompressed size (2 bytes, big-endian)
208
+ size = read_size_bytes(2) + 1
209
+
210
+ # Read uncompressed data
211
+ data = @input.read(size)
212
+
213
+ if data.nil? || data.bytesize != size
214
+ raise Omnizip::IOError,
215
+ "Unexpected end of stream"
216
+ end
217
+
218
+ # XZ Utils pattern: Copy from input to the dictionary as is.
219
+ # Reference: lzma2_decoder.c:195 - dict_write(dict, in, in_pos, in_size, &coder->compressed_size)
220
+ #
221
+ # If the LZMA decoder exists, add the data to its dictionary directly
222
+ # Otherwise, store it in @uncompressed_buffer for later use
223
+ if @lzma_decoder
224
+ # LZMA decoder exists - add data to its dictionary
225
+ @lzma_decoder.add_to_dictionary(data)
226
+ else
227
+ # LZMA decoder doesn't exist yet - store data for later
228
+ # This will be added to the dictionary when the first compressed chunk arrives
229
+ @uncompressed_buffer ||= String.new(encoding: "ASCII-8BIT")
230
+ @uncompressed_buffer << data
231
+ end
232
+
233
+ data
234
+ end
235
+
236
+ # Decode compressed chunk
237
+ #
238
+ # XZ Utils pattern (lzma2_decoder.c:84-103, 154-161, 163-191):
239
+ # - control >= 0xC0: New properties present, call decoder.reset()
240
+ # - control >= 0xA0: State reset only
241
+ # - control >= 0x80: LZMA chunk with explicit uncompressed/compressed size
242
+ # - control 0x03-0x7F: INVALID (rejected in decode_chunk)
243
+ # - LZMA decoder is created once and reused across all chunks
244
+ #
245
+ # @param control [Integer] Control byte
246
+ # @param chunk_num [Integer] Chunk sequence number
247
+ # @return [String] Decompressed data
248
+ def decode_compressed_chunk(control, chunk_num)
249
+ if control >= 0x80
250
+ # Compressed chunk with explicit uncompressed/compressed size
251
+ # Read uncompressed size (2 bytes, big-endian)
252
+ # High 3 bits are in bits 2-0 of the control byte (bits 19-17 of uncompressed size)
253
+ uncompressed_low_bytes = [@input.getbyte, @input.getbyte]
254
+ uncompressed_low = (uncompressed_low_bytes[0] << 8) | uncompressed_low_bytes[1]
255
+ # XZ Utils lzma2_decoder.c:87: (control & 0x1F) << 16, then += each byte
256
+ # High 5 bits of (uncompressed_size - 1) are in bits 4-0 of control byte
257
+ uncompressed_high = control & 0x1F
258
+ uncompressed_size = (uncompressed_high << 16) + uncompressed_low + 1
259
+
260
+ # Read compressed size (2 bytes, big-endian)
261
+ compressed_size = read_size_bytes(2) + 1
262
+ else
263
+ # This should never be reached because control bytes 0x03-0x7F are
264
+ # rejected in decode_chunk() before this method is called.
265
+ # Control bytes < 0x80 should only be 0x01 or 0x02, which are
266
+ # handled by decode_uncompressed_chunk(), not this method.
267
+ raise Omnizip::FormatError,
268
+ "Invalid LZMA2 control byte: 0x#{control.to_s(16).upcase} " \
269
+ "(control < 0x80 but not 0x01 or 0x02)"
270
+ end
271
+ # Note: For control >= 0x80, compressed_data will be read below.
272
+ # For control < 0x80 (unreachable), this method raises above.
273
+
274
+ # Read properties byte
275
+ # LZMA2 format: Properties byte is ONLY present for control >= 0xC0
276
+ # For control >= 0xA0 but < 0xC0, use default properties (no properties byte)
277
+ # For control < 0xA0 (but >= 0x80), use previous properties (no properties byte)
278
+ # Reference: XZ Utils lzma2_decoder.c:92-96, 154-160
279
+ if control >= 0xC0
280
+ # New properties present - read properties byte
281
+ properties = @input.getbyte
282
+ if properties.nil?
283
+ raise Omnizip::IOError,
284
+ "Unexpected end of stream"
285
+ end
286
+ else
287
+ # No properties byte for control >= 0xA0 but < 0xC0
288
+ # Use default properties for LZMA2
289
+ properties = nil
290
+ end
291
+
292
+ if control >= 0x80
293
+ # Read compressed data
294
+ compressed_data = @input.read(compressed_size)
295
+ if compressed_data.nil? || compressed_data.bytesize != compressed_size
296
+ raise Omnizip::IOError, "Unexpected end of stream"
297
+ end
298
+ end
299
+
300
+ # Decompress using LZMA
301
+ # Pass control byte to handle decoder creation/reset logic
302
+ decompress_lzma_chunk(compressed_data, uncompressed_size, properties,
303
+ control, chunk_num)
304
+ end
305
+
306
+ # Decompress LZMA chunk
307
+ #
308
+ # XZ Utils pattern (lzma2_decoder.c:92-103, 154-191):
309
+ # - Create LZMA decoder on first chunk or when control >= 0xC0
310
+ # - Call decoder.reset() when new properties are present (control >= 0xC0)
311
+ # - Reuse decoder state across chunks (preserves probability models)
312
+ # - Reset range decoder between chunks (lzma_decoder.c:1014-1017)
313
+ #
314
+ # @param compressed_data [String] Compressed data (no LZMA header)
315
+ # @param expected_size [Integer] Expected decompressed size (from LZMA2 chunk header)
316
+ # @param properties [Integer, nil] LZMA properties byte from LZMA2 chunk (if present)
317
+ # @param control [Integer] LZMA2 control byte for this chunk
318
+ # @param chunk_num [Integer] Chunk sequence number
319
+ # @return [String] Decompressed data
320
+ def decompress_lzma_chunk(compressed_data, expected_size, properties,
321
+ control, chunk_num)
322
+ # XZ Utils pattern (lzma2_decoder.c:140-141):
323
+ # Pass the chunk's uncompressed_size to the LZMA decoder.
324
+ # The block header's uncompressed_size is for validation only.
325
+ # For simple compressed chunks (control < 0x80), expected_size is nil,
326
+ # which means decode until LZMA end-of-stream marker.
327
+ lzma_uncompressed_size = expected_size || 0xFFFFFFFFFFFFFFFF # UNKNOWN = decode until EOS
328
+
329
+ # Decode lc, lp, pb from LZMA chunk properties byte
330
+ # In XZ format, the chunk properties byte is inside the compressed chunk
331
+ # and contains: (pb * 9 * 5) + (lp * 9) + lc
332
+ # Reference: /tmp/xz-source/src/liblzma/lzma/lzma_decoder.c:1199-1209
333
+ if properties && properties >= 0
334
+ # Decode lc, lp, pb from chunk properties byte using XZ Utils formula
335
+ pb = properties / (9 * 5)
336
+ remainder = properties - (pb * 9 * 5)
337
+ lp = remainder / 9
338
+ lc = remainder - (lp * 9)
339
+ else
340
+ # Default values when no properties present
341
+ # XZ Utils defaults: lc=3, lp=0, pb=2
342
+ lc = 3
343
+ lp = 0
344
+ pb = 2
345
+ end
346
+
347
+ # XZ Utils pattern: Create/reuse LZMA decoder across chunks
348
+ # lzma2_decoder.c:92-103, 154-161: Handle decoder creation and reset
349
+ #
350
+ # IMPORTANT: We need to handle the case where the first chunk(s) are
351
+ # uncompressed. The uncompressed data must be added to the LZMA decoder's
352
+ # dictionary BEFORE we create the decoder, so we'll pass it as preloaded data.
353
+ if chunk_num.zero? || !@lzma_decoder
354
+ # First chunk - create LZMA decoder in lzma2_mode
355
+ # NO LZMA HEADER - pass compressed data directly
356
+ # XZ Utils: lzma_lz_decoder_create + lzma_lzma_decoder_create
357
+ input_buffer = StringIO.new(compressed_data)
358
+ input_buffer.set_encoding("ASCII-8BIT")
359
+
360
+ # Check if we have uncompressed data to preload into the dictionary
361
+ preloaded_data = @uncompressed_buffer if @uncompressed_buffer && !@uncompressed_buffer.empty?
362
+
363
+ @lzma_decoder = Omnizip::Algorithms::XzUtilsDecoder.new(input_buffer,
364
+ lzma2_mode: true,
365
+ lc: lc,
366
+ lp: lp,
367
+ pb: pb,
368
+ dict_size: @dict_size,
369
+ uncompressed_size: lzma_uncompressed_size,
370
+ preloaded_data: preloaded_data) # Pass uncompressed data to preload
371
+
372
+ # Clear uncompressed buffer after passing to decoder
373
+ @uncompressed_buffer = nil if preloaded_data
374
+ else
375
+ # Subsequent chunks - reuse decoder, reset if needed
376
+ # XZ Utils lzma2_decoder.c:92-96, 154-161
377
+
378
+ # Determine if dictionary should be preserved
379
+ # Use the same logic as at line 414 for consistency
380
+ # XZ Utils LZMA2 control byte decoding (lzma2_decoder.c:75-79):
381
+ # - control >= 0xE0: LZMA2 compressed + reset dictionary + properties byte present
382
+ # - control = 0x01: end of chunk marker
383
+ # XZ Utils sets need_dictionary_reset = true ONLY for control >= 0xE0 || control == 1
384
+ # Therefore, dict_reset is ONLY called for control >= 0xE0 || control == 1
385
+ # - control = 0xC0: LZMA2 compressed + state reset + default properties (NO dict reset!)
386
+ # - control < 0x80: LZMA2 uncompressed
387
+ # - 0x80 <= control < 0xC0: LZMA2 compressed + preserve dictionary
388
+ # Note: chunk_num >= 1 here (not the first chunk)
389
+ preserve_dict = !(control >= 0xE0 || control == 1)
390
+
391
+ if control >= 0xC0
392
+ # New properties present - reset decoder with new properties
393
+ @lzma_decoder.reset(new_lc: lc, new_lp: lp, new_pb: pb,
394
+ preserve_dict: preserve_dict)
395
+
396
+ # Pass compressed data directly (NO LZMA HEADER)
397
+ input_buffer = StringIO.new(compressed_data)
398
+ input_buffer.set_encoding("ASCII-8BIT")
399
+
400
+ @lzma_decoder.set_input(input_buffer)
401
+ elsif control >= 0xA0
402
+ # State reset only (no new properties)
403
+ # IMPORTANT: XZ Utils source code (lzma2_decoder.c:107-109) shows that
404
+ # for control >= 0xA0, it calls coder->lzma.reset(), which resets
405
+ # rep distances to 0 (see lzma_decoder.c:1071-1074).
406
+ #
407
+ # A rep match with distance=0 is valid - it means "copy the last byte"
408
+ # (distance 0 from the current position, i.e., the byte just written).
409
+ @lzma_decoder.reset(preserve_dict: preserve_dict)
410
+
411
+ # Pass compressed data directly (NO LZMA HEADER)
412
+ input_buffer = StringIO.new(compressed_data)
413
+ input_buffer.set_encoding("ASCII-8BIT")
414
+
415
+ @lzma_decoder.set_input(input_buffer)
416
+
417
+ if @lzma2_debug
418
+ warn "DEBUG: decompress_lzma_chunk - After set_input, checking range_decoder..."
419
+ range_decoder = @lzma_decoder.range_decoder
420
+ if range_decoder
421
+ warn " range_decoder exists: code=0x#{range_decoder.code.to_s(16)}, range=0x#{range_decoder.range.to_s(16)}, init_bytes_remaining=#{range_decoder.init_bytes_remaining}"
422
+ else
423
+ warn " range_decoder is nil"
424
+ end
425
+ end
426
+ else
427
+ # For control >= 0x80 but < 0xA0: No reset
428
+ # Pass compressed data directly (NO LZMA HEADER)
429
+ input_buffer = StringIO.new(compressed_data)
430
+ input_buffer.set_encoding("ASCII-8BIT")
431
+
432
+ @lzma_decoder.set_input(input_buffer)
433
+ end
434
+
435
+ # XZ Utils: Set uncompressed size for each chunk (lzma2_decoder.c:140-141)
436
+ @lzma_decoder.set_uncompressed_size(lzma_uncompressed_size,
437
+ allow_eopm: false)
438
+
439
+ if @lzma2_debug
440
+ warn "DEBUG: decompress_lzma_chunk - Reusing LZMA decoder, set uncompressed_size=#{lzma_uncompressed_size}"
441
+ end
442
+ end
443
+
444
+ # For first chunk or when control >= 0xE0 or control == 1, reset dictionary (preserve_dict = false)
445
+ # For other chunks with control < 0xE0 and control != 1, preserve dictionary
446
+ # XZ Utils LZMA2 control byte decoding (lzma2_decoder.c:75-79):
447
+ # - control >= 0xE0: LZMA2 compressed + reset dictionary + properties byte present
448
+ # - control = 0x01: end of chunk marker
449
+ # XZ Utils sets need_dictionary_reset = true ONLY for control >= 0xE0 || control == 1
450
+ # Therefore, dict_reset is ONLY called for control >= 0xE0 || control == 1
451
+ # - control = 0xC0: LZMA2 compressed + state reset + default properties (NO dict reset!)
452
+ # - control < 0x80: LZMA2 uncompressed
453
+ # - 0x80 <= control < 0xC0: LZMA2 compressed + preserve dictionary
454
+ preserve_dictionary = chunk_num.zero? ? false : !(control >= 0xE0 || control == 1)
455
+
456
+ decompressed = @lzma_decoder.decode_stream(nil,
457
+ preserve_dict: preserve_dictionary,
458
+ check_rc_finished: false)
459
+
460
+ @lzma_decoder.compact_buffer
461
+
462
+ if @lzma2_debug
463
+ warn "DEBUG: decompress_lzma_chunk - expected=#{lzma_uncompressed_size}, got=#{decompressed.bytesize}"
464
+ end
465
+
466
+ # Verify size matches expected
467
+ if @lzma2_debug
468
+ # puts "DEBUG: Size check - decompressed=#{decompressed.bytesize}, expected=#{lzma_uncompressed_size}"
469
+ end
470
+ if decompressed.bytesize != lzma_uncompressed_size
471
+ raise Omnizip::DecompressionError, "Decompressed size mismatch: expected #{lzma_uncompressed_size}, " \
472
+ "got #{decompressed.bytesize}"
473
+ end
474
+
475
+ decompressed
476
+ end
477
+
478
+ # Build LZMA header for decompression
479
+ #
480
+ # @param uncompressed_size [Integer] Expected size after decompression
481
+ # @param properties [Integer, nil] LZMA properties byte (lc/lp/pb encoding) from LZMA2 chunk
482
+ # @return [String] LZMA header (13 bytes)
483
+ def build_lzma_header(uncompressed_size, properties = nil)
484
+ header = String.new(encoding: "ASCII-8BIT")
485
+
486
+ # The properties byte from LZMA2 encodes lc, lp, pb (not dictionary size!)
487
+ # Decode using XZ Utils formula from lzma_lzma_lclppb_decode:
488
+ # pb = byte / (9 * 5)
489
+ # byte -= pb * 9 * 5
490
+ # lp = byte / 9
491
+ # lc = byte - lp * 9
492
+ if properties && properties >= 0
493
+ prop_byte = properties
494
+ pb = prop_byte / (9 * 5)
495
+ remainder = prop_byte - (pb * 9 * 5)
496
+ lp = remainder / 9
497
+ lc = remainder - (lp * 9)
498
+
499
+ props = lc + (lp * 9) + (pb * 9 * 5)
500
+
501
+ if @lzma2_debug
502
+ warn "DEBUG: build_lzma_header - properties=0x#{prop_byte.to_s(16)} -> lc=#{lc}, lp=#{lp}, pb=#{pb}, props=0x#{props.to_s(16)}"
503
+ end
504
+ else
505
+ # Default values when no properties present
506
+ lc = 0
507
+ lp = 0
508
+ pb = 0
509
+
510
+ if @lzma2_debug
511
+ warn "DEBUG: build_lzma_header - no properties, using defaults lc=0, lp=0, pb=0"
512
+ end
513
+ end
514
+
515
+ # Calculate props encoding (props encoding is calculated the same way for both cases)
516
+ props = lc + (lp * 9) + (pb * 9 * 5)
517
+
518
+ header << [props].pack("C")
519
+
520
+ # Dictionary size from @dict_size (set during initialization from LZMA2 filter properties)
521
+ header << [@dict_size].pack("V")
522
+
523
+ # Uncompressed size (8 bytes, little-endian)
524
+ header << [uncompressed_size].pack("Q<")
525
+
526
+ header
527
+ end
528
+
529
+ # Read size bytes in big-endian order
530
+ #
531
+ # @param num_bytes [Integer] Number of bytes to read
532
+ # @return [Integer] Size value
533
+ def read_size_bytes(num_bytes)
534
+ size = 0
535
+ num_bytes.times do
536
+ byte = @input.getbyte
537
+ raise Omnizip::IOError, "Unexpected end of stream" if byte.nil?
538
+
539
+ size = (size << 8) | byte
540
+ end
541
+ size
542
+ end
543
+ end
544
+ end
545
+ end
546
+ end
547
+ end