omnizip 0.3.57 → 0.3.58

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: 1ea5d1a7c799ac0f1b17c60e1c715fc0bf95a2d8dc3d3a02e0776bac6efbccf0
4
- data.tar.gz: 198583bbdc571acdd26a8a1e25f4a6ce0e5aa6b33d613c247bf49556d164200c
3
+ metadata.gz: 04bb0d1c81ef7f4571014bb6679ad0d4750d4c078729daea82c88f643e246818
4
+ data.tar.gz: 7523e6a77a43db5eb02ec7c16ef4adf0751150129f329af82eb11297f93a68f6
5
5
  SHA512:
6
- metadata.gz: edaf17357204a214beecdd32e18bd53139bb6a7b9797b29a181a44db80b531e847f6d3e48da97f6ce5f02e80feeb456c71e593df92b471b4d5875a8d13ae1e98
7
- data.tar.gz: 6f82822274ad086eef57304f2386a43f979525dd6893f0eabf693b6c8c60a08a71729beb5c2a3328c8617871bbbc4b9d33a2b6801ae801eeb3614a8f4cbd6d4e
6
+ metadata.gz: da1c027f6e44246e6421760d3197501db38957aeb1541c0db6e3553ab73b5e03a221a362b0165d4196bf1185f0022b341529321cdce9c2a339c3cf2f31b4f733
7
+ data.tar.gz: 7732ed6d8268d006195f7648980e2f8619ea89d45767932afd587f508592f627697a9cc436f6f3e1a01b41a8a579034f654c1bc33cc3331fced28af5bd68b8ff
data/CHANGELOG.md CHANGED
@@ -7,6 +7,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.57] - 2026-09-02
11
+
12
+ ### Fixed
13
+ - TAR archives no longer corrupt silently on long paths: the writer
14
+ now splits entry names over 99 bytes across the ustar prefix +
15
+ name fields at a "/" boundary, the reader joins them back for
16
+ consumers, and paths no ustar fields can represent raise
17
+ `FormatError` instead of truncating. Verified against system tar.
18
+ - `:auto` profile sampling walked directories in the OS's
19
+ iteration order, resolving different files (and compression
20
+ settings) per platform; the walk is sorted and deterministic now.
21
+ - The getting-started docs' 7z examples used a Reader API that
22
+ never shipped (`each_file`, `close`, `Reader.info`) — every
23
+ snippet raised NoMethodError verbatim. Rewritten against the real
24
+ surface and executed to verify.
25
+
26
+ ### Changed
27
+ - The last 28 bare `raise "string"` sites (RAR tree, cpio entries,
28
+ parity internals, zip compat streams, two commands) gained their
29
+ matching error classes — `lib/` now contains zero bare raises.
30
+ - The dead `--preserve-ntfs-streams` CLI flag is removed; nothing
31
+ read it and no code path implements NTFS stream preservation.
32
+
10
33
  ## [0.3.56] - 2026-09-02
11
34
 
12
35
  ### Fixed
@@ -76,7 +76,7 @@ writer.write
76
76
 
77
77
  IMPORTANT: RAR5 CRC32 checksums only work with STORE compression. When LZMA is used, CRC32 is automatically disabled. Use BLAKE2sp (always present) for compressed file integrity.
78
78
 
79
- === RAR5 Multi-Volume Archives (v0.5.0)
79
+ === RAR5 Multi-Volume Archives
80
80
 
81
81
  Split large archives across multiple volumes:
82
82
 
@@ -110,36 +110,30 @@ volumes = writer.write
110
110
  # Minimum volume size: 64 KB
111
111
  ----
112
112
 
113
- === RAR5 Solid Compression (v0.5.0)
113
+ === RAR5 Solid Archives
114
114
 
115
- Achieve 10-30% better compression ratios for similar files:
115
+ `solid: true` requests a shared solid block, but the RAR-compatible
116
+ LZSS encoder is not implemented yet — the writer warns and writes
117
+ independent STORE entries instead, so the archive stays extractable
118
+ by official unrar:
116
119
 
