zip_tricks 5.2.0 → 5.3.0
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 +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +9 -0
- data/lib/zip_tricks/file_reader.rb +3 -1
- data/lib/zip_tricks/streamer.rb +40 -8
- data/lib/zip_tricks/streamer/entry.rb +5 -1
- data/lib/zip_tricks/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 96ce140b83c0f42fa013278de28cf3c2668fcec1bf1150951c6e6a6a00291125
|
4
|
+
data.tar.gz: f5f3fbca524376d336c04dd3f2e728bc7315187f70cefcaf97958a247b19e95d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c794589191612f8ceba1fbef03e801a9610a7d29b5593a7d4ceecd27466706de10aa44ceb152771a13fc3aba42b38a8989104704284c4bfd18b14eb3d5828af
|
7
|
+
data.tar.gz: 65e8f07cd490e0a40a6770064eb76d85d9b43177f5fed7b5c46afa68d9347ae67f4c22e140924a9ae476932856e8ed9cd732d217ee5d7cc643971dac8b92729e
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 5.3
|
2
|
+
|
3
|
+
* Raise in `Streamer#close` when the IO offset of the Streamer does not match the size of the written entries. This is a situation which
|
4
|
+
can occur if one adds the local headers, writes the bodies of the files to the socket/output directly, and forgets to adjust the internal
|
5
|
+
Streamer offset. The unadjusted offset would then produce incorrect values in both the local headers which come after the missing
|
6
|
+
offset adjustment _and_ in the central directory headers. Some ZIP unarchivers are able to recover from this (ones that read
|
7
|
+
files "straight-ahead" but others aren't - if the ZIP unarchiver uses central directory entries it would be using incorrect offsets.
|
8
|
+
Instead of producing an invalid ZIP, raise an exception which explains what happened and how it can be resolved.
|
9
|
+
|
1
10
|
## 5.2
|
2
11
|
|
3
12
|
* Remove `Streamer#add_compressed_entry` and `SizeEstimator#add_compressed_entry`
|
@@ -82,7 +82,9 @@ class ZipTricks::FileReader
|
|
82
82
|
|
83
83
|
private_constant :StoredReader, :InflatingReader
|
84
84
|
|
85
|
-
# Represents a file within the ZIP archive being read
|
85
|
+
# Represents a file within the ZIP archive being read. This is different from
|
86
|
+
# the Entry object used in Streamer for ZIP writing, since during writing more
|
87
|
+
# data can be kept in memory for immediate use.
|
86
88
|
class ZipEntry
|
87
89
|
# @return [Fixnum] bit-packed version signature of the program that made the archive
|
88
90
|
attr_accessor :made_by
|
data/lib/zip_tricks/streamer.rb
CHANGED
@@ -91,6 +91,7 @@ class ZipTricks::Streamer
|
|
91
91
|
InvalidOutput = Class.new(ArgumentError)
|
92
92
|
Overflow = Class.new(StandardError)
|
93
93
|
UnknownMode = Class.new(StandardError)
|
94
|
+
OffsetOutOfSync = Class.new(StandardError)
|
94
95
|
|
95
96
|
private_constant :DeflatedWriter, :StoredWriter, :STORED, :DEFLATED
|
96
97
|
|
@@ -149,7 +150,6 @@ class ZipTricks::Streamer
|
|
149
150
|
@dedupe_filenames = auto_rename_duplicate_filenames
|
150
151
|
@out = ZipTricks::WriteAndTell.new(stream)
|
151
152
|
@files = []
|
152
|
-
@local_header_offsets = []
|
153
153
|
@path_set = ZipTricks::PathSet.new
|
154
154
|
@writer = writer
|
155
155
|
end
|
@@ -360,14 +360,16 @@ class ZipTricks::Streamer
|
|
360
360
|
#
|
361
361
|
# @return [Integer] the offset the output IO is at after closing the archive
|
362
362
|
def close
|
363
|
+
# Make sure offsets are in order
|
364
|
+
verify_offsets!
|
365
|
+
|
363
366
|
# Record the central directory offset, so that it can be written into the EOCD record
|
364
367
|
cdir_starts_at = @out.tell
|
365
368
|
|
366
369
|
# Write out the central directory entries, one for each file
|
367
|
-
@files.
|
368
|
-
header_loc = @local_header_offsets.fetch(i)
|
370
|
+
@files.each do |entry|
|
369
371
|
@writer.write_central_directory_file_header(io: @out,
|
370
|
-
local_file_header_location:
|
372
|
+
local_file_header_location: entry.local_header_offset,
|
371
373
|
gp_flags: entry.gp_flags,
|
372
374
|
storage_mode: entry.storage_mode,
|
373
375
|
compressed_size: entry.compressed_size,
|
@@ -420,15 +422,40 @@ class ZipTricks::Streamer
|
|
420
422
|
last_entry.compressed_size = compressed_size
|
421
423
|
last_entry.uncompressed_size = uncompressed_size
|
422
424
|
|
425
|
+
offset_before_data_descriptor = @out.tell
|
423
426
|
@writer.write_data_descriptor(io: @out,
|
424
427
|
crc32: last_entry.crc32,
|
425
428
|
compressed_size: last_entry.compressed_size,
|
426
429
|
uncompressed_size: last_entry.uncompressed_size)
|
430
|
+
last_entry.bytes_used_for_data_descriptor = @out.tell - offset_before_data_descriptor
|
431
|
+
|
427
432
|
@out.tell
|
428
433
|
end
|
429
434
|
|
430
435
|
private
|
431
436
|
|
437
|
+
def verify_offsets!
|
438
|
+
# We need to check whether the offsets noted for the entries actually make sense
|
439
|
+
computed_offset = @files.map(&:total_bytes_used).inject(0, &:+)
|
440
|
+
actual_offset = @out.tell
|
441
|
+
if computed_offset != actual_offset
|
442
|
+
message = <<-EMS
|
443
|
+
The offset of the Streamer output IO is out of sync with the expected value. All entries written so far,
|
444
|
+
including their compressed bodies, local headers and data descriptors, add up to a certain offset,
|
445
|
+
but this offset does not match the actual offset of the IO.
|
446
|
+
|
447
|
+
Entries add up to #{computed_offset} bytes and the IO is at #{actual_offset} bytes.
|
448
|
+
|
449
|
+
This can happen if you write local headers for an entry, write the "body" of the entry directly to the IO
|
450
|
+
object which is your destination, but do not adjust the offset known to the Streamer object. To adjust
|
451
|
+
the offfset you need to call `Streamer#simulate_write(body_size)` after outputting the entry. Otherwise
|
452
|
+
the local header offsets of the entries you write are going to be incorrect and some ZIP applications
|
453
|
+
are going to have problems opening your archive.
|
454
|
+
EMS
|
455
|
+
raise OffsetOutOfSync, message
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
432
459
|
def add_file_and_write_local_header(
|
433
460
|
filename:,
|
434
461
|
modification_time:,
|
@@ -461,16 +488,18 @@ class ZipTricks::Streamer
|
|
461
488
|
uncompressed_size = 0
|
462
489
|
end
|
463
490
|
|
491
|
+
local_header_starts_at = @out.tell
|
492
|
+
|
464
493
|
e = Entry.new(filename,
|
465
494
|
crc32,
|
466
495
|
compressed_size,
|
467
496
|
uncompressed_size,
|
468
497
|
storage_mode,
|
469
498
|
modification_time,
|
470
|
-
use_data_descriptor
|
471
|
-
|
472
|
-
|
473
|
-
|
499
|
+
use_data_descriptor,
|
500
|
+
_local_file_header_offset = local_header_starts_at,
|
501
|
+
_bytes_used_for_local_header = 0,
|
502
|
+
_bytes_used_for_data_descriptor = 0)
|
474
503
|
|
475
504
|
@writer.write_local_file_header(io: @out,
|
476
505
|
gp_flags: e.gp_flags,
|
@@ -480,6 +509,9 @@ class ZipTricks::Streamer
|
|
480
509
|
mtime: e.mtime,
|
481
510
|
filename: e.filename,
|
482
511
|
storage_mode: e.storage_mode)
|
512
|
+
e.bytes_used_for_local_header = @out.tell - e.local_header_offset
|
513
|
+
|
514
|
+
@files << e
|
483
515
|
end
|
484
516
|
|
485
517
|
def remove_backslash(filename)
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Normally you will not have to use this class directly
|
5
5
|
class ZipTricks::Streamer::Entry < Struct.new(:filename, :crc32, :compressed_size,
|
6
6
|
:uncompressed_size, :storage_mode, :mtime,
|
7
|
-
:use_data_descriptor)
|
7
|
+
:use_data_descriptor, :local_header_offset, :bytes_used_for_local_header, :bytes_used_for_data_descriptor)
|
8
8
|
def initialize(*)
|
9
9
|
super
|
10
10
|
filename.force_encoding(Encoding::UTF_8)
|
@@ -15,6 +15,10 @@ class ZipTricks::Streamer::Entry < Struct.new(:filename, :crc32, :compressed_siz
|
|
15
15
|
end)
|
16
16
|
end
|
17
17
|
|
18
|
+
def total_bytes_used
|
19
|
+
bytes_used_for_local_header + compressed_size + bytes_used_for_data_descriptor
|
20
|
+
end
|
21
|
+
|
18
22
|
# Set the general purpose flags for the entry. We care about is the EFS
|
19
23
|
# bit (bit 11) which should be set if the filename is UTF8. If it is, we need to set the
|
20
24
|
# bit so that the unarchiving application knows that the filename in the archive is UTF-8
|
data/lib/zip_tricks/version.rb
CHANGED