omnizip 0.4.0 → 0.4.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a04b0c83ee4e9c6b57823c8db709178ed2b88e073f658fb6573d9f69fa7459f
4
- data.tar.gz: 1c5d9b7e86c1d1322cfd8a8193fcec2c8b7a4d28a21b6ee4b6fca3a359bc01e3
3
+ metadata.gz: 48ed1a8b9fa1d9c51d338c611430fbd78f12de0a9d5d9de3ebff23ac3b9b767c
4
+ data.tar.gz: 6b173fab258e290030227c869b703631023c621699e810753259b14ef613ef34
5
5
  SHA512:
6
- metadata.gz: c22355d1136d66e0c6632ce6b4ad57a1b27c8cf826b0f5593318bffd20e85de77ed8072e280a88aa01433ef658fb1adc9139ff1ff8aa6d31735efb6aea1fc9f5
7
- data.tar.gz: b06259b9ca3ede7ed15bdfa33537a9d9a17099a59ac5b0d5dc95a4f29a46ead222641abf4e8a17f17a283b1272f99d589c3541d799da0f932fc58a1401aa0d2c
6
+ metadata.gz: 07fba2b58cca8f0c0429042e4a2813d5618158cb8231625ad1e6f5c32d1bc532d45a8bb952a3087d6274862647dbab0480aca8c96561f24c5a3debf2a1f7dd63
7
+ data.tar.gz: 8422215bde30fa926b235b20dddbeba195573a82d1678ea98d541be6e37e6e14c7a6ae444e53b1a4505733a6420a4d9d3a53cec3605c751c5bf6eac49678ef86
data/CHANGELOG.md CHANGED
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Fixed
11
+ - RAR recovery-record repair fails loudly instead of pretending:
12
+ `recover_with_reed_solomon` returned nil and `recover_with_xor`
13
+ applied a transform the record does not use. Neither unrar (its
14
+ recvol5/rs16 cover only the separate .rev volumes) nor any public
15
+ spec carries the in-archive RAR5 RS parameters, so both paths now
16
+ raise `NotImplementedError` with par2 guidance, surfaced through
17
+ `ArchiveRepairer` results. The `ozip repair` counterpart (Rust)
18
+ ships in omnizip-rs with the same honest contract.
19
+
20
+ ### Added
21
+ - `rake rust:build` — one command to build and vendor the Rust
22
+ backend's cdylib (clones omnizip-rs or reuses a checkout via
23
+ REPO=); the loader gains the `vendor/` resolution tier behind
24
+ `OMNIZIP_FFI_DYLIB`. No toolchain, no failure: the gem stays
25
+ pure Ruby. docs/rust-backend.md documents the tier policy,
26
+ resolution order, and CI pinning.
27
+
28
+
10
29
  ### Added
11
30
  - Rust-accelerated backend tier: `Omnizip::Backends` is the single
12
31
  tier switch between the pure-Ruby cores and the `omnizip-ffi`
File without changes
@@ -266,10 +266,16 @@ module Omnizip
266
266
  # @param parity_data [String] Parity information
267
267
  # @return [String, nil] Recovered data
268
268
  def recover_with_reed_solomon(_corrupted_data, _parity_data)
269
- # Placeholder for Reed-Solomon recovery
270
- # Real implementation would use reed-solomon gem
271
- # For now, return nil to indicate recovery not available
272
- nil
269
+ # The in-archive RAR5 recovery record's RS parameters exist
270
+ # only in the proprietary rar binary — unrar carries no
271
+ # implementation (its recvol5/rs16 cover only the separate
272
+ # .rev volume feature), and no independent spec is public.
273
+ # Fail loudly with actionable guidance instead of pretending
274
+ # recovery happened.
275
+ raise NotImplementedError,
276
+ "in-archive RAR5 Reed-Solomon recovery is not implemented " \
277
+ "(rar-proprietary format); protect archives with external " \
278
+ "parity (par2) instead"
273
279
  end
274
280
 
275
281
  # Recover data using XOR (RAR4)
@@ -277,14 +283,15 @@ module Omnizip
277
283
  # @param corrupted_data [String] Corrupted block
278
284
  # @param parity_data [String] Parity information
279
285
  # @return [String] Recovered data