117
120
  [source,ruby]
118
121
  ----
119
122
  require 'omnizip/formats/rar/rar5/writer'
120
123
 
121
- # Enable solid compression
122
124
  writer = Omnizip::Formats::Rar::Rar5::Writer.new('project.rar',
123
- compression: :lzma,
124
- level: 5,
125
- solid: true # Shared dictionary across files
125
+ solid: true # warns: falls back to independent STORE entries
126
126
  )
127
127
  writer.add_directory('source_code/')
128
128
  writer.write
129
+ ----
129
130
 
130
- # Best for:
131
- # - Source code repositories
132
- # - Log files
133
- # - Text documents
134
- # - Similar structured data
135
-
136
- # Trade-offs:
137
- # - Cannot extract individual files without decompressing entire block
138
- # - Corruption may affect multiple files
139
- # - Slightly longer extraction time for single files
131
+ Solid compression (shared dictionary across files, better ratios
132
+ for similar content) arrives when the RAR-compatible LZSS encoder
133
+ lands.
140
134
  ----
141
135
 
142
- === RAR5 AES-256 Encryption (v0.5.0)
136
+ === RAR5 AES-256 Encryption
143
137
 
144
138
  Password-protect archives with industry-standard encryption:
145
139
 
@@ -177,7 +171,7 @@ writer.write
177
171
  # - Password verification before decryption
178
172
  ----
179
173
 
180
- === RAR5 PAR2 Recovery Records (v0.5.0)
174
+ === RAR5 PAR2 Recovery Records
181
175
 
182
176
  Add error correction for archive recovery:
183
177
 
@@ -216,7 +210,7 @@ files = writer.write
216
210
  # - Works with multi-volume, solid, and encrypted archives
217
211
  ----
218
212
 
219
- === RAR5 Combined Features (v0.5.0)
213
+ === RAR5 Combined Features
220
214
 
221
215
  Use all features together for comprehensive protection:
222
216
 
@@ -262,13 +256,13 @@ puts " Total size: #{files.sum { |f| File.size(f) } / 1024 / 1024}MB"
262
256
 
263
257
  === RAR5 Best Practices
264
258
 
265
- **For Maximum Compression:**
259
+ **For Maximum Compatibility:**
266
260
  [source,ruby]
267
261
  ----
268
262
  writer = Omnizip::Formats::Rar::Rar5::Writer.new('archive.rar',
269
263
  compression: :lzma,
270
- level: 5, # Best compression
271
- solid: true, # 10-30% better ratios
264
+ level: 5, # Honored by the 7z-style writers; RAR5 entries
265
+ # are STORE until the LZSS encoder lands
272
266
  include_mtime: true
273
267
  )
274
268
  ----
@@ -80,7 +80,10 @@ module Omnizip
80
80
  end
81
81
  end
82
82
 
83
- ARCHIVE_EXTENSIONS = %w[.zip .7z .tar .rar .cpio .iso .rpm .xar .msi].freeze
83
+ # Archive-vs-stream routing derives from the registry's
84
+ # extension routes so new formats route here automatically
85
+ ARCHIVE_EXTENSIONS = (Convenience::ARCHIVE_FORMAT_EXTENSIONS.keys +
86
+ Convenience::READ_ARCHIVE_FORMAT_EXTENSIONS.keys).freeze
84
87
 
85
88
  private
86
89
 
@@ -199,6 +199,11 @@ module Omnizip
199
199
  if @options[:solid] && Compression::Lzss.available?
200
200
  write_solid_block(f, @files)
201
201
  else
202
+ if @options[:solid]
203
+ warn "omnizip: solid: true requested but the " \
204
+ "RAR-compatible LZSS encoder is not available " \
205
+ "— writing independent STORE entries instead"
206
+ end
202
207
  @files.each do |file|
