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,489 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Omnizip
6
+ module Formats
7
+ module Zip
8
+ # ZIP archive writer
9
+ class Writer
10
+ include Omnizip::Formats::Zip::Constants
11
+
12
+ attr_reader :file_path, :entries
13
+
14
+ def initialize(file_path)
15
+ @file_path = file_path
16
+ @entries = []
17
+ @local_headers = []
18
+ end
19
+
20
+ # Add a file to the archive
21
+ def add_file(file_path, archive_path = nil, preserve_links: true)
22
+ archive_path ||= File.basename(file_path)
23
+
24
+ if File.directory?(file_path)
25
+ add_directory(archive_path)
26
+ elsif preserve_links && LinkHandler.symlink?(file_path)
27
+ add_symlink(archive_path, LinkHandler.read_link_target(file_path))
28
+ elsif preserve_links && LinkHandler.hardlink?(file_path)
29
+ # For hard links, we add as regular file but track inode
30
+ data = File.binread(file_path)
31
+ add_data(archive_path, data, File.stat(file_path))
32
+ else
33
+ data = File.binread(file_path)
34
+ add_data(archive_path, data, File.stat(file_path))
35
+ end
36
+ end
37
+
38
+ # Add a symbolic link to the archive
39
+ def add_symlink(archive_path, target)
40
+ unless LinkHandler.symlink_supported?
41
+ warn "Warning: Symbolic links not supported on #{RUBY_PLATFORM}, storing as regular file"
42
+ add_data(archive_path, target)
43
+ return
44
+ end
45
+
46
+ entry = create_entry(
47
+ filename: archive_path,
48
+ uncompressed_data: target,
49
+ symlink: true,
50
+ symlink_target: target,
51
+ )
52
+
53
+ @entries << entry
54
+ end
55
+
56
+ # Add a hard link to the archive
57
+ def add_hardlink(archive_path, target_path)
58
+ unless LinkHandler.hardlink_supported?
59
+ warn "Warning: Hard links not supported on #{RUBY_PLATFORM}, storing as regular file"
60
+ # Store the target file content instead
61
+ if File.exist?(target_path)
62
+ data = File.binread(target_path)
63
+ add_data(archive_path, data, File.stat(target_path))
64
+ else
65
+ add_data(archive_path, "")
66
+ end
67
+ return
68
+ end
69
+
70
+ # For hard links, we store the first occurrence as a regular file
71
+ # and subsequent ones reference the original
72
+ entry = create_entry(
73
+ filename: archive_path,
74
+ uncompressed_data: "",
75
+ hardlink: true,
76
+ hardlink_target: target_path,
77
+ )
78
+
79
+ @entries << entry
80
+ end
81
+
82
+ # Add a directory to the archive
83
+ def add_directory(archive_path)
84
+ archive_path = "#{archive_path}/" unless archive_path.end_with?("/")
85
+
86
+ entry = create_entry(
87
+ filename: archive_path,
88
+ uncompressed_data: "",
89
+ directory: true,
90
+ )
91
+
92
+ @entries << entry
93
+ end
94
+
95
+ # Add data directly to the archive. +compression_method+
96
+ # (a ZIP method code) overrides the archive-wide default for
97
+ # this entry alone.
98
+ def add_data(archive_path, data, stat = nil, compression_method: nil)
99
+ entry = create_entry(
100
+ filename: archive_path,
101
+ uncompressed_data: data,
102
+ stat: stat,
103
+ )
104
+
105
+ entry[:compression_method] = compression_method
106
+ @entries << entry
107
+ end
108
+
109
+ # Write the archive to disk
110
+ def write(compression_method: COMPRESSION_DEFLATE, level: 6)
111
+ File.open(file_path, "wb") do |io|
112
+ write_to_io(io, compression_method: compression_method,
113
+ level: level)
114
+ end
115
+ end
116
+
117
+ # Add an entry whose payload is already compressed. Bypasses
118
+ # per-entry compression in +#write+, so +#write_precompressed+
119
+ # must be used instead of +#write+ to emit the archive.
120
+ #
121
+ # @param filename [String] Entry name in the archive
122
+ # @param uncompressed_size [Integer] Size before compression
123
+ # @param compressed_size [Integer] Size of +compressed_data+
124
+ # @param crc32 [Integer] CRC32 of the uncompressed data
125
+ # @param compressed_data [String] Pre-compressed payload
126
+ # @param stat [File::Stat, nil] Optional stat for the source file
127
+ def add_precompressed_entry(filename:, uncompressed_size:,
128
+ compressed_size:, crc32:,
129
+ compressed_data:, stat: nil)
130
+ entry = create_entry(
131
+ filename: filename,
132
+ uncompressed_data: "",
133
+ stat: stat,
134
+ )
135
+ entry[:compressed_size] = compressed_size
136
+ entry[:uncompressed_size] = uncompressed_size
137
+ entry[:crc32] = crc32
138
+ entry[:compressed_data] = compressed_data
139
+ @entries << entry
140
+ entry
141
+ end
142
+
143
+ # Write the archive using pre-compressed entry payloads (set
144
+ # via +#add_precompressed_entry+).
145
+ #
146
+ # @param compression_method [Integer] ZIP compression method
147
+ # code recorded in the headers
148
+ def write_precompressed(compression_method: COMPRESSION_DEFLATE)
149
+ File.open(file_path, "wb") do |io|
150
+ write_precompressed_to_io(io, compression_method: compression_method)
151
+ end
152
+ end
153
+
154
+ def write_precompressed_to_io(io, compression_method: COMPRESSION_DEFLATE)
155
+ check_classic_entry_count!
156
+ entries.each { |entry| check_classic_size_limit!(entry) }
157
+ local_header_offsets = []
158
+
159
+ entries.each do |entry|
160
+ offset = io.pos
161
+ local_header_offsets << offset
162
+
163
+ local_header = create_local_header(entry, compression_method)
164
+ local_header.compressed_size = entry[:compressed_size]
165
+ local_header.uncompressed_size = entry[:uncompressed_size]
166
+ local_header.crc32 = entry[:crc32]
167
+ io.write(local_header.to_binary)
168
+ io.write(entry[:compressed_data]) unless entry[:directory]
169
+ end
170
+
171
+ central_directory_offset = io.pos
172
+
173
+ entries.each_with_index do |entry, index|
174
+ central_header = create_central_header(
175
+ entry,
176
+ compression_method,
177
+ local_header_offsets[index],
178
+ )
179
+ io.write(central_header.to_binary)
180
+ end
181
+
182
+ central_directory_size = io.pos - central_directory_offset
183
+
184
+ eocd = create_eocd(
185
+ total_entries: entries.size,
186
+ central_directory_size: central_directory_size,
187
+ central_directory_offset: central_directory_offset,
188
+ )
189
+ io.write(eocd.to_binary)
190
+ end
191
+
192
+ # Write to an IO object
193
+ def write_to_io(io, compression_method: COMPRESSION_DEFLATE, level: 6)
194
+ check_classic_entry_count!
195
+ local_header_offsets = []
196
+
197
+ # Write local file headers and data. An entry-level
198
+ # :compression_method overrides the archive-wide default
199
+ # (used by the buffer layer's per-entry :store option).
200
+ entries.each do |entry|
201
+ offset = io.pos
202
+ local_header_offsets << offset
203
+
204
+ entry_method = entry[:compression_method] || compression_method
205
+
206
+ # Create local file header
207
+ local_header = create_local_header(entry, entry_method)
208
+
209
+ # Compress data if not a directory
210
+ if entry[:directory]
211
+ compressed_data = ""
212
+ entry[:compressed_size] = 0
213
+ entry[:uncompressed_size] = 0
214
+ entry[:crc32] = 0
215
+ else
216
+ compressed_data = compress_data(
217
+ entry[:uncompressed_data],
218
+ entry_method,
219
+ level,
220
+ )
221
+ entry[:compressed_size] = compressed_data.bytesize
222
+ entry[:uncompressed_size] = entry[:uncompressed_data].bytesize
223
+ entry[:crc32] = calculate_crc32(entry[:uncompressed_data])
224
+ end
225
+
226
+ check_classic_size_limit!(entry)
227
+
228
+ # Update local header with compressed sizes
229
+ local_header.compressed_size = entry[:compressed_size]
230
+ local_header.uncompressed_size = entry[:uncompressed_size]
231
+ local_header.crc32 = entry[:crc32]
232
+
233
+ # Write local header
234
+ io.write(local_header.to_binary)
235
+
236
+ # Write compressed data
237
+ io.write(compressed_data) unless entry[:directory]
238
+ end
239
+
240
+ # Record start of central directory
241
+ central_directory_offset = io.pos
242
+ check_classic_offset_limit!(central_directory_offset)
243
+
244
+ # Write central directory headers
245
+ entries.each_with_index do |entry, index|
246
+ central_header = create_central_header(
247
+ entry,
248
+ entry[:compression_method] || compression_method,
249
+ local_header_offsets[index],
250
+ )
251
+ io.write(central_header.to_binary)
252
+ end
253
+
254
+ # Calculate central directory size
255
+ central_directory_size = io.pos - central_directory_offset
256
+
257
+ # Write end of central directory record
258
+ eocd = create_eocd(
259
+ total_entries: entries.size,
260
+ central_directory_size: central_directory_size,
261
+ central_directory_offset: central_directory_offset,
262
+ )
263
+ io.write(eocd.to_binary)
264
+ end
265
+
266
+ # Classic (non-ZIP64) ZIP headers pack sizes and offsets as
267
+ # 32-bit values and entry counts as 16-bit; exceeding them
268
+ # raises instead of letting Array#pack fail with a bare
269
+ # RangeError. ZIP64 writing is not supported.
270
+ MAX_CLASSIC_SIZE = 0xFFFFFFFF
271
+ MAX_CLASSIC_ENTRIES = 0xFFFF
272
+ private_constant :MAX_CLASSIC_SIZE, :MAX_CLASSIC_ENTRIES
273
+
274
+ private
275
+
276
+ def check_classic_entry_count!
277
+ return if entries.size <= MAX_CLASSIC_ENTRIES
278
+
279
+ raise Omnizip::UnsupportedFormatError,
280
+ "#{entries.size} entries exceed the classic ZIP " \
281
+ "limit of #{MAX_CLASSIC_ENTRIES} (ZIP64 writing is " \
282
+ "not supported)"
283
+ end
284
+
285
+ def check_classic_size_limit!(entry)
286
+ return if entry[:compressed_size].to_i <= MAX_CLASSIC_SIZE &&
287
+ entry[:uncompressed_size].to_i <= MAX_CLASSIC_SIZE
288
+
289
+ raise Omnizip::UnsupportedFormatError,
290
+ "entry #{entry[:filename].inspect} exceeds the 4 GiB " \
291
+ "classic ZIP size limit (ZIP64 writing is not supported)"
292
+ end
293
+
294
+ def check_classic_offset_limit!(offset)
295
+ return if offset <= MAX_CLASSIC_SIZE
296
+
297
+ raise Omnizip::UnsupportedFormatError,
298
+ "archive layout exceeds the 4 GiB classic ZIP " \
299
+ "offset limit (ZIP64 writing is not supported)"
300
+ end
301
+
302
+ # Create an entry hash
303
+ def create_entry(
304
+ filename:,
305
+ uncompressed_data:,
306
+ directory: false,
307
+ stat: nil,
308
+ symlink: false,
309
+ symlink_target: nil,
310
+ hardlink: false,
311
+ hardlink_target: nil
312
+ )
313
+ now = Time.now
314
+
315
+ {
316
+ filename: filename,
317
+ uncompressed_data: uncompressed_data,
318
+ directory: directory,
319
+ stat: stat,
320
+ mtime: now,
321
+ compressed_size: 0,
322
+ uncompressed_size: uncompressed_data.bytesize,
323
+ crc32: 0,
324
+ symlink: symlink,
325
+ symlink_target: symlink_target,
326
+ hardlink: hardlink,
327
+ hardlink_target: hardlink_target,
328
+ }
329
+ end
330
+
331
+ # Create local file header from entry
332
+ def create_local_header(entry, compression_method)
333
+ mtime = entry[:mtime]
334
+
335
+ LocalFileHeader.new(
336
+ version_needed: version_for_method(compression_method),
337
+ flags: FLAG_UTF8,
338
+ compression_method: entry[:directory] ? COMPRESSION_STORE : compression_method,
339
+ last_mod_time: dos_time(mtime),
340
+ last_mod_date: dos_date(mtime),
341
+ crc32: 0, # Will be updated after compression
342
+ compressed_size: 0, # Will be updated after compression
343
+ uncompressed_size: 0, # Will be updated after compression
344
+ filename: entry[:filename],
345
+ )
346
+ end
347
+
348
+ # Create central directory header from entry
349
+ def create_central_header(entry, compression_method,
350
+ local_header_offset)
351
+ mtime = entry[:mtime]
352
+
353
+ # Build extra field for links
354
+ extra_field = ""
355
+ if entry[:symlink] && entry[:symlink_target]
356
+ unix_field = UnixExtraField.for_symlink(entry[:symlink_target])
357
+ extra_field = unix_field.to_binary
358
+ elsif entry[:hardlink] && entry[:hardlink_target]
359
+ unix_field = UnixExtraField.for_hardlink
360
+ extra_field = unix_field.to_binary
361
+ end
362
+
363
+ external_attrs = if entry[:directory]
364
+ UNIX_DIR_PERMISSIONS | ATTR_DIRECTORY
365
+ elsif entry[:symlink]
366
+ UNIX_SYMLINK_PERMISSIONS
367
+ elsif entry[:stat]
368
+ (entry[:stat].mode & 0o777) << 16
369
+ else
370
+ UNIX_FILE_PERMISSIONS
371
+ end
372
+
373
+ CentralDirectoryHeader.new(
374
+ version_made_by: VERSION_MADE_BY_UNIX | version_for_method(compression_method),
375
+ version_needed: version_for_method(compression_method),
376
+ flags: FLAG_UTF8,
377
+ compression_method: entry[:directory] ? COMPRESSION_STORE : compression_method,
378
+ last_mod_time: dos_time(mtime),
379
+ last_mod_date: dos_date(mtime),
380
+ crc32: entry[:crc32],
381
+ compressed_size: entry[:compressed_size],
382
+ uncompressed_size: entry[:uncompressed_size],
383
+ disk_number_start: 0,
384
+ internal_attributes: 0,
385
+ external_attributes: external_attrs,
386
+ local_header_offset: local_header_offset,
387
+ filename: entry[:filename],
388
+ extra_field: extra_field,
389
+ )
390
+ end
391
+
392
+ # Create end of central directory record
393
+ def create_eocd(total_entries:, central_directory_size:,
394
+ central_directory_offset:)
395
+ EndOfCentralDirectory.new(
396
+ disk_number: 0,
397
+ disk_number_with_cd: 0,
398
+ total_entries_this_disk: total_entries,
399
+ total_entries: total_entries,
400
+ central_directory_size: central_directory_size,
401
+ central_directory_offset: central_directory_offset,
402
+ )
403
+ end
404
+
405
+ # Compress data based on compression method
406
+ def compress_data(data, method, level)
407
+ case method
408
+ when COMPRESSION_STORE
409
+ data
410
+ when COMPRESSION_DEFLATE
411
+ compress_deflate(data, level)
412
+ when COMPRESSION_BZIP2
413
+ compress_bzip2(data, level)
414
+ when COMPRESSION_LZMA
415
+ compress_lzma(data, level)
416
+ when COMPRESSION_ZSTANDARD
417
+ compress_zstandard(data, level)
418
+ else
419
+ raise Omnizip::UnsupportedFormatError,
420
+ "Unsupported compression method: #{method}"
421
+ end
422
+ end
423
+
424
+ # Compress using Deflate
425
+ def compress_deflate(data, level)
426
+ require "zlib"
427
+ # ZIP uses raw deflate without zlib wrapper
428
+ Zlib::Deflate.new(level, -Zlib::MAX_WBITS).deflate(data, Zlib::FINISH)
429
+ rescue StandardError => e
430
+ raise Omnizip::CompressionError,
431
+ "Deflate compression failed: #{e.message}"
432
+ end
433
+
434
+ # Compress using BZip2
435
+ def compress_bzip2(data, level)
436
+ algorithm = AlgorithmRegistry.get(:bzip2)
437
+ algorithm.compress(data, level: level)
438
+ rescue StandardError => e
439
+ raise Omnizip::CompressionError,
440
+ "BZip2 compression failed: #{e.message}"
441
+ end
442
+
443
+ # Compress using LZMA
444
+ def compress_lzma(data, level)
445
+ algorithm = AlgorithmRegistry.get(:lzma)
446
+ algorithm.compress(data, level: level)
447
+ rescue StandardError => e
448
+ raise Omnizip::CompressionError,
449
+ "LZMA compression failed: #{e.message}"
450
+ end
451
+
452
+ # Compress using Zstandard
453
+ def compress_zstandard(data, level)
454
+ algorithm = AlgorithmRegistry.get(:zstandard)
455
+ algorithm.compress(data, level: level)
456
+ rescue StandardError => e
457
+ raise Omnizip::CompressionError,
458
+ "Zstandard compression failed: #{e.message}"
459
+ end
460
+
461
+ # Calculate CRC32 checksum
462
+ def calculate_crc32(data)
463
+ Omnizip::Checksums::Crc32.new.tap { |c| c.update(data) }.finalize
464
+ end
465
+
466
+ # Get version needed for compression method
467
+ def version_for_method(method)
468
+ case method
469
+ when COMPRESSION_STORE then VERSION_DEFAULT
470
+ when COMPRESSION_DEFLATE then VERSION_DEFLATE
471
+ when COMPRESSION_BZIP2 then VERSION_BZIP2
472
+ when COMPRESSION_LZMA then VERSION_LZMA
473
+ else VERSION_DEFAULT
474
+ end
475
+ end
476
+
477
+ # Convert Time to DOS time format
478
+ def dos_time(time)
479
+ ((time.hour << 11) | (time.min << 5) | (time.sec / 2)) & 0xFFFF
480
+ end
481
+
482
+ # Convert Time to DOS date format
483
+ def dos_date(time)
484
+ (((time.year - 1980) << 9) | (time.month << 5) | time.day) & 0xFFFF
485
+ end
486
+ end
487
+ end
488
+ end
489
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Zip
6
+ # ZIP64 End of Central Directory Record
7
+ # Used when the archive exceeds ZIP format limits (>4GB or >65535 entries)
8
+ class Zip64EndOfCentralDirectory
9
+ include Omnizip::Formats::Zip::Constants
10
+
11
+ attr_accessor :signature, :record_size, :version_made_by, :version_needed,
12
+ :disk_number, :disk_number_with_cd,
13
+ :total_entries_this_disk, :total_entries,
14
+ :central_directory_size, :central_directory_offset,
15
+ :extensible_data_sector
16
+
17
+ def initialize(
18
+ signature: ZIP64_END_OF_CENTRAL_DIRECTORY_SIGNATURE,
19
+ record_size: 44, # Size of remaining record (not including signature and size field)
20
+ version_made_by: VERSION_MADE_BY_UNIX | VERSION_ZIP64,
21
+ version_needed: VERSION_ZIP64,
22
+ disk_number: 0,
23
+ disk_number_with_cd: 0,
24
+ total_entries_this_disk: 0,
25
+ total_entries: 0,
26
+ central_directory_size: 0,
27
+ central_directory_offset: 0,
28
+ extensible_data_sector: ""
29
+ )
30
+ @signature = signature
31
+ @record_size = record_size
32
+ @version_made_by = version_made_by
33
+ @version_needed = version_needed
34
+ @disk_number = disk_number
35
+ @disk_number_with_cd = disk_number_with_cd
36
+ @total_entries_this_disk = total_entries_this_disk
37
+ @total_entries = total_entries
38
+ @central_directory_size = central_directory_size
39
+ @central_directory_offset = central_directory_offset
40
+ @extensible_data_sector = extensible_data_sector
41
+ end
42
+
43
+ # Serialize to binary format
44
+ def to_binary
45
+ @record_size = 44 + extensible_data_sector.bytesize
46
+
47
+ [
48
+ signature,
49
+ record_size,
50
+ version_made_by,
51
+ version_needed,
52
+ disk_number,
53
+ disk_number_with_cd,
54
+ total_entries_this_disk,
55
+ total_entries,
56
+ central_directory_size,
57
+ central_directory_offset,
58
+ ].pack("VQvvVVQQQQ") + extensible_data_sector.b
59
+ end
60
+
61
+ # Parse from binary data
62
+ def self.from_binary(data)
63
+ signature, record_size, version_made_by, version_needed,
64
+ disk_number, disk_number_with_cd,
65
+ total_entries_this_disk, total_entries,
66
+ central_directory_size, central_directory_offset = data.unpack("VQvvVVQQQQ")
67
+
68
+ unless signature == ZIP64_END_OF_CENTRAL_DIRECTORY_SIGNATURE
69
+ raise Omnizip::FormatError,
70
+ "Invalid ZIP64 EOCD signature"
71
+ end
72
+
73
+ # Extensible data sector starts after the fixed 56 bytes (4+8+2+2+4+4+8+8+8+8)
74
+ extensible_data_sector = if data.bytesize > 56
75
+ data[56..]
76
+ else
77
+ ""
78
+ end
79
+
80
+ new(
81
+ signature: signature,
82
+ record_size: record_size,
83
+ version_made_by: version_made_by,
84
+ version_needed: version_needed,
85
+ disk_number: disk_number,
86
+ disk_number_with_cd: disk_number_with_cd,
87
+ total_entries_this_disk: total_entries_this_disk,
88
+ total_entries: total_entries,
89
+ central_directory_size: central_directory_size,
90
+ central_directory_offset: central_directory_offset,
91
+ extensible_data_sector: extensible_data_sector,
92
+ )
93
+ end
94
+
95
+ # Total size of this record in bytes
96
+ def total_size
97
+ 12 + record_size # 4 (signature) + 8 (record_size) + record_size
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Zip
6
+ # ZIP64 End of Central Directory Locator
7
+ # Points to the ZIP64 End of Central Directory Record
8
+ class Zip64EndOfCentralDirectoryLocator
9
+ include Omnizip::Formats::Zip::Constants
10
+
11
+ attr_accessor :signature, :disk_number_with_zip64_eocd,
12
+ :zip64_eocd_offset, :total_disks
13
+
14
+ def initialize(
15
+ signature: ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE,
16
+ disk_number_with_zip64_eocd: 0,
17
+ zip64_eocd_offset: 0,
18
+ total_disks: 1
19
+ )
20
+ @signature = signature
21
+ @disk_number_with_zip64_eocd = disk_number_with_zip64_eocd
22
+ @zip64_eocd_offset = zip64_eocd_offset
23
+ @total_disks = total_disks
24
+ end
25
+
26
+ # Serialize to binary format
27
+ def to_binary
28
+ [
29
+ signature,
30
+ disk_number_with_zip64_eocd,
31
+ zip64_eocd_offset,
32
+ total_disks,
33
+ ].pack("VVQV")
34
+ end
35
+
36
+ # Parse from binary data
37
+ def self.from_binary(data)
38
+ signature, disk_number, offset, total_disks = data.unpack("VVQV")
39
+
40
+ unless signature == ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE
41
+ raise Omnizip::FormatError,
42
+ "Invalid ZIP64 EOCD Locator signature"
43
+ end
44
+
45
+ new(
46
+ signature: signature,
47
+ disk_number_with_zip64_eocd: disk_number,
48
+ zip64_eocd_offset: offset,
49
+ total_disks: total_disks,
50
+ )
51
+ end
52
+
53
+ # Size of this record in bytes (always 20 bytes)
54
+ def self.record_size
55
+ 20
56
+ end
57
+
58
+ def record_size
59
+ self.class.record_size
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end