omnizip 0.4.7-arm-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (632) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +293 -0
  5. data/CHANGELOG.md +1647 -0
  6. data/CONTEXT.md +68 -0
  7. data/COPYING +502 -0
  8. data/Gemfile +19 -0
  9. data/LICENSE +12 -0
  10. data/README.adoc +1327 -0
  11. data/Rakefile +15 -0
  12. data/TODO.refactor/00-overview.md +67 -0
  13. data/TODO.refactor/01-registry-base-class.md +81 -0
  14. data/TODO.refactor/02-error-hierarchy.md +57 -0
  15. data/TODO.refactor/03-autoload-entry-point.md +69 -0
  16. data/TODO.refactor/04-filter-base-consolidation.md +49 -0
  17. data/TODO.refactor/05-send-private-methods.md +64 -0
  18. data/TODO.refactor/06-instance-variable-access.md +69 -0
  19. data/TODO.refactor/07-respond-to-replacement.md +237 -0
  20. data/TODO.refactor/08-spec-doubles.md +27 -0
  21. data/TODO.refactor/09-cli-shared-module.md +35 -0
  22. data/TODO.refactor/10-format-detector-ocp.md +34 -0
  23. data/TODO.refactor/11-convenience-decoupling.md +38 -0
  24. data/TODO.refactor/12-thread-safety.md +8 -0
  25. data/TODO.refactor/13-lutaml-model-migration.md +158 -0
  26. data/TODO.refactor/14-add-missing-specs.md +25 -0
  27. data/benchmark/README.md +260 -0
  28. data/benchmark/benchmark_suite.rb +125 -0
  29. data/benchmark/compression_bench.rb +181 -0
  30. data/benchmark/filter_bench.rb +180 -0
  31. data/benchmark/models/benchmark_result.rb +59 -0
  32. data/benchmark/models/comparison_result.rb +69 -0
  33. data/benchmark/profile_suite.rb +167 -0
  34. data/benchmark/reporter.rb +150 -0
  35. data/benchmark/run_benchmarks.rb +66 -0
  36. data/benchmark/test_data.rb +137 -0
  37. data/config/formats/rar3_spec.yml +92 -0
  38. data/config/formats/rar5_spec.yml +102 -0
  39. data/docs/.github/workflows/docs.yml +142 -0
  40. data/docs/.gitignore +21 -0
  41. data/docs/.lychee.toml +67 -0
  42. data/docs/Gemfile +13 -0
  43. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  44. data/docs/README.md +101 -0
  45. data/docs/_config.yml +112 -0
  46. data/docs/assets/logo.svg +1 -0
  47. data/docs/assets/omnizip-logo.pdf +1540 -11
  48. data/docs/comparison/feature-matrix.adoc +694 -0
  49. data/docs/comparison/index.adoc +113 -0
  50. data/docs/comparison/vs-7zip.adoc +309 -0
  51. data/docs/comparison/vs-peazip.adoc +77 -0
  52. data/docs/comparison/vs-rubyzip.adoc +342 -0
  53. data/docs/comparison/vs-winrar.adoc +100 -0
  54. data/docs/compatibility.adoc +579 -0
  55. data/docs/concepts/index.adoc +129 -0
  56. data/docs/developer/architecture.adoc +256 -0
  57. data/docs/developer/contributing.adoc +158 -0
  58. data/docs/developer/index.adoc +25 -0
  59. data/docs/developer/testing.adoc +212 -0
  60. data/docs/getting-started/basic-usage.adoc +263 -0
  61. data/docs/getting-started/index.adoc +42 -0
  62. data/docs/getting-started/installation.adoc +138 -0
  63. data/docs/getting-started/quick-start.adoc +183 -0
  64. data/docs/getting-started/your-first-archive.adoc +219 -0
  65. data/docs/guides/advanced-features/encryption.adoc +277 -0
  66. data/docs/guides/advanced-features/index.adoc +59 -0
  67. data/docs/guides/advanced-features/parallel-processing.adoc +144 -0
  68. data/docs/guides/advanced-features/progress-tracking.adoc +124 -0
  69. data/docs/guides/advanced-features/streaming.adoc +142 -0
  70. data/docs/guides/archive-formats/gzip-format.adoc +105 -0
  71. data/docs/guides/archive-formats/index.adoc +160 -0
  72. data/docs/guides/archive-formats/ole-format.adoc +151 -0
  73. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  74. data/docs/guides/archive-formats/rar5.adoc +521 -0
  75. data/docs/guides/archive-formats/rpm-format.adoc +108 -0
  76. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  77. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  78. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  79. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  80. data/docs/guides/compression-algorithms/bzip2.adoc +114 -0
  81. data/docs/guides/compression-algorithms/deflate.adoc +313 -0
  82. data/docs/guides/compression-algorithms/index.adoc +190 -0
  83. data/docs/guides/compression-algorithms/lzma.adoc +394 -0
  84. data/docs/guides/compression-algorithms/lzma2.adoc +244 -0
  85. data/docs/guides/compression-algorithms/ppmd.adoc +313 -0
  86. data/docs/guides/compression-algorithms/zstandard.adoc +296 -0
  87. data/docs/guides/creating-archives.adoc +348 -0
  88. data/docs/guides/extracting-archives.adoc +53 -0
  89. data/docs/guides/format-conversion.adoc +64 -0
  90. data/docs/guides/index.adoc +49 -0
  91. data/docs/guides/migration-rubyzip.adoc +217 -0
  92. data/docs/guides/parity-archives.adoc +605 -0
  93. data/docs/guides/performance-tuning.adoc +88 -0
  94. data/docs/index.adoc +228 -0
  95. data/docs/lychee.toml +67 -0
  96. data/docs/reference/api/overview.adoc +187 -0
  97. data/docs/reference/cli/compress-command.adoc +114 -0
  98. data/docs/reference/cli/overview.adoc +140 -0
  99. data/docs/reference/index.adoc +26 -0
  100. data/docs/resources/faq.adoc +185 -0
  101. data/docs/resources/quick-reference.adoc +222 -0
  102. data/docs/rust-backend.md +0 -0
  103. data/docs/troubleshooting/index.adoc +207 -0
  104. data/docs/xar_format.md +216 -0
  105. data/examples/api_comparison.rb +205 -0
  106. data/examples/deflate64_example.rb +96 -0
  107. data/examples/par2_demo.rb +121 -0
  108. data/examples/quick_start_native.rb +150 -0
  109. data/examples/quick_start_rubyzip.rb +115 -0
  110. data/examples/rubyzip_compatibility_demo.rb +194 -0
  111. data/exe/omnizip +27 -0
  112. data/lib/omnizip/algorithm.rb +176 -0
  113. data/lib/omnizip/algorithm_registry.rb +65 -0
  114. data/lib/omnizip/algorithms/.keep +0 -0
  115. data/lib/omnizip/algorithms/bzip2/bwt.rb +236 -0
  116. data/lib/omnizip/algorithms/bzip2/bz2.rb +687 -0
  117. data/lib/omnizip/algorithms/bzip2/rle.rb +146 -0
  118. data/lib/omnizip/algorithms/bzip2.rb +108 -0
  119. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  120. data/lib/omnizip/algorithms/deflate/decoder.rb +37 -0
  121. data/lib/omnizip/algorithms/deflate/encoder.rb +45 -0
  122. data/lib/omnizip/algorithms/deflate.rb +135 -0
  123. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  124. data/lib/omnizip/algorithms/deflate64/decoder.rb +151 -0
  125. data/lib/omnizip/algorithms/deflate64/encoder.rb +95 -0
  126. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +352 -0
  127. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +140 -0
  128. data/lib/omnizip/algorithms/deflate64.rb +118 -0
  129. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  130. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  131. data/lib/omnizip/algorithms/lzma/decoder.rb +146 -0
  132. data/lib/omnizip/algorithms/lzma/dictionary.rb +70 -0
  133. data/lib/omnizip/algorithms/lzma/distance_coder.rb +326 -0
  134. data/lib/omnizip/algorithms/lzma/encoder.rb +139 -0
  135. data/lib/omnizip/algorithms/lzma/length_coder.rb +172 -0
  136. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +204 -0
  137. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +208 -0
  138. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +368 -0
  139. data/lib/omnizip/algorithms/lzma/lzma1_encoder.rb +105 -0
  140. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +194 -0
  141. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  142. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  143. data/lib/omnizip/algorithms/lzma/match_finder.rb +233 -0
  144. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  145. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +84 -0
  146. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +159 -0
  147. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  148. data/lib/omnizip/algorithms/lzma/range_coder.rb +82 -0
  149. data/lib/omnizip/algorithms/lzma/range_decoder.rb +274 -0
  150. data/lib/omnizip/algorithms/lzma/range_encoder.rb +202 -0
  151. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  152. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +323 -0
  153. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +420 -0
  154. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +640 -0
  155. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +224 -0
  156. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +167 -0
  157. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +258 -0
  158. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  159. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +314 -0
  160. data/lib/omnizip/algorithms/lzma/xz_state.rb +108 -0
  161. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +1311 -0
  162. data/lib/omnizip/algorithms/lzma.rb +266 -0
  163. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +180 -0
  164. data/lib/omnizip/algorithms/lzma2/constants.rb +38 -0
  165. data/lib/omnizip/algorithms/lzma2/encoder.rb +145 -0
  166. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +165 -0
  167. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  168. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +122 -0
  169. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  170. data/lib/omnizip/algorithms/lzma2.rb +133 -0
  171. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  172. data/lib/omnizip/algorithms/ppmd7/context.rb +151 -0
  173. data/lib/omnizip/algorithms/ppmd7/decoder.rb +127 -0
  174. data/lib/omnizip/algorithms/ppmd7/encoder.rb +153 -0
  175. data/lib/omnizip/algorithms/ppmd7/model.rb +245 -0
  176. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  177. data/lib/omnizip/algorithms/ppmd7.rb +146 -0
  178. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  179. data/lib/omnizip/algorithms/ppmd8/context.rb +32 -0
  180. data/lib/omnizip/algorithms/ppmd8/decoder.rb +104 -0
  181. data/lib/omnizip/algorithms/ppmd8/encoder.rb +135 -0
  182. data/lib/omnizip/algorithms/ppmd8/model.rb +246 -0
  183. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  184. data/lib/omnizip/algorithms/ppmd8.rb +122 -0
  185. data/lib/omnizip/algorithms/ppmd_base.rb +142 -0
  186. data/lib/omnizip/algorithms/registration.rb +28 -0
  187. data/lib/omnizip/algorithms/zstandard/constants.rb +158 -0
  188. data/lib/omnizip/algorithms/zstandard/decoder.rb +249 -0
  189. data/lib/omnizip/algorithms/zstandard/dictionary.rb +73 -0
  190. data/lib/omnizip/algorithms/zstandard/encoder.rb +294 -0
  191. data/lib/omnizip/algorithms/zstandard/frame/block.rb +143 -0
  192. data/lib/omnizip/algorithms/zstandard/frame/header.rb +233 -0
  193. data/lib/omnizip/algorithms/zstandard/frame.rb +33 -0
  194. data/lib/omnizip/algorithms/zstandard/fse/bitstream.rb +183 -0
  195. data/lib/omnizip/algorithms/zstandard/fse/encoder.rb +534 -0
  196. data/lib/omnizip/algorithms/zstandard/fse/interleaved.rb +92 -0
  197. data/lib/omnizip/algorithms/zstandard/fse/table.rb +188 -0
  198. data/lib/omnizip/algorithms/zstandard/fse/table_description.rb +203 -0
  199. data/lib/omnizip/algorithms/zstandard/fse.rb +53 -0
  200. data/lib/omnizip/algorithms/zstandard/huffman.rb +276 -0
  201. data/lib/omnizip/algorithms/zstandard/huffman_encoder.rb +327 -0
  202. data/lib/omnizip/algorithms/zstandard/ldm.rb +121 -0
  203. data/lib/omnizip/algorithms/zstandard/literals.rb +241 -0
  204. data/lib/omnizip/algorithms/zstandard/literals_encoder.rb +96 -0
  205. data/lib/omnizip/algorithms/zstandard/match_finder.rb +483 -0
  206. data/lib/omnizip/algorithms/zstandard/sequences.rb +350 -0
  207. data/lib/omnizip/algorithms/zstandard/sequences_encoder.rb +333 -0
  208. data/lib/omnizip/algorithms/zstandard/xxhash.rb +159 -0
  209. data/lib/omnizip/algorithms/zstandard.rb +210 -0
  210. data/lib/omnizip/algorithms.rb +35 -0
  211. data/lib/omnizip/archive/builder.rb +48 -0
  212. data/lib/omnizip/archive/reader_session.rb +67 -0
  213. data/lib/omnizip/archive.rb +86 -0
  214. data/lib/omnizip/archive_handler.rb +82 -0
  215. data/lib/omnizip/archive_handlers/cpio_handler.rb +47 -0
  216. data/lib/omnizip/archive_handlers/iso_handler.rb +54 -0
  217. data/lib/omnizip/archive_handlers/ole_handler.rb +37 -0
  218. data/lib/omnizip/archive_handlers/rar_handler.rb +96 -0
  219. data/lib/omnizip/archive_handlers/rpm_handler.rb +45 -0
  220. data/lib/omnizip/archive_handlers/seven_zip_handler.rb +89 -0
  221. data/lib/omnizip/archive_handlers/tar_handler.rb +75 -0
  222. data/lib/omnizip/archive_handlers/xar_handler.rb +49 -0
  223. data/lib/omnizip/archive_handlers/zip_handler.rb +115 -0
  224. data/lib/omnizip/archive_handlers.rb +18 -0
  225. data/lib/omnizip/backends.rb +160 -0
  226. data/lib/omnizip/buffer/memory_archive.rb +246 -0
  227. data/lib/omnizip/buffer/memory_extractor.rb +234 -0
  228. data/lib/omnizip/buffer/seven_zip_bridge.rb +171 -0
  229. data/lib/omnizip/buffer.rb +187 -0
  230. data/lib/omnizip/checksum_registry.rb +41 -0
  231. data/lib/omnizip/checksums/crc32.rb +101 -0
  232. data/lib/omnizip/checksums/crc64.rb +102 -0
  233. data/lib/omnizip/checksums/crc_base.rb +158 -0
  234. data/lib/omnizip/checksums/registration.rb +16 -0
  235. data/lib/omnizip/checksums/verifier.rb +130 -0
  236. data/lib/omnizip/checksums.rb +11 -0
  237. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  238. data/lib/omnizip/chunked/reader.rb +78 -0
  239. data/lib/omnizip/chunked/writer.rb +123 -0
  240. data/lib/omnizip/chunked.rb +123 -0
  241. data/lib/omnizip/cli/output_formatter.rb +112 -0
  242. data/lib/omnizip/cli.rb +604 -0
  243. data/lib/omnizip/commands/.keep +0 -0
  244. data/lib/omnizip/commands/archive_create_command.rb +245 -0
  245. data/lib/omnizip/commands/archive_extract_command.rb +231 -0
  246. data/lib/omnizip/commands/archive_list_command.rb +204 -0
  247. data/lib/omnizip/commands/archive_repair_command.rb +129 -0
  248. data/lib/omnizip/commands/archive_verify_command.rb +115 -0
  249. data/lib/omnizip/commands/compress_command.rb +115 -0
  250. data/lib/omnizip/commands/decompress_command.rb +149 -0
  251. data/lib/omnizip/commands/list_command.rb +51 -0
  252. data/lib/omnizip/commands/metadata_command.rb +215 -0
  253. data/lib/omnizip/commands/parity_create_command.rb +114 -0
  254. data/lib/omnizip/commands/parity_repair_command.rb +120 -0
  255. data/lib/omnizip/commands/parity_verify_command.rb +122 -0
  256. data/lib/omnizip/commands/profile_list_command.rb +54 -0
  257. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  258. data/lib/omnizip/commands.rb +21 -0
  259. data/lib/omnizip/convenience.rb +389 -0
  260. data/lib/omnizip/converter/conversion_registry.rb +50 -0
  261. data/lib/omnizip/converter/conversion_strategy.rb +108 -0
  262. data/lib/omnizip/converter/extract_repack_strategy.rb +51 -0
  263. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +43 -0
  264. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +54 -0
  265. data/lib/omnizip/converter.rb +124 -0
  266. data/lib/omnizip/crypto/aes256/cipher.rb +104 -0
  267. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  268. data/lib/omnizip/crypto/aes256/key_derivation.rb +100 -0
  269. data/lib/omnizip/crypto/aes256.rb +102 -0
  270. data/lib/omnizip/crypto.rb +11 -0
  271. data/lib/omnizip/entry.rb +44 -0
  272. data/lib/omnizip/error.rb +110 -0
  273. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +95 -0
  274. data/lib/omnizip/eta/moving_average_estimator.rb +96 -0
  275. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  276. data/lib/omnizip/eta/sample_history.rb +143 -0
  277. data/lib/omnizip/eta/time_estimator.rb +106 -0
  278. data/lib/omnizip/eta.rb +68 -0
  279. data/lib/omnizip/extraction/filter_chain.rb +179 -0
  280. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  281. data/lib/omnizip/extraction/pattern_matcher.rb +66 -0
  282. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  283. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  284. data/lib/omnizip/extraction/selective_extractor.rb +247 -0
  285. data/lib/omnizip/extraction.rb +115 -0
  286. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  287. data/lib/omnizip/file_type.rb +117 -0
  288. data/lib/omnizip/filter.rb +141 -0
  289. data/lib/omnizip/filter_pipeline.rb +108 -0
  290. data/lib/omnizip/filter_registry.rb +113 -0
  291. data/lib/omnizip/filters/bcj.rb +277 -0
  292. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  293. data/lib/omnizip/filters/bcj2/decoder.rb +263 -0
  294. data/lib/omnizip/filters/bcj2/encoder.rb +58 -0
  295. data/lib/omnizip/filters/bcj2/stream_data.rb +91 -0
  296. data/lib/omnizip/filters/bcj2.rb +93 -0
  297. data/lib/omnizip/filters/bcj_arm.rb +174 -0
  298. data/lib/omnizip/filters/bcj_arm64.rb +242 -0
  299. data/lib/omnizip/filters/bcj_ia64.rb +194 -0
  300. data/lib/omnizip/filters/bcj_ppc.rb +188 -0
  301. data/lib/omnizip/filters/bcj_sparc.rb +174 -0
  302. data/lib/omnizip/filters/bcj_x86.rb +191 -0
  303. data/lib/omnizip/filters/delta.rb +195 -0
  304. data/lib/omnizip/filters/xz_delta.rb +258 -0
  305. data/lib/omnizip/filters.rb +20 -0
  306. data/lib/omnizip/format_detector.rb +166 -0
  307. data/lib/omnizip/formats/.keep +0 -0
  308. data/lib/omnizip/formats/bzip2_file.rb +159 -0
  309. data/lib/omnizip/formats/cpio/bounded_io.rb +66 -0
  310. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  311. data/lib/omnizip/formats/cpio/entry.rb +389 -0
  312. data/lib/omnizip/formats/cpio/reader.rb +194 -0
  313. data/lib/omnizip/formats/cpio/writer.rb +232 -0
  314. data/lib/omnizip/formats/cpio.rb +132 -0
  315. data/lib/omnizip/formats/format_spec_loader.rb +228 -0
  316. data/lib/omnizip/formats/gzip.rb +236 -0
  317. data/lib/omnizip/formats/iso/directory_builder.rb +321 -0
  318. data/lib/omnizip/formats/iso/directory_record.rb +162 -0
  319. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  320. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  321. data/lib/omnizip/formats/iso/reader.rb +194 -0
  322. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  323. data/lib/omnizip/formats/iso/volume_builder.rb +319 -0
  324. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  325. data/lib/omnizip/formats/iso/writer.rb +543 -0
  326. data/lib/omnizip/formats/iso.rb +133 -0
  327. data/lib/omnizip/formats/lzip.rb +161 -0
  328. data/lib/omnizip/formats/lzma_alone.rb +149 -0
  329. data/lib/omnizip/formats/msi/cab_extractor.rb +181 -0
  330. data/lib/omnizip/formats/msi/constants.rb +157 -0
  331. data/lib/omnizip/formats/msi/directory_resolver.rb +188 -0
  332. data/lib/omnizip/formats/msi/entry.rb +134 -0
  333. data/lib/omnizip/formats/msi/reader.rb +301 -0
  334. data/lib/omnizip/formats/msi/string_pool.rb +246 -0
  335. data/lib/omnizip/formats/msi/table_parser.rb +244 -0
  336. data/lib/omnizip/formats/msi.rb +73 -0
  337. data/lib/omnizip/formats/ole/allocation_table.rb +263 -0
  338. data/lib/omnizip/formats/ole/constants.rb +61 -0
  339. data/lib/omnizip/formats/ole/dirent.rb +439 -0
  340. data/lib/omnizip/formats/ole/header.rb +199 -0
  341. data/lib/omnizip/formats/ole/ranges_io.rb +347 -0
  342. data/lib/omnizip/formats/ole/storage.rb +482 -0
  343. data/lib/omnizip/formats/ole/types/variant.rb +338 -0
  344. data/lib/omnizip/formats/ole.rb +143 -0
  345. data/lib/omnizip/formats/rar/archive_repairer.rb +240 -0
  346. data/lib/omnizip/formats/rar/archive_verifier.rb +192 -0
  347. data/lib/omnizip/formats/rar/block_parser.rb +282 -0
  348. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  349. data/lib/omnizip/formats/rar/compression/dispatcher.rb +210 -0
  350. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +212 -0
  351. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +154 -0
  352. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  353. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  354. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  355. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  356. data/lib/omnizip/formats/rar/compression/lz77_huffman.rb +25 -0
  357. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +103 -0
  358. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +238 -0
  359. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +250 -0
  360. data/lib/omnizip/formats/rar/compression/ppmd.rb +16 -0
  361. data/lib/omnizip/formats/rar/compression.rb +17 -0
  362. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  363. data/lib/omnizip/formats/rar/constants.rb +88 -0
  364. data/lib/omnizip/formats/rar/decompressor.rb +316 -0
  365. data/lib/omnizip/formats/rar/external_writer.rb +311 -0
  366. data/lib/omnizip/formats/rar/header.rb +209 -0
  367. data/lib/omnizip/formats/rar/license_validator.rb +111 -0
  368. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  369. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  370. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  371. data/lib/omnizip/formats/rar/models.rb +14 -0
  372. data/lib/omnizip/formats/rar/parity_handler.rb +299 -0
  373. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +200 -0
  374. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +584 -0
  375. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  376. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  377. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +96 -0
  378. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  379. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +162 -0
  380. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  381. data/lib/omnizip/formats/rar/rar5/header.rb +208 -0
  382. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  383. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  384. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  385. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  386. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  387. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +260 -0
  388. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  389. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +176 -0
  390. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +108 -0
  391. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +139 -0
  392. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  393. data/lib/omnizip/formats/rar/rar5/vint.rb +53 -0
  394. data/lib/omnizip/formats/rar/rar5/writer.rb +540 -0
  395. data/lib/omnizip/formats/rar/rar_format_base.rb +239 -0
  396. data/lib/omnizip/formats/rar/reader.rb +377 -0
  397. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  398. data/lib/omnizip/formats/rar/volume_manager.rb +166 -0
  399. data/lib/omnizip/formats/rar/writer.rb +437 -0
  400. data/lib/omnizip/formats/rar.rb +193 -0
  401. data/lib/omnizip/formats/rar3/compressor.rb +71 -0
  402. data/lib/omnizip/formats/rar3/decompressor.rb +64 -0
  403. data/lib/omnizip/formats/rar3/reader.rb +107 -0
  404. data/lib/omnizip/formats/rar3/writer.rb +220 -0
  405. data/lib/omnizip/formats/rar3.rb +15 -0
  406. data/lib/omnizip/formats/rar5/compressor.rb +71 -0
  407. data/lib/omnizip/formats/rar5/decompressor.rb +64 -0
  408. data/lib/omnizip/formats/rar5/reader.rb +130 -0
  409. data/lib/omnizip/formats/rar5/writer.rb +65 -0
  410. data/lib/omnizip/formats/rar5.rb +15 -0
  411. data/lib/omnizip/formats/rpm/constants.rb +58 -0
  412. data/lib/omnizip/formats/rpm/entry.rb +106 -0
  413. data/lib/omnizip/formats/rpm/header.rb +106 -0
  414. data/lib/omnizip/formats/rpm/lead.rb +132 -0
  415. data/lib/omnizip/formats/rpm/tag.rb +228 -0
  416. data/lib/omnizip/formats/rpm/writer.rb +652 -0
  417. data/lib/omnizip/formats/rpm.rb +458 -0
  418. data/lib/omnizip/formats/seven_zip/bcj2_stream_decompressor.rb +274 -0
  419. data/lib/omnizip/formats/seven_zip/coder_chain.rb +169 -0
  420. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  421. data/lib/omnizip/formats/seven_zip/encoded_header.rb +110 -0
  422. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +139 -0
  423. data/lib/omnizip/formats/seven_zip/file_collector.rb +143 -0
  424. data/lib/omnizip/formats/seven_zip/header.rb +102 -0
  425. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +132 -0
  426. data/lib/omnizip/formats/seven_zip/header_writer.rb +425 -0
  427. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  428. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +65 -0
  429. data/lib/omnizip/formats/seven_zip/models/folder.rb +67 -0
  430. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  431. data/lib/omnizip/formats/seven_zip/models.rb +20 -0
  432. data/lib/omnizip/formats/seven_zip/parser.rb +671 -0
  433. data/lib/omnizip/formats/seven_zip/reader.rb +626 -0
  434. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +611 -0
  435. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +308 -0
  436. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  437. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +166 -0
  438. data/lib/omnizip/formats/seven_zip/writer.rb +801 -0
  439. data/lib/omnizip/formats/seven_zip.rb +179 -0
  440. data/lib/omnizip/formats/tar/constants.rb +73 -0
  441. data/lib/omnizip/formats/tar/entry.rb +98 -0
  442. data/lib/omnizip/formats/tar/header.rb +206 -0
  443. data/lib/omnizip/formats/tar/reader.rb +119 -0
  444. data/lib/omnizip/formats/tar/writer.rb +212 -0
  445. data/lib/omnizip/formats/tar.rb +74 -0
  446. data/lib/omnizip/formats/xar/constants.rb +119 -0
  447. data/lib/omnizip/formats/xar/entry.rb +268 -0
  448. data/lib/omnizip/formats/xar/header.rb +223 -0
  449. data/lib/omnizip/formats/xar/reader.rb +400 -0
  450. data/lib/omnizip/formats/xar/toc.rb +570 -0
  451. data/lib/omnizip/formats/xar/writer.rb +461 -0
  452. data/lib/omnizip/formats/xar.rb +145 -0
  453. data/lib/omnizip/formats/xz/reader.rb +121 -0
  454. data/lib/omnizip/formats/xz/writer.rb +416 -0
  455. data/lib/omnizip/formats/xz.rb +210 -0
  456. data/lib/omnizip/formats/xz_const.rb +49 -0
  457. data/lib/omnizip/formats/xz_impl/block_decoder.rb +761 -0
  458. data/lib/omnizip/formats/xz_impl/block_encoder.rb +304 -0
  459. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  460. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +182 -0
  461. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  462. data/lib/omnizip/formats/xz_impl/index_encoder.rb +120 -0
  463. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +470 -0
  464. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +95 -0
  465. data/lib/omnizip/formats/xz_impl/stream_footer.rb +79 -0
  466. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +115 -0
  467. data/lib/omnizip/formats/xz_impl/stream_header.rb +53 -0
  468. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +106 -0
  469. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  470. data/lib/omnizip/formats/xz_impl.rb +52 -0
  471. data/lib/omnizip/formats/zip/central_directory_header.rb +223 -0
  472. data/lib/omnizip/formats/zip/constants.rb +69 -0
  473. data/lib/omnizip/formats/zip/end_of_central_directory.rb +132 -0
  474. data/lib/omnizip/formats/zip/local_file_header.rb +136 -0
  475. data/lib/omnizip/formats/zip/reader.rb +376 -0
  476. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  477. data/lib/omnizip/formats/zip/writer.rb +489 -0
  478. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +102 -0
  479. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +64 -0
  480. data/lib/omnizip/formats/zip/zip64_extra_field.rb +112 -0
  481. data/lib/omnizip/formats/zip.rb +50 -0
  482. data/lib/omnizip/formats.rb +29 -0
  483. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  484. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  485. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  486. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  487. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  488. data/lib/omnizip/implementations/base.rb +19 -0
  489. data/lib/omnizip/implementations/rust/archive.rb +93 -0
  490. data/lib/omnizip/implementations/rust/library.rb +221 -0
  491. data/lib/omnizip/implementations/rust.rb +26 -0
  492. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +428 -0
  493. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +456 -0
  494. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +285 -0
  495. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +197 -0
  496. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +194 -0
  497. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +139 -0
  498. data/lib/omnizip/implementations/seven_zip/lzma.rb +21 -0
  499. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +56 -0
  500. data/lib/omnizip/implementations/seven_zip/lzma2.rb +12 -0
  501. data/lib/omnizip/implementations/seven_zip.rb +11 -0
  502. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +547 -0
  503. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +748 -0
  504. data/lib/omnizip/implementations/xz_utils/lzma2.rb +13 -0
  505. data/lib/omnizip/implementations/xz_utils.rb +10 -0
  506. data/lib/omnizip/implementations.rb +25 -0
  507. data/lib/omnizip/io/buffered_input.rb +147 -0
  508. data/lib/omnizip/io/buffered_output.rb +106 -0
  509. data/lib/omnizip/io/source.rb +143 -0
  510. data/lib/omnizip/io/stream_manager.rb +117 -0
  511. data/lib/omnizip/io.rb +15 -0
  512. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  513. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  514. data/lib/omnizip/link_handler.rb +129 -0
  515. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  516. data/lib/omnizip/metadata/entry_metadata.rb +153 -0
  517. data/lib/omnizip/metadata/metadata_editor.rb +169 -0
  518. data/lib/omnizip/metadata/metadata_registry.rb +71 -0
  519. data/lib/omnizip/metadata/metadata_validator.rb +101 -0
  520. data/lib/omnizip/metadata.rb +58 -0
  521. data/lib/omnizip/models/.keep +0 -0
  522. data/lib/omnizip/models/algorithm_metadata.rb +41 -0
  523. data/lib/omnizip/models/attribute_apply.rb +40 -0
  524. data/lib/omnizip/models/compression_options.rb +53 -0
  525. data/lib/omnizip/models/conversion_options.rb +79 -0
  526. data/lib/omnizip/models/conversion_result.rb +141 -0
  527. data/lib/omnizip/models/eta_result.rb +45 -0
  528. data/lib/omnizip/models/extraction_rule.rb +115 -0
  529. data/lib/omnizip/models/filter_chain.rb +142 -0
  530. data/lib/omnizip/models/filter_config.rb +148 -0
  531. data/lib/omnizip/models/match_result.rb +141 -0
  532. data/lib/omnizip/models/optimization_suggestion.rb +95 -0
  533. data/lib/omnizip/models/parallel_options.rb +116 -0
  534. data/lib/omnizip/models/performance_result.rb +85 -0
  535. data/lib/omnizip/models/profile_report.rb +116 -0
  536. data/lib/omnizip/models/progress_options.rb +39 -0
  537. data/lib/omnizip/models/split_options.rb +116 -0
  538. data/lib/omnizip/optimization_registry.rb +45 -0
  539. data/lib/omnizip/parallel/engine.rb +52 -0
  540. data/lib/omnizip/parallel/job_queue.rb +209 -0
  541. data/lib/omnizip/parallel/job_scheduler.rb +225 -0
  542. data/lib/omnizip/parallel/parallel_compressor.rb +326 -0
  543. data/lib/omnizip/parallel/parallel_extractor.rb +238 -0
  544. data/lib/omnizip/parallel/thread_pool.rb +60 -0
  545. data/lib/omnizip/parallel/worker_pool.rb +227 -0
  546. data/lib/omnizip/parallel.rb +156 -0
  547. data/lib/omnizip/parity/chunked_block_processor.rb +194 -0
  548. data/lib/omnizip/parity/galois16.rb +145 -0
  549. data/lib/omnizip/parity/models/creator_packet.rb +71 -0
  550. data/lib/omnizip/parity/models/file_description_packet.rb +131 -0
  551. data/lib/omnizip/parity/models/ifsc_packet.rb +111 -0
  552. data/lib/omnizip/parity/models/main_packet.rb +126 -0
  553. data/lib/omnizip/parity/models/packet.rb +156 -0
  554. data/lib/omnizip/parity/models/packet_registry.rb +102 -0
  555. data/lib/omnizip/parity/models/recovery_slice_packet.rb +76 -0
  556. data/lib/omnizip/parity/models.rb +27 -0
  557. data/lib/omnizip/parity/par2_creator.rb +496 -0
  558. data/lib/omnizip/parity/par2_repairer.rb +409 -0
  559. data/lib/omnizip/parity/par2_verifier.rb +373 -0
  560. data/lib/omnizip/parity/par2cmdline_algorithm.rb +108 -0
  561. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  562. data/lib/omnizip/parity/reed_solomon_decoder.rb +263 -0
  563. data/lib/omnizip/parity/reed_solomon_encoder.rb +108 -0
  564. data/lib/omnizip/parity/reed_solomon_matrix.rb +339 -0
  565. data/lib/omnizip/parity.rb +207 -0
  566. data/lib/omnizip/password/encryption_registry.rb +26 -0
  567. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  568. data/lib/omnizip/password/password_validator.rb +129 -0
  569. data/lib/omnizip/password/winzip_aes_strategy.rb +190 -0
  570. data/lib/omnizip/password/zip_crypto_strategy.rb +135 -0
  571. data/lib/omnizip/password.rb +88 -0
  572. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  573. data/lib/omnizip/pipe/stream_decompressor.rb +173 -0
  574. data/lib/omnizip/pipe.rb +120 -0
  575. data/lib/omnizip/platform/ntfs_streams.rb +200 -0
  576. data/lib/omnizip/platform.rb +189 -0
  577. data/lib/omnizip/profile/archive_profile.rb +36 -0
  578. data/lib/omnizip/profile/balanced_profile.rb +31 -0
  579. data/lib/omnizip/profile/binary_profile.rb +33 -0
  580. data/lib/omnizip/profile/compression_profile.rb +157 -0
  581. data/lib/omnizip/profile/custom_profile.rb +155 -0
  582. data/lib/omnizip/profile/fast_profile.rb +31 -0
  583. data/lib/omnizip/profile/maximum_profile.rb +31 -0
  584. data/lib/omnizip/profile/profile_detector.rb +108 -0
  585. data/lib/omnizip/profile/profile_registry.rb +160 -0
  586. data/lib/omnizip/profile/text_profile.rb +33 -0
  587. data/lib/omnizip/profile.rb +261 -0
  588. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  589. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  590. data/lib/omnizip/profiler/report_generator.rb +158 -0
  591. data/lib/omnizip/profiler.rb +192 -0
  592. data/lib/omnizip/progress/callback_reporter.rb +34 -0
  593. data/lib/omnizip/progress/console_reporter.rb +59 -0
  594. data/lib/omnizip/progress/log_reporter.rb +89 -0
  595. data/lib/omnizip/progress/operation_progress.rb +118 -0
  596. data/lib/omnizip/progress/progress_bar.rb +156 -0
  597. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  598. data/lib/omnizip/progress/progress_tracker.rb +215 -0
  599. data/lib/omnizip/progress/silent_reporter.rb +22 -0
  600. data/lib/omnizip/progress.rb +131 -0
  601. data/lib/omnizip/registry.rb +111 -0
  602. data/lib/omnizip/rubyzip_compat.rb +61 -0
  603. data/lib/omnizip/temp/safe_extract.rb +124 -0
  604. data/lib/omnizip/temp/temp_file.rb +123 -0
  605. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  606. data/lib/omnizip/temp.rb +184 -0
  607. data/lib/omnizip/version.rb +5 -0
  608. data/lib/omnizip/zip/entry.rb +160 -0
  609. data/lib/omnizip/zip/file.rb +485 -0
  610. data/lib/omnizip/zip/input_stream.rb +270 -0
  611. data/lib/omnizip/zip/output_stream.rb +320 -0
  612. data/lib/omnizip/zip.rb +23 -0
  613. data/lib/omnizip.rb +157 -0
  614. data/lib/tasks/msi_test_files.rake +66 -0
  615. data/lib/tasks/platform_gems.rake +147 -0
  616. data/lib/tasks/rust_backend.rake +48 -0
  617. data/readme-docs/advanced-features.adoc +514 -0
  618. data/readme-docs/api-usage.adoc +445 -0
  619. data/readme-docs/architecture.adoc +450 -0
  620. data/readme-docs/archive-formats.adoc +479 -0
  621. data/readme-docs/cli-usage.adoc +222 -0
  622. data/readme-docs/compression-algorithms.adoc +446 -0
  623. data/readme-docs/compression-profiles.adoc +247 -0
  624. data/readme-docs/encryption-checksums.adoc +328 -0
  625. data/readme-docs/format-converter.adoc +316 -0
  626. data/readme-docs/installation.adoc +228 -0
  627. data/readme-docs/par2-archives.adoc +608 -0
  628. data/readme-docs/performance-profiler.adoc +389 -0
  629. data/readme-docs/preprocessing-filters.adoc +280 -0
  630. data/vendor/libomnizip_ffi.so +0 -0
  631. data/xz-file-format-1.2.1.txt +1174 -0
  632. metadata +768 -0