203
208
  write_file_entry(f, file)
204
209
  end
@@ -152,6 +152,8 @@ module Omnizip
152
152
  end
153
153
 
154
154
  def write_precompressed_to_io(io, compression_method: COMPRESSION_DEFLATE)
155
+ check_classic_entry_count!
156
+ entries.each { |entry| check_classic_size_limit!(entry) }
155
157
  local_header_offsets = []
156
158
 
157
159
  entries.each do |entry|
@@ -189,6 +191,7 @@ module Omnizip
189
191
 
190
192
  # Write to an IO object
191
193
  def write_to_io(io, compression_method: COMPRESSION_DEFLATE, level: 6)
194
+ check_classic_entry_count!
192
195
  local_header_offsets = []
193
196
 
194
197
  # Write local file headers and data. An entry-level
@@ -220,6 +223,8 @@ module Omnizip
220
223
  entry[:crc32] = calculate_crc32(entry[:uncompressed_data])
221
224
  end
222
225
 
226
+ check_classic_size_limit!(entry)
227
+
223
228
  # Update local header with compressed sizes
224
229
  local_header.compressed_size = entry[:compressed_size]
225
230
  local_header.uncompressed_size = entry[:uncompressed_size]
@@ -234,6 +239,7 @@ module Omnizip
234
239
 
235
240
  # Record start of central directory
236
241
  central_directory_offset = io.pos
242
+ check_classic_offset_limit!(central_directory_offset)
237
243
 
238
244
  # Write central directory headers
239
245
  entries.each_with_index do |entry, index|
@@ -257,8 +263,42 @@ module Omnizip
257
263
  io.write(eocd.to_binary)
258
264
  end
259
265
 
266
+ # Classic (non-ZIP64) ZIP headers pack sizes and offsets as
267
+ # 32-bit values and entry counts as 16-bit; exceeding them
268
+ # raises instead of letting Array#pack fail with a bare
269
+ # RangeError. ZIP64 writing is not supported.
270
+ MAX_CLASSIC_SIZE = 0xFFFFFFFF
271
+ MAX_CLASSIC_ENTRIES = 0xFFFF
272
+ private_constant :MAX_CLASSIC_SIZE, :MAX_CLASSIC_ENTRIES
273
+
260
274
  private
261
275
 
276
+ def check_classic_entry_count!
277
+ return if entries.size <= MAX_CLASSIC_ENTRIES
278
+
279
+ raise Omnizip::UnsupportedFormatError,
280
+ "#{entries.size} entries exceed the classic ZIP " \
281
+ "limit of #{MAX_CLASSIC_ENTRIES} (ZIP64 writing is " \
282
+ "not supported)"
283
+ end
284
+
285
+ def check_classic_size_limit!(entry)
286
+ return if entry[:compressed_size].to_i <= MAX_CLASSIC_SIZE &&
287
+ entry[:uncompressed_size].to_i <= MAX_CLASSIC_SIZE
288
+
289
+ raise Omnizip::UnsupportedFormatError,
290
+ "entry #{entry[:filename].inspect} exceeds the 4 GiB " \
291
+ "classic ZIP size limit (ZIP64 writing is not supported)"
292
+ end
293
+
294
+ def check_classic_offset_limit!(offset)
295
+ return if offset <= MAX_CLASSIC_SIZE
296
+
297
+ raise Omnizip::UnsupportedFormatError,
298
+ "archive layout exceeds the 4 GiB classic ZIP " \
299
+ "offset limit (ZIP64 writing is not supported)"
300
+ end
301
+
262
302
  # Create an entry hash
263
303
  def create_entry(
264
304
  filename:,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Omnizip
4
- VERSION = "0.3.57"
4
+ VERSION = "0.3.58"
5
5
  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.3.57
4
+ version: 0.3.58
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-02 00:00:00.000000000 Z
11
+ date: 2026-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64