zip_tricks 5.2.0 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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