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,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require_relative "../algorithm_registry"
5
+
6
+ module Omnizip
7
+ module Formats
8
+ # BZIP2 file format
9
+ #
10
+ # BZIP2 is a file compression format that uses the BZip2 algorithm
11
+ # with block-sorting compression (Burrows-Wheeler Transform).
12
+ #
13
+ # Format structure:
14
+ # - Magic bytes: "BZh" (0x42 0x5A 0x68)
15
+ # - Block size indicator: '1'-'9' (100KB - 900KB)
16
+ # - Compressed blocks
17
+ # - End-of-stream marker
18
+ #
19
+ # The format supports multiple compressed blocks, each with its own
20
+ # CRC32 checksum for data integrity verification.
21
+ module Bzip2File
22
+ # BZIP2 magic bytes
23
+ BZIP2_MAGIC = "BZh"
24
+
25
+ # Block size markers ('1' to '9')
26
+ BLOCK_SIZE_MIN = 1
27
+ BLOCK_SIZE_MAX = 9
28
+
29
+ # Stream markers
30
+ STREAM_MAGIC = 0x314159265359 # π in hex
31
+ BLOCK_MAGIC = 0x177245385090 # Block start marker
32
+ STREAM_END_MAGIC = 0x177245385090 # Stream end marker
33
+
34
+ class << self
35
+ # Compress a file with BZIP2
36
+ #
37
+ # @param input_path [String] Input file path
38
+ # @param output_path [String] Output BZIP2 file path
39
+ # @param options [Hash] Compression options
40
+ # @option options [Integer] :level Compression level (1-9)
41
+ def compress(input_path, output_path, options = {})
42
+ input_data = File.binread(input_path)
43
+
44
+ File.open(output_path, "wb") do |output|
45
+ compress_stream(StringIO.new(input_data), output, options)
46
+ end
47
+ end
48
+
49
+ # Decompress a BZIP2 file
50
+ #
51
+ # @param input_path [String] Input BZIP2 file path
52
+ # @param output_path [String] Output file path
53
+ def decompress(input_path, output_path)
54
+ File.open(input_path, "rb") do |input|
55
+ File.open(output_path, "wb") do |output|
56
+ decompress_stream(input, output)
57
+ end
58
+ end
59
+ end
60
+
61
+ # Compress data stream with BZIP2
62
+ #
63
+ # @param input_io [IO] Input stream
64
+ # @param output_io [IO] Output stream
65
+ # @param options [Hash] Compression options
66
+ def compress_stream(input_io, output_io, options = {})
67
+ level = options[:level] || 9
68
+ level = level.clamp(BLOCK_SIZE_MIN, BLOCK_SIZE_MAX)
69
+
70
+ input_data = input_io.read
71
+
72
+ # Write BZIP2 header
73
+ write_header(output_io, level)
74
+
75
+ # Get BZip2 algorithm
76
+ bzip2 = AlgorithmRegistry.get(:bzip2).new
77
+
78
+ # Compress data
79
+ compressed_io = StringIO.new
80
+ compressed_io.set_encoding(Encoding::BINARY)
81
+
82
+ bzip2.compress(
83
+ StringIO.new(input_data),
84
+ compressed_io,
85
+ build_compression_options(level),
86
+ )
87
+
88
+ # Write compressed data
89
+ compressed_io.rewind
90
+ compressed_data = compressed_io.read
91
+ output_io.write(compressed_data)
92
+ end
93
+
94
+ # Decompress BZIP2 stream
95
+ #
96
+ # @param input_io [IO] Input stream
97
+ # @param output_io [IO] Output stream
98
+ def decompress_stream(input_io, output_io)
99
+ # Read and verify header
100
+ read_header(input_io)
101
+
102
+ # Get BZip2 algorithm
103
+ bzip2 = AlgorithmRegistry.get(:bzip2).new
104
+
105
+ # Decompress data
106
+ decompressed_io = StringIO.new
107
+ decompressed_io.set_encoding(Encoding::BINARY)
108
+
109
+ bzip2.decompress(input_io, decompressed_io)
110
+
111
+ # Write decompressed data
112
+ decompressed_io.rewind
113
+ output_io.write(decompressed_io.read)
114
+ end
115
+
116
+ # Register BZIP2 format when loaded
117
+ def register!
118
+ require_relative "../format_registry"
119
+ FormatRegistry.register(".bz2", Omnizip::Formats::Bzip2File)
120
+ FormatRegistry.register(".bzip2", Omnizip::Formats::Bzip2File)
121
+ end
122
+
123
+ private
124
+
125
+ # Write BZIP2 header
126
+ #
127
+ # @param output [IO] Output stream
128
+ # @param level [Integer] Compression level (1-9)
129
+ def write_header(output, level)
130
+ # BZIP2 magic: "BZh" + block size
131
+ header = "#{BZIP2_MAGIC}#{level}"
132
+ output.write(header)
133
+ end
134
+
135
+ # Read BZIP2 header
136
+ #
137
+ # @param input [IO] Input stream
138
+ # @return [Integer] Block size level
139
+ def read_header(input)
140
+ magic = input.read(3)
141
+ unless magic == BZIP2_MAGIC
142
+ raise Error, "Not a BZIP2 file (invalid magic bytes)"
143
+ end
144
+
145
+ level_char = input.read(1)
146
+ level = level_char.to_i
147
+
148
+ unless level.between?(BLOCK_SIZE_MIN, BLOCK_SIZE_MAX)
149
+ raise Error, "Invalid BZIP2 block size: #{level_char}"
150
+ end
151
+
152
+ level
153
+ end
154
+
155
+ # Build compression options
156
+ #
157
+ # @param level [Integer] Compression level
158
+ # @return [Object] Compression options
159
+ def build_compression_options(level)
160
+ require_relative "../models/compression_options"
161
+
162
+ Models::CompressionOptions.new.tap do |opts|
163
+ opts.level = level
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ # Auto-register on load
172
+ Omnizip::Formats::Bzip2File.register!
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Omnizip
4
+ module Formats
5
+ module Cpio
6
+ # CPIO format constants
7
+ #
8
+ # Defines magic numbers, file types, and format specifications
9
+ # for different CPIO archive formats.
10
+ module Constants
11
+ # Magic numbers for different CPIO formats
12
+ MAGIC_BINARY = 0o070707 # Old binary format
13
+ MAGIC_ODC = "070707" # Old portable ASCII format
14
+ MAGIC_NEWC = "070701" # New ASCII format (SVR4, most common)
15
+ MAGIC_CRC = "070702" # New ASCII with CRC
16
+
17
+ # File type masks (from POSIX)
18
+ S_IFMT = 0o170000 # File type mask
19
+ S_IFSOCK = 0o140000 # Socket
20
+ S_IFLNK = 0o120000 # Symbolic link
21
+ S_IFREG = 0o100000 # Regular file
22
+ S_IFBLK = 0o060000 # Block device
23
+ S_IFDIR = 0o040000 # Directory
24
+ S_IFCHR = 0o020000 # Character device
25
+ S_IFIFO = 0o010000 # FIFO/pipe
26
+
27
+ # Permission bits
28
+ S_ISUID = 0o004000 # Set UID bit
29
+ S_ISGID = 0o002000 # Set GID bit
30
+ S_ISVTX = 0o001000 # Sticky bit
31
+ S_IRWXU = 0o000700 # User permissions
32
+ S_IRUSR = 0o000400 # User read
33
+ S_IWUSR = 0o000200 # User write
34
+ S_IXUSR = 0o000100 # User execute
35
+ S_IRWXG = 0o000070 # Group permissions
36
+ S_IRGRP = 0o000040 # Group read
37
+ S_IWGRP = 0o000020 # Group write
38
+ S_IXGRP = 0o000010 # Group execute
39
+ S_IRWXO = 0o000007 # Other permissions
40
+ S_IROTH = 0o000004 # Other read
41
+ S_IWOTH = 0o000002 # Other write
42
+ S_IXOTH = 0o000001 # Other execute
43
+
44
+ # CPIO newc header size (110 bytes for newc format)
45
+ NEWC_HEADER_SIZE = 110
46
+
47
+ # Trailer entry name
48
+ TRAILER_NAME = "TRAILER!!!"
49
+
50
+ # Alignment for newc format (4 bytes)
51
+ NEWC_ALIGNMENT = 4
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,385 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "constants"
4
+
5
+ module Omnizip
6
+ module Formats
7
+ module Cpio
8
+ # CPIO archive entry
9
+ #
10
+ # Represents a file, directory, or special file in a CPIO archive.
11
+ # Supports newc, CRC, and ODC formats.
12
+ class Entry
13
+ include Constants
14
+
15
+ # @return [String] Magic number identifying format
16
+ attr_accessor :magic
17
+
18
+ # @return [Integer] Inode number
19
+ attr_accessor :ino
20
+
21
+ # @return [Integer] File mode and type
22
+ attr_accessor :mode
23
+
24
+ # @return [Integer] User ID
25
+ attr_accessor :uid
26
+
27
+ # @return [Integer] Group ID
28
+ attr_accessor :gid
29
+
30
+ # @return [Integer] Number of hard links
31
+ attr_accessor :nlink
32
+
33
+ # @return [Integer] Modification time (Unix timestamp)
34
+ attr_accessor :mtime
35
+
36
+ # @return [Integer] File size in bytes
37
+ attr_accessor :filesize
38
+
39
+ # @return [Integer] Device major number
40
+ attr_accessor :dev_major
41
+
42
+ # @return [Integer] Device minor number
43
+ attr_accessor :dev_minor
44
+
45
+ # @return [Integer] Special device major number (for device files)
46
+ attr_accessor :rdev_major
47
+
48
+ # @return [Integer] Special device minor number (for device files)
49
+ attr_accessor :rdev_minor
50
+
51
+ # @return [Integer] Filename length (including null terminator)
52
+ attr_accessor :namesize
53
+
54
+ # @return [Integer] Checksum (CRC format only)
55
+ attr_accessor :checksum
56
+
57
+ # @return [String] Entry name/path
58
+ attr_accessor :name
59
+
60
+ # @return [String] File data
61
+ attr_accessor :data
62
+
63
+ # Initialize CPIO entry
64
+ #
65
+ # @param attributes [Hash] Entry attributes
66
+ def initialize(attributes = {})
67
+ @magic = attributes.fetch(:magic, MAGIC_NEWC)
68
+ @ino = attributes.fetch(:ino, 0)
69
+ @mode = attributes.fetch(:mode, S_IFREG | 0o644)
70
+ @uid = attributes.fetch(:uid, 0)
71
+ @gid = attributes.fetch(:gid, 0)
72
+ @nlink = attributes.fetch(:nlink, 1)
73
+ @mtime = attributes.fetch(:mtime, Time.now.to_i)
74
+ @filesize = attributes.fetch(:filesize, 0)
75
+ @dev_major = attributes.fetch(:dev_major, 0)
76
+ @dev_minor = attributes.fetch(:dev_minor, 0)
77
+ @rdev_major = attributes.fetch(:rdev_major, 0)
78
+ @rdev_minor = attributes.fetch(:rdev_minor, 0)
79
+ @namesize = attributes.fetch(:namesize, 0)
80
+ @checksum = attributes.fetch(:checksum, 0)
81
+ @name = attributes.fetch(:name, "")
82
+ @data = attributes.fetch(:data, "")
83
+
84
+ # Auto-calculate namesize if not provided
85
+ @namesize = @name.bytesize + 1 if @namesize.zero? && !@name.empty?
86
+ @filesize = @data.bytesize if @filesize.zero? && !@data.empty?
87
+ end
88
+
89
+ # Check if entry is a directory
90
+ #
91
+ # @return [Boolean] true if directory
92
+ def directory?
93
+ (@mode & S_IFMT) == S_IFDIR
94
+ end
95
+
96
+ # Check if entry is a regular file
97
+ #
98
+ # @return [Boolean] true if regular file
99
+ def file?
100
+ (@mode & S_IFMT) == S_IFREG
101
+ end
102
+
103
+ # Check if entry is a symbolic link
104
+ #
105
+ # @return [Boolean] true if symlink
106
+ def symlink?
107
+ (@mode & S_IFMT) == S_IFLNK
108
+ end
109
+
110
+ # Check if entry is a device
111
+ #
112
+ # @return [Boolean] true if device (block or character)
113
+ def device?
114
+ type = @mode & S_IFMT
115
+ [S_IFBLK, S_IFCHR].include?(type)
116
+ end
117
+
118
+ # Check if entry is the trailer
119
+ #
120
+ # @return [Boolean] true if trailer entry
121
+ def trailer?
122
+ @name == TRAILER_NAME
123
+ end
124
+
125
+ # Convert entry to binary format
126
+ #
127
+ # @param format [Symbol] CPIO format (:newc, :crc, :odc)
128
+ # @return [String] Binary representation
129
+ def to_binary(format: :newc)
130
+ case format
131
+ when :newc, :crc
132
+ to_newc_binary
133
+ when :odc
134
+ to_odc_binary
135
+ else
136
+ raise ArgumentError, "Unsupported CPIO format: #{format}"
137
+ end
138
+ end
139
+
140
+ # Convert to newc format binary
141
+ #
142
+ # @return [String] Binary data in newc format
143
+ def to_newc_binary
144
+ # Build header (110 bytes, ASCII hex)
145
+ header = format(
146
+ "%06s%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
147
+ @magic,
148
+ @ino & 0xFFFFFFFF,
149
+ @mode & 0xFFFFFFFF,
150
+ @uid & 0xFFFFFFFF,
151
+ @gid & 0xFFFFFFFF,
152
+ @nlink & 0xFFFFFFFF,
153
+ @mtime & 0xFFFFFFFF,
154
+ @filesize & 0xFFFFFFFF,
155
+ @dev_major & 0xFFFFFFFF,
156
+ @dev_minor & 0xFFFFFFFF,
157
+ @rdev_major & 0xFFFFFFFF,
158
+ @rdev_minor & 0xFFFFFFFF,
159
+ @namesize & 0xFFFFFFFF,
160
+ @checksum & 0xFFFFFFFF,
161
+ )
162
+
163
+ # Assemble complete entry
164
+ result = +""
165
+ result << header
166
+ result << @name
167
+ result << "\x00"
168
+
169
+ # Pad header+name to 4-byte boundary
170
+ header_name_size = header.bytesize + @name.bytesize + 1
171
+ padding = padding_to_align(header_name_size, NEWC_ALIGNMENT)
172
+ result << ("\x00" * padding) if padding.positive?
173
+
174
+ # Add file data
175
+ result << @data
176
+
177
+ # Pad data to 4-byte boundary
178
+ data_padding = padding_to_align(@data.bytesize, NEWC_ALIGNMENT)
179
+ result << ("\x00" * data_padding) if data_padding.positive?
180
+
181
+ result
182
+ end
183
+
184
+ # Convert to ODC format binary
185
+ #
186
+ # @return [String] Binary data in ODC format
187
+ def to_odc_binary
188
+ # ODC format uses 6-character octal fields
189
+ header = format(
190
+ "%06o%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o",
191
+ MAGIC_BINARY,
192
+ (@dev_major << 8) | @dev_minor,
193
+ @ino & 0o777777,
194
+ @mode & 0o777777,
195
+ @uid & 0o777777,
196
+ @gid & 0o777777,
197
+ @nlink & 0o777777,
198
+ (@rdev_major << 8) | @rdev_minor,
199
+ @mtime & 0o77777777777,
200
+ @namesize & 0o777777,
201
+ @filesize & 0o77777777777,
202
+ )
203
+
204
+ result = +""
205
+ result << header
206
+ result << @name
207
+ result << "\x00"
208
+ result << @data
209
+
210
+ result
211
+ end
212
+
213
+ # Parse entry from binary data
214
+ #
215
+ # @param io [IO] Input stream
216
+ # @param format [Symbol, nil] Format hint (:newc, :crc, :odc, nil=auto-detect)
217
+ # @return [Entry] Parsed entry
218
+ def self.parse(io, format: nil)
219
+ # Read magic to detect format
220
+ magic = io.read(6)
221
+ io.seek(-6, ::IO::SEEK_CUR) # Rewind
222
+
223
+ format ||= detect_format(magic)
224
+
225
+ case format
226
+ when :newc, :crc
227
+ parse_newc(io)
228
+ when :odc
229
+ parse_odc(io)
230
+ else
231
+ raise "Unknown CPIO format"
232
+ end
233
+ end
234
+
235
+ # Detect CPIO format from magic
236
+ #
237
+ # @param magic [String] Magic bytes
238
+ # @return [Symbol] Format type
239
+ def self.detect_format(magic)
240
+ case magic
241
+ when MAGIC_NEWC then :newc
242
+ when MAGIC_CRC then :crc
243
+ when MAGIC_ODC then :odc
244
+ else
245
+ # Try binary format
246
+ magic_int = magic.unpack1("n")
247
+ magic_int == MAGIC_BINARY ? :binary : nil
248
+ end
249
+ end
250
+
251
+ # Parse newc format entry
252
+ #
253
+ # @param io [IO] Input stream
254
+ # @return [Entry] Parsed entry
255
+ def self.parse_newc(io)
256
+ header = io.read(NEWC_HEADER_SIZE)
257
+ raise "Truncated CPIO header" unless header && header.bytesize == NEWC_HEADER_SIZE
258
+
259
+ # Parse ASCII hex fields
260
+ magic = header[0, 6]
261
+ ino = header[6, 8].to_i(16)
262
+ mode = header[14, 8].to_i(16)
263
+ uid = header[22, 8].to_i(16)
264
+ gid = header[30, 8].to_i(16)
265
+ nlink = header[38, 8].to_i(16)
266
+ mtime = header[46, 8].to_i(16)
267
+ filesize = header[54, 8].to_i(16)
268
+ dev_major = header[62, 8].to_i(16)
269
+ dev_minor = header[70, 8].to_i(16)
270
+ rdev_major = header[78, 8].to_i(16)
271
+ rdev_minor = header[86, 8].to_i(16)
272
+ namesize = header[94, 8].to_i(16)
273
+ checksum = header[102, 8].to_i(16)
274
+
275
+ # Read filename
276
+ name_data = io.read(namesize)
277
+ name = name_data.chomp("\x00")
278
+
279
+ # Skip padding to 4-byte boundary
280
+ header_name_size = NEWC_HEADER_SIZE + namesize
281
+ padding = padding_to_align(header_name_size, NEWC_ALIGNMENT)
282
+ io.read(padding) if padding.positive?
283
+
284
+ # Read file data
285
+ data = io.read(filesize)
286
+
287
+ # Skip padding to 4-byte boundary
288
+ data_padding = padding_to_align(filesize, NEWC_ALIGNMENT)
289
+ io.read(data_padding) if data_padding.positive?
290
+
291
+ new(
292
+ magic: magic,
293
+ ino: ino,
294
+ mode: mode,
295
+ uid: uid,
296
+ gid: gid,
297
+ nlink: nlink,
298
+ mtime: mtime,
299
+ filesize: filesize,
300
+ dev_major: dev_major,
301
+ dev_minor: dev_minor,
302
+ rdev_major: rdev_major,
303
+ rdev_minor: rdev_minor,
304
+ namesize: namesize,
305
+ checksum: checksum,
306
+ name: name,
307
+ data: data || "",
308
+ )
309
+ end
310
+
311
+ # Parse ODC format entry
312
+ #
313
+ # @param io [IO] Input stream
314
+ # @return [Entry] Parsed entry
315
+ def self.parse_odc(io)
316
+ header = io.read(76)
317
+ raise "Truncated CPIO header" unless header && header.bytesize == 76
318
+
319
+ # Parse octal fields
320
+ magic = header[0, 6]
321
+ dev = header[6, 6].to_i(8)
322
+ ino = header[12, 6].to_i(8)
323
+ mode = header[18, 6].to_i(8)
324
+ uid = header[24, 6].to_i(8)
325
+ gid = header[30, 6].to_i(8)
326
+ nlink = header[36, 6].to_i(8)
327
+ rdev = header[42, 6].to_i(8)
328
+ mtime = header[48, 11].to_i(8)
329
+ namesize = header[59, 6].to_i(8)
330
+ filesize = header[65, 11].to_i(8)
331
+
332
+ # Extract device numbers
333
+ dev_major = dev >> 8
334
+ dev_minor = dev & 0xFF
335
+ rdev_major = rdev >> 8
336
+ rdev_minor = rdev & 0xFF
337
+
338
+ # Read filename
339
+ name_data = io.read(namesize)
340
+ name = name_data.chomp("\x00")
341
+
342
+ # Read file data
343
+ data = io.read(filesize)
344
+
345
+ new(
346
+ magic: magic,
347
+ ino: ino,
348
+ mode: mode,
349
+ uid: uid,
350
+ gid: gid,
351
+ nlink: nlink,
352
+ mtime: mtime,
353
+ filesize: filesize,
354
+ dev_major: dev_major,
355
+ dev_minor: dev_minor,
356
+ rdev_major: rdev_major,
357
+ rdev_minor: rdev_minor,
358
+ namesize: namesize,
359
+ checksum: 0,
360
+ name: name,
361
+ data: data || "",
362
+ )
363
+ end
364
+
365
+ private
366
+
367
+ # Calculate padding needed to align to boundary
368
+ #
369
+ # @param size [Integer] Current size
370
+ # @param alignment [Integer] Alignment boundary
371
+ # @return [Integer] Padding bytes needed
372
+ def padding_to_align(size, alignment)
373
+ remainder = size % alignment
374
+ remainder.zero? ? 0 : alignment - remainder
375
+ end
376
+
377
+ # Class method for padding calculation
378
+ def self.padding_to_align(size, alignment)
379
+ remainder = size % alignment
380
+ remainder.zero? ? 0 : alignment - remainder
381
+ end
382
+ end
383
+ end
384
+ end
385
+ end