omnizip 0.4.7-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (632) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +293 -0
  5. data/CHANGELOG.md +1647 -0
  6. data/CONTEXT.md +68 -0
  7. data/COPYING +502 -0
  8. data/Gemfile +19 -0
  9. data/LICENSE +12 -0
  10. data/README.adoc +1327 -0
  11. data/Rakefile +15 -0
  12. data/TODO.refactor/00-overview.md +67 -0
  13. data/TODO.refactor/01-registry-base-class.md +81 -0
  14. data/TODO.refactor/02-error-hierarchy.md +57 -0
  15. data/TODO.refactor/03-autoload-entry-point.md +69 -0
  16. data/TODO.refactor/04-filter-base-consolidation.md +49 -0
  17. data/TODO.refactor/05-send-private-methods.md +64 -0
  18. data/TODO.refactor/06-instance-variable-access.md +69 -0
  19. data/TODO.refactor/07-respond-to-replacement.md +237 -0
  20. data/TODO.refactor/08-spec-doubles.md +27 -0
  21. data/TODO.refactor/09-cli-shared-module.md +35 -0
  22. data/TODO.refactor/10-format-detector-ocp.md +34 -0
  23. data/TODO.refactor/11-convenience-decoupling.md +38 -0
  24. data/TODO.refactor/12-thread-safety.md +8 -0
  25. data/TODO.refactor/13-lutaml-model-migration.md +158 -0
  26. data/TODO.refactor/14-add-missing-specs.md +25 -0
  27. data/benchmark/README.md +260 -0
  28. data/benchmark/benchmark_suite.rb +125 -0
  29. data/benchmark/compression_bench.rb +181 -0
  30. data/benchmark/filter_bench.rb +180 -0
  31. data/benchmark/models/benchmark_result.rb +59 -0
  32. data/benchmark/models/comparison_result.rb +69 -0
  33. data/benchmark/profile_suite.rb +167 -0
  34. data/benchmark/reporter.rb +150 -0
  35. data/benchmark/run_benchmarks.rb +66 -0
  36. data/benchmark/test_data.rb +137 -0
  37. data/config/formats/rar3_spec.yml +92 -0
  38. data/config/formats/rar5_spec.yml +102 -0
  39. data/docs/.github/workflows/docs.yml +142 -0
  40. data/docs/.gitignore +21 -0
  41. data/docs/.lychee.toml +67 -0
  42. data/docs/Gemfile +13 -0
  43. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  44. data/docs/README.md +101 -0
  45. data/docs/_config.yml +112 -0
  46. data/docs/assets/logo.svg +1 -0
  47. data/docs/assets/omnizip-logo.pdf +1540 -11
  48. data/docs/comparison/feature-matrix.adoc +694 -0
  49. data/docs/comparison/index.adoc +113 -0
  50. data/docs/comparison/vs-7zip.adoc +309 -0
  51. data/docs/comparison/vs-peazip.adoc +77 -0
  52. data/docs/comparison/vs-rubyzip.adoc +342 -0
  53. data/docs/comparison/vs-winrar.adoc +100 -0
  54. data/docs/compatibility.adoc +579 -0
  55. data/docs/concepts/index.adoc +129 -0
  56. data/docs/developer/architecture.adoc +256 -0
  57. data/docs/developer/contributing.adoc +158 -0
  58. data/docs/developer/index.adoc +25 -0
  59. data/docs/developer/testing.adoc +212 -0
  60. data/docs/getting-started/basic-usage.adoc +263 -0
  61. data/docs/getting-started/index.adoc +42 -0
  62. data/docs/getting-started/installation.adoc +138 -0
  63. data/docs/getting-started/quick-start.adoc +183 -0
  64. data/docs/getting-started/your-first-archive.adoc +219 -0
  65. data/docs/guides/advanced-features/encryption.adoc +277 -0
  66. data/docs/guides/advanced-features/index.adoc +59 -0
  67. data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
  68. data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
  69. data/docs/guides/advanced-features/streaming.adoc +142 -0
  70. data/docs/guides/archive-formats/gzip-format.adoc +105 -0
  71. data/docs/guides/archive-formats/index.adoc +160 -0
  72. data/docs/guides/archive-formats/ole-format.adoc +151 -0
  73. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  74. data/docs/guides/archive-formats/rar5.adoc +521 -0
  75. data/docs/guides/archive-formats/rpm-format.adoc +108 -0
  76. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  77. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  78. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  79. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  80. data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
  81. data/docs/guides/compression-algorithms/deflate.adoc +313 -0
  82. data/docs/guides/compression-algorithms/index.adoc +190 -0
  83. data/docs/guides/compression-algorithms/lzma.adoc +394 -0
  84. data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
  85. data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
  86. data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
  87. data/docs/guides/creating-archives.adoc +348 -0
  88. data/docs/guides/extracting-archives.adoc +53 -0
  89. data/docs/guides/format-conversion.adoc +64 -0
  90. data/docs/guides/index.adoc +49 -0
  91. data/docs/guides/migration-rubyzip.adoc +217 -0
  92. data/docs/guides/parity-archives.adoc +605 -0
  93. data/docs/guides/performance-tuning.adoc +88 -0
  94. data/docs/index.adoc +228 -0
  95. data/docs/lychee.toml +67 -0
  96. data/docs/reference/api/overview.adoc +187 -0
  97. data/docs/reference/cli/compress-command.adoc +114 -0
  98. data/docs/reference/cli/overview.adoc +140 -0
  99. data/docs/reference/index.adoc +26 -0
  100. data/docs/resources/faq.adoc +185 -0
  101. data/docs/resources/quick-reference.adoc +222 -0
  102. data/docs/rust-backend.md +0 -0
  103. data/docs/troubleshooting/index.adoc +207 -0
  104. data/docs/xar_format.md +216 -0
  105. data/examples/api_comparison.rb +205 -0
  106. data/examples/deflate64_example.rb +96 -0
  107. data/examples/par2_demo.rb +121 -0
  108. data/examples/quick_start_native.rb +150 -0
  109. data/examples/quick_start_rubyzip.rb +115 -0
  110. data/examples/rubyzip_compatibility_demo.rb +194 -0
  111. data/exe/omnizip +27 -0
  112. data/lib/omnizip/algorithm.rb +176 -0
  113. data/lib/omnizip/algorithm_registry.rb +65 -0
  114. data/lib/omnizip/algorithms/.keep +0 -0
  115. data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
  116. data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
  117. data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
  118. data/lib/omnizip/algorithms/bzip2.rb +108 -0
  119. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  120. data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
  121. data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
  122. data/lib/omnizip/algorithms/deflate.rb +135 -0
  123. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  124. data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
  125. data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
  126. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
  127. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
  128. data/lib/omnizip/algorithms/deflate64.rb +118 -0
  129. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  130. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  131. data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
  132. data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
  133. data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
  134. data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
  135. data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
  136. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
  137. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
  138. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
  139. data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
  140. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
  141. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  142. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  143. data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
  144. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  145. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
  146. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
  147. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  148. data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
  149. data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
  150. data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
  151. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  152. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
  153. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
  154. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
  155. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
  156. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
  157. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
  158. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  159. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
  160. data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
  161. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
  162. data/lib/omnizip/algorithms/lzma.rb +266 -0
  163. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
  164. data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
  165. data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
  166. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
  167. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  168. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
  169. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  170. data/lib/omnizip/algorithms/lzma2.rb +133 -0
  171. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  172. data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
  173. data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
  174. data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
  175. data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
  176. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  177. data/lib/omnizip/algorithms/ppmd7.rb +146 -0
  178. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  179. data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
  180. data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
  181. data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
  182. data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
  183. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  184. data/lib/omnizip/algorithms/ppmd8.rb +122 -0
  185. data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
  186. data/lib/omnizip/algorithms/registration.rb +28 -0
  187. data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
  188. data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
  189. data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
  190. data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
  191. data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
  192. data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
  193. data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
  194. data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
  195. data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
  196. data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
  197. data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
  198. data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
  199. data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
  200. data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
  201. data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
  202. data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
  203. data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
  204. data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
  205. data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
  206. data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
  207. data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
  208. data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
  209. data/lib/omnizip/algorithms/zstandard.rb +210 -0
  210. data/lib/omnizip/algorithms.rb +35 -0
  211. data/lib/omnizip/archive/builder.rb +48 -0
  212. data/lib/omnizip/archive/reader_session.rb +67 -0
  213. data/lib/omnizip/archive.rb +86 -0
  214. data/lib/omnizip/archive_handler.rb +82 -0
  215. data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
  216. data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
  217. data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
  218. data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
  219. data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
  220. data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
  221. data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
  222. data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
  223. data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
  224. data/lib/omnizip/archive_handlers.rb +18 -0
  225. data/lib/omnizip/backends.rb +160 -0
  226. data/lib/omnizip/buffer/memory_archive.rb +246 -0
  227. data/lib/omnizip/buffer/memory_extractor.rb +234 -0
  228. data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
  229. data/lib/omnizip/buffer.rb +187 -0
  230. data/lib/omnizip/checksum_registry.rb +41 -0
  231. data/lib/omnizip/checksums/crc32.rb +101 -0
  232. data/lib/omnizip/checksums/crc64.rb +102 -0
  233. data/lib/omnizip/checksums/crc_base.rb +158 -0
  234. data/lib/omnizip/checksums/registration.rb +16 -0
  235. data/lib/omnizip/checksums/verifier.rb +130 -0
  236. data/lib/omnizip/checksums.rb +11 -0
  237. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  238. data/lib/omnizip/chunked/reader.rb +78 -0
  239. data/lib/omnizip/chunked/writer.rb +123 -0
  240. data/lib/omnizip/chunked.rb +123 -0
  241. data/lib/omnizip/cli/output_formatter.rb +112 -0
  242. data/lib/omnizip/cli.rb +604 -0
  243. data/lib/omnizip/commands/.keep +0 -0
  244. data/lib/omnizip/commands/archive_create_command.rb +245 -0
  245. data/lib/omnizip/commands/archive_extract_command.rb +231 -0
  246. data/lib/omnizip/commands/archive_list_command.rb +204 -0
  247. data/lib/omnizip/commands/archive_repair_command.rb +129 -0
  248. data/lib/omnizip/commands/archive_verify_command.rb +115 -0
  249. data/lib/omnizip/commands/compress_command.rb +115 -0
  250. data/lib/omnizip/commands/decompress_command.rb +149 -0
  251. data/lib/omnizip/commands/list_command.rb +51 -0
  252. data/lib/omnizip/commands/metadata_command.rb +215 -0
  253. data/lib/omnizip/commands/parity_create_command.rb +114 -0
  254. data/lib/omnizip/commands/parity_repair_command.rb +120 -0
  255. data/lib/omnizip/commands/parity_verify_command.rb +122 -0
  256. data/lib/omnizip/commands/profile_list_command.rb +54 -0
  257. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  258. data/lib/omnizip/commands.rb +21 -0
  259. data/lib/omnizip/convenience.rb +389 -0
  260. data/lib/omnizip/converter/conversion_registry.rb +50 -0
  261. data/lib/omnizip/converter/conversion_strategy.rb +108 -0
  262. data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
  263. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
  264. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
  265. data/lib/omnizip/converter.rb +124 -0
  266. data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
  267. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  268. data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
  269. data/lib/omnizip/crypto/aes256.rb +102 -0
  270. data/lib/omnizip/crypto.rb +11 -0
  271. data/lib/omnizip/entry.rb +44 -0
  272. data/lib/omnizip/error.rb +110 -0
  273. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
  274. data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
  275. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  276. data/lib/omnizip/eta/sample_history.rb +143 -0
  277. data/lib/omnizip/eta/time_estimator.rb +106 -0
  278. data/lib/omnizip/eta.rb +68 -0
  279. data/lib/omnizip/extraction/filter_chain.rb +179 -0
  280. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  281. data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
  282. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  283. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  284. data/lib/omnizip/extraction/selective_extractor.rb +247 -0
  285. data/lib/omnizip/extraction.rb +115 -0
  286. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  287. data/lib/omnizip/file_type.rb +117 -0
  288. data/lib/omnizip/filter.rb +141 -0
  289. data/lib/omnizip/filter_pipeline.rb +108 -0
  290. data/lib/omnizip/filter_registry.rb +113 -0
  291. data/lib/omnizip/filters/bcj.rb +277 -0
  292. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  293. data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
  294. data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
  295. data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
  296. data/lib/omnizip/filters/bcj2.rb +93 -0
  297. data/lib/omnizip/filters/bcj_arm.rb +174 -0
  298. data/lib/omnizip/filters/bcj_arm64.rb +242 -0
  299. data/lib/omnizip/filters/bcj_ia64.rb +194 -0
  300. data/lib/omnizip/filters/bcj_ppc.rb +188 -0
  301. data/lib/omnizip/filters/bcj_sparc.rb +174 -0
  302. data/lib/omnizip/filters/bcj_x86.rb +191 -0
  303. data/lib/omnizip/filters/delta.rb +195 -0
  304. data/lib/omnizip/filters/xz_delta.rb +258 -0
  305. data/lib/omnizip/filters.rb +20 -0
  306. data/lib/omnizip/format_detector.rb +166 -0
  307. data/lib/omnizip/formats/.keep +0 -0
  308. data/lib/omnizip/formats/bzip2_file.rb +159 -0
  309. data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
  310. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  311. data/lib/omnizip/formats/cpio/entry.rb +389 -0
  312. data/lib/omnizip/formats/cpio/reader.rb +194 -0
  313. data/lib/omnizip/formats/cpio/writer.rb +232 -0
  314. data/lib/omnizip/formats/cpio.rb +132 -0
  315. data/lib/omnizip/formats/format_spec_loader.rb +228 -0
  316. data/lib/omnizip/formats/gzip.rb +236 -0
  317. data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
  318. data/lib/omnizip/formats/iso/directory_record.rb +162 -0
  319. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  320. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  321. data/lib/omnizip/formats/iso/reader.rb +194 -0
  322. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  323. data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
  324. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  325. data/lib/omnizip/formats/iso/writer.rb +543 -0
  326. data/lib/omnizip/formats/iso.rb +133 -0
  327. data/lib/omnizip/formats/lzip.rb +161 -0
  328. data/lib/omnizip/formats/lzma_alone.rb +149 -0
  329. data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
  330. data/lib/omnizip/formats/msi/constants.rb +157 -0
  331. data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
  332. data/lib/omnizip/formats/msi/entry.rb +134 -0
  333. data/lib/omnizip/formats/msi/reader.rb +301 -0
  334. data/lib/omnizip/formats/msi/string_pool.rb +246 -0
  335. data/lib/omnizip/formats/msi/table_parser.rb +244 -0
  336. data/lib/omnizip/formats/msi.rb +73 -0
  337. data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
  338. data/lib/omnizip/formats/ole/constants.rb +61 -0
  339. data/lib/omnizip/formats/ole/dirent.rb +439 -0
  340. data/lib/omnizip/formats/ole/header.rb +199 -0
  341. data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
  342. data/lib/omnizip/formats/ole/storage.rb +482 -0
  343. data/lib/omnizip/formats/ole/types/variant.rb +338 -0
  344. data/lib/omnizip/formats/ole.rb +143 -0
  345. data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
  346. data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
  347. data/lib/omnizip/formats/rar/block_parser.rb +282 -0
  348. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  349. data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
  350. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
  351. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
  352. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  353. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  354. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  355. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  356. data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
  357. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
  358. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
  359. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
  360. data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
  361. data/lib/omnizip/formats/rar/compression.rb +17 -0
  362. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  363. data/lib/omnizip/formats/rar/constants.rb +88 -0
  364. data/lib/omnizip/formats/rar/decompressor.rb +316 -0
  365. data/lib/omnizip/formats/rar/external_writer.rb +311 -0
  366. data/lib/omnizip/formats/rar/header.rb +209 -0
  367. data/lib/omnizip/formats/rar/license_validator.rb +111 -0
  368. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  369. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  370. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  371. data/lib/omnizip/formats/rar/models.rb +14 -0
  372. data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
  373. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
  374. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
  375. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  376. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  377. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
  378. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  379. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
  380. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  381. data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
  382. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  383. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  384. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  385. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  386. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  387. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
  388. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  389. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
  390. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
  391. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
  392. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  393. data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
  394. data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
  395. data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
  396. data/lib/omnizip/formats/rar/reader.rb +377 -0
  397. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  398. data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
  399. data/lib/omnizip/formats/rar/writer.rb +437 -0
  400. data/lib/omnizip/formats/rar.rb +193 -0
  401. data/lib/omnizip/formats/rar3/compressor.rb +71 -0
  402. data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
  403. data/lib/omnizip/formats/rar3/reader.rb +107 -0
  404. data/lib/omnizip/formats/rar3/writer.rb +220 -0
  405. data/lib/omnizip/formats/rar3.rb +15 -0
  406. data/lib/omnizip/formats/rar5/compressor.rb +71 -0
  407. data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
  408. data/lib/omnizip/formats/rar5/reader.rb +130 -0
  409. data/lib/omnizip/formats/rar5/writer.rb +65 -0
  410. data/lib/omnizip/formats/rar5.rb +15 -0
  411. data/lib/omnizip/formats/rpm/constants.rb +58 -0
  412. data/lib/omnizip/formats/rpm/entry.rb +106 -0
  413. data/lib/omnizip/formats/rpm/header.rb +106 -0
  414. data/lib/omnizip/formats/rpm/lead.rb +132 -0
  415. data/lib/omnizip/formats/rpm/tag.rb +228 -0
  416. data/lib/omnizip/formats/rpm/writer.rb +652 -0
  417. data/lib/omnizip/formats/rpm.rb +458 -0
  418. data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
  419. data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
  420. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  421. data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
  422. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
  423. data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
  424. data/lib/omnizip/formats/seven_zip/header.rb +102 -0
  425. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
  426. data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
  427. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  428. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
  429. data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
  430. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  431. data/lib/omnizip/formats/seven_zip/models.rb +20 -0
  432. data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
  433. data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
  434. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
  435. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
  436. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  437. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
  438. data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
  439. data/lib/omnizip/formats/seven_zip.rb +179 -0
  440. data/lib/omnizip/formats/tar/constants.rb +73 -0
  441. data/lib/omnizip/formats/tar/entry.rb +98 -0
  442. data/lib/omnizip/formats/tar/header.rb +206 -0
  443. data/lib/omnizip/formats/tar/reader.rb +119 -0
  444. data/lib/omnizip/formats/tar/writer.rb +212 -0
  445. data/lib/omnizip/formats/tar.rb +74 -0
  446. data/lib/omnizip/formats/xar/constants.rb +119 -0
  447. data/lib/omnizip/formats/xar/entry.rb +268 -0
  448. data/lib/omnizip/formats/xar/header.rb +223 -0
  449. data/lib/omnizip/formats/xar/reader.rb +400 -0
  450. data/lib/omnizip/formats/xar/toc.rb +570 -0
  451. data/lib/omnizip/formats/xar/writer.rb +461 -0
  452. data/lib/omnizip/formats/xar.rb +145 -0
  453. data/lib/omnizip/formats/xz/reader.rb +121 -0
  454. data/lib/omnizip/formats/xz/writer.rb +416 -0
  455. data/lib/omnizip/formats/xz.rb +210 -0
  456. data/lib/omnizip/formats/xz_const.rb +49 -0
  457. data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
  458. data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
  459. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  460. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
  461. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  462. data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
  463. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
  464. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
  465. data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
  466. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
  467. data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
  468. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
  469. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  470. data/lib/omnizip/formats/xz_impl.rb +52 -0
  471. data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
  472. data/lib/omnizip/formats/zip/constants.rb +69 -0
  473. data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
  474. data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
  475. data/lib/omnizip/formats/zip/reader.rb +376 -0
  476. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  477. data/lib/omnizip/formats/zip/writer.rb +489 -0
  478. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
  479. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
  480. data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
  481. data/lib/omnizip/formats/zip.rb +50 -0
  482. data/lib/omnizip/formats.rb +29 -0
  483. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  484. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  485. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  486. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  487. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  488. data/lib/omnizip/implementations/base.rb +19 -0
  489. data/lib/omnizip/implementations/rust/archive.rb +93 -0
  490. data/lib/omnizip/implementations/rust/library.rb +221 -0
  491. data/lib/omnizip/implementations/rust.rb +26 -0
  492. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
  493. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
  494. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
  495. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
  496. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
  497. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
  498. data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
  499. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
  500. data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
  501. data/lib/omnizip/implementations/seven_zip.rb +11 -0
  502. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
  503. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
  504. data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
  505. data/lib/omnizip/implementations/xz_utils.rb +10 -0
  506. data/lib/omnizip/implementations.rb +25 -0
  507. data/lib/omnizip/io/buffered_input.rb +147 -0
  508. data/lib/omnizip/io/buffered_output.rb +106 -0
  509. data/lib/omnizip/io/source.rb +143 -0
  510. data/lib/omnizip/io/stream_manager.rb +117 -0
  511. data/lib/omnizip/io.rb +15 -0
  512. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  513. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  514. data/lib/omnizip/link_handler.rb +129 -0
  515. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  516. data/lib/omnizip/metadata/entry_metadata.rb +153 -0
  517. data/lib/omnizip/metadata/metadata_editor.rb +169 -0
  518. data/lib/omnizip/metadata/metadata_registry.rb +71 -0
  519. data/lib/omnizip/metadata/metadata_validator.rb +101 -0
  520. data/lib/omnizip/metadata.rb +58 -0
  521. data/lib/omnizip/models/.keep +0 -0
  522. data/lib/omnizip/models/algorithm_metadata.rb +41 -0
  523. data/lib/omnizip/models/attribute_apply.rb +40 -0
  524. data/lib/omnizip/models/compression_options.rb +53 -0
  525. data/lib/omnizip/models/conversion_options.rb +79 -0
  526. data/lib/omnizip/models/conversion_result.rb +141 -0
  527. data/lib/omnizip/models/eta_result.rb +45 -0
  528. data/lib/omnizip/models/extraction_rule.rb +115 -0
  529. data/lib/omnizip/models/filter_chain.rb +142 -0
  530. data/lib/omnizip/models/filter_config.rb +148 -0
  531. data/lib/omnizip/models/match_result.rb +141 -0
  532. data/lib/omnizip/models/optimization_suggestion.rb +95 -0
  533. data/lib/omnizip/models/parallel_options.rb +116 -0
  534. data/lib/omnizip/models/performance_result.rb +85 -0
  535. data/lib/omnizip/models/profile_report.rb +116 -0
  536. data/lib/omnizip/models/progress_options.rb +39 -0
  537. data/lib/omnizip/models/split_options.rb +116 -0
  538. data/lib/omnizip/optimization_registry.rb +45 -0
  539. data/lib/omnizip/parallel/engine.rb +52 -0
  540. data/lib/omnizip/parallel/job_queue.rb +209 -0
  541. data/lib/omnizip/parallel/job_scheduler.rb +225 -0
  542. data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
  543. data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
  544. data/lib/omnizip/parallel/thread_pool.rb +60 -0
  545. data/lib/omnizip/parallel/worker_pool.rb +227 -0
  546. data/lib/omnizip/parallel.rb +156 -0
  547. data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
  548. data/lib/omnizip/parity/galois16.rb +145 -0
  549. data/lib/omnizip/parity/models/creator_packet.rb +71 -0
  550. data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
  551. data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
  552. data/lib/omnizip/parity/models/main_packet.rb +126 -0
  553. data/lib/omnizip/parity/models/packet.rb +156 -0
  554. data/lib/omnizip/parity/models/packet_registry.rb +102 -0
  555. data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
  556. data/lib/omnizip/parity/models.rb +27 -0
  557. data/lib/omnizip/parity/par2_creator.rb +496 -0
  558. data/lib/omnizip/parity/par2_repairer.rb +409 -0
  559. data/lib/omnizip/parity/par2_verifier.rb +373 -0
  560. data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
  561. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  562. data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
  563. data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
  564. data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
  565. data/lib/omnizip/parity.rb +207 -0
  566. data/lib/omnizip/password/encryption_registry.rb +26 -0
  567. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  568. data/lib/omnizip/password/password_validator.rb +129 -0
  569. data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
  570. data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
  571. data/lib/omnizip/password.rb +88 -0
  572. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  573. data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
  574. data/lib/omnizip/pipe.rb +120 -0
  575. data/lib/omnizip/platform/ntfs_streams.rb +200 -0
  576. data/lib/omnizip/platform.rb +189 -0
  577. data/lib/omnizip/profile/archive_profile.rb +36 -0
  578. data/lib/omnizip/profile/balanced_profile.rb +31 -0
  579. data/lib/omnizip/profile/binary_profile.rb +33 -0
  580. data/lib/omnizip/profile/compression_profile.rb +157 -0
  581. data/lib/omnizip/profile/custom_profile.rb +155 -0
  582. data/lib/omnizip/profile/fast_profile.rb +31 -0
  583. data/lib/omnizip/profile/maximum_profile.rb +31 -0
  584. data/lib/omnizip/profile/profile_detector.rb +108 -0
  585. data/lib/omnizip/profile/profile_registry.rb +160 -0
  586. data/lib/omnizip/profile/text_profile.rb +33 -0
  587. data/lib/omnizip/profile.rb +261 -0
  588. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  589. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  590. data/lib/omnizip/profiler/report_generator.rb +158 -0
  591. data/lib/omnizip/profiler.rb +192 -0
  592. data/lib/omnizip/progress/callback_reporter.rb +34 -0
  593. data/lib/omnizip/progress/console_reporter.rb +59 -0
  594. data/lib/omnizip/progress/log_reporter.rb +89 -0
  595. data/lib/omnizip/progress/operation_progress.rb +118 -0
  596. data/lib/omnizip/progress/progress_bar.rb +156 -0
  597. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  598. data/lib/omnizip/progress/progress_tracker.rb +215 -0
  599. data/lib/omnizip/progress/silent_reporter.rb +22 -0
  600. data/lib/omnizip/progress.rb +131 -0
  601. data/lib/omnizip/registry.rb +111 -0
  602. data/lib/omnizip/rubyzip_compat.rb +61 -0
  603. data/lib/omnizip/temp/safe_extract.rb +124 -0
  604. data/lib/omnizip/temp/temp_file.rb +123 -0
  605. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  606. data/lib/omnizip/temp.rb +184 -0
  607. data/lib/omnizip/version.rb +5 -0
  608. data/lib/omnizip/zip/entry.rb +160 -0
  609. data/lib/omnizip/zip/file.rb +485 -0
  610. data/lib/omnizip/zip/input_stream.rb +270 -0
  611. data/lib/omnizip/zip/output_stream.rb +320 -0
  612. data/lib/omnizip/zip.rb +23 -0
  613. data/lib/omnizip.rb +157 -0
  614. data/lib/tasks/msi_test_files.rake +66 -0
  615. data/lib/tasks/platform_gems.rake +147 -0
  616. data/lib/tasks/rust_backend.rake +48 -0
  617. data/readme-docs/advanced-features.adoc +514 -0
  618. data/readme-docs/api-usage.adoc +445 -0
  619. data/readme-docs/architecture.adoc +450 -0
  620. data/readme-docs/archive-formats.adoc +479 -0
  621. data/readme-docs/cli-usage.adoc +222 -0
  622. data/readme-docs/compression-algorithms.adoc +446 -0
  623. data/readme-docs/compression-profiles.adoc +247 -0
  624. data/readme-docs/encryption-checksums.adoc +328 -0
  625. data/readme-docs/format-converter.adoc +316 -0
  626. data/readme-docs/installation.adoc +228 -0
  627. data/readme-docs/par2-archives.adoc +608 -0
  628. data/readme-docs/performance-profiler.adoc +389 -0
  629. data/readme-docs/preprocessing-filters.adoc +280 -0
  630. data/vendor/libomnizip_ffi.so +0 -0
  631. data/xz-file-format-1.2.1.txt +1174 -0
  632. metadata +768 -0
@@ -0,0 +1,304 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require "zlib"
5
+
6
+ module Omnizip
7
+ module Formats
8
+ module XzImpl
9
+ # XZ Block encoder
10
+ # Based on XZ Utils block_header_encoder.c
11
+ class BlockEncoder
12
+ include Omnizip::Formats::XzConst
13
+
14
+ attr_reader :uncompressed_size, :compressed_size
15
+
16
+ def initialize(check_type: CHECK_CRC64, dict_size: 8 * 1024 * 1024,
17
+ include_block_sizes: false)
18
+ @check_type = check_type
19
+ @dict_size = dict_size
20
+ @uncompressed_size = 0
21
+ @compressed_size = 0
22
+ # For simple single-block streams, omit size fields from block header
23
+ # This matches XZ Utils behavior for basic compression
24
+ # Multi-block streams should set this to true for seeking support
25
+ @include_block_sizes = include_block_sizes
26
+ end
27
+
28
+ # Encode a block with LZMA2 compression
29
+ # Returns: { header: String, data: String, padding: String, check: String, compressed_size: Integer, uncompressed_size: Integer }
30
+ def encode_block(input_data)
31
+ @uncompressed_size = input_data.bytesize
32
+
33
+ # Compress data with LZMA2
34
+ compressed_data = compress_with_lzma2(input_data)
35
+ @compressed_size = compressed_data.bytesize
36
+
37
+ # Encode block header
38
+ header = encode_block_header
39
+
40
+ # Calculate check value
41
+ check = calculate_check(input_data)
42
+
43
+ # Add padding to align block
44
+ padding = calculate_padding(header.bytesize + compressed_data.bytesize)
45
+
46
+ {
47
+ header: header,
48
+ data: compressed_data,
49
+ padding: "\x00" * padding,
50
+ check: check,
51
+ compressed_size: @compressed_size,
52
+ uncompressed_size: @uncompressed_size,
53
+ }
54
+ end
55
+
56
+ # Get unpadded block size (for index)
57
+ def unpadded_size
58
+ # Unpadded size = actual header + compressed data + check
59
+ # Note: "Unpadded" means EXCLUDING the block padding (padding after compressed data)
60
+ # but INCLUDES the check value
61
+ actual_header_size = calculate_actual_header_size
62
+ check_size = case @check_type
63
+ when CHECK_NONE then 0
64
+ when CHECK_CRC32 then 4
65
+ when CHECK_CRC64 then 8
66
+ else 8
67
+ end
68
+ actual_header_size + @compressed_size + check_size
69
+ end
70
+
71
+ private
72
+
73
+ def compress_with_lzma2(data)
74
+ # Use XZ Utils LZMA2 encoder for XZ format (proper chunk structure)
75
+ encoder = Omnizip::Implementations::XZUtils::LZMA2::Encoder.new(
76
+ dict_size: @dict_size,
77
+ lc: 3,
78
+ lp: 0,
79
+ pb: 2,
80
+ standalone: false, # XZ format (not standalone LZMA2)
81
+ )
82
+ encoder.encode(data)
83
+ end
84
+
85
+ def encode_block_header
86
+ output = StringIO.new
87
+ output.set_encoding(Encoding::BINARY)
88
+
89
+ # Build header content (without size byte and CRC32)
90
+ header_data = StringIO.new
91
+ header_data.set_encoding(Encoding::BINARY)
92
+
93
+ # Block Flags byte
94
+ flags = encode_block_flags
95
+ header_data.write([flags].pack("C"))
96
+
97
+ # Compressed Size (if present)
98
+ # XZ Utils: Only include if NOT VLI_UNKNOWN
99
+ # For simple single-block streams, we can omit this field
100
+ if @include_block_sizes
101
+ header_data.write(encode_vli(@compressed_size))
102
+ end
103
+
104
+ # Uncompressed Size (if present, MUST come before filters per XZ Utils)
105
+ # XZ Utils: Only include if NOT VLI_UNKNOWN
106
+ # For simple single-block streams, we can omit this field
107
+ if @include_block_sizes
108
+ header_data.write(encode_vli(@uncompressed_size))
109
+ end
110
+
111
+ # Filters (MUST come after Uncompressed Size per XZ Utils)
112
+ header_data.write(encode_filter_flags)
113
+
114
+ # Calculate total header size with padding
115
+ content = header_data.string
116
+
117
+ # XZ Utils block header structure: [size_byte][content][padding][CRC32]
118
+ # Total = 1 + content.bytesize + padding + 4, must be multiple of 4
119
+ # XZ Utils uses a minimum block header size and specific padding requirements
120
+ # For small inputs, XZ Utils pads more than necessary
121
+ # Round UP to next multiple of 4: ((n + 3) / 4) * 4
122
+ # Then ensure minimum size matches XZ Utils behavior (12 bytes for small headers)
123
+ content_plus_size_and_crc = 1 + content.bytesize + 4
124
+ header_size = ((content_plus_size_and_crc + 3) / 4) * 4
125
+
126
+ # For very small blocks (like single-byte inputs), XZ Utils uses extra padding
127
+ # This appears to be for compatibility or alignment reasons
128
+ # Minimum block header size is 12 bytes, and we pad to at least 12 bytes
129
+ header_size = [header_size, 12].max
130
+
131
+ # Additionally, match XZ Utils padding behavior for small blocks
132
+ # XZ Utils seems to prefer block headers that are multiples of 8 or have specific padding
133
+ # For our case (7 bytes of content), we need to reach 15 bytes of content
134
+ # to match the reference (for XZ Utils compatibility)
135
+ if @include_block_sizes && content.bytesize < 15
136
+ # For small blocks with size fields, pad to at least 15 bytes of content
137
+ # to match XZ Utils behavior (12 bytes of padding + 7 bytes of data)
138
+ needed_padding = 15 - content.bytesize
139
+ if needed_padding.positive?
140
+ content += "\x00" * needed_padding
141
+ # Recalculate header_size with new content size
142
+ content_plus_size_and_crc = 1 + content.bytesize + 4
143
+ header_size = ((content_plus_size_and_crc + 3) / 4) * 4
144
+ end
145
+ end
146
+
147
+ # Write Block Header Size (as (total / 4) - 1)
148
+ size_byte = (header_size / 4) - 1
149
+ output.write([size_byte].pack("C"))
150
+
151
+ # Write header content
152
+ output.write(content)
153
+
154
+ # Add padding (header_size already includes size_byte and will include CRC32)
155
+ padding_size = header_size - 1 - content.bytesize - 4
156
+ output.write("\x00" * padding_size) if padding_size.positive?
157
+
158
+ # Calculate CRC32 of size_byte + content + padding (NOT including CRC32 itself)
159
+ # According to XZ spec, CRC32 covers everything in Block Header except CRC32 field
160
+ # This includes the padding bytes!
161
+ crc = Zlib.crc32(output.string)
162
+
163
+ # Write CRC32
164
+ output.write([crc].pack("V"))
165
+
166
+ output.string
167
+ end
168
+
169
+ def encode_block_flags
170
+ # Bit 0-1: Number of filters - 1 (we use 1 filter = LZMA2, so 0)
171
+ # IMPORTANT: spec says filter_count = (flags & 0x03) + 1
172
+ # So for 1 filter, we set (1 - 1) = 0 in these bits
173
+ # Bit 6: Compressed Size present (optional in XZ spec)
174
+ # Bit 7: Uncompressed Size present (optional in XZ spec)
175
+ #
176
+ # XZ Utils behavior: For simple single-block streams, these fields
177
+ # are omitted to save space. They're only needed for:
178
+ # - Multi-block streams (to know where each block ends)
179
+ # - Random access (to seek to specific blocks)
180
+ # - Memory allocation planning (for multithreading)
181
+ flags = 0
182
+ flags |= 0x00 # Filter count - 1 = 0 (for 1 filter)
183
+
184
+ # Only include size fields if explicitly requested
185
+ if @include_block_sizes
186
+ flags |= 0x40 # Compressed Size present
187
+ flags |= 0x80 # Uncompressed Size present
188
+ end
189
+
190
+ flags
191
+ end
192
+
193
+ def encode_filter_flags
194
+ output = StringIO.new
195
+ output.set_encoding(Encoding::BINARY)
196
+
197
+ # Filter ID (LZMA2 = 0x21)
198
+ output.write(encode_vli(FILTER_LZMA2))
199
+
200
+ # Size of Properties (1 byte for LZMA2)
201
+ output.write(encode_vli(1))
202
+
203
+ # Properties (dictionary size encoded)
204
+ dict_byte = Algorithms::LZMA2.encode_dict_size(@dict_size)
205
+ output.write([dict_byte].pack("C"))
206
+
207
+ output.string
208
+ end
209
+
210
+ def encode_vli(value)
211
+ # Variable Length Integer encoding (1-9 bytes)
212
+ output = String.new(encoding: Encoding::BINARY)
213
+
214
+ loop do
215
+ byte = value & 0x7F
216
+ value >>= 7
217
+
218
+ if value.zero?
219
+ output << [byte].pack("C")
220
+ break
221
+ else
222
+ output << [byte | 0x80].pack("C")
223
+ end
224
+ end
225
+
226
+ output
227
+ end
228
+
229
+ def calculate_header_size
230
+ # Estimate header size (used for pre-allocation)
231
+ # Actual size calculated in encode_block_header
232
+ 32 # Conservative estimate
233
+ end
234
+
235
+ def calculate_padding(size)
236
+ # Blocks must be padded to 4-byte boundary
237
+ remainder = size % 4
238
+ remainder.zero? ? 0 : 4 - remainder
239
+ end
240
+
241
+ def calculate_check(data)
242
+ case @check_type
243
+ when CHECK_NONE
244
+ ""
245
+ when CHECK_CRC32
246
+ crc = Zlib.crc32(data)
247
+ [crc].pack("V")
248
+ when CHECK_CRC64
249
+ # Use existing CRC64 implementation
250
+ crc = Omnizip::Checksums::Crc64.calculate(data)
251
+ [crc].pack("Q<") # Little-endian 64-bit
252
+ else
253
+ raise Omnizip::FormatError, "Unsupported check type: #{@check_type}"
254
+ end
255
+ end
256
+
257
+ def calculate_actual_header_size
258
+ # Calculate the exact header size that was written
259
+ # This mirrors the logic in encode_block_header
260
+
261
+ # Build header content
262
+ header_data = StringIO.new
263
+ header_data.set_encoding(Encoding::BINARY)
264
+
265
+ # Block Flags byte
266
+ flags = encode_block_flags
267
+ header_data.write([flags].pack("C"))
268
+
269
+ # Compressed Size (if present)
270
+ if @include_block_sizes
271
+ header_data.write(encode_vli(@compressed_size))
272
+ end
273
+
274
+ # Uncompressed Size (if present, MUST come before filters per XZ Utils)
275
+ if @include_block_sizes
276
+ header_data.write(encode_vli(@uncompressed_size))
277
+ end
278
+
279
+ # Filters (MUST come after Uncompressed Size per XZ Utils)
280
+ header_data.write(encode_filter_flags)
281
+
282
+ content = header_data.string
283
+
284
+ # Calculate total header size with padding (matching encode_block_header logic)
285
+ content_plus_size_and_crc = 1 + content.bytesize + 4
286
+ header_size = ((content_plus_size_and_crc + 3) / 4) * 4
287
+ header_size = [header_size, 12].max
288
+
289
+ # Additionally, match XZ Utils padding behavior for small blocks
290
+ if @include_block_sizes && content.bytesize < 15
291
+ needed_padding = 15 - content.bytesize
292
+ if needed_padding.positive?
293
+ content += "\x00" * needed_padding
294
+ content_plus_size_and_crc = 1 + content.bytesize + 4
295
+ header_size = ((content_plus_size_and_crc + 3) / 4) * 4
296
+ end
297
+ end
298
+
299
+ header_size
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module XzImpl
6
+ # XZ block header
7
+ #
8
+ # Block header contains:
9
+ # - Header size (1 byte) - size in 4-byte blocks
10
+ # - Block flags (1 byte)
11
+ # - Compressed size (variable, optional)
12
+ # - Uncompressed size (variable, optional)
13
+ # - Filter flags (variable)
14
+ # - Padding to 4-byte boundary
15
+ # - CRC32 (4 bytes)
16
+ class BlockHeader
17
+ # Filter IDs
18
+ FILTER_LZMA2 = 0x21
19
+
20
+ attr_reader :compressed_size, :uncompressed_size, :filters
21
+
22
+ # Initialize block header
23
+ #
24
+ # @param options [Hash] Header options
25
+ def initialize(options = {})
26
+ @compressed_size = options[:compressed_size]
27
+ @uncompressed_size = options[:uncompressed_size]
28
+ @filters = options[:filters] || [{ id: FILTER_LZMA2 }]
29
+ end
30
+
31
+ # Encode block header to bytes
32
+ #
33
+ # @return [String] Encoded header
34
+ def encode
35
+ # Block flags byte
36
+ flags = 0
37
+ flags |= 0x40 if @compressed_size
38
+ flags |= 0x80 if @uncompressed_size
39
+
40
+ # Number of filters (0 = 1 filter, 3 = 4 filters)
41
+ filter_count = [@filters.size - 1, 3].min
42
+ flags |= filter_count
43
+
44
+ data = [flags].pack("C")
45
+
46
+ # Add sizes if present (encoded as multibyte integers)
47
+ if @compressed_size
48
+ data << encode_multibyte_integer(@compressed_size)
49
+ end
50
+
51
+ if @uncompressed_size
52
+ data << encode_multibyte_integer(@uncompressed_size)
53
+ end
54
+
55
+ # Add filter properties
56
+ @filters.each do |filter|
57
+ data << encode_filter(filter)
58
+ end
59
+
60
+ # Calculate header size (including size byte and CRC32)
61
+ # Round up to 4-byte blocks
62
+ header_size_bytes = 1 + data.bytesize + 4
63
+ header_size_blocks = (header_size_bytes + 3) / 4
64
+
65
+ # Add padding
66
+ padding_size = (header_size_blocks * 4) - header_size_bytes
67
+ data << ("\0" * padding_size) if padding_size.positive?
68
+
69
+ # Prepend header size
70
+ full_header = [header_size_blocks].pack("C") + data
71
+
72
+ # Append CRC32
73
+ crc32 = Zlib.crc32(full_header)
74
+ full_header + [crc32].pack("V")
75
+ end
76
+
77
+ # Decode block header from stream
78
+ #
79
+ # @param io [IO] Input stream
80
+ # @return [BlockHeader] Decoded header
81
+ def self.decode(io)
82
+ header_size_blocks = io.read(1).unpack1("C")
83
+ return nil if header_size_blocks.nil? || header_size_blocks.zero?
84
+
85
+ header_size_bytes = header_size_blocks * 4
86
+
87
+ # Read rest of header (excluding size byte and CRC32)
88
+ header_data_size = header_size_bytes - 1 - 4
89
+ header_data = io.read(header_data_size)
90
+
91
+ # Read and verify CRC32
92
+ crc32_expected = io.read(4).unpack1("V")
93
+ full_header = [header_size_blocks].pack("C") + header_data
94
+ crc32_actual = Zlib.crc32(full_header)
95
+
96
+ unless crc32_expected == crc32_actual
97
+ raise Error, "XZ block header CRC32 mismatch"
98
+ end
99
+
100
+ # Parse header data
101
+ flags = header_data.unpack1("C")
102
+ offset = 1
103
+
104
+ options = {}
105
+
106
+ # Read compressed size if present
107
+ if flags.anybits?(0x40)
108
+ options[:compressed_size], bytes_read =
109
+ decode_multibyte_integer(header_data[offset..])
110
+ offset += bytes_read
111
+ end
112
+
113
+ # Read uncompressed size if present
114
+ if flags.anybits?(0x80)
115
+ options[:uncompressed_size], bytes_read =
116
+ decode_multibyte_integer(header_data[offset..])
117
+ offset += bytes_read
118
+ end
119
+
120
+ # Parse filters
121
+ filter_count = (flags & 0x03) + 1
122
+ options[:filters] = []
123
+
124
+ filter_count.times do
125
+ filter, bytes_read = decode_filter(header_data[offset..])
126
+ options[:filters] << filter
127
+ offset += bytes_read
128
+ end
129
+
130
+ new(options)
131
+ end
132
+
133
+ private
134
+
135
+ # Encode multibyte integer (VLI - Variable Length Integer)
136
+ #
137
+ # @param value [Integer] Value to encode
138
+ # @return [String] Encoded bytes
139
+ def encode_multibyte_integer(value)
140
+ bytes = []
141
+ loop do
142
+ byte = value & 0x7F
143
+ value >>= 7
144
+ byte |= 0x80 if value.positive?
145
+ bytes << byte
146
+ break if value.zero?
147
+ end
148
+ bytes.pack("C*")
149
+ end
150
+
151
+ # Decode multibyte integer
152
+ #
153
+ # @param data [String] Data to decode
154
+ # @return [Array<Integer, Integer>] Value and bytes consumed
155
+ def self.decode_multibyte_integer(data)
156
+ value = 0
157
+ shift = 0
158
+ offset = 0
159
+
160
+ loop do
161
+ byte = data[offset].unpack1("C")
162
+ value |= (byte & 0x7F) << shift
163
+ offset += 1
164
+ break if byte.nobits?(0x80)
165
+
166
+ shift += 7
167
+ end
168
+
169
+ [value, offset]
170
+ end
171
+
172
+ # Encode filter
173
+ #
174
+ # @param filter [Hash] Filter specification
175
+ # @return [String] Encoded filter
176
+ def encode_filter(filter)
177
+ filter_id = filter[:id] || FILTER_LZMA2
178
+ props = filter[:properties] || ""
179
+
180
+ # Encode filter ID as VLI
181
+ id_bytes = encode_multibyte_integer(filter_id)
182
+
183
+ # Encode properties size as VLI
184
+ props_size_bytes = encode_multibyte_integer(props.bytesize)
185
+
186
+ id_bytes + props_size_bytes + props
187
+ end
188
+
189
+ # Decode filter
190
+ #
191
+ # @param data [String] Data to decode
192
+ # @return [Array<Hash, Integer>] Filter and bytes consumed
193
+ def self.decode_filter(data)
194
+ filter_id, offset = decode_multibyte_integer(data)
195
+
196
+ props_size, bytes_read = decode_multibyte_integer(data[offset..])
197
+ offset += bytes_read
198
+
199
+ props = data[offset, props_size]
200
+ offset += props_size
201
+
202
+ filter = { id: filter_id }
203
+ filter[:properties] = props unless props.empty?
204
+
205
+ [filter, offset]
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,182 @@
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
+ require "zlib"
25
+
26
+ module Omnizip
27
+ module Formats
28
+ module XzImpl
29
+ # XZ Block Header parser
30
+ #
31
+ # Block Header format:
32
+ # - Block Header Size: (size_in_4byte_units - 1) encoded as 1 byte
33
+ # - Block Flags: 1 byte (bit 7=uncompressed_size_present, bit 6=compressed_size_present, bits 0-1=num_filters)
34
+ # - Compressed Size: VLI (if flag bit 6 is set)
35
+ # - Uncompressed Size: VLI (if flag bit 7 is set)
36
+ # - Filters: for each filter: id(1) + props_size(1) + properties(props_size bytes)
37
+ # - Padding: 0-3 bytes to align to 4-byte boundary
38
+ # - CRC32: 4 bytes of header + padding
39
+ #
40
+ # Reference: /tmp/xz-source/src/liblzma/common/block_header_decoder.c
41
+ class BlockHeaderParser
42
+ # Filter IDs (from XZ spec)
43
+ FILTER_LZMA2 = 0x21
44
+ FILTER_DELTA = 0x03
45
+ FILTER_BCJ_X86 = 0x04
46
+ FILTER_BCJ_POWERPC = 0x05
47
+ FILTER_BCJ_IA64 = 0x06
48
+ FILTER_BCJ_ARM = 0x07
49
+ FILTER_BCJ_ARMTHUMB = 0x08
50
+ FILTER_BCJ_SPARC = 0x09
51
+
52
+ # Parse block header from input stream
53
+ #
54
+ # @param input [IO] Input stream positioned at block header start
55
+ # @return [Hash] Parsed header data with keys:
56
+ # - compressed_size: Integer or nil
57
+ # - uncompressed_size: Integer or nil
58
+ # - filters: Array of {id: Integer, properties: String or nil}
59
+ # - header_size: Integer (total header size in bytes)
60
+ # @raise [RuntimeError] If header is invalid or CRC mismatch
61
+ def self.parse(input)
62
+ # Read block header size byte
63
+ size_byte = input.getbyte
64
+ if size_byte.nil?
65
+ raise FormatError,
66
+ "Unexpected end of stream in block header"
67
+ end
68
+
69
+ # Calculate actual header size: stored as (size / 4) - 1
70
+ # So actual size = (stored + 1) * 4
71
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/api/lzma/block.h:340
72
+ # #define lzma_block_header_size_decode(b) (((uint32_t)(b) + 1) * 4)
73
+ header_size = ((size_byte + 1) * 4)
74
+
75
+ if header_size < 8 || header_size > 1024
76
+ raise FormatError, "Invalid block header size: #{header_size}"
77
+ end
78
+
79
+ # Read remaining header (minus size byte)
80
+ remaining_size = header_size - 1
81
+ header_data = input.read(remaining_size)
82
+
83
+ if header_data.nil? || header_data.bytesize < remaining_size
84
+ raise FormatError, "Unexpected end of stream in block header data"
85
+ end
86
+
87
+ # Reconstruct full header for CRC verification
88
+ full_header = [size_byte].pack("C") + header_data
89
+
90
+ # CRC32 is at the end (last 4 bytes)
91
+ crc_offset = header_size - 4
92
+ stored_crc = full_header[crc_offset..].unpack1("V")
93
+
94
+ # CRC data is: size_byte + header_fields + padding (but NOT the CRC itself)
95
+ crc_data = full_header[0..(crc_offset - 1)]
96
+ actual_crc = Zlib.crc32(crc_data)
97
+
98
+ if actual_crc != stored_crc
99
+ raise FormatError,
100
+ "Block header CRC mismatch: expected #{stored_crc}, got #{actual_crc}"
101
+ end
102
+
103
+ # Parse block header (excluding padding and CRC)
104
+ parse_buffer = StringIO.new(crc_data[1..]) # Skip size byte, parse until padding
105
+
106
+ # Parse block flags (1 byte)
107
+ block_flags = parse_buffer.getbyte
108
+ if block_flags.nil?
109
+ raise FormatError,
110
+ "Unexpected end of block header flags"
111
+ end
112
+
113
+ has_compressed_size = block_flags.anybits?(0x40)
114
+ has_uncompressed_size = block_flags.anybits?(0x80)
115
+ # Number of filters is encoded as (num_filters - 1) in bits 0-1
116
+ num_filters = (block_flags & 0x03) + 1
117
+
118
+ # Parse compressed size (VLI, if present)
119
+ compressed_size = nil
120
+ if has_compressed_size
121
+ compressed_size = VLI.decode(parse_buffer)
122
+ end
123
+
124
+ # Parse uncompressed size (VLI, if present)
125
+ uncompressed_size = nil
126
+ if has_uncompressed_size
127
+ uncompressed_size = VLI.decode(parse_buffer)
128
+ end
129
+
130
+ # Parse filters
131
+ filters = []
132
+ num_filters.times do
133
+ # Filter ID is stored as VLI (can be multi-byte for custom filters)
134
+ # But standard filters are single-byte values
135
+ # Reference: /Users/mulgogi/src/external/xz/src/liblzma/common/filter_common.c:44-52
136
+ filter_id = VLI.decode(parse_buffer)
137
+
138
+ # Validate filter ID against XZ spec
139
+ # Standard filter IDs: 0x01-0x04 are reserved for 7z compatibility (invalid for XZ)
140
+ # Valid XZ filters: 0x03 (Delta), 0x04-0x0B (BCJ filters), 0x21 (LZMA2)
141
+ # Reference: xz-file-format-1.2.1.txt Section 5.4.1
142
+ if filter_id < 0x03 || (filter_id > 0x0B && filter_id < 0x21)
143
+ raise FormatError,
144
+ "Unsupported or invalid filter ID: 0x#{filter_id.to_s(16).upcase}"
145
+ end
146
+
147
+ # Reserved custom filter range (>= 0x4000000000000000) is invalid
148
+ if filter_id >= 0x4000_0000_0000_0000
149
+ raise FormatError,
150
+ "Invalid reserved custom filter ID: 0x#{filter_id.to_s(16).upcase}"
151
+ end
152
+
153
+ props_size = parse_buffer.getbyte
154
+ if props_size.nil?
155
+ raise FormatError,
156
+ "Unexpected end of stream in filter props size"
157
+ end
158
+
159
+ properties = if props_size.positive?
160
+ props_data = parse_buffer.read(props_size)
161
+ if props_data.nil? || props_data.bytesize < props_size
162
+ raise FormatError,
163
+ "Unexpected end of stream in filter properties"
164
+ end
165
+
166
+ props_data
167
+ end
168
+
169
+ filters << { id: filter_id, properties: properties }
170
+ end
171
+
172
+ {
173
+ compressed_size: compressed_size,
174
+ uncompressed_size: uncompressed_size,
175
+ filters: filters,
176
+ header_size: header_size,
177
+ }
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end