280
- def recover_with_xor(corrupted_data, parity_data)
281
- # Simple XOR recovery
282
- result = corrupted_data.bytes.map.with_index do |byte, i|
283
- parity_byte = parity_data.bytes[i % parity_data.size]
284
- byte ^ parity_byte
285
- end
286
-
287
- result.pack("C*")
286
+ def recover_with_xor(_corrupted_data, _parity_data)
287
+ # RAR4's integrated recovery record is likewise rar-proprietary
288
+ # (unrar has no repair path for it either); a cyclic XOR with
289
+ # arbitrary parity bytes is not the record's actual transform
290
+ # and would silently fabricate corrupt bytes. Refuse honestly.
291
+ raise NotImplementedError,
292
+ "in-archive RAR4 recovery-record repair is not implemented " \
293
+ "(rar-proprietary format); protect archives with external " \
294
+ "parity (par2) instead"
288
295
  end
289
296
  end
290
297
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Omnizip
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.2"
5
5
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # One command to build the Rust-accelerated backend's cdylib into
4
+ # the gem's vendor dir (TODO.ref-parity/62 — the distribution
5
+ # story). Requires git + a Rust toolchain; the gem stays fully
6
+ # functional (pure Ruby) without ever running this.
7
+ #
8
+ # bundle exec rake rust:build
9
+ # bundle exec rake rust:build REPO=/path/to/omnizip-rs
10
+ desc "Build the omnizip-ffi cdylib into vendor/ for the Rust tier"
11
+ task "rust:build" do
12
+ repo = ENV.fetch("REPO", nil)
13
+ gem_root = File.expand_path("../..", __dir__)
14
+ build = File.join(gem_root, "build", "rust")
15
+
16
+ require "fileutils"
17
+ FileUtils.mkdir_p(build)
18
+ src = if repo
19
+ File.expand_path(repo)
20
+ else
21
+ target = File.join(build, "omnizip-rs")
22
+ if File.directory?(File.join(target, ".git"))
23
+ system("git", "-C", target, "fetch", "--quiet", "origin") or abort "git fetch failed in #{target}"
24
+ system("git", "-C", target, "reset", "--quiet", "--hard", "origin/main") or abort "git reset failed"
25
+ else
26
+ system("git", "clone", "--quiet", "--depth", "1",
27
+ "https://github.com/omnizip/omnizip-rs.git", target) or abort "clone failed"
28
+ end
29
+ target
30
+ end
31
+
32
+ abort "#{src} has no omnizip-ffi crate" unless File.directory?(File.join(src, "omnizip-ffi"))
33
+
34
+ system("cargo", "build", "--release", "-p", "omnizip-ffi", chdir: src) or abort "cargo build failed"
35
+
36
+ vendor = File.join(gem_root, "vendor")
37
+ FileUtils.mkdir_p(vendor)
38
+ %w[dylib so dll].each do |ext|
39
+ candidate = File.join(src, "target", "release", "libomnizip_ffi.#{ext}")
40
+ next unless File.file?(candidate)
41
+
42
+ FileUtils.cp(candidate, vendor)
43
+ puts "vendored: #{File.join(vendor, "libomnizip_ffi.#{ext}")}"
44
+ puts "tier: OMNIZIP_BACKEND=auto now uses the Rust decoders"
45
+ exit 0
46
+ end
47
+ abort "cdylib not found under #{src}/target/release"
48
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnizip
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-19 00:00:00.000000000 Z
11
+ date: 2026-09-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -211,6 +211,7 @@ files:
211
211
  - docs/reference/index.adoc
212
212
  - docs/resources/faq.adoc
213
213
  - docs/resources/quick-reference.adoc
214
+ - docs/rust-backend.md
214
215
  - docs/troubleshooting/index.adoc
215
216
  - docs/xar_format.md
216
217
  - examples/api_comparison.rb
@@ -722,6 +723,7 @@ files:
722
723
  - lib/omnizip/zip/input_stream.rb
723
724
  - lib/omnizip/zip/output_stream.rb
724
725
  - lib/tasks/msi_test_files.rake
726
+ - lib/tasks/rust_backend.rake
725
727
  - readme-docs/advanced-features.adoc
726
728
  - readme-docs/api-usage.adoc
727
729
  - readme-docs/architecture.adoc