@@ -0,0 +1,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Xar
6
+ # XAR archive header parser and builder
7
+ #
8
+ # The XAR header is 28 bytes (or 64 bytes for extended format):
9
+ # - Bytes 0-3: Magic number (0x78617221 = "xar!")
10
+ # - Bytes 4-5: Header size (little-endian)
11
+ # - Bytes 6-7: Format version (little-endian)
12
+ # - Bytes 8-15: TOC compressed size (big-endian uint64)
13
+ # - Bytes 16-23: TOC uncompressed size (big-endian uint64)
14
+ # - Bytes 24-27: Checksum algorithm (big-endian uint32)
15
+ # - Bytes 28-63: (Optional) Checksum name for CKSUM_OTHER
16
+ class Header
17
+ include Omnizip::Formats::Xar::Constants
18
+
19
+ attr_reader :magic, :header_size, :version, :toc_compressed_size,
20
+ :toc_uncompressed_size, :checksum_algorithm,
21
+ :checksum_name
22
+
23
+ # Parse header from binary data
24
+ #
25
+ # @param data [String] Binary header data (28+ bytes)
26
+ # @return [Header] Parsed header object
27
+ # @raise [ArgumentError] If data is invalid
28
+ def self.parse(data)
29
+ if data.bytesize < HEADER_SIZE
30
+ raise ArgumentError,
31
+ "Header data too short (#{data.bytesize} bytes)"
32
+ end
33
+
34
+ magic = data[0, 4].unpack1("N")
35
+ # XAR spec: header_size and version are little-endian, rest are big-endian
36
+ # However, some tools (like macOS xar) store these in big-endian format.
37
+ # We detect this by checking if the parsed values make sense.
38
+ header_size_le = data[4, 2].unpack1("v") # little-endian
39
+ header_size_be = data[4, 2].unpack1("n") # big-endian
40
+ version_le = data[6, 2].unpack1("v") # little-endian
41
+ version_be = data[6, 2].unpack1("n") # big-endian
42
+
43
+ # Detect endianness: standard header is 28 bytes, version is 1
44
+ # If little-endian gives valid values, use it; otherwise use big-endian
45
+ if header_size_le == HEADER_SIZE && version_le == XAR_VERSION
46
+ header_size = header_size_le
47
+ version = version_le
48
+ elsif header_size_be == HEADER_SIZE && version_be == XAR_VERSION
49
+ header_size = header_size_be
50
+ version = version_be
51
+ else
52
+ # Default to little-endian (spec-compliant)
53
+ header_size = header_size_le
54
+ version = version_le
55
+ # Normalize version 256 to 1 (big-endian encoding of version 1)
56
+ version = 1 if version == 256
57
+ end
58
+ toc_compressed_size = data[8, 8].unpack1("Q>") # big-endian uint64
59
+ toc_uncompressed_size = data[16, 8].unpack1("Q>") # big-endian uint64
60
+ checksum_algorithm = data[24, 4].unpack1("N")
61
+
62
+ # Parse checksum name for custom algorithms
63
+ checksum_name = nil
64
+ if checksum_algorithm == CKSUM_OTHER && data.bytesize >= HEADER_SIZE_EX
65
+ checksum_name = data[28, 36].strip
66
+ end
67
+
68
+ new(
69
+ magic: magic,
70
+ header_size: header_size,
71
+ version: version,
72
+ toc_compressed_size: toc_compressed_size,
73
+ toc_uncompressed_size: toc_uncompressed_size,
74
+ checksum_algorithm: checksum_algorithm,
75
+ checksum_name: checksum_name,
76
+ )
77
+ end
78
+
79
+ # Read header from file
80
+ #
81
+ # @param file [IO] File handle positioned at start
82
+ # @return [Header] Parsed header
83
+ def self.read(file)
84
+ data = file.read(HEADER_SIZE_EX) # Read max possible size
85
+ raise ArgumentError, "Failed to read header" unless data
86
+
87
+ # Parse to get actual header size
88
+ header = parse(data)
89
+
90
+ # Seek back if we read too much
91
+ if data.bytesize > header.header_size
92
+ file.seek(header.header_size, ::IO::SEEK_SET)
93
+ end
94
+
95
+ header
96
+ end
97
+
98
+ # Initialize header
99
+ #
100
+ # @param magic [Integer] Magic number
101
+ # @param header_size [Integer] Header size in bytes
102
+ # @param version [Integer] Format version
103
+ # @param toc_compressed_size [Integer] Compressed TOC size
104
+ # @param toc_uncompressed_size [Integer] Uncompressed TOC size
105
+ # @param checksum_algorithm [Integer] Checksum algorithm constant
106
+ # @param checksum_name [String, nil] Checksum name for CKSUM_OTHER
107
+ def initialize(magic: MAGIC,
108
+ header_size: HEADER_SIZE,
109
+ version: XAR_VERSION,
110
+ toc_compressed_size: 0,
111
+ toc_uncompressed_size: 0,
112
+ checksum_algorithm: CKSUM_SHA1,
113
+ checksum_name: nil)
114
+ @magic = magic
115
+ @header_size = checksum_algorithm == CKSUM_OTHER && checksum_name ? HEADER_SIZE_EX : header_size
116
+ @version = version
117
+ @toc_compressed_size = toc_compressed_size
118
+ @toc_uncompressed_size = toc_uncompressed_size
119
+ @checksum_algorithm = checksum_algorithm
120
+ @checksum_name = checksum_name
121
+ end
122
+
123
+ # Validate header
124
+ #
125
+ # @return [Boolean] true if valid
126
+ # @raise [ArgumentError] If header is invalid
127
+ def validate!
128
+ unless @magic == MAGIC
129
+ raise ArgumentError,
130
+ format("Invalid magic: 0x%08x (expected 0x%08x)", @magic,
131
+ MAGIC)
132
+ end
133
+
134
+ unless @header_size >= HEADER_SIZE
135
+ raise ArgumentError, "Header size too small: #{@header_size}"
136
+ end
137
+
138
+ unless @version == XAR_VERSION
139
+ raise ArgumentError, "Unsupported version: #{@version}"
140
+ end
141
+
142
+ unless [CKSUM_NONE, CKSUM_SHA1, CKSUM_MD5,
143
+ CKSUM_OTHER].include?(@checksum_algorithm)
144
+ raise ArgumentError,
145
+ "Unknown checksum algorithm: #{@checksum_algorithm}"
146
+ end
147
+
148
+ if @checksum_algorithm == CKSUM_OTHER && @checksum_name.to_s.strip.empty?
149
+ raise ArgumentError, "Custom checksum requires checksum_name"
150
+ end
151
+
152
+ true
153
+ end
154
+
155
+ # Check if header is valid
156
+ #
157
+ # @return [Boolean] true if valid
158
+ def valid?
159
+ validate!
160
+ rescue ArgumentError
161
+ false
162
+ end
163
+
164
+ # Get checksum algorithm name
165
+ #
166
+ # @return [String] Checksum algorithm name
167
+ def checksum_algorithm_name
168
+ if @checksum_algorithm == CKSUM_OTHER
169
+ @checksum_name || "unknown"
170
+ else
171
+ CHECKSUM_NAMES[@checksum_algorithm] || "unknown"
172
+ end
173
+ end
174
+
175
+ # Get checksum size in bytes
176
+ #
177
+ # @return [Integer] Checksum size
178
+ def checksum_size
179
+ CHECKSUM_SIZES[checksum_algorithm_name] || 0
180
+ end
181
+
182
+ # Check if checksum is used
183
+ #
184
+ # @return [Boolean] true if checksum is used
185
+ def checksum?
186
+ @checksum_algorithm != CKSUM_NONE
187
+ end
188
+
189
+ # Serialize header to binary
190
+ #
191
+ # @return [String] Binary header data
192
+ def to_bytes
193
+ data = +""
194
+ data << [@magic].pack("N") # 4 bytes, big-endian
195
+ data << [@header_size].pack("v") # 2 bytes, little-endian
196
+ data << [@version].pack("v") # 2 bytes, little-endian
197
+ data << [@toc_compressed_size].pack("Q>") # 8 bytes, big-endian
198
+ data << [@toc_uncompressed_size].pack("Q>") # 8 bytes, big-endian
199
+ data << [@checksum_algorithm].pack("N") # 4 bytes, big-endian
200
+
201
+ # Add checksum name for custom algorithms
202
+ if @checksum_algorithm == CKSUM_OTHER && @checksum_name
203
+ name_bytes = @checksum_name.to_s.encode("ASCII").ljust(36, "\x00")
204
+ data << name_bytes[0, 36]
205
+ end
206
+
207
+ data
208
+ end
209
+
210
+ # Update TOC sizes
211
+ #
212
+ # @param compressed [Integer] Compressed TOC size
213
+ # @param uncompressed [Integer] Uncompressed TOC size
214
+ # @return [Header] self for chaining
215
+ def update_toc_sizes(compressed, uncompressed)
216
+ @toc_compressed_size = compressed
217
+ @toc_uncompressed_size = uncompressed
218
+ self
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,400 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zlib"
4
+ require "digest"
5
+ require "fileutils"
6
+ require "stringio"
7
+
8
+ module Omnizip
9
+ module Formats
10
+ module Xar
11
+ # XAR archive reader
12
+ #
13
+ # Provides read access to XAR archives with support for:
14
+ # - Multiple compression algorithms (gzip, bzip2, lzma, xz, none)
15
+ # - Checksum verification
16
+ # - Extended attributes
17
+ # - Hardlinks and symlinks
18
+ class Reader
19
+ include Omnizip::Formats::Xar::Constants
20
+
21
+ attr_reader :file_path, :header, :toc, :entries
22
+
23
+ # Open a XAR archive for reading
24
+ #
25
+ # @param file_path [String] Path to XAR file
26
+ # @return [Reader] Reader instance
27
+ def self.open(file_path)
28
+ reader = new(file_path)
29
+ reader.open
30
+
31
+ if block_given?
32
+ begin
33
+ yield reader
34
+ ensure
35
+ reader.close
36
+ end
37
+ else
38
+ reader
39
+ end
40
+ end
41
+
42
+ # Read and list entries from XAR archive
43
+ #
44
+ # @param file_path [String] Path to XAR file
45
+ # @return [Array<Entry>] List of entries
46
+ def self.list(file_path)
47
+ open(file_path, &:entries) # rubocop:disable Security/Open
48
+ end
49
+
50
+ # Extract XAR archive to directory
51
+ #
52
+ # @param file_path [String] Path to XAR file
53
+ # @param output_dir [String] Output directory
54
+ def self.extract(file_path, output_dir)
55
+ open(file_path) do |reader| # rubocop:disable Security/Open
56
+ reader.extract_all(output_dir)
57
+ end
58
+ end
59
+
60
+ # Initialize reader
61
+ #
62
+ # @param file_path [String] Path to XAR file
63
+ def initialize(file_path)
64
+ @file_path = file_path
65
+ @file = nil
66
+ @header = nil
67
+ @toc = nil
68
+ @entries = []
69
+ @heap_offset = 0
70
+ end
71
+
72
+ # Open and parse the archive
73
+ #
74
+ # @return [Reader] self
75
+ def open
76
+ @file = File.open(@file_path, "rb")
77
+ read_header
78
+ read_toc
79
+ self
80
+ end
81
+
82
+ # Close the archive
83
+ def close
84
+ @file&.close
85
+ @file = nil
86
+ end
87
+
88
+ # Check if archive is open
89
+ #
90
+ # @return [Boolean] true if open
91
+ def open?
92
+ !@file.nil?
93
+ end
94
+
95
+ # Get all entries
96
+ #
97
+ # @return [Array<Entry>] List of entries
98
+ def list
99
+ @entries
100
+ end
101
+
102
+ # Get entry by name
103
+ #
104
+ # @param name [String] Entry name
105
+ # @return [Entry, nil] Entry or nil if not found
106
+ def get_entry(name)
107
+ @entries.find { |e| e.name == name }
108
+ end
109
+
110
+ # Read entry data
111
+ #
112
+ # @param entry [Entry] Entry to read
113
+ # @return [String, nil] Entry data or nil if no data
114
+ def read_data(entry)
115
+ return nil unless entry.data_length&.positive?
116
+ return nil unless @file
117
+
118
+ @file.seek(@heap_offset + entry.data_offset)
119
+ # In XAR format:
120
+ # - data_length is the compressed (archived) size (what to read from heap)
121
+ # - data_size is the uncompressed (extracted) size (decompressed size)
122
+ compressed_data = @file.read(entry.data_length)
123
+
124
+ decompress_data(compressed_data, entry.data_encoding, entry.data_size)
125
+ end
126
+
127
+ # Extract all entries to directory
128
+ #
129
+ # @param output_dir [String] Output directory
130
+ def extract_all(output_dir)
131
+ FileUtils.mkdir_p(output_dir)
132
+
133
+ # Sort entries to ensure directories are created first
134
+ sorted_entries = @entries.sort_by do |e|
135
+ [e.directory? ? 0 : 1, e.name]
136
+ end
137
+
138
+ sorted_entries.each do |entry|
139
+ extract_entry(entry, output_dir)
140
+ end
141
+ end
142
+
143
+ # Extract single entry to directory
144
+ #
145
+ # @param entry [Entry] Entry to extract
146
+ # @param output_dir [String] Output directory
147
+ def extract_entry(entry, output_dir)
148
+ full_path = File.join(output_dir, entry.name)
149
+
150
+ case entry.type
151
+ when TYPE_DIRECTORY
152
+ FileUtils.mkdir_p(full_path)
153
+ when TYPE_SYMLINK
154
+ extract_symlink(entry, full_path)
155
+ when TYPE_HARDLINK
156
+ extract_hardlink(entry, full_path, output_dir)
157
+ when TYPE_FILE
158
+ extract_file(entry, full_path)
159
+ when TYPE_BLOCK, TYPE_CHAR
160
+ extract_device(entry, full_path)
161
+ when TYPE_FIFO
162
+ extract_fifo(entry, full_path)
163
+ else
164
+ # Unknown type, try to extract as file
165
+ extract_file(entry, full_path) if entry.data_size&.positive?
166
+ end
167
+
168
+ # Set file metadata
169
+ set_entry_metadata(entry, full_path)
170
+ end
171
+
172
+ # Get archive information
173
+ #
174
+ # @return [Hash] Archive info
175
+ def info
176
+ {
177
+ file_path: @file_path,
178
+ header: {
179
+ version: @header&.version,
180
+ checksum_algorithm: @header&.checksum_algorithm_name,
181
+ toc_compressed_size: @header&.toc_compressed_size,
182
+ toc_uncompressed_size: @header&.toc_uncompressed_size,
183
+ },
184
+ entry_count: @entries.size,
185
+ file_count: @entries.count(&:file?),
186
+ directory_count: @entries.count(&:directory?),
187
+ symlink_count: @entries.count(&:symlink?),
188
+ total_size: @entries.sum { |e| e.size || 0 },
189
+ }
190
+ end
191
+
192
+ private
193
+
194
+ # Read and parse header
195
+ def read_header
196
+ @header = Header.read(@file)
197
+ @header.validate!
198
+ end
199
+
200
+ # Read and parse TOC
201
+ def read_toc
202
+ # Read compressed TOC
203
+ @file.seek(@header.header_size)
204
+ compressed_toc = @file.read(@header.toc_compressed_size)
205
+
206
+ raise Omnizip::InvalidArchiveError, "Failed to read TOC" unless compressed_toc
207
+
208
+ # Parse TOC
209
+ @toc = Toc.parse(compressed_toc, @header.toc_uncompressed_size)
210
+ @entries = @toc.entries
211
+
212
+ # Calculate heap offset:
213
+ # The heap starts immediately after the compressed TOC.
214
+ # The TOC checksum is stored INSIDE the heap (at offset 0), not after it.
215
+ # File data offsets in the TOC are relative to the heap start.
216
+ @heap_offset = @header.header_size + @header.toc_compressed_size
217
+ end
218
+
219
+ # Decompress data based on encoding
220
+ #
221
+ # @param data [String] Compressed data
222
+ # @param encoding [String] Compression encoding
223
+ # @param expected_size [Integer] Expected decompressed size
224
+ # @return [String] Decompressed data
225
+ def decompress_data(data, encoding, _expected_size = nil)
226
+ case encoding
227
+ when COMPRESSION_GZIP, "application/x-gzip"
228
+ decompress_gzip(data)
229
+ when COMPRESSION_BZIP2, "application/x-bzip2"
230
+ decompress_bzip2(data)
231
+ when COMPRESSION_LZMA, "application/x-lzma"
232
+ decompress_lzma(data)
233
+ when COMPRESSION_XZ, "application/x-xz"
234
+ decompress_xz(data)
235
+ else
236
+ # No compression or unknown
237
+ data || +""
238
+ end
239
+ end
240
+
241
+ # Decompress gzip data
242
+ #
243
+ # @param data [String] Zlib compressed data (XAR uses zlib, not actual gzip)
244
+ # @return [String] Decompressed data
245
+ def decompress_gzip(data)
246
+ # XAR "gzip" compression is actually zlib format (with 0x78xx header)
247
+ # Try different decompression methods for robustness
248
+
249
+ # Method 1: Standard zlib format (with header)
250
+ begin
251
+ result = Zlib::Inflate.inflate(data)
252
+ return result
253
+ rescue Zlib::Error
254
+ # Continue to next method
255
+ end
256
+
257
+ # Method 2: Raw deflate (some implementations may use this)
258
+ begin
259
+ inf = Zlib::Inflate.new(-Zlib::MAX_WBITS)
260
+ result = inf.inflate(data)
261
+ inf.finish
262
+ inf.close
263
+ return result
264
+ rescue Zlib::Error
265
+ # Continue to next method
266
+ end
267
+
268
+ # Method 3: Raw deflate without finish (for truncated data)
269
+ begin
270
+ inf = Zlib::Inflate.new(-Zlib::MAX_WBITS)
271
+ result = inf.inflate(data)
272
+ inf.close
273
+ result
274
+ rescue Zlib::Error => e
275
+ raise Omnizip::DecompressionError, "Failed to decompress data: #{e.message}"
276
+ end
277
+ end
278
+
279
+ # Decompress bzip2 data
280
+ #
281
+ # @param data [String] Bzip2 compressed data
282
+ # @return [String] Decompressed data
283
+ def decompress_bzip2(data)
284
+ decompressor = Omnizip::Algorithms::Bzip2::Decompressor.new
285
+ decompressor.decompress(data)
286
+ end
287
+
288
+ # Decompress LZMA data
289
+ #
290
+ # @param data [String] LZMA compressed data
291
+ # @return [String] Decompressed data
292
+ def decompress_lzma(data)
293
+ decoder = Omnizip::Algorithms::Lzma::Decoder.new
294
+ decoder.decode(data)
295
+ end
296
+
297
+ # Decompress XZ data
298
+ #
299
+ # @param data [String] XZ compressed data
300
+ # @return [String] Decompressed data
301
+ def decompress_xz(data)
302
+ reader = Omnizip::Formats::Xz::StreamReader.new(StringIO.new(data))
303
+ reader.read
304
+ ensure
305
+ reader&.close
306
+ end
307
+
308
+ # Extract file
309
+ #
310
+ # @param entry [Entry] File entry
311
+ # @param path [String] Output path
312
+ def extract_file(entry, path)
313
+ FileUtils.mkdir_p(File.dirname(path))
314
+
315
+ data = read_data(entry)
316
+ return unless data
317
+
318
+ File.binwrite(path, data)
319
+ end
320
+
321
+ # Extract symlink
322
+ #
323
+ # @param entry [Entry] Symlink entry
324
+ # @param path [String] Output path
325
+ def extract_symlink(entry, path)
326
+ FileUtils.mkdir_p(File.dirname(path))
327
+
328
+ target = entry.link_target
329
+ return unless target
330
+
331
+ File.unlink(path) if File.symlink?(path)
332
+ File.symlink(target, path)
333
+ end
334
+
335
+ # Extract hardlink
336
+ #
337
+ # @param entry [Entry] Hardlink entry
338
+ # @param path [String] Output path
339
+ # @param output_dir [String] Output directory
340
+ def extract_hardlink(entry, path, output_dir)
341
+ FileUtils.mkdir_p(File.dirname(path))
342
+
343
+ target = entry.link_target
344
+ return unless target
345
+
346
+ target_path = File.join(output_dir, target)
347
+
348
+ # If target exists, create hardlink
349
+ if File.exist?(target_path)
350
+ FileUtils.rm_f(path)
351
+ File.link(target_path, path)
352
+ end
353
+ end
354
+
355
+ # Extract device node
356
+ #
357
+ # @param entry [Entry] Device entry
358
+ # @param path [String] Output path
359
+ def extract_device(entry, path)
360
+ # Creating device nodes requires root privileges
361
+ # This is a no-op on most systems
362
+ end
363
+
364
+ # Extract FIFO
365
+ #
366
+ # @param entry [Entry] FIFO entry
367
+ # @param path [String] Output path
368
+ def extract_fifo(entry, path)
369
+ # Creating FIFOs may require privileges
370
+ # This is a no-op on most systems
371
+ end
372
+
373
+ # Set entry metadata on extracted file
374
+ #
375
+ # @param entry [Entry] Entry
376
+ # @param path [String] File path
377
+ def set_entry_metadata(entry, path)
378
+ return unless File.exist?(path)
379
+
380
+ # Set mode
381
+ File.chmod(entry.mode, path) if entry.mode&.positive?
382
+
383
+ # Set timestamps
384
+ if entry.mtime
385
+ File.utime(entry.atime || entry.mtime, entry.mtime, path)
386
+ end
387
+
388
+ # Set ownership (requires privileges)
389
+ if entry.uid && entry.gid
390
+ begin
391
+ File.chown(entry.uid, entry.gid, path)
392
+ rescue Errno::EPERM
393
+ # Ignore permission errors
394
+ end
395
+ end
396
+ end
397
+ end
398
+ end
399
+ end
400
+ end