omnizip 0.3.1

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 (511) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +32 -0
  4. data/.rubocop_todo.yml +754 -0
  5. data/COPYING +502 -0
  6. data/Gemfile +17 -0
  7. data/LICENSE +12 -0
  8. data/README.adoc +1045 -0
  9. data/Rakefile +12 -0
  10. data/benchmark/README.md +260 -0
  11. data/benchmark/benchmark_suite.rb +125 -0
  12. data/benchmark/compression_bench.rb +181 -0
  13. data/benchmark/filter_bench.rb +180 -0
  14. data/benchmark/models/benchmark_result.rb +59 -0
  15. data/benchmark/models/comparison_result.rb +69 -0
  16. data/benchmark/profile_suite.rb +167 -0
  17. data/benchmark/reporter.rb +150 -0
  18. data/benchmark/run_benchmarks.rb +66 -0
  19. data/benchmark/test_data.rb +137 -0
  20. data/config/formats/rar3_spec.yml +91 -0
  21. data/config/formats/rar5_spec.yml +102 -0
  22. data/docs/.github/workflows/docs.yml +142 -0
  23. data/docs/.gitignore +21 -0
  24. data/docs/.lychee.toml +67 -0
  25. data/docs/Gemfile +13 -0
  26. data/docs/RAR_WRITE_SUPPORT.md +26 -0
  27. data/docs/README.md +101 -0
  28. data/docs/_config.yml +112 -0
  29. data/docs/assets/logo.svg +1 -0
  30. data/docs/assets/omnizip-logo.pdf +1540 -11
  31. data/docs/comparison/feature-matrix.adoc +694 -0
  32. data/docs/comparison/index.adoc +113 -0
  33. data/docs/comparison/vs-7zip.adoc +309 -0
  34. data/docs/comparison/vs-peazip.adoc +77 -0
  35. data/docs/comparison/vs-rubyzip.adoc +342 -0
  36. data/docs/comparison/vs-winrar.adoc +100 -0
  37. data/docs/compatibility.adoc +579 -0
  38. data/docs/concepts/index.adoc +129 -0
  39. data/docs/developer/architecture.adoc +256 -0
  40. data/docs/developer/contributing.adoc +158 -0
  41. data/docs/developer/index.adoc +25 -0
  42. data/docs/developer/testing.adoc +212 -0
  43. data/docs/getting-started/basic-usage.adoc +271 -0
  44. data/docs/getting-started/index.adoc +42 -0
  45. data/docs/getting-started/installation.adoc +138 -0
  46. data/docs/getting-started/quick-start.adoc +185 -0
  47. data/docs/getting-started/your-first-archive.adoc +218 -0
  48. data/docs/guides/advanced-features/encryption.adoc +300 -0
  49. data/docs/guides/advanced-features/index.adoc +49 -0
  50. data/docs/guides/advanced-features/parallel-processing.adoc +246 -0
  51. data/docs/guides/advanced-features/progress-tracking.adoc +320 -0
  52. data/docs/guides/advanced-features/streaming.adoc +212 -0
  53. data/docs/guides/archive-formats/gzip-format.adoc +107 -0
  54. data/docs/guides/archive-formats/index.adoc +130 -0
  55. data/docs/guides/archive-formats/rar-format.adoc +104 -0
  56. data/docs/guides/archive-formats/rar5.adoc +521 -0
  57. data/docs/guides/archive-formats/seven-zip-format.adoc +35 -0
  58. data/docs/guides/archive-formats/tar-format.adoc +106 -0
  59. data/docs/guides/archive-formats/xz-format.adoc +118 -0
  60. data/docs/guides/archive-formats/zip-format.adoc +35 -0
  61. data/docs/guides/compression-algorithms/bzip2.adoc +113 -0
  62. data/docs/guides/compression-algorithms/deflate.adoc +319 -0
  63. data/docs/guides/compression-algorithms/index.adoc +190 -0
  64. data/docs/guides/compression-algorithms/lzma.adoc +398 -0
  65. data/docs/guides/compression-algorithms/lzma2.adoc +327 -0
  66. data/docs/guides/compression-algorithms/ppmd.adoc +316 -0
  67. data/docs/guides/compression-algorithms/zstandard.adoc +361 -0
  68. data/docs/guides/creating-archives.adoc +354 -0
  69. data/docs/guides/extracting-archives.adoc +53 -0
  70. data/docs/guides/format-conversion.adoc +64 -0
  71. data/docs/guides/index.adoc +49 -0
  72. data/docs/guides/migration-rubyzip.adoc +217 -0
  73. data/docs/guides/parity-archives.adoc +605 -0
  74. data/docs/guides/performance-tuning.adoc +88 -0
  75. data/docs/index.adoc +218 -0
  76. data/docs/lychee.toml +67 -0
  77. data/docs/reference/api/overview.adoc +188 -0
  78. data/docs/reference/cli/compress-command.adoc +114 -0
  79. data/docs/reference/cli/overview.adoc +140 -0
  80. data/docs/reference/index.adoc +26 -0
  81. data/docs/resources/faq.adoc +185 -0
  82. data/docs/resources/quick-reference.adoc +222 -0
  83. data/docs/troubleshooting/index.adoc +208 -0
  84. data/examples/api_comparison.rb +205 -0
  85. data/examples/deflate64_example.rb +96 -0
  86. data/examples/par2_demo.rb +121 -0
  87. data/examples/quick_start_native.rb +150 -0
  88. data/examples/quick_start_rubyzip.rb +115 -0
  89. data/examples/rubyzip_compatibility_demo.rb +194 -0
  90. data/exe/omnizip +27 -0
  91. data/lib/omnizip/algorithm.rb +130 -0
  92. data/lib/omnizip/algorithm_registry.rb +86 -0
  93. data/lib/omnizip/algorithms/.keep +0 -0
  94. data/lib/omnizip/algorithms/bzip2/bwt.rb +225 -0
  95. data/lib/omnizip/algorithms/bzip2/decoder.rb +193 -0
  96. data/lib/omnizip/algorithms/bzip2/encoder.rb +237 -0
  97. data/lib/omnizip/algorithms/bzip2/huffman.rb +206 -0
  98. data/lib/omnizip/algorithms/bzip2/mtf.rb +101 -0
  99. data/lib/omnizip/algorithms/bzip2/rle.rb +151 -0
  100. data/lib/omnizip/algorithms/bzip2.rb +130 -0
  101. data/lib/omnizip/algorithms/deflate/constants.rb +28 -0
  102. data/lib/omnizip/algorithms/deflate/decoder.rb +38 -0
  103. data/lib/omnizip/algorithms/deflate/encoder.rb +46 -0
  104. data/lib/omnizip/algorithms/deflate.rb +128 -0
  105. data/lib/omnizip/algorithms/deflate64/constants.rb +45 -0
  106. data/lib/omnizip/algorithms/deflate64/decoder.rb +153 -0
  107. data/lib/omnizip/algorithms/deflate64/encoder.rb +98 -0
  108. data/lib/omnizip/algorithms/deflate64/huffman_coder.rb +354 -0
  109. data/lib/omnizip/algorithms/deflate64/lz77_encoder.rb +142 -0
  110. data/lib/omnizip/algorithms/deflate64.rb +109 -0
  111. data/lib/omnizip/algorithms/lzma/bit_model.rb +120 -0
  112. data/lib/omnizip/algorithms/lzma/constants.rb +112 -0
  113. data/lib/omnizip/algorithms/lzma/decoder.rb +148 -0
  114. data/lib/omnizip/algorithms/lzma/dictionary.rb +69 -0
  115. data/lib/omnizip/algorithms/lzma/distance_coder.rb +415 -0
  116. data/lib/omnizip/algorithms/lzma/encoder.rb +142 -0
  117. data/lib/omnizip/algorithms/lzma/length_coder.rb +260 -0
  118. data/lib/omnizip/algorithms/lzma/literal_decoder.rb +320 -0
  119. data/lib/omnizip/algorithms/lzma/literal_encoder.rb +210 -0
  120. data/lib/omnizip/algorithms/lzma/lzip_decoder.rb +341 -0
  121. data/lib/omnizip/algorithms/lzma/lzma_alone_decoder.rb +192 -0
  122. data/lib/omnizip/algorithms/lzma/lzma_state.rb +128 -0
  123. data/lib/omnizip/algorithms/lzma/match.rb +32 -0
  124. data/lib/omnizip/algorithms/lzma/match_finder.rb +205 -0
  125. data/lib/omnizip/algorithms/lzma/match_finder_config.rb +142 -0
  126. data/lib/omnizip/algorithms/lzma/match_finder_factory.rb +88 -0
  127. data/lib/omnizip/algorithms/lzma/optimal_encoder.rb +130 -0
  128. data/lib/omnizip/algorithms/lzma/probability_models.rb +72 -0
  129. data/lib/omnizip/algorithms/lzma/range_coder.rb +85 -0
  130. data/lib/omnizip/algorithms/lzma/range_decoder.rb +434 -0
  131. data/lib/omnizip/algorithms/lzma/range_encoder.rb +194 -0
  132. data/lib/omnizip/algorithms/lzma/state.rb +127 -0
  133. data/lib/omnizip/algorithms/lzma/xz_buffered_range_encoder.rb +325 -0
  134. data/lib/omnizip/algorithms/lzma/xz_encoder.rb +426 -0
  135. data/lib/omnizip/algorithms/lzma/xz_encoder_fast.rb +645 -0
  136. data/lib/omnizip/algorithms/lzma/xz_match_finder_adapter.rb +227 -0
  137. data/lib/omnizip/algorithms/lzma/xz_price_calculator.rb +169 -0
  138. data/lib/omnizip/algorithms/lzma/xz_probability_models.rb +261 -0
  139. data/lib/omnizip/algorithms/lzma/xz_range_encoder.rb +223 -0
  140. data/lib/omnizip/algorithms/lzma/xz_range_encoder_exact.rb +331 -0
  141. data/lib/omnizip/algorithms/lzma/xz_state.rb +116 -0
  142. data/lib/omnizip/algorithms/lzma/xz_utils_decoder.rb +2055 -0
  143. data/lib/omnizip/algorithms/lzma.rb +238 -0
  144. data/lib/omnizip/algorithms/lzma2/chunk_manager.rb +182 -0
  145. data/lib/omnizip/algorithms/lzma2/constants.rb +41 -0
  146. data/lib/omnizip/algorithms/lzma2/encoder.rb +147 -0
  147. data/lib/omnizip/algorithms/lzma2/lzma2_chunk.rb +161 -0
  148. data/lib/omnizip/algorithms/lzma2/properties.rb +179 -0
  149. data/lib/omnizip/algorithms/lzma2/simple_lzma2_encoder.rb +127 -0
  150. data/lib/omnizip/algorithms/lzma2/xz_encoder_adapter.rb +85 -0
  151. data/lib/omnizip/algorithms/lzma2.rb +141 -0
  152. data/lib/omnizip/algorithms/ppmd7/constants.rb +74 -0
  153. data/lib/omnizip/algorithms/ppmd7/context.rb +154 -0
  154. data/lib/omnizip/algorithms/ppmd7/decoder.rb +126 -0
  155. data/lib/omnizip/algorithms/ppmd7/encoder.rb +163 -0
  156. data/lib/omnizip/algorithms/ppmd7/model.rb +248 -0
  157. data/lib/omnizip/algorithms/ppmd7/symbol_state.rb +57 -0
  158. data/lib/omnizip/algorithms/ppmd7.rb +116 -0
  159. data/lib/omnizip/algorithms/ppmd8/constants.rb +61 -0
  160. data/lib/omnizip/algorithms/ppmd8/context.rb +34 -0
  161. data/lib/omnizip/algorithms/ppmd8/decoder.rb +107 -0
  162. data/lib/omnizip/algorithms/ppmd8/encoder.rb +138 -0
  163. data/lib/omnizip/algorithms/ppmd8/model.rb +250 -0
  164. data/lib/omnizip/algorithms/ppmd8/restoration_method.rb +78 -0
  165. data/lib/omnizip/algorithms/ppmd8.rb +82 -0
  166. data/lib/omnizip/algorithms/ppmd_base.rb +138 -0
  167. data/lib/omnizip/algorithms/sevenzip_lzma2.rb +123 -0
  168. data/lib/omnizip/algorithms/xz_lzma2.rb +118 -0
  169. data/lib/omnizip/algorithms/zstandard/constants.rb +25 -0
  170. data/lib/omnizip/algorithms/zstandard/decoder.rb +46 -0
  171. data/lib/omnizip/algorithms/zstandard/encoder.rb +51 -0
  172. data/lib/omnizip/algorithms/zstandard.rb +138 -0
  173. data/lib/omnizip/buffer/memory_archive.rb +251 -0
  174. data/lib/omnizip/buffer/memory_extractor.rb +224 -0
  175. data/lib/omnizip/buffer.rb +176 -0
  176. data/lib/omnizip/checksum_registry.rb +114 -0
  177. data/lib/omnizip/checksums/crc32.rb +100 -0
  178. data/lib/omnizip/checksums/crc64.rb +101 -0
  179. data/lib/omnizip/checksums/crc_base.rb +158 -0
  180. data/lib/omnizip/checksums/verifier.rb +131 -0
  181. data/lib/omnizip/chunked/memory_manager.rb +194 -0
  182. data/lib/omnizip/chunked/reader.rb +78 -0
  183. data/lib/omnizip/chunked/writer.rb +120 -0
  184. data/lib/omnizip/chunked.rb +129 -0
  185. data/lib/omnizip/cli/output_formatter.rb +104 -0
  186. data/lib/omnizip/cli.rb +572 -0
  187. data/lib/omnizip/commands/.keep +0 -0
  188. data/lib/omnizip/commands/archive_create_command.rb +427 -0
  189. data/lib/omnizip/commands/archive_extract_command.rb +272 -0
  190. data/lib/omnizip/commands/archive_list_command.rb +218 -0
  191. data/lib/omnizip/commands/archive_repair_command.rb +131 -0
  192. data/lib/omnizip/commands/archive_verify_command.rb +117 -0
  193. data/lib/omnizip/commands/compress_command.rb +117 -0
  194. data/lib/omnizip/commands/decompress_command.rb +120 -0
  195. data/lib/omnizip/commands/list_command.rb +53 -0
  196. data/lib/omnizip/commands/metadata_command.rb +153 -0
  197. data/lib/omnizip/commands/parity_create_command.rb +122 -0
  198. data/lib/omnizip/commands/parity_repair_command.rb +122 -0
  199. data/lib/omnizip/commands/parity_verify_command.rb +124 -0
  200. data/lib/omnizip/commands/profile_list_command.rb +56 -0
  201. data/lib/omnizip/commands/profile_show_command.rb +44 -0
  202. data/lib/omnizip/convenience.rb +359 -0
  203. data/lib/omnizip/converter/conversion_registry.rb +49 -0
  204. data/lib/omnizip/converter/conversion_strategy.rb +121 -0
  205. data/lib/omnizip/converter/seven_zip_to_zip_strategy.rb +97 -0
  206. data/lib/omnizip/converter/zip_to_seven_zip_strategy.rb +112 -0
  207. data/lib/omnizip/converter.rb +105 -0
  208. data/lib/omnizip/crypto/aes256/cipher.rb +100 -0
  209. data/lib/omnizip/crypto/aes256/constants.rb +28 -0
  210. data/lib/omnizip/crypto/aes256/key_derivation.rb +101 -0
  211. data/lib/omnizip/crypto/aes256.rb +102 -0
  212. data/lib/omnizip/error.rb +106 -0
  213. data/lib/omnizip/eta/exponential_smoothing_estimator.rb +98 -0
  214. data/lib/omnizip/eta/moving_average_estimator.rb +99 -0
  215. data/lib/omnizip/eta/rate_calculator.rb +104 -0
  216. data/lib/omnizip/eta/sample_history.rb +143 -0
  217. data/lib/omnizip/eta/time_estimator.rb +106 -0
  218. data/lib/omnizip/eta.rb +63 -0
  219. data/lib/omnizip/extraction/filter_chain.rb +177 -0
  220. data/lib/omnizip/extraction/glob_pattern.rb +140 -0
  221. data/lib/omnizip/extraction/pattern_matcher.rb +70 -0
  222. data/lib/omnizip/extraction/predicate_pattern.rb +52 -0
  223. data/lib/omnizip/extraction/regex_pattern.rb +50 -0
  224. data/lib/omnizip/extraction/selective_extractor.rb +240 -0
  225. data/lib/omnizip/extraction.rb +111 -0
  226. data/lib/omnizip/file_type/mime_classifier.rb +144 -0
  227. data/lib/omnizip/file_type.rb +113 -0
  228. data/lib/omnizip/filter.rb +139 -0
  229. data/lib/omnizip/filter_pipeline.rb +108 -0
  230. data/lib/omnizip/filter_registry.rb +166 -0
  231. data/lib/omnizip/filters/bcj.rb +279 -0
  232. data/lib/omnizip/filters/bcj2/constants.rb +53 -0
  233. data/lib/omnizip/filters/bcj2/decoder.rb +200 -0
  234. data/lib/omnizip/filters/bcj2/encoder.rb +61 -0
  235. data/lib/omnizip/filters/bcj2/stream_data.rb +93 -0
  236. data/lib/omnizip/filters/bcj2.rb +99 -0
  237. data/lib/omnizip/filters/bcj_arm.rb +176 -0
  238. data/lib/omnizip/filters/bcj_arm64.rb +244 -0
  239. data/lib/omnizip/filters/bcj_ia64.rb +196 -0
  240. data/lib/omnizip/filters/bcj_ppc.rb +190 -0
  241. data/lib/omnizip/filters/bcj_sparc.rb +176 -0
  242. data/lib/omnizip/filters/bcj_x86.rb +193 -0
  243. data/lib/omnizip/filters/delta.rb +196 -0
  244. data/lib/omnizip/filters/filter_base.rb +72 -0
  245. data/lib/omnizip/filters/registry.rb +123 -0
  246. data/lib/omnizip/filters/xz_delta.rb +258 -0
  247. data/lib/omnizip/format_detector.rb +162 -0
  248. data/lib/omnizip/format_registry.rb +59 -0
  249. data/lib/omnizip/formats/.keep +0 -0
  250. data/lib/omnizip/formats/bzip2_file.rb +172 -0
  251. data/lib/omnizip/formats/cpio/constants.rb +55 -0
  252. data/lib/omnizip/formats/cpio/entry.rb +385 -0
  253. data/lib/omnizip/formats/cpio/reader.rb +196 -0
  254. data/lib/omnizip/formats/cpio/writer.rb +234 -0
  255. data/lib/omnizip/formats/cpio.rb +140 -0
  256. data/lib/omnizip/formats/format_spec_loader.rb +230 -0
  257. data/lib/omnizip/formats/gzip.rb +238 -0
  258. data/lib/omnizip/formats/iso/directory_builder.rb +297 -0
  259. data/lib/omnizip/formats/iso/directory_record.rb +152 -0
  260. data/lib/omnizip/formats/iso/joliet.rb +204 -0
  261. data/lib/omnizip/formats/iso/path_table.rb +125 -0
  262. data/lib/omnizip/formats/iso/reader.rb +197 -0
  263. data/lib/omnizip/formats/iso/rock_ridge.rb +349 -0
  264. data/lib/omnizip/formats/iso/volume_builder.rb +320 -0
  265. data/lib/omnizip/formats/iso/volume_descriptor.rb +168 -0
  266. data/lib/omnizip/formats/iso/writer.rb +530 -0
  267. data/lib/omnizip/formats/iso.rb +140 -0
  268. data/lib/omnizip/formats/lzip.rb +175 -0
  269. data/lib/omnizip/formats/lzma_alone.rb +171 -0
  270. data/lib/omnizip/formats/rar/archive_repairer.rb +243 -0
  271. data/lib/omnizip/formats/rar/archive_verifier.rb +195 -0
  272. data/lib/omnizip/formats/rar/block_parser.rb +243 -0
  273. data/lib/omnizip/formats/rar/compression/bit_stream.rb +180 -0
  274. data/lib/omnizip/formats/rar/compression/dispatcher.rb +217 -0
  275. data/lib/omnizip/formats/rar/compression/lz77_huffman/decoder.rb +216 -0
  276. data/lib/omnizip/formats/rar/compression/lz77_huffman/encoder.rb +158 -0
  277. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_builder.rb +217 -0
  278. data/lib/omnizip/formats/rar/compression/lz77_huffman/huffman_coder.rb +189 -0
  279. data/lib/omnizip/formats/rar/compression/lz77_huffman/match_finder.rb +135 -0
  280. data/lib/omnizip/formats/rar/compression/lz77_huffman/sliding_window.rb +165 -0
  281. data/lib/omnizip/formats/rar/compression/ppmd/context.rb +105 -0
  282. data/lib/omnizip/formats/rar/compression/ppmd/decoder.rb +219 -0
  283. data/lib/omnizip/formats/rar/compression/ppmd/encoder.rb +262 -0
  284. data/lib/omnizip/formats/rar/compression_method_registry.rb +106 -0
  285. data/lib/omnizip/formats/rar/constants.rb +82 -0
  286. data/lib/omnizip/formats/rar/decompressor.rb +238 -0
  287. data/lib/omnizip/formats/rar/external_writer.rb +312 -0
  288. data/lib/omnizip/formats/rar/header.rb +192 -0
  289. data/lib/omnizip/formats/rar/license_validator.rb +109 -0
  290. data/lib/omnizip/formats/rar/models/rar_archive.rb +77 -0
  291. data/lib/omnizip/formats/rar/models/rar_entry.rb +65 -0
  292. data/lib/omnizip/formats/rar/models/rar_volume.rb +56 -0
  293. data/lib/omnizip/formats/rar/parity_handler.rb +292 -0
  294. data/lib/omnizip/formats/rar/rar5/compression/lzma.rb +202 -0
  295. data/lib/omnizip/formats/rar/rar5/compression/lzss.rb +578 -0
  296. data/lib/omnizip/formats/rar/rar5/compression/store.rb +60 -0
  297. data/lib/omnizip/formats/rar/rar5/crc32.rb +39 -0
  298. data/lib/omnizip/formats/rar/rar5/encryption/aes256_cbc.rb +97 -0
  299. data/lib/omnizip/formats/rar/rar5/encryption/encryption_header.rb +114 -0
  300. data/lib/omnizip/formats/rar/rar5/encryption/encryption_manager.rb +166 -0
  301. data/lib/omnizip/formats/rar/rar5/encryption/key_derivation.rb +97 -0
  302. data/lib/omnizip/formats/rar/rar5/header.rb +187 -0
  303. data/lib/omnizip/formats/rar/rar5/models/encryption_options.rb +74 -0
  304. data/lib/omnizip/formats/rar/rar5/models/recovery_options.rb +63 -0
  305. data/lib/omnizip/formats/rar/rar5/models/solid_options.rb +63 -0
  306. data/lib/omnizip/formats/rar/rar5/models/volume_options.rb +74 -0
  307. data/lib/omnizip/formats/rar/rar5/multi_volume/ARCHITECTURE.md +290 -0
  308. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_manager.rb +264 -0
  309. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_splitter.rb +155 -0
  310. data/lib/omnizip/formats/rar/rar5/multi_volume/volume_writer.rb +194 -0
  311. data/lib/omnizip/formats/rar/rar5/solid/solid_encoder.rb +109 -0
  312. data/lib/omnizip/formats/rar/rar5/solid/solid_manager.rb +142 -0
  313. data/lib/omnizip/formats/rar/rar5/solid/solid_stream.rb +121 -0
  314. data/lib/omnizip/formats/rar/rar5/vint.rb +65 -0
  315. data/lib/omnizip/formats/rar/rar5/writer.rb +466 -0
  316. data/lib/omnizip/formats/rar/rar_format_base.rb +241 -0
  317. data/lib/omnizip/formats/rar/reader.rb +366 -0
  318. data/lib/omnizip/formats/rar/recovery_record.rb +245 -0
  319. data/lib/omnizip/formats/rar/volume_manager.rb +168 -0
  320. data/lib/omnizip/formats/rar/writer.rb +431 -0
  321. data/lib/omnizip/formats/rar.rb +205 -0
  322. data/lib/omnizip/formats/rar3/compressor.rb +73 -0
  323. data/lib/omnizip/formats/rar3/decompressor.rb +66 -0
  324. data/lib/omnizip/formats/rar3/reader.rb +386 -0
  325. data/lib/omnizip/formats/rar3/writer.rb +219 -0
  326. data/lib/omnizip/formats/rar5/compressor.rb +73 -0
  327. data/lib/omnizip/formats/rar5/decompressor.rb +66 -0
  328. data/lib/omnizip/formats/rar5/reader.rb +342 -0
  329. data/lib/omnizip/formats/rar5/writer.rb +214 -0
  330. data/lib/omnizip/formats/seven_zip/coder_chain.rb +150 -0
  331. data/lib/omnizip/formats/seven_zip/constants.rb +126 -0
  332. data/lib/omnizip/formats/seven_zip/encoded_header.rb +114 -0
  333. data/lib/omnizip/formats/seven_zip/encrypted_header.rb +142 -0
  334. data/lib/omnizip/formats/seven_zip/file_collector.rb +144 -0
  335. data/lib/omnizip/formats/seven_zip/header.rb +106 -0
  336. data/lib/omnizip/formats/seven_zip/header_encryptor.rb +134 -0
  337. data/lib/omnizip/formats/seven_zip/header_writer.rb +466 -0
  338. data/lib/omnizip/formats/seven_zip/models/coder_info.rb +30 -0
  339. data/lib/omnizip/formats/seven_zip/models/file_entry.rb +58 -0
  340. data/lib/omnizip/formats/seven_zip/models/folder.rb +69 -0
  341. data/lib/omnizip/formats/seven_zip/models/stream_info.rb +42 -0
  342. data/lib/omnizip/formats/seven_zip/parser.rb +660 -0
  343. data/lib/omnizip/formats/seven_zip/reader.rb +458 -0
  344. data/lib/omnizip/formats/seven_zip/split_archive_reader.rb +632 -0
  345. data/lib/omnizip/formats/seven_zip/split_archive_writer.rb +315 -0
  346. data/lib/omnizip/formats/seven_zip/stream_compressor.rb +151 -0
  347. data/lib/omnizip/formats/seven_zip/stream_decompressor.rb +162 -0
  348. data/lib/omnizip/formats/seven_zip/writer.rb +740 -0
  349. data/lib/omnizip/formats/seven_zip.rb +93 -0
  350. data/lib/omnizip/formats/tar/constants.rb +73 -0
  351. data/lib/omnizip/formats/tar/entry.rb +94 -0
  352. data/lib/omnizip/formats/tar/header.rb +168 -0
  353. data/lib/omnizip/formats/tar/reader.rb +121 -0
  354. data/lib/omnizip/formats/tar/writer.rb +216 -0
  355. data/lib/omnizip/formats/tar.rb +84 -0
  356. data/lib/omnizip/formats/xz/reader.rb +116 -0
  357. data/lib/omnizip/formats/xz.rb +237 -0
  358. data/lib/omnizip/formats/xz_impl/block_decoder.rb +754 -0
  359. data/lib/omnizip/formats/xz_impl/block_encoder.rb +306 -0
  360. data/lib/omnizip/formats/xz_impl/block_header.rb +210 -0
  361. data/lib/omnizip/formats/xz_impl/block_header_parser.rb +186 -0
  362. data/lib/omnizip/formats/xz_impl/constants.rb +49 -0
  363. data/lib/omnizip/formats/xz_impl/index_decoder.rb +174 -0
  364. data/lib/omnizip/formats/xz_impl/index_encoder.rb +122 -0
  365. data/lib/omnizip/formats/xz_impl/stream_decoder.rb +468 -0
  366. data/lib/omnizip/formats/xz_impl/stream_encoder.rb +99 -0
  367. data/lib/omnizip/formats/xz_impl/stream_footer.rb +81 -0
  368. data/lib/omnizip/formats/xz_impl/stream_footer_parser.rb +117 -0
  369. data/lib/omnizip/formats/xz_impl/stream_header.rb +55 -0
  370. data/lib/omnizip/formats/xz_impl/stream_header_parser.rb +108 -0
  371. data/lib/omnizip/formats/xz_impl/vli.rb +128 -0
  372. data/lib/omnizip/formats/xz_impl/writer.rb +421 -0
  373. data/lib/omnizip/formats/zip/central_directory_header.rb +195 -0
  374. data/lib/omnizip/formats/zip/constants.rb +69 -0
  375. data/lib/omnizip/formats/zip/end_of_central_directory.rb +133 -0
  376. data/lib/omnizip/formats/zip/local_file_header.rb +138 -0
  377. data/lib/omnizip/formats/zip/reader.rb +250 -0
  378. data/lib/omnizip/formats/zip/unix_extra_field.rb +153 -0
  379. data/lib/omnizip/formats/zip/writer.rb +375 -0
  380. data/lib/omnizip/formats/zip/zip64_end_of_central_directory.rb +104 -0
  381. data/lib/omnizip/formats/zip/zip64_end_of_central_directory_locator.rb +66 -0
  382. data/lib/omnizip/formats/zip/zip64_extra_field.rb +114 -0
  383. data/lib/omnizip/formats/zip.rb +50 -0
  384. data/lib/omnizip/implementations/base/lzma2_decoder_base.rb +75 -0
  385. data/lib/omnizip/implementations/base/lzma2_encoder_base.rb +128 -0
  386. data/lib/omnizip/implementations/base/lzma_decoder_base.rb +83 -0
  387. data/lib/omnizip/implementations/base/lzma_encoder_base.rb +108 -0
  388. data/lib/omnizip/implementations/base/state_machine_base.rb +182 -0
  389. data/lib/omnizip/implementations/seven_zip/lzma/decoder.rb +421 -0
  390. data/lib/omnizip/implementations/seven_zip/lzma/encoder.rb +465 -0
  391. data/lib/omnizip/implementations/seven_zip/lzma/match_finder.rb +288 -0
  392. data/lib/omnizip/implementations/seven_zip/lzma/range_decoder.rb +200 -0
  393. data/lib/omnizip/implementations/seven_zip/lzma/range_encoder.rb +197 -0
  394. data/lib/omnizip/implementations/seven_zip/lzma/state_machine.rb +141 -0
  395. data/lib/omnizip/implementations/seven_zip/lzma2/encoder.rb +519 -0
  396. data/lib/omnizip/implementations/xz_utils/lzma2/decoder.rb +723 -0
  397. data/lib/omnizip/implementations/xz_utils/lzma2/encoder.rb +750 -0
  398. data/lib/omnizip/io/buffered_input.rb +146 -0
  399. data/lib/omnizip/io/buffered_output.rb +105 -0
  400. data/lib/omnizip/io/stream_manager.rb +115 -0
  401. data/lib/omnizip/link_handler/hard_link.rb +79 -0
  402. data/lib/omnizip/link_handler/symbolic_link.rb +74 -0
  403. data/lib/omnizip/link_handler.rb +124 -0
  404. data/lib/omnizip/metadata/archive_metadata.rb +114 -0
  405. data/lib/omnizip/metadata/entry_metadata.rb +146 -0
  406. data/lib/omnizip/metadata/metadata_editor.rb +171 -0
  407. data/lib/omnizip/metadata/metadata_registry.rb +64 -0
  408. data/lib/omnizip/metadata/metadata_validator.rb +99 -0
  409. data/lib/omnizip/metadata.rb +57 -0
  410. data/lib/omnizip/models/.keep +0 -0
  411. data/lib/omnizip/models/algorithm_metadata.rb +73 -0
  412. data/lib/omnizip/models/compression_options.rb +71 -0
  413. data/lib/omnizip/models/conversion_options.rb +87 -0
  414. data/lib/omnizip/models/conversion_result.rb +135 -0
  415. data/lib/omnizip/models/eta_result.rb +46 -0
  416. data/lib/omnizip/models/extraction_rule.rb +115 -0
  417. data/lib/omnizip/models/filter_chain.rb +144 -0
  418. data/lib/omnizip/models/filter_config.rb +183 -0
  419. data/lib/omnizip/models/match_result.rb +124 -0
  420. data/lib/omnizip/models/optimization_suggestion.rb +91 -0
  421. data/lib/omnizip/models/parallel_options.rb +104 -0
  422. data/lib/omnizip/models/performance_result.rb +79 -0
  423. data/lib/omnizip/models/profile_report.rb +82 -0
  424. data/lib/omnizip/models/progress_options.rb +38 -0
  425. data/lib/omnizip/models/split_options.rb +116 -0
  426. data/lib/omnizip/optimization_registry.rb +81 -0
  427. data/lib/omnizip/parallel/job_queue.rb +209 -0
  428. data/lib/omnizip/parallel/job_scheduler.rb +203 -0
  429. data/lib/omnizip/parallel/parallel_compressor.rb +347 -0
  430. data/lib/omnizip/parallel/parallel_extractor.rb +329 -0
  431. data/lib/omnizip/parallel/worker_pool.rb +223 -0
  432. data/lib/omnizip/parallel.rb +149 -0
  433. data/lib/omnizip/parity/chunked_block_processor.rb +196 -0
  434. data/lib/omnizip/parity/galois16.rb +145 -0
  435. data/lib/omnizip/parity/models/creator_packet.rb +73 -0
  436. data/lib/omnizip/parity/models/file_description_packet.rb +133 -0
  437. data/lib/omnizip/parity/models/ifsc_packet.rb +123 -0
  438. data/lib/omnizip/parity/models/main_packet.rb +128 -0
  439. data/lib/omnizip/parity/models/packet.rb +156 -0
  440. data/lib/omnizip/parity/models/packet_registry.rb +109 -0
  441. data/lib/omnizip/parity/models/recovery_slice_packet.rb +78 -0
  442. data/lib/omnizip/parity/par2_creator.rb +531 -0
  443. data/lib/omnizip/parity/par2_repairer.rb +407 -0
  444. data/lib/omnizip/parity/par2_verifier.rb +364 -0
  445. data/lib/omnizip/parity/par2cmdline_algorithm.rb +110 -0
  446. data/lib/omnizip/parity/par2cmdline_coefficients.rb +78 -0
  447. data/lib/omnizip/parity/reed_solomon_decoder.rb +266 -0
  448. data/lib/omnizip/parity/reed_solomon_encoder.rb +111 -0
  449. data/lib/omnizip/parity/reed_solomon_matrix.rb +342 -0
  450. data/lib/omnizip/parity.rb +186 -0
  451. data/lib/omnizip/password/encryption_registry.rb +65 -0
  452. data/lib/omnizip/password/encryption_strategy.rb +96 -0
  453. data/lib/omnizip/password/password_validator.rb +129 -0
  454. data/lib/omnizip/password/winzip_aes_strategy.rb +192 -0
  455. data/lib/omnizip/password/zip_crypto_strategy.rb +141 -0
  456. data/lib/omnizip/password.rb +87 -0
  457. data/lib/omnizip/pipe/stream_compressor.rb +124 -0
  458. data/lib/omnizip/pipe/stream_decompressor.rb +174 -0
  459. data/lib/omnizip/pipe.rb +121 -0
  460. data/lib/omnizip/platform/ntfs_streams.rb +201 -0
  461. data/lib/omnizip/platform.rb +189 -0
  462. data/lib/omnizip/profile/archive_profile.rb +39 -0
  463. data/lib/omnizip/profile/balanced_profile.rb +33 -0
  464. data/lib/omnizip/profile/binary_profile.rb +36 -0
  465. data/lib/omnizip/profile/compression_profile.rb +158 -0
  466. data/lib/omnizip/profile/custom_profile.rb +157 -0
  467. data/lib/omnizip/profile/fast_profile.rb +33 -0
  468. data/lib/omnizip/profile/maximum_profile.rb +33 -0
  469. data/lib/omnizip/profile/profile_detector.rb +110 -0
  470. data/lib/omnizip/profile/profile_registry.rb +161 -0
  471. data/lib/omnizip/profile/text_profile.rb +36 -0
  472. data/lib/omnizip/profile.rb +190 -0
  473. data/lib/omnizip/profiler/memory_profiler.rb +66 -0
  474. data/lib/omnizip/profiler/method_profiler.rb +49 -0
  475. data/lib/omnizip/profiler/report_generator.rb +169 -0
  476. data/lib/omnizip/profiler.rb +204 -0
  477. data/lib/omnizip/progress/callback_reporter.rb +36 -0
  478. data/lib/omnizip/progress/console_reporter.rb +62 -0
  479. data/lib/omnizip/progress/log_reporter.rb +91 -0
  480. data/lib/omnizip/progress/operation_progress.rb +118 -0
  481. data/lib/omnizip/progress/progress_bar.rb +156 -0
  482. data/lib/omnizip/progress/progress_reporter.rb +40 -0
  483. data/lib/omnizip/progress/progress_tracker.rb +190 -0
  484. data/lib/omnizip/progress/silent_reporter.rb +24 -0
  485. data/lib/omnizip/progress.rb +127 -0
  486. data/lib/omnizip/rubyzip_compat.rb +63 -0
  487. data/lib/omnizip/temp/safe_extract.rb +168 -0
  488. data/lib/omnizip/temp/temp_file.rb +124 -0
  489. data/lib/omnizip/temp/temp_file_pool.rb +109 -0
  490. data/lib/omnizip/temp.rb +181 -0
  491. data/lib/omnizip/version.rb +5 -0
  492. data/lib/omnizip/zip/entry.rb +156 -0
  493. data/lib/omnizip/zip/file.rb +485 -0
  494. data/lib/omnizip/zip/input_stream.rb +273 -0
  495. data/lib/omnizip/zip/output_stream.rb +324 -0
  496. data/lib/omnizip.rb +156 -0
  497. data/readme-docs/advanced-features.adoc +515 -0
  498. data/readme-docs/api-usage.adoc +444 -0
  499. data/readme-docs/architecture.adoc +449 -0
  500. data/readme-docs/archive-formats.adoc +479 -0
  501. data/readme-docs/cli-usage.adoc +222 -0
  502. data/readme-docs/compression-algorithms.adoc +442 -0
  503. data/readme-docs/compression-profiles.adoc +247 -0
  504. data/readme-docs/encryption-checksums.adoc +328 -0
  505. data/readme-docs/format-converter.adoc +325 -0
  506. data/readme-docs/installation.adoc +228 -0
  507. data/readme-docs/par2-archives.adoc +608 -0
  508. data/readme-docs/performance-profiler.adoc +389 -0
  509. data/readme-docs/preprocessing-filters.adoc +280 -0
  510. data/xz-file-format-1.2.1.txt +1174 -0
  511. metadata +617 -0
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+ require_relative "../../algorithm_registry"
5
+ require_relative "../../filter_registry"
6
+ require_relative "../../filter_pipeline"
7
+
8
+ module Omnizip
9
+ module Formats
10
+ module SevenZip
11
+ # Builds coder chains from .7z folder specifications
12
+ # Maps method IDs to algorithms and filters, reconstructing the
13
+ # decompression pipeline
14
+ class CoderChain
15
+ include Constants
16
+
17
+ # Build coder chain from folder specification
18
+ #
19
+ # @param folder [Models::Folder] Folder specification
20
+ # @return [Hash] Coder chain configuration
21
+ # @raise [RuntimeError] if unsupported method encountered
22
+ def self.build_from_folder(folder)
23
+ return nil if folder.coders.empty?
24
+
25
+ # For now, support single coder or coder+filter combinations
26
+ main_coder = folder.coders.last
27
+ algorithm = algorithm_for_method(main_coder.method_id)
28
+
29
+ # Check for filters
30
+ filters = []
31
+ if folder.coders.size > 1
32
+ folder.coders[0..-2].each do |coder|
33
+ filter = filter_for_method(coder.method_id)
34
+ filters << filter if filter
35
+ end
36
+ end
37
+
38
+ {
39
+ algorithm: algorithm,
40
+ filters: filters,
41
+ properties: main_coder.properties,
42
+ unpack_size: folder.unpack_sizes.last,
43
+ }
44
+ end
45
+
46
+ # Map method ID to algorithm
47
+ #
48
+ # @param method_id [Integer] Method ID from .7z file
49
+ # @return [Symbol] Algorithm identifier
50
+ # @raise [RuntimeError] if method not supported
51
+ def self.algorithm_for_method(method_id)
52
+ case method_id
53
+ when MethodId::COPY
54
+ nil # No decompression needed
55
+ when MethodId::LZMA
56
+ :lzma
57
+ when MethodId::LZMA2
58
+ :lzma2
59
+ when MethodId::PPMD
60
+ :ppmd7
61
+ when MethodId::BZIP2
62
+ :bzip2
63
+ when MethodId::DEFLATE
64
+ :deflate
65
+ when MethodId::DEFLATE64
66
+ :deflate64
67
+ else
68
+ raise "Unsupported compression method: " \
69
+ "0x#{method_id.to_s(16)}"
70
+ end
71
+ end
72
+
73
+ # Map method ID to filter
74
+ #
75
+ # @param method_id [Integer] Method ID from .7z file
76
+ # @return [Symbol, nil] Filter identifier or nil
77
+ def self.filter_for_method(method_id)
78
+ case method_id
79
+ when FilterId::BCJ_X86
80
+ :bcj_x86
81
+ when FilterId::BCJ_PPC
82
+ :bcj_ppc
83
+ when FilterId::BCJ_IA64
84
+ :bcj_ia64
85
+ when FilterId::BCJ_ARM
86
+ :bcj_arm
87
+ when FilterId::BCJ_ARMT
88
+ :bcj_armt
89
+ when FilterId::BCJ_SPARC
90
+ :bcj_sparc
91
+ when FilterId::ARM64
92
+ :bcj_arm64
93
+ when FilterId::DELTA
94
+ :delta
95
+ end
96
+ end
97
+
98
+ # Create decompressor for coder chain
99
+ #
100
+ # @param chain_config [Hash] Chain configuration
101
+ # @param input_io [IO] Input stream
102
+ # @return [Object] Decompressor instance
103
+ def self.create_decompressor(chain_config, input_io)
104
+ return nil unless chain_config
105
+ return input_io unless chain_config[:algorithm]
106
+
107
+ # Get algorithm
108
+ algo_class = AlgorithmRegistry.get(chain_config[:algorithm])
109
+ unless algo_class
110
+ raise "Algorithm not found: #{chain_config[:algorithm]}"
111
+ end
112
+
113
+ # Create algorithm instance
114
+ decompressor = algo_class.new
115
+ # Pass properties if algorithm supports them
116
+ # Some algorithms (LZMA2) need properties
117
+ if chain_config[:properties] && !chain_config[:properties].empty? && decompressor.respond_to?(:properties=)
118
+ decompressor.properties = chain_config[:properties]
119
+ end
120
+
121
+ # Apply filters if present
122
+ if chain_config[:filters] && !chain_config[:filters].empty?
123
+ # Build filter pipeline
124
+ pipeline = FilterPipeline.new
125
+ chain_config[:filters].each do |filter_sym|
126
+ filter_class = FilterRegistry.get(filter_sym)
127
+ raise "Filter not found: #{filter_sym}" unless filter_class
128
+
129
+ pipeline.add_filter(filter_class.new)
130
+ end
131
+
132
+ # Return composite: input -> algorithm -> filters
133
+ {
134
+ decompressor: decompressor,
135
+ pipeline: pipeline,
136
+ input: input_io,
137
+ }
138
+ else
139
+ # Just algorithm
140
+ {
141
+ decompressor: decompressor,
142
+ pipeline: nil,
143
+ input: input_io,
144
+ }
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module SevenZip
6
+ # Constants for .7z archive format
7
+ # Based on 7-Zip specification
8
+ module Constants
9
+ # Archive signature and header
10
+ SIGNATURE = "7z\xBC\xAF\x27\x1C".b.freeze
11
+ SIGNATURE_SIZE = 6
12
+ START_HEADER_SIZE = 32 # 0x20
13
+ MAJOR_VERSION = 0
14
+ MINOR_VERSION = 4
15
+
16
+ # Property IDs for .7z format structure
17
+ module PropertyId
18
+ K_END = 0x00
19
+ HEADER = 0x01
20
+ ARCHIVE_PROPERTIES = 0x02
21
+ ADDITIONAL_STREAMS_INFO = 0x03
22
+ MAIN_STREAMS_INFO = 0x04
23
+ FILES_INFO = 0x05
24
+ PACK_INFO = 0x06
25
+ UNPACK_INFO = 0x07
26
+ SUBSTREAMS_INFO = 0x08
27
+ SIZE = 0x09
28
+ CRC = 0x0A
29
+ FOLDER = 0x0B
30
+ CODERS_UNPACK_SIZE = 0x0C
31
+ NUM_UNPACK_STREAM = 0x0D
32
+ EMPTY_STREAM = 0x0E
33
+ EMPTY_FILE = 0x0F
34
+ ANTI = 0x10
35
+ NAME = 0x11
36
+ CTIME = 0x12
37
+ ATIME = 0x13
38
+ MTIME = 0x14
39
+ WIN_ATTRIB = 0x15
40
+ COMMENT = 0x16
41
+ ENCODED_HEADER = 0x17
42
+ START_POS = 0x18
43
+ DUMMY = 0x19
44
+ end
45
+
46
+ # Method IDs for compression algorithms
47
+ module MethodId
48
+ # Compression methods
49
+ COPY = 0x00
50
+ LZMA = 0x030101
51
+ LZMA2 = 0x21
52
+ PPMD = 0x030401
53
+ BZIP2 = 0x040202
54
+ DEFLATE = 0x040108
55
+ DEFLATE64 = 0x040109
56
+
57
+ # Crypto methods
58
+ AES = 0x06F10701
59
+
60
+ def self.name(id)
61
+ case id
62
+ when COPY then "Copy"
63
+ when LZMA then "LZMA"
64
+ when LZMA2 then "LZMA2"
65
+ when PPMD then "PPMd"
66
+ when BZIP2 then "BZip2"
67
+ when DEFLATE then "Deflate"
68
+ when DEFLATE64 then "Deflate64"
69
+ when AES then "AES256"
70
+ else "Unknown(0x#{id.to_s(16)})"
71
+ end
72
+ end
73
+ end
74
+
75
+ # Filter IDs
76
+ module FilterId
77
+ # BCJ filters for executable files
78
+ BCJ_X86 = 0x03030103
79
+ BCJ_PPC = 0x03030205
80
+ BCJ_IA64 = 0x03030401
81
+ BCJ_ARM = 0x03030501
82
+ BCJ_ARMT = 0x03030701
83
+ BCJ_SPARC = 0x03030805
84
+ ARM64 = 0x03030601
85
+
86
+ # BCJ2 filter
87
+ BCJ2 = 0x03030111
88
+
89
+ # Swap filters for byte order conversion
90
+ SWAP2 = 0x03030204
91
+ SWAP4 = 0x03030208
92
+
93
+ # Delta filter
94
+ DELTA = 0x03
95
+
96
+ def self.name(id)
97
+ case id
98
+ when BCJ_X86 then "BCJ-x86"
99
+ when BCJ_PPC then "BCJ-PPC"
100
+ when BCJ_IA64 then "BCJ-IA64"
101
+ when BCJ_ARM then "BCJ-ARM"
102
+ when BCJ_ARMT then "BCJ-ARMT"
103
+ when BCJ_SPARC then "BCJ-SPARC"
104
+ when DELTA then "Delta"
105
+ when ARM64 then "BCJ-ARM64"
106
+ when BCJ2 then "BCJ2"
107
+ when SWAP2 then "Swap2"
108
+ when SWAP4 then "Swap4"
109
+ else "Unknown(0x#{id.to_s(16)})"
110
+ end
111
+ end
112
+
113
+ def self.bcj_filter?(id)
114
+ [BCJ_X86, BCJ_PPC, BCJ_IA64, BCJ_ARM, BCJ_ARMT, BCJ_SPARC,
115
+ ARM64].include?(id)
116
+ end
117
+ end
118
+
119
+ # Maximum limits
120
+ MAX_NUM_CODERS = 4
121
+ MAX_NUM_BONDS = 3
122
+ MAX_NUM_PACK_STREAMS = 4
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+ require_relative "../../algorithms/lzma2"
5
+ require_relative "../../checksums/crc32"
6
+
7
+ module Omnizip
8
+ module Formats
9
+ module SevenZip
10
+ # Handles 7-Zip encoded headers
11
+ #
12
+ # 7-Zip can compress the Next Header metadata with LZMA2 to save space.
13
+ # This module provides functionality to encode and decode headers.
14
+ module EncodedHeader
15
+ include Constants
16
+
17
+ module_function
18
+
19
+ # Encode next header with LZMA2 compression
20
+ #
21
+ # @param header_data [String] Uncompressed header data
22
+ # @return [String] Encoded header property with compressed data
23
+ def encode(header_data)
24
+ # Compress header with LZMA2
25
+ compressed = compress_header(header_data)
26
+
27
+ # Build encoded header property
28
+ encoded = String.new(encoding: "BINARY")
29
+ encoded << [PropertyId::ENCODED_HEADER].pack("C")
30
+
31
+ # Write pack info for compressed header
32
+ encoded << [PropertyId::PACK_INFO].pack("C")
33
+ encoded << encode_uint64(0) # Pack position
34
+ encoded << encode_uint64(1) # Number of pack streams
35
+
36
+ # Write size
37
+ encoded << [PropertyId::SIZE].pack("C")
38
+ encoded << encode_uint64(compressed.bytesize)
39
+
40
+ encoded << [PropertyId::K_END].pack("C")
41
+
42
+ # Write coder info (LZMA2)
43
+ encoded << [PropertyId::UNPACK_INFO].pack("C")
44
+ encoded << [PropertyId::FOLDER].pack("C")
45
+ encoded << encode_uint64(1) # Number of folders
46
+ encoded << [0].pack("C") # External flag (0 = inline)
47
+
48
+ # Number of coders
49
+ encoded << encode_uint64(1)
50
+
51
+ # Coder info for LZMA2
52
+ # Method ID: LZMA2 = 0x21
53
+ encoded << [1].pack("C") # Main byte (1 byte for ID, no properties)
54
+ encoded << [0x21].pack("C") # LZMA2 method ID
55
+
56
+ # Unpack size
57
+ encoded << [PropertyId::CODERS_UNPACK_SIZE].pack("C")
58
+ encoded << encode_uint64(header_data.bytesize)
59
+
60
+ encoded << [PropertyId::K_END].pack("C")
61
+
62
+ # Append compressed data
63
+ encoded << compressed
64
+
65
+ encoded
66
+ end
67
+
68
+ # Compress header data with LZMA2
69
+ #
70
+ # @param header_data [String] Uncompressed header
71
+ # @return [String] Compressed header
72
+ def compress_header(header_data)
73
+ # Use 7-Zip SDK LZMA2 encoder for 7-Zip format
74
+ encoder = Omnizip::Implementations::SevenZip::LZMA2::Encoder.new(
75
+ dict_size: 4096, # Small dictionary for headers
76
+ lc: 3,
77
+ lp: 0,
78
+ pb: 2,
79
+ standalone: false, # No property byte
80
+ )
81
+
82
+ encoder.encode(header_data)
83
+ end
84
+
85
+ # Encode unsigned 64-bit integer in 7-Zip variable-length format
86
+ #
87
+ # @param value [Integer] Value to encode
88
+ # @return [String] Encoded bytes
89
+ def encode_uint64(value)
90
+ return [value].pack("C") if value < 0x80
91
+
92
+ result = String.new(encoding: "BINARY")
93
+ shift = 0
94
+
95
+ loop do
96
+ byte = value & 0x7F
97
+ value >>= 7
98
+
99
+ if value.zero?
100
+ result << [byte].pack("C")
101
+ break
102
+ else
103
+ result << [byte | 0x80].pack("C")
104
+ end
105
+
106
+ shift += 7
107
+ end
108
+
109
+ result
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+
5
+ module Omnizip
6
+ module Formats
7
+ module SevenZip
8
+ # Encrypted header model for .7z archives
9
+ # Stores metadata for header encryption
10
+ class EncryptedHeader
11
+ include Constants
12
+
13
+ attr_accessor :encrypted_data, :salt, :iv, :original_size, :crc
14
+
15
+ # Initialize encrypted header
16
+ #
17
+ # @param encrypted_data [String] Encrypted header bytes
18
+ # @param salt [String] PBKDF2 salt
19
+ # @param iv [String] AES initialization vector
20
+ # @param original_size [Integer] Size before encryption
21
+ # @param crc [Integer, nil] CRC32 of encrypted data (optional)
22
+ def initialize(encrypted_data: nil, salt: nil, iv: nil,
23
+ original_size: 0, crc: nil)
24
+ @encrypted_data = encrypted_data
25
+ @salt = salt
26
+ @iv = iv
27
+ @original_size = original_size
28
+ @crc = crc
29
+ end
30
+
31
+ # Serialize encrypted header to binary format
32
+ #
33
+ # Format:
34
+ # - 1 byte: PropertyId::ENCODED_HEADER marker
35
+ # - 8 bytes: Encrypted data size (little-endian)
36
+ # - 16 bytes: Salt
37
+ # - 16 bytes: IV
38
+ # - 8 bytes: Original size (little-endian)
39
+ # - 4 bytes: CRC32 (optional, 0 if not set)
40
+ # - N bytes: Encrypted data
41
+ #
42
+ # @return [String] Binary representation
43
+ def to_binary
44
+ data = String.new(encoding: "BINARY")
45
+
46
+ # Marker for encoded header
47
+ data << [PropertyId::ENCODED_HEADER].pack("C")
48
+
49
+ # Encrypted data size
50
+ data << [@encrypted_data.bytesize].pack("Q<")
51
+
52
+ # Encryption parameters
53
+ data << @salt
54
+ data << @iv
55
+
56
+ # Original size
57
+ data << [@original_size].pack("Q<")
58
+
59
+ # CRC (0 if not set)
60
+ data << [crc || 0].pack("V")
61
+
62
+ # Encrypted data
63
+ data << @encrypted_data
64
+
65
+ data
66
+ end
67
+
68
+ # Parse encrypted header from binary data
69
+ #
70
+ # @param data [String] Binary data
71
+ # @return [EncryptedHeader] Parsed header
72
+ # @raise [RuntimeError] if data is invalid
73
+ def self.from_binary(data)
74
+ raise "Invalid encrypted header: too short" if data.bytesize < 54
75
+
76
+ pos = 0
77
+
78
+ # Check marker
79
+ marker = data.getbyte(pos)
80
+ pos += 1
81
+ unless marker == PropertyId::ENCODED_HEADER
82
+ raise "Invalid encrypted header marker: expected #{PropertyId::ENCODED_HEADER}, got #{marker}"
83
+ end
84
+
85
+ # Read encrypted data size
86
+ encrypted_size = data[pos, 8].unpack1("Q<")
87
+ pos += 8
88
+
89
+ # Read salt
90
+ salt = data[pos, 16]
91
+ pos += 16
92
+
93
+ # Read IV
94
+ iv = data[pos, 16]
95
+ pos += 16
96
+
97
+ # Read original size
98
+ original_size = data[pos, 8].unpack1("Q<")
99
+ pos += 8
100
+
101
+ # Read CRC
102
+ crc = data[pos, 4].unpack1("V")
103
+ pos += 4
104
+
105
+ # Read encrypted data
106
+ encrypted_data = data[pos, encrypted_size]
107
+
108
+ new(
109
+ encrypted_data: encrypted_data,
110
+ salt: salt,
111
+ iv: iv,
112
+ original_size: original_size,
113
+ crc: crc.zero? ? nil : crc,
114
+ )
115
+ end
116
+
117
+ # Check if header is valid
118
+ #
119
+ # @return [Boolean] true if has all required fields
120
+ def valid?
121
+ !@encrypted_data.nil? &&
122
+ !@salt.nil? &&
123
+ !@iv.nil? &&
124
+ @original_size.positive? &&
125
+ @encrypted_data.bytesize.positive?
126
+ end
127
+
128
+ # Verify CRC if set
129
+ #
130
+ # @return [Boolean] true if CRC matches or not set
131
+ def verify_crc
132
+ return true if @crc.nil?
133
+
134
+ require_relative "../../checksums/crc32"
135
+ calc_crc = Omnizip::Checksums::Crc32.new
136
+ calc_crc.update(@encrypted_data)
137
+ calc_crc.value == @crc
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require_relative "models/file_entry"
5
+
6
+ module Omnizip
7
+ module Formats
8
+ module SevenZip
9
+ # Collects files and directories for archiving
10
+ # Handles file metadata, timestamps, and attributes
11
+ class FileCollector
12
+ attr_reader :entries
13
+
14
+ # Initialize collector
15
+ def initialize
16
+ @entries = []
17
+ @base_path = nil
18
+ end
19
+
20
+ # Add path (file or directory) to collection
21
+ #
22
+ # @param path [String] Path to file or directory
23
+ # @param archive_path [String, nil] Path in archive (nil = auto)
24
+ # @param recursive [Boolean] Recursively add directories
25
+ def add_path(path, archive_path: nil, recursive: true)
26
+ path = File.expand_path(path)
27
+ raise "Path not found: #{path}" unless File.exist?(path)
28
+
29
+ @base_path ||= File.dirname(path)
30
+
31
+ if File.directory?(path)
32
+ add_directory(path, archive_path, recursive)
33
+ else
34
+ add_file(path, archive_path)
35
+ end
36
+ end
37
+
38
+ # Add files matching glob pattern
39
+ #
40
+ # @param pattern [String] Glob pattern
41
+ # @param base_path [String, nil] Base path for relative names
42
+ def add_glob(pattern, base_path: nil)
43
+ @base_path ||= base_path || Dir.pwd
44
+
45
+ Dir.glob(pattern).each do |path|
46
+ add_path(path)
47
+ end
48
+ end
49
+
50
+ # Get collected file entries
51
+ #
52
+ # @return [Array<Models::FileEntry>] File entries
53
+ def collect_files
54
+ @entries.sort_by(&:name)
55
+ end
56
+
57
+ private
58
+
59
+ # Add single file
60
+ #
61
+ # @param file_path [String] Full path to file
62
+ # @param archive_path [String, nil] Path in archive
63
+ def add_file(file_path, archive_path)
64
+ archive_name = archive_path || relative_path(file_path)
65
+
66
+ entry = Models::FileEntry.new.tap do |e|
67
+ e.name = archive_name
68
+ e.size = File.size(file_path)
69
+ e.has_stream = e.size.positive?
70
+ e.is_dir = false
71
+ e.mtime = File.mtime(file_path)
72
+ e.attributes = file_attributes(file_path)
73
+ e.source_path = file_path
74
+ end
75
+
76
+ @entries << entry
77
+ end
78
+
79
+ # Add directory and optionally its contents
80
+ #
81
+ # @param dir_path [String] Directory path
82
+ # @param archive_path [String, nil] Path in archive
83
+ # @param recursive [Boolean] Add contents recursively
84
+ def add_directory(dir_path, archive_path, recursive)
85
+ archive_name = archive_path || relative_path(dir_path)
86
+ archive_name += "/" unless archive_name.end_with?("/")
87
+
88
+ # Add directory entry
89
+ entry = Models::FileEntry.new.tap do |e|
90
+ e.name = archive_name
91
+ e.size = 0
92
+ e.has_stream = false
93
+ e.is_dir = true
94
+ e.mtime = File.mtime(dir_path)
95
+ e.attributes = file_attributes(dir_path)
96
+ end
97
+
98
+ @entries << entry
99
+
100
+ return unless recursive
101
+
102
+ # Add contents
103
+ Dir.each_child(dir_path) do |child|
104
+ child_path = File.join(dir_path, child)
105
+ add_path(child_path, archive_path: nil, recursive: true)
106
+ end
107
+ end
108
+
109
+ # Get relative path for archive
110
+ #
111
+ # @param path [String] Full path
112
+ # @return [String] Relative path
113
+ def relative_path(path)
114
+ if @base_path && path.start_with?(@base_path)
115
+ path[@base_path.length..].sub(%r{^/}, "")
116
+ else
117
+ File.basename(path)
118
+ end
119
+ end
120
+
121
+ # Get file attributes (Unix permissions as Windows attributes)
122
+ #
123
+ # @param path [String] File path
124
+ # @return [Integer] Attribute flags
125
+ def file_attributes(path)
126
+ attrs = 0
127
+ stat = File.stat(path)
128
+
129
+ # Windows FILE_ATTRIBUTE_DIRECTORY = 0x10
130
+ attrs |= 0x10 if stat.directory?
131
+
132
+ # Windows FILE_ATTRIBUTE_ARCHIVE = 0x20
133
+ attrs |= 0x20 unless stat.directory?
134
+
135
+ # Convert Unix permissions to Windows read-only flag
136
+ # FILE_ATTRIBUTE_READONLY = 0x01
137
+ attrs |= 0x01 unless stat.writable?
138
+
139
+ attrs
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end