2021-05-24 01:24:22 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-01-16 06:11:23 +08:00
|
|
|
require 'forwardable'
|
|
|
|
|
2022-02-08 06:05:19 +08:00
|
|
|
require_relative 'dirtyable'
|
|
|
|
|
2010-11-30 16:27:59 +08:00
|
|
|
module Zip
|
2022-11-07 05:26:37 +08:00
|
|
|
class CentralDirectory # :nodoc:
|
2022-01-16 06:11:23 +08:00
|
|
|
extend Forwardable
|
2022-02-08 06:05:19 +08:00
|
|
|
include Dirtyable
|
2022-01-16 06:11:23 +08:00
|
|
|
|
2022-01-18 01:45:19 +08:00
|
|
|
END_OF_CD_SIG = 0x06054b50
|
|
|
|
ZIP64_END_OF_CD_SIG = 0x06064b50
|
|
|
|
ZIP64_EOCD_LOCATOR_SIG = 0x07064b50
|
2022-01-12 04:16:53 +08:00
|
|
|
|
2013-08-27 04:26:14 +08:00
|
|
|
STATIC_EOCD_SIZE = 22
|
2021-06-11 20:50:09 +08:00
|
|
|
ZIP64_STATIC_EOCD_SIZE = 56
|
2022-01-12 04:16:53 +08:00
|
|
|
ZIP64_EOCD_LOC_SIZE = 20
|
2022-01-18 01:45:19 +08:00
|
|
|
MAX_FILE_COMMENT_SIZE = (1 << 16) - 1
|
|
|
|
MAX_END_OF_CD_SIZE =
|
|
|
|
MAX_FILE_COMMENT_SIZE + STATIC_EOCD_SIZE + ZIP64_EOCD_LOC_SIZE
|
2010-11-30 16:27:59 +08:00
|
|
|
|
2022-01-15 21:10:54 +08:00
|
|
|
attr_accessor :comment
|
|
|
|
|
2022-01-16 06:11:23 +08:00
|
|
|
def_delegators :@entry_set,
|
|
|
|
:<<, :delete, :each, :entries, :find_entry, :glob,
|
|
|
|
:include?, :size
|
2010-11-30 16:27:59 +08:00
|
|
|
|
2022-02-08 06:05:19 +08:00
|
|
|
mark_dirty :<<, :comment=, :delete
|
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def initialize(entries = EntrySet.new, comment = '') # :nodoc:
|
2022-02-08 06:05:19 +08:00
|
|
|
super(dirty_on_create: false)
|
2015-06-08 15:45:23 +08:00
|
|
|
@entry_set = entries.kind_of?(EntrySet) ? entries : EntrySet.new(entries)
|
2013-08-27 04:26:14 +08:00
|
|
|
@comment = comment
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
|
|
|
|
2022-01-18 06:04:45 +08:00
|
|
|
def read_from_stream(io)
|
|
|
|
read_eocds(io)
|
|
|
|
read_central_directory_entries(io)
|
|
|
|
end
|
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def write_to_stream(io) # :nodoc:
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
cdir_offset = io.tell
|
2013-06-03 02:33:03 +08:00
|
|
|
@entry_set.each { |entry| entry.write_c_dir_entry(io) }
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
eocd_offset = io.tell
|
|
|
|
cdir_size = eocd_offset - cdir_offset
|
2022-11-18 02:02:32 +08:00
|
|
|
if Zip.write_zip64_support &&
|
|
|
|
(cdir_offset > 0xFFFFFFFF || cdir_size > 0xFFFFFFFF || @entry_set.size > 0xFFFF)
|
|
|
|
write_64_e_o_c_d(io, cdir_offset, cdir_size)
|
|
|
|
write_64_eocd_locator(io, eocd_offset)
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
end
|
|
|
|
write_e_o_c_d(io, cdir_offset, cdir_size)
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
|
|
|
|
2022-01-18 06:04:45 +08:00
|
|
|
# Reads the End of Central Directory Record (and the Zip64 equivalent if
|
|
|
|
# needs be) and returns the number of entries in the archive. This is a
|
|
|
|
# convenience method that avoids reading in all of the entry data to get a
|
|
|
|
# very quick entry count.
|
|
|
|
def count_entries(io)
|
|
|
|
read_eocds(io)
|
|
|
|
@size
|
|
|
|
end
|
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def ==(other) # :nodoc:
|
2022-01-18 06:04:45 +08:00
|
|
|
return false unless other.kind_of?(CentralDirectory)
|
|
|
|
|
|
|
|
@entry_set.entries.sort == other.entries.sort && comment == other.comment
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def write_e_o_c_d(io, offset, cdir_size) # :nodoc:
|
2012-02-14 06:03:34 +08:00
|
|
|
tmp = [
|
2022-01-18 01:45:19 +08:00
|
|
|
END_OF_CD_SIG,
|
2013-06-03 02:33:03 +08:00
|
|
|
0, # @numberOfThisDisk
|
|
|
|
0, # @numberOfDiskWithStartOfCDir
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
@entry_set ? [@entry_set.size, 0xFFFF].min : 0,
|
|
|
|
@entry_set ? [@entry_set.size, 0xFFFF].min : 0,
|
|
|
|
[cdir_size, 0xFFFFFFFF].min,
|
|
|
|
[offset, 0xFFFFFFFF].min,
|
2014-07-23 17:54:43 +08:00
|
|
|
@comment ? @comment.bytesize : 0
|
2012-02-14 06:03:34 +08:00
|
|
|
]
|
|
|
|
io << tmp.pack('VvvvvVVv')
|
|
|
|
io << @comment
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
2013-06-03 02:33:03 +08:00
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def write_64_e_o_c_d(io, offset, cdir_size) # :nodoc:
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
tmp = [
|
2022-01-18 01:45:19 +08:00
|
|
|
ZIP64_END_OF_CD_SIG,
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
44, # size of zip64 end of central directory record (excludes signature and field itself)
|
|
|
|
VERSION_MADE_BY,
|
|
|
|
VERSION_NEEDED_TO_EXTRACT_ZIP64,
|
|
|
|
0, # @numberOfThisDisk
|
|
|
|
0, # @numberOfDiskWithStartOfCDir
|
|
|
|
@entry_set ? @entry_set.size : 0, # number of entries on this disk
|
|
|
|
@entry_set ? @entry_set.size : 0, # number of entries total
|
|
|
|
cdir_size, # size of central directory
|
2019-09-22 17:06:20 +08:00
|
|
|
offset # offset of start of central directory in its disk
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
]
|
|
|
|
io << tmp.pack('VQ<vvVVQ<Q<Q<Q<')
|
|
|
|
end
|
|
|
|
|
|
|
|
def write_64_eocd_locator(io, zip64_eocd_offset)
|
|
|
|
tmp = [
|
2022-01-18 01:45:19 +08:00
|
|
|
ZIP64_EOCD_LOCATOR_SIG,
|
Add read/write support for zip64 extensions
This commit adds the capability of creating archives larger than
4GB via zip64 extensions. It also fixes bugs reading archives of
this size (specifically, the 64-bit offset of the local file
header was not being read from the central directory entry).
To maximize compatibility, zip64 extensions are used only when
required. Unfortunately, at the time we write a local file header,
we don't know the size of the file and thus whether a Zip64
Extended Information Extra Field will be required. Therefore
this commit writes a 'placeholder' extra field to reserve space
for the zip64 entry, which will be written if necessary when
we update the local entry with the final sizes and CRC. I use
the signature "\x99\x99" for this field, following the example
of DotNetZip which does the same.
This commit also adds a rake task, zip64_full_test, which
fully tests zip64 by actually creating and verifying a 4GB zip
file. Please note, however, that this test requires UnZip
version 6.00 or newer, which may not be supplied by your OS.
This test doesn't run along with the main unit tests because
it takes a few minutes to complete.
2013-09-28 10:41:00 +08:00
|
|
|
0, # number of disk containing the start of zip64 eocd record
|
|
|
|
zip64_eocd_offset, # offset of the start of zip64 eocd record in its disk
|
|
|
|
1 # total number of disks
|
|
|
|
]
|
|
|
|
io << tmp.pack('VVQ<V')
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
2013-06-03 02:33:03 +08:00
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def unpack_64_e_o_c_d(buffer) # :nodoc:
|
2022-01-18 01:45:19 +08:00
|
|
|
_, # ZIP64_END_OF_CD_SIG. We know we have this at this point.
|
2021-06-11 20:50:09 +08:00
|
|
|
@size_of_zip64_e_o_c_d,
|
|
|
|
@version_made_by,
|
|
|
|
@version_needed_for_extract,
|
|
|
|
@number_of_this_disk,
|
|
|
|
@number_of_disk_with_start_of_cdir,
|
|
|
|
@total_number_of_entries_in_cdir_on_this_disk,
|
|
|
|
@size,
|
|
|
|
@size_in_bytes,
|
2022-01-18 01:45:19 +08:00
|
|
|
@cdir_offset = buffer.unpack('VQ<vvVVQ<Q<Q<Q<')
|
2021-06-11 20:50:09 +08:00
|
|
|
|
|
|
|
zip64_extensible_data_size =
|
|
|
|
@size_of_zip64_e_o_c_d - ZIP64_STATIC_EOCD_SIZE + 12
|
|
|
|
@zip64_extensible_data = if zip64_extensible_data_size.zero?
|
|
|
|
''
|
|
|
|
else
|
|
|
|
buffer.slice(
|
|
|
|
ZIP64_STATIC_EOCD_SIZE,
|
|
|
|
zip64_extensible_data_size
|
|
|
|
)
|
|
|
|
end
|
2013-08-27 04:26:14 +08:00
|
|
|
end
|
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def unpack_64_eocd_locator(buffer) # :nodoc:
|
2022-01-18 01:45:19 +08:00
|
|
|
_, # ZIP64_EOCD_LOCATOR_SIG. We know we have this at this point.
|
|
|
|
_, zip64_eocd_offset, = buffer.unpack('VVQ<V')
|
2021-06-11 05:44:51 +08:00
|
|
|
|
2022-01-18 01:45:19 +08:00
|
|
|
zip64_eocd_offset
|
|
|
|
end
|
2021-06-11 05:44:51 +08:00
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def unpack_e_o_c_d(buffer) # :nodoc:
|
2022-01-18 01:45:19 +08:00
|
|
|
_, # END_OF_CD_SIG. We know we have this at this point.
|
2021-06-12 06:23:34 +08:00
|
|
|
num_disk,
|
|
|
|
num_disk_cdir,
|
|
|
|
num_cdir_disk,
|
|
|
|
num_entries,
|
|
|
|
size_in_bytes,
|
|
|
|
cdir_offset,
|
2022-01-18 01:45:19 +08:00
|
|
|
comment_length = buffer.unpack('VvvvvVVv')
|
2021-06-11 05:44:51 +08:00
|
|
|
|
2021-06-12 06:23:34 +08:00
|
|
|
@number_of_this_disk = num_disk unless num_disk == 0xFFFF
|
|
|
|
@number_of_disk_with_start_of_cdir = num_disk_cdir unless num_disk_cdir == 0xFFFF
|
|
|
|
@total_number_of_entries_in_cdir_on_this_disk = num_cdir_disk unless num_cdir_disk == 0xFFFF
|
|
|
|
@size = num_entries unless num_entries == 0xFFFF
|
|
|
|
@size_in_bytes = size_in_bytes unless size_in_bytes == 0xFFFFFFFF
|
|
|
|
@cdir_offset = cdir_offset unless cdir_offset == 0xFFFFFFFF
|
|
|
|
|
2021-06-11 05:44:51 +08:00
|
|
|
@comment = if comment_length.positive?
|
2022-01-18 01:45:19 +08:00
|
|
|
buffer.slice(STATIC_EOCD_SIZE, comment_length)
|
2021-06-11 05:44:51 +08:00
|
|
|
else
|
|
|
|
''
|
|
|
|
end
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
2011-11-18 04:53:04 +08:00
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def read_central_directory_entries(io) # :nodoc:
|
2021-06-18 18:44:58 +08:00
|
|
|
# `StringIO` doesn't raise `EINVAL` if you seek beyond the current end,
|
|
|
|
# so we need to catch that *and* query `io#eof?` here.
|
|
|
|
eof = false
|
2010-11-30 16:27:59 +08:00
|
|
|
begin
|
2013-08-27 04:26:14 +08:00
|
|
|
io.seek(@cdir_offset, IO::SEEK_SET)
|
2010-11-30 16:27:59 +08:00
|
|
|
rescue Errno::EINVAL
|
2021-06-18 18:44:58 +08:00
|
|
|
eof = true
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
2021-06-18 18:44:58 +08:00
|
|
|
raise Error, 'Zip consistency problem while reading central directory entry' if eof || io.eof?
|
|
|
|
|
2013-06-03 15:56:24 +08:00
|
|
|
@entry_set = EntrySet.new
|
2012-02-14 00:55:08 +08:00
|
|
|
@size.times do
|
2020-09-21 01:11:49 +08:00
|
|
|
entry = Entry.read_c_dir_entry(io)
|
|
|
|
next unless entry
|
|
|
|
|
2022-02-23 18:13:13 +08:00
|
|
|
offset = if entry.zip64?
|
2020-09-21 01:11:49 +08:00
|
|
|
entry.extra['Zip64'].relative_header_offset
|
|
|
|
else
|
|
|
|
entry.local_header_offset
|
|
|
|
end
|
|
|
|
|
|
|
|
unless offset.nil?
|
|
|
|
io_save = io.tell
|
|
|
|
io.seek(offset, IO::SEEK_SET)
|
2021-11-17 05:42:11 +08:00
|
|
|
entry.read_extra_field(read_local_extra_field(io), local: true)
|
2020-09-21 01:11:49 +08:00
|
|
|
io.seek(io_save, IO::SEEK_SET)
|
|
|
|
end
|
|
|
|
|
|
|
|
@entry_set << entry
|
2012-02-14 00:55:08 +08:00
|
|
|
end
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
2011-11-18 04:53:04 +08:00
|
|
|
|
2020-09-21 01:11:49 +08:00
|
|
|
def read_local_extra_field(io)
|
|
|
|
buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH) || ''
|
|
|
|
return '' unless buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
|
|
|
|
|
|
|
|
head, _, _, _, _, _, _, _, _, _, n_len, e_len = buf.unpack('VCCvvvvVVVvv')
|
|
|
|
return '' unless head == ::Zip::LOCAL_ENTRY_SIGNATURE
|
|
|
|
|
|
|
|
io.seek(n_len, IO::SEEK_CUR) # Skip over the entry name.
|
|
|
|
io.read(e_len)
|
|
|
|
end
|
|
|
|
|
2024-03-02 06:14:48 +08:00
|
|
|
def read_eocds(io) # :nodoc:
|
2022-01-18 01:45:19 +08:00
|
|
|
base_location, data = eocd_data(io)
|
|
|
|
|
|
|
|
eocd_location = data.rindex([END_OF_CD_SIG].pack('V'))
|
|
|
|
raise Error, 'Zip end of central directory signature not found' unless eocd_location
|
2011-11-18 04:53:04 +08:00
|
|
|
|
2022-01-18 01:45:19 +08:00
|
|
|
zip64_eocd_locator = data.rindex([ZIP64_EOCD_LOCATOR_SIG].pack('V'))
|
|
|
|
|
|
|
|
if zip64_eocd_locator
|
|
|
|
zip64_eocd_location = data.rindex([ZIP64_END_OF_CD_SIG].pack('V'))
|
|
|
|
|
|
|
|
zip64_eocd_data =
|
|
|
|
if zip64_eocd_location
|
|
|
|
data.slice(zip64_eocd_location..zip64_eocd_locator)
|
|
|
|
else
|
|
|
|
zip64_eocd_location = unpack_64_eocd_locator(
|
|
|
|
data.slice(zip64_eocd_locator..eocd_location)
|
|
|
|
)
|
|
|
|
unless zip64_eocd_location
|
|
|
|
raise Error, 'Zip64 end of central directory signature not found'
|
|
|
|
end
|
|
|
|
|
|
|
|
io.seek(zip64_eocd_location, IO::SEEK_SET)
|
|
|
|
io.read(base_location + zip64_eocd_locator - zip64_eocd_location)
|
|
|
|
end
|
|
|
|
|
|
|
|
unpack_64_e_o_c_d(zip64_eocd_data)
|
|
|
|
end
|
|
|
|
|
|
|
|
unpack_e_o_c_d(data.slice(eocd_location..-1))
|
2013-08-27 04:26:14 +08:00
|
|
|
end
|
|
|
|
|
2022-01-18 01:45:19 +08:00
|
|
|
def eocd_data(io)
|
2010-11-30 16:27:59 +08:00
|
|
|
begin
|
2022-01-18 01:45:19 +08:00
|
|
|
io.seek(-MAX_END_OF_CD_SIZE, IO::SEEK_END)
|
2010-11-30 16:27:59 +08:00
|
|
|
rescue Errno::EINVAL
|
2011-11-18 04:53:04 +08:00
|
|
|
io.seek(0, IO::SEEK_SET)
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
2022-01-18 01:45:19 +08:00
|
|
|
|
|
|
|
[io.tell, io.read]
|
2013-08-27 04:26:14 +08:00
|
|
|
end
|
2010-11-30 16:27:59 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-03 02:33:03 +08:00
|
|
|
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
|
|
# rubyzip is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the ruby license.
|