rubyzip 1.1.7 → 1.2.1
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.
Potentially problematic release.
This version of rubyzip might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +75 -40
- data/Rakefile +3 -4
- data/lib/zip.rb +3 -5
- data/lib/zip/central_directory.rb +7 -7
- data/lib/zip/compressor.rb +0 -0
- data/lib/zip/constants.rb +2 -2
- data/lib/zip/crypto/null_encryption.rb +3 -3
- data/lib/zip/crypto/traditional_encryption.rb +5 -5
- data/lib/zip/decompressor.rb +2 -2
- data/lib/zip/deflater.rb +8 -6
- data/lib/zip/dos_time.rb +4 -5
- data/lib/zip/entry.rb +75 -81
- data/lib/zip/entry_set.rb +11 -11
- data/lib/zip/errors.rb +1 -0
- data/lib/zip/extra_field.rb +6 -6
- data/lib/zip/extra_field/generic.rb +7 -7
- data/lib/zip/extra_field/ntfs.rb +14 -16
- data/lib/zip/extra_field/old_unix.rb +9 -10
- data/lib/zip/extra_field/universal_time.rb +14 -14
- data/lib/zip/extra_field/unix.rb +8 -9
- data/lib/zip/extra_field/zip64.rb +12 -11
- data/lib/zip/extra_field/zip64_placeholder.rb +1 -1
- data/lib/zip/file.rb +47 -60
- data/lib/zip/filesystem.rb +132 -135
- data/lib/zip/inflater.rb +3 -3
- data/lib/zip/input_stream.rb +13 -7
- data/lib/zip/ioextras.rb +1 -3
- data/lib/zip/ioextras/abstract_input_stream.rb +5 -9
- data/lib/zip/ioextras/abstract_output_stream.rb +2 -4
- data/lib/zip/null_compressor.rb +2 -2
- data/lib/zip/null_decompressor.rb +3 -3
- data/lib/zip/null_input_stream.rb +0 -0
- data/lib/zip/output_stream.rb +8 -9
- data/lib/zip/pass_thru_compressor.rb +4 -4
- data/lib/zip/pass_thru_decompressor.rb +2 -3
- data/lib/zip/streamable_directory.rb +2 -2
- data/lib/zip/streamable_stream.rb +2 -2
- data/lib/zip/version.rb +1 -1
- data/samples/example.rb +29 -39
- data/samples/example_filesystem.rb +16 -18
- data/samples/example_recursive.rb +32 -25
- data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +23 -25
- data/samples/qtzip.rb +17 -26
- data/samples/write_simple.rb +12 -13
- data/samples/zipfind.rb +24 -32
- data/test/basic_zip_file_test.rb +11 -15
- data/test/case_sensitivity_test.rb +69 -0
- data/test/central_directory_entry_test.rb +32 -36
- data/test/central_directory_test.rb +46 -50
- data/test/crypto/null_encryption_test.rb +8 -4
- data/test/crypto/traditional_encryption_test.rb +5 -5
- data/test/data/notzippedruby.rb +1 -1
- data/test/data/oddExtraField.zip +0 -0
- data/test/data/test.xls +0 -0
- data/test/deflater_test.rb +10 -12
- data/test/encryption_test.rb +2 -2
- data/test/entry_set_test.rb +50 -25
- data/test/entry_test.rb +76 -87
- data/test/errors_test.rb +0 -2
- data/test/extra_field_test.rb +19 -21
- data/test/file_extract_directory_test.rb +12 -14
- data/test/file_extract_test.rb +33 -40
- data/test/file_permissions_test.rb +69 -0
- data/test/file_split_test.rb +24 -27
- data/test/file_test.rb +196 -172
- data/test/filesystem/dir_iterator_test.rb +13 -17
- data/test/filesystem/directory_test.rb +80 -90
- data/test/filesystem/file_mutating_test.rb +51 -63
- data/test/filesystem/file_nonmutating_test.rb +222 -228
- data/test/filesystem/file_stat_test.rb +17 -19
- data/test/gentestfiles.rb +47 -55
- data/test/inflater_test.rb +1 -1
- data/test/input_stream_test.rb +46 -34
- data/test/ioextras/abstract_input_stream_test.rb +22 -23
- data/test/ioextras/abstract_output_stream_test.rb +32 -32
- data/test/ioextras/fake_io_test.rb +1 -1
- data/test/local_entry_test.rb +36 -38
- data/test/output_stream_test.rb +20 -21
- data/test/pass_thru_compressor_test.rb +5 -6
- data/test/pass_thru_decompressor_test.rb +0 -1
- data/test/samples/example_recursive_test.rb +37 -0
- data/test/settings_test.rb +18 -15
- data/test/test_helper.rb +50 -44
- data/test/unicode_file_names_and_comments_test.rb +5 -7
- data/test/zip64_full_test.rb +9 -11
- data/test/zip64_support_test.rb +0 -1
- metadata +14 -32
    
        data/lib/zip/errors.rb
    CHANGED
    
    
    
        data/lib/zip/extra_field.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ module Zip | |
| 3 3 | 
             
                ID_MAP = {}
         | 
| 4 4 |  | 
| 5 5 | 
             
                def initialize(binstr = nil)
         | 
| 6 | 
            -
                  binstr  | 
| 6 | 
            +
                  merge(binstr) if binstr
         | 
| 7 7 | 
             
                end
         | 
| 8 8 |  | 
| 9 9 | 
             
                def extra_field_type_exist(binstr, id, len, i)
         | 
| @@ -51,7 +51,7 @@ module Zip | |
| 51 51 | 
             
                end
         | 
| 52 52 |  | 
| 53 53 | 
             
                def create(name)
         | 
| 54 | 
            -
                  unless field_class = ID_MAP.values.find { |k| k.name == name }
         | 
| 54 | 
            +
                  unless (field_class = ID_MAP.values.find { |k| k.name == name })
         | 
| 55 55 | 
             
                    raise Error, "Unknown extra field '#{name}'"
         | 
| 56 56 | 
             
                  end
         | 
| 57 57 | 
             
                  self[name] = field_class.new
         | 
| @@ -61,7 +61,7 @@ module Zip | |
| 61 61 | 
             
                # does not prevent known fields from being read back in
         | 
| 62 62 | 
             
                def ordered_values
         | 
| 63 63 | 
             
                  result = []
         | 
| 64 | 
            -
                   | 
| 64 | 
            +
                  each { |k, v| k == 'Unknown' ? result.push(v) : result.unshift(v) }
         | 
| 65 65 | 
             
                  result
         | 
| 66 66 | 
             
                end
         | 
| 67 67 |  | 
| @@ -69,7 +69,7 @@ module Zip | |
| 69 69 | 
             
                  ordered_values.map! { |v| v.to_local_bin.force_encoding('BINARY') }.join
         | 
| 70 70 | 
             
                end
         | 
| 71 71 |  | 
| 72 | 
            -
                alias  | 
| 72 | 
            +
                alias to_s to_local_bin
         | 
| 73 73 |  | 
| 74 74 | 
             
                def to_c_dir_bin
         | 
| 75 75 | 
             
                  ordered_values.map! { |v| v.to_c_dir_bin.force_encoding('BINARY') }.join
         | 
| @@ -83,8 +83,8 @@ module Zip | |
| 83 83 | 
             
                  to_local_bin.bytesize
         | 
| 84 84 | 
             
                end
         | 
| 85 85 |  | 
| 86 | 
            -
                alias  | 
| 87 | 
            -
                alias  | 
| 86 | 
            +
                alias length local_size
         | 
| 87 | 
            +
                alias size local_size
         | 
| 88 88 | 
             
              end
         | 
| 89 89 | 
             
            end
         | 
| 90 90 |  | 
| @@ -2,12 +2,12 @@ module Zip | |
| 2 2 | 
             
              class ExtraField::Generic
         | 
| 3 3 | 
             
                def self.register_map
         | 
| 4 4 | 
             
                  if self.const_defined?(:HEADER_ID)
         | 
| 5 | 
            -
                    ::Zip::ExtraField::ID_MAP[ | 
| 5 | 
            +
                    ::Zip::ExtraField::ID_MAP[const_get(:HEADER_ID)] = self
         | 
| 6 6 | 
             
                  end
         | 
| 7 7 | 
             
                end
         | 
| 8 8 |  | 
| 9 9 | 
             
                def self.name
         | 
| 10 | 
            -
                  @name ||=  | 
| 10 | 
            +
                  @name ||= to_s.split('::')[-1]
         | 
| 11 11 | 
             
                end
         | 
| 12 12 |  | 
| 13 13 | 
             
                # return field [size, content] or false
         | 
| @@ -16,28 +16,28 @@ module Zip | |
| 16 16 | 
             
                    # If nil, start with empty.
         | 
| 17 17 | 
             
                    return false
         | 
| 18 18 | 
             
                  elsif binstr[0, 2] != self.class.const_get(:HEADER_ID)
         | 
| 19 | 
            -
                    $stderr.puts  | 
| 19 | 
            +
                    $stderr.puts 'Warning: weired extra feild header ID. skip parsing'
         | 
| 20 20 | 
             
                    return false
         | 
| 21 21 | 
             
                  end
         | 
| 22 | 
            -
                  [binstr[2, 2].unpack( | 
| 22 | 
            +
                  [binstr[2, 2].unpack('v')[0], binstr[4..-1]]
         | 
| 23 23 | 
             
                end
         | 
| 24 24 |  | 
| 25 25 | 
             
                def ==(other)
         | 
| 26 26 | 
             
                  return false if self.class != other.class
         | 
| 27 27 | 
             
                  each do |k, v|
         | 
| 28 | 
            -
                    v != other[k] | 
| 28 | 
            +
                    return false if v != other[k]
         | 
| 29 29 | 
             
                  end
         | 
| 30 30 | 
             
                  true
         | 
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| 33 33 | 
             
                def to_local_bin
         | 
| 34 34 | 
             
                  s = pack_for_local
         | 
| 35 | 
            -
                  self.class.const_get(:HEADER_ID) + [s.bytesize].pack( | 
| 35 | 
            +
                  self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
         | 
| 36 36 | 
             
                end
         | 
| 37 37 |  | 
| 38 38 | 
             
                def to_c_dir_bin
         | 
| 39 39 | 
             
                  s = pack_for_c_dir
         | 
| 40 | 
            -
                  self.class.const_get(:HEADER_ID) + [s.bytesize].pack( | 
| 40 | 
            +
                  self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
         | 
| 41 41 | 
             
                end
         | 
| 42 42 | 
             
              end
         | 
| 43 43 | 
             
            end
         | 
    
        data/lib/zip/extra_field/ntfs.rb
    CHANGED
    
    | @@ -5,14 +5,14 @@ module Zip | |
| 5 5 | 
             
                HEADER_ID = [0x000A].pack('v')
         | 
| 6 6 | 
             
                register_map
         | 
| 7 7 |  | 
| 8 | 
            -
                WINDOWS_TICK =  | 
| 9 | 
            -
                SEC_TO_UNIX_EPOCH =  | 
| 8 | 
            +
                WINDOWS_TICK = 10_000_000.0
         | 
| 9 | 
            +
                SEC_TO_UNIX_EPOCH = 11_644_473_600
         | 
| 10 10 |  | 
| 11 11 | 
             
                def initialize(binstr = nil)
         | 
| 12 12 | 
             
                  @ctime = nil
         | 
| 13 13 | 
             
                  @mtime = nil
         | 
| 14 14 | 
             
                  @atime = nil
         | 
| 15 | 
            -
                  binstr  | 
| 15 | 
            +
                  binstr && merge(binstr)
         | 
| 16 16 | 
             
                end
         | 
| 17 17 |  | 
| 18 18 | 
             
                attr_accessor :atime, :ctime, :mtime
         | 
| @@ -20,18 +20,17 @@ module Zip | |
| 20 20 | 
             
                def merge(binstr)
         | 
| 21 21 | 
             
                  return if binstr.empty?
         | 
| 22 22 | 
             
                  size, content = initial_parse(binstr)
         | 
| 23 | 
            -
                  (size && content)  | 
| 23 | 
            +
                  (size && content) || return
         | 
| 24 24 |  | 
| 25 25 | 
             
                  content = content[4..-1]
         | 
| 26 26 | 
             
                  tags = parse_tags(content)
         | 
| 27 27 |  | 
| 28 28 | 
             
                  tag1 = tags[1]
         | 
| 29 | 
            -
                   | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
                  end
         | 
| 29 | 
            +
                  return unless tag1
         | 
| 30 | 
            +
                  ntfs_mtime, ntfs_atime, ntfs_ctime = tag1.unpack('Q<Q<Q<')
         | 
| 31 | 
            +
                  ntfs_mtime && @mtime ||= from_ntfs_time(ntfs_mtime)
         | 
| 32 | 
            +
                  ntfs_atime && @atime ||= from_ntfs_time(ntfs_atime)
         | 
| 33 | 
            +
                  ntfs_ctime && @ctime ||= from_ntfs_time(ntfs_ctime)
         | 
| 35 34 | 
             
                end
         | 
| 36 35 |  | 
| 37 36 | 
             
                def ==(other)
         | 
| @@ -48,16 +47,14 @@ module Zip | |
| 48 47 | 
             
                # But 7-zip for Windows only stores at central dir
         | 
| 49 48 | 
             
                def pack_for_c_dir
         | 
| 50 49 | 
             
                  # reserved 0 and tag 1
         | 
| 51 | 
            -
                  s = [0, 1].pack( | 
| 50 | 
            +
                  s = [0, 1].pack('Vv')
         | 
| 52 51 |  | 
| 53 52 | 
             
                  tag1 = ''.force_encoding(Encoding::BINARY)
         | 
| 54 53 | 
             
                  if @mtime
         | 
| 55 54 | 
             
                    tag1 << [to_ntfs_time(@mtime)].pack('Q<')
         | 
| 56 55 | 
             
                    if @atime
         | 
| 57 56 | 
             
                      tag1 << [to_ntfs_time(@atime)].pack('Q<')
         | 
| 58 | 
            -
                      if @ctime
         | 
| 59 | 
            -
                        tag1 << [to_ntfs_time(@ctime)].pack('Q<')
         | 
| 60 | 
            -
                      end
         | 
| 57 | 
            +
                      tag1 << [to_ntfs_time(@ctime)].pack('Q<') if @ctime
         | 
| 61 58 | 
             
                    end
         | 
| 62 59 | 
             
                  end
         | 
| 63 60 | 
             
                  s << [tag1.bytesize].pack('v') << tag1
         | 
| @@ -65,11 +62,12 @@ module Zip | |
| 65 62 | 
             
                end
         | 
| 66 63 |  | 
| 67 64 | 
             
                private
         | 
| 65 | 
            +
             | 
| 68 66 | 
             
                def parse_tags(content)
         | 
| 69 67 | 
             
                  return {} if content.nil?
         | 
| 70 68 | 
             
                  tags = {}
         | 
| 71 69 | 
             
                  i = 0
         | 
| 72 | 
            -
                  while i < content.bytesize | 
| 70 | 
            +
                  while i < content.bytesize
         | 
| 73 71 | 
             
                    tag, size = content[i, 4].unpack('vv')
         | 
| 74 72 | 
             
                    i += 4
         | 
| 75 73 | 
             
                    break unless tag && size
         | 
| @@ -89,4 +87,4 @@ module Zip | |
| 89 87 | 
             
                  ((time.to_f + SEC_TO_UNIX_EPOCH) * WINDOWS_TICK).to_i
         | 
| 90 88 | 
             
                end
         | 
| 91 89 | 
             
              end
         | 
| 92 | 
            -
            end
         | 
| 90 | 
            +
            end
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            module Zip
         | 
| 2 2 | 
             
              # Olf Info-ZIP Extra for UNIX uid/gid and file timestampes
         | 
| 3 3 | 
             
              class ExtraField::OldUnix < ExtraField::Generic
         | 
| 4 | 
            -
                HEADER_ID =  | 
| 4 | 
            +
                HEADER_ID = 'UX'
         | 
| 5 5 | 
             
                register_map
         | 
| 6 6 |  | 
| 7 7 | 
             
                def initialize(binstr = nil)
         | 
| @@ -9,7 +9,7 @@ module Zip | |
| 9 9 | 
             
                  @gid = 0
         | 
| 10 10 | 
             
                  @atime = nil
         | 
| 11 11 | 
             
                  @mtime = nil
         | 
| 12 | 
            -
                  binstr  | 
| 12 | 
            +
                  binstr && merge(binstr)
         | 
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                attr_accessor :uid, :gid, :atime, :mtime
         | 
| @@ -18,8 +18,8 @@ module Zip | |
| 18 18 | 
             
                  return if binstr.empty?
         | 
| 19 19 | 
             
                  size, content = initial_parse(binstr)
         | 
| 20 20 | 
             
                  # size: 0 for central directory. 4 for local header
         | 
| 21 | 
            -
                  return if  | 
| 22 | 
            -
                  atime, mtime, uid, gid = content.unpack( | 
| 21 | 
            +
                  return if !size || size == 0
         | 
| 22 | 
            +
                  atime, mtime, uid, gid = content.unpack('VVvv')
         | 
| 23 23 | 
             
                  @uid ||= uid
         | 
| 24 24 | 
             
                  @gid ||= gid
         | 
| 25 25 | 
             
                  @atime ||= atime
         | 
| @@ -29,17 +29,16 @@ module Zip | |
| 29 29 | 
             
                def ==(other)
         | 
| 30 30 | 
             
                  @uid == other.uid &&
         | 
| 31 31 | 
             
                    @gid == other.gid &&
         | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 32 | 
            +
                    @atime == other.atime &&
         | 
| 33 | 
            +
                    @mtime == other.mtime
         | 
| 34 34 | 
             
                end
         | 
| 35 35 |  | 
| 36 36 | 
             
                def pack_for_local
         | 
| 37 | 
            -
                  [@atime, @mtime, @uid, @gid].pack( | 
| 37 | 
            +
                  [@atime, @mtime, @uid, @gid].pack('VVvv')
         | 
| 38 38 | 
             
                end
         | 
| 39 39 |  | 
| 40 40 | 
             
                def pack_for_c_dir
         | 
| 41 | 
            -
                  [@atime, @mtime].pack( | 
| 41 | 
            +
                  [@atime, @mtime].pack('VV')
         | 
| 42 42 | 
             
                end
         | 
| 43 43 | 
             
              end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
            end
         | 
| 44 | 
            +
            end
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            module Zip
         | 
| 2 2 | 
             
              # Info-ZIP Additional timestamp field
         | 
| 3 3 | 
             
              class ExtraField::UniversalTime < ExtraField::Generic
         | 
| 4 | 
            -
                HEADER_ID =  | 
| 4 | 
            +
                HEADER_ID = 'UT'
         | 
| 5 5 | 
             
                register_map
         | 
| 6 6 |  | 
| 7 7 | 
             
                def initialize(binstr = nil)
         | 
| @@ -9,7 +9,7 @@ module Zip | |
| 9 9 | 
             
                  @mtime = nil
         | 
| 10 10 | 
             
                  @atime = nil
         | 
| 11 11 | 
             
                  @flag  = nil
         | 
| 12 | 
            -
                  binstr  | 
| 12 | 
            +
                  binstr && merge(binstr)
         | 
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                attr_accessor :atime, :ctime, :mtime, :flag
         | 
| @@ -17,11 +17,11 @@ module Zip | |
| 17 17 | 
             
                def merge(binstr)
         | 
| 18 18 | 
             
                  return if binstr.empty?
         | 
| 19 19 | 
             
                  size, content = initial_parse(binstr)
         | 
| 20 | 
            -
                  size  | 
| 21 | 
            -
                  @flag, mtime, atime, ctime = content.unpack( | 
| 22 | 
            -
                  mtime  | 
| 23 | 
            -
                  atime  | 
| 24 | 
            -
                  ctime  | 
| 20 | 
            +
                  size || return
         | 
| 21 | 
            +
                  @flag, mtime, atime, ctime = content.unpack('CVVV')
         | 
| 22 | 
            +
                  mtime && @mtime ||= ::Zip::DOSTime.at(mtime)
         | 
| 23 | 
            +
                  atime && @atime ||= ::Zip::DOSTime.at(atime)
         | 
| 24 | 
            +
                  ctime && @ctime ||= ::Zip::DOSTime.at(ctime)
         | 
| 25 25 | 
             
                end
         | 
| 26 26 |  | 
| 27 27 | 
             
                def ==(other)
         | 
| @@ -31,17 +31,17 @@ module Zip | |
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| 33 33 | 
             
                def pack_for_local
         | 
| 34 | 
            -
                  s = [@flag].pack( | 
| 35 | 
            -
                  @flag & 1 != 0  | 
| 36 | 
            -
                  @flag & 2 != 0  | 
| 37 | 
            -
                  @flag & 4 != 0  | 
| 34 | 
            +
                  s = [@flag].pack('C')
         | 
| 35 | 
            +
                  @flag & 1 != 0 && s << [@mtime.to_i].pack('V')
         | 
| 36 | 
            +
                  @flag & 2 != 0 && s << [@atime.to_i].pack('V')
         | 
| 37 | 
            +
                  @flag & 4 != 0 && s << [@ctime.to_i].pack('V')
         | 
| 38 38 | 
             
                  s
         | 
| 39 39 | 
             
                end
         | 
| 40 40 |  | 
| 41 41 | 
             
                def pack_for_c_dir
         | 
| 42 | 
            -
                  s = [@flag].pack( | 
| 43 | 
            -
                  @flag & 1 == 1  | 
| 42 | 
            +
                  s = [@flag].pack('C')
         | 
| 43 | 
            +
                  @flag & 1 == 1 && s << [@mtime.to_i].pack('V')
         | 
| 44 44 | 
             
                  s
         | 
| 45 45 | 
             
                end
         | 
| 46 46 | 
             
              end
         | 
| 47 | 
            -
            end
         | 
| 47 | 
            +
            end
         | 
    
        data/lib/zip/extra_field/unix.rb
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            module Zip
         | 
| 2 2 | 
             
              # Info-ZIP Extra for UNIX uid/gid
         | 
| 3 3 | 
             
              class ExtraField::IUnix < ExtraField::Generic
         | 
| 4 | 
            -
                HEADER_ID =  | 
| 4 | 
            +
                HEADER_ID = 'Ux'
         | 
| 5 5 | 
             
                register_map
         | 
| 6 6 |  | 
| 7 7 | 
             
                def initialize(binstr = nil)
         | 
| 8 8 | 
             
                  @uid = 0
         | 
| 9 9 | 
             
                  @gid = 0
         | 
| 10 | 
            -
                  binstr  | 
| 10 | 
            +
                  binstr && merge(binstr)
         | 
| 11 11 | 
             
                end
         | 
| 12 12 |  | 
| 13 13 | 
             
                attr_accessor :uid, :gid
         | 
| @@ -16,10 +16,10 @@ module Zip | |
| 16 16 | 
             
                  return if binstr.empty?
         | 
| 17 17 | 
             
                  size, content = initial_parse(binstr)
         | 
| 18 18 | 
             
                  # size: 0 for central directory. 4 for local header
         | 
| 19 | 
            -
                  return if  | 
| 20 | 
            -
                  uid, gid = content.unpack( | 
| 21 | 
            -
                  @uid | 
| 22 | 
            -
                  @gid | 
| 19 | 
            +
                  return if !size || size == 0
         | 
| 20 | 
            +
                  uid, gid = content.unpack('vv')
         | 
| 21 | 
            +
                  @uid ||= uid
         | 
| 22 | 
            +
                  @gid ||= gid
         | 
| 23 23 | 
             
                end
         | 
| 24 24 |  | 
| 25 25 | 
             
                def ==(other)
         | 
| @@ -27,12 +27,11 @@ module Zip | |
| 27 27 | 
             
                end
         | 
| 28 28 |  | 
| 29 29 | 
             
                def pack_for_local
         | 
| 30 | 
            -
                  [@uid, @gid].pack( | 
| 30 | 
            +
                  [@uid, @gid].pack('vv')
         | 
| 31 31 | 
             
                end
         | 
| 32 32 |  | 
| 33 33 | 
             
                def pack_for_c_dir
         | 
| 34 34 | 
             
                  ''
         | 
| 35 35 | 
             
                end
         | 
| 36 36 | 
             
              end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
            end
         | 
| 37 | 
            +
            end
         | 
| @@ -6,21 +6,22 @@ module Zip | |
| 6 6 | 
             
                register_map
         | 
| 7 7 |  | 
| 8 8 | 
             
                def initialize(binstr = nil)
         | 
| 9 | 
            -
                   | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 9 | 
            +
                  # unparsed binary; we don't actually know what this contains
         | 
| 10 | 
            +
                  # without looking for FFs in the associated file header
         | 
| 11 | 
            +
                  # call parse after initializing with a binary string
         | 
| 12 | 
            +
                  @content = nil
         | 
| 12 13 | 
             
                  @original_size          = nil
         | 
| 13 14 | 
             
                  @compressed_size        = nil
         | 
| 14 15 | 
             
                  @relative_header_offset = nil
         | 
| 15 16 | 
             
                  @disk_start_number      = nil
         | 
| 16 | 
            -
                  binstr  | 
| 17 | 
            +
                  binstr && merge(binstr)
         | 
| 17 18 | 
             
                end
         | 
| 18 19 |  | 
| 19 20 | 
             
                def ==(other)
         | 
| 20 21 | 
             
                  other.original_size == @original_size &&
         | 
| 21 22 | 
             
                    other.compressed_size == @compressed_size &&
         | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 23 | 
            +
                    other.relative_header_offset == @relative_header_offset &&
         | 
| 24 | 
            +
                    other.disk_start_number == @disk_start_number
         | 
| 24 25 | 
             
                end
         | 
| 25 26 |  | 
| 26 27 | 
             
                def merge(binstr)
         | 
| @@ -51,16 +52,16 @@ module Zip | |
| 51 52 | 
             
                def pack_for_local
         | 
| 52 53 | 
             
                  # local header entries must contain original size and compressed size; other fields do not apply
         | 
| 53 54 | 
             
                  return '' unless @original_size && @compressed_size
         | 
| 54 | 
            -
                  [@original_size, @compressed_size].pack( | 
| 55 | 
            +
                  [@original_size, @compressed_size].pack('Q<Q<')
         | 
| 55 56 | 
             
                end
         | 
| 56 57 |  | 
| 57 58 | 
             
                def pack_for_c_dir
         | 
| 58 59 | 
             
                  # central directory entries contain only fields that didn't fit in the main entry part
         | 
| 59 60 | 
             
                  packed = ''.force_encoding('BINARY')
         | 
| 60 | 
            -
                  packed << [@original_size].pack( | 
| 61 | 
            -
                  packed << [@compressed_size].pack( | 
| 62 | 
            -
                  packed << [@relative_header_offset].pack( | 
| 63 | 
            -
                  packed << [@disk_start_number].pack( | 
| 61 | 
            +
                  packed << [@original_size].pack('Q<') if @original_size
         | 
| 62 | 
            +
                  packed << [@compressed_size].pack('Q<') if @compressed_size
         | 
| 63 | 
            +
                  packed << [@relative_header_offset].pack('Q<') if @relative_header_offset
         | 
| 64 | 
            +
                  packed << [@disk_start_number].pack('V') if @disk_start_number
         | 
| 64 65 | 
             
                  packed
         | 
| 65 66 | 
             
                end
         | 
| 66 67 | 
             
              end
         | 
    
        data/lib/zip/file.rb
    CHANGED
    
    | @@ -43,13 +43,13 @@ module Zip | |
| 43 43 | 
             
              # interface for accessing the filesystem, ie. the File and Dir classes.
         | 
| 44 44 |  | 
| 45 45 | 
             
              class File < CentralDirectory
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                CREATE               = 1
         | 
| 46 | 
            +
                CREATE               = true
         | 
| 48 47 | 
             
                SPLIT_SIGNATURE      = 0x08074b50
         | 
| 49 48 | 
             
                ZIP64_EOCD_SIGNATURE = 0x06064b50
         | 
| 50 | 
            -
                MAX_SEGMENT_SIZE     =  | 
| 51 | 
            -
                MIN_SEGMENT_SIZE     =  | 
| 49 | 
            +
                MAX_SEGMENT_SIZE     = 3_221_225_472
         | 
| 50 | 
            +
                MIN_SEGMENT_SIZE     = 65_536
         | 
| 52 51 | 
             
                DATA_BUFFER_SIZE     = 8192
         | 
| 52 | 
            +
                IO_METHODS           = [:tell, :seek, :read, :close]
         | 
| 53 53 |  | 
| 54 54 | 
             
                attr_reader :name
         | 
| 55 55 |  | 
| @@ -64,20 +64,22 @@ module Zip | |
| 64 64 |  | 
| 65 65 | 
             
                # Opens a zip archive. Pass true as the second parameter to create
         | 
| 66 66 | 
             
                # a new archive if it doesn't exist already.
         | 
| 67 | 
            -
                def initialize(file_name, create =  | 
| 67 | 
            +
                def initialize(file_name, create = false, buffer = false, options = {})
         | 
| 68 68 | 
             
                  super()
         | 
| 69 69 | 
             
                  @name    = file_name
         | 
| 70 70 | 
             
                  @comment = ''
         | 
| 71 | 
            -
                  @create  = create
         | 
| 71 | 
            +
                  @create  = create ? true : false # allow any truthy value to mean true
         | 
| 72 72 | 
             
                  case
         | 
| 73 73 | 
             
                  when !buffer && ::File.size?(file_name)
         | 
| 74 | 
            -
                    @create =  | 
| 75 | 
            -
                    @ | 
| 74 | 
            +
                    @create = false
         | 
| 75 | 
            +
                    @file_permissions = ::File.stat(file_name).mode
         | 
| 76 76 | 
             
                    ::File.open(name, 'rb') do |f|
         | 
| 77 77 | 
             
                      read_from_stream(f)
         | 
| 78 78 | 
             
                    end
         | 
| 79 | 
            -
                  when create
         | 
| 79 | 
            +
                  when @create
         | 
| 80 80 | 
             
                    @entry_set = EntrySet.new
         | 
| 81 | 
            +
                  when ::File.zero?(file_name)
         | 
| 82 | 
            +
                    raise Error, "File #{file_name} has zero size. Did you mean to pass the create flag?"
         | 
| 81 83 | 
             
                  else
         | 
| 82 84 | 
             
                    raise Error, "File #{file_name} not found"
         | 
| 83 85 | 
             
                  end
         | 
| @@ -92,7 +94,7 @@ module Zip | |
| 92 94 | 
             
                  # Same as #new. If a block is passed the ZipFile object is passed
         | 
| 93 95 | 
             
                  # to the block and is automatically closed afterwards just as with
         | 
| 94 96 | 
             
                  # ruby's builtin File.open method.
         | 
| 95 | 
            -
                  def open(file_name, create =  | 
| 97 | 
            +
                  def open(file_name, create = false)
         | 
| 96 98 | 
             
                    zf = ::Zip::File.new(file_name, create)
         | 
| 97 99 | 
             
                    return zf unless block_given?
         | 
| 98 100 | 
             
                    begin
         | 
| @@ -115,23 +117,24 @@ module Zip | |
| 115 117 | 
             
                  # (This can be used to extract data from a
         | 
| 116 118 | 
             
                  # downloaded zip archive without first saving it to disk.)
         | 
| 117 119 | 
             
                  def open_buffer(io, options = {})
         | 
| 118 | 
            -
                    unless  | 
| 119 | 
            -
                      raise "Zip::File.open_buffer expects  | 
| 120 | 
            +
                    unless IO_METHODS.map { |method| io.respond_to?(method) }.all? || io.is_a?(String)
         | 
| 121 | 
            +
                      raise "Zip::File.open_buffer expects a String or IO-like argument (responds to #{IO_METHODS.join(', ')}). Found: #{io.class}"
         | 
| 120 122 | 
             
                    end
         | 
| 121 123 | 
             
                    if io.is_a?(::String)
         | 
| 122 124 | 
             
                      require 'stringio'
         | 
| 123 125 | 
             
                      io = ::StringIO.new(io)
         | 
| 124 | 
            -
                    elsif io. | 
| 126 | 
            +
                    elsif io.respond_to?(:binmode)
         | 
| 125 127 | 
             
                      # https://github.com/rubyzip/rubyzip/issues/119
         | 
| 126 128 | 
             
                      io.binmode
         | 
| 127 129 | 
             
                    end
         | 
| 128 130 | 
             
                    zf = ::Zip::File.new(io, true, true, options)
         | 
| 129 131 | 
             
                    zf.read_from_stream(io)
         | 
| 132 | 
            +
                    return zf unless block_given?
         | 
| 130 133 | 
             
                    yield zf
         | 
| 131 134 | 
             
                    begin
         | 
| 132 135 | 
             
                      zf.write_buffer(io)
         | 
| 133 136 | 
             
                    rescue IOError => e
         | 
| 134 | 
            -
                      raise unless e.message ==  | 
| 137 | 
            +
                      raise unless e.message == 'not opened for writing'
         | 
| 135 138 | 
             
                    end
         | 
| 136 139 | 
             
                  end
         | 
| 137 140 |  | 
| @@ -181,7 +184,7 @@ module Zip | |
| 181 184 | 
             
                  def save_splited_part(zip_file, partial_zip_file_name, zip_file_size, szip_file_index, segment_size, segment_count)
         | 
| 182 185 | 
             
                    ssegment_size  = zip_file_size - zip_file.pos
         | 
| 183 186 | 
             
                    ssegment_size  = segment_size if ssegment_size > segment_size
         | 
| 184 | 
            -
                    szip_file_name = "#{partial_zip_file_name}.#{'%03d' | 
| 187 | 
            +
                    szip_file_name = "#{partial_zip_file_name}.#{format('%03d', szip_file_index)}"
         | 
| 185 188 | 
             
                    ::File.open(szip_file_name, 'wb') do |szip_file|
         | 
| 186 189 | 
             
                      if szip_file_index == 1
         | 
| 187 190 | 
             
                        ssegment_size = put_split_signature(szip_file, segment_size)
         | 
| @@ -191,7 +194,7 @@ module Zip | |
| 191 194 | 
             
                        segment_bytes_left = ssegment_size - chunk_bytes
         | 
| 192 195 | 
             
                        buffer_size        = segment_bytes_left < DATA_BUFFER_SIZE ? segment_bytes_left : DATA_BUFFER_SIZE
         | 
| 193 196 | 
             
                        chunk              = zip_file.read(buffer_size)
         | 
| 194 | 
            -
                        chunk_bytes | 
| 197 | 
            +
                        chunk_bytes += buffer_size
         | 
| 195 198 | 
             
                        szip_file << chunk
         | 
| 196 199 | 
             
                        # Info for track splitting
         | 
| 197 200 | 
             
                        yield segment_count, szip_file_index, chunk_bytes, ssegment_size if block_given?
         | 
| @@ -208,7 +211,7 @@ module Zip | |
| 208 211 | 
             
                    return if zip_file_size <= segment_size
         | 
| 209 212 | 
             
                    segment_count = get_segment_count_for_split(zip_file_size, segment_size)
         | 
| 210 213 | 
             
                    # Checking for correct zip structure
         | 
| 211 | 
            -
                     | 
| 214 | 
            +
                    open(zip_file_name) {}
         | 
| 212 215 | 
             
                    partial_zip_file_name = get_partial_zip_file_name(zip_file_name, partial_zip_file_name)
         | 
| 213 216 | 
             
                    szip_file_index       = 0
         | 
| 214 217 | 
             
                    ::File.open(zip_file_name, 'rb') do |zip_file|
         | 
| @@ -222,7 +225,6 @@ module Zip | |
| 222 225 | 
             
                  end
         | 
| 223 226 | 
             
                end
         | 
| 224 227 |  | 
| 225 | 
            -
             | 
| 226 228 | 
             
                # Returns an input stream to the specified entry. If a block is passed
         | 
| 227 229 | 
             
                # the stream object is passed to the block and the stream is automatically
         | 
| 228 230 | 
             
                # closed afterwards just as with ruby's builtin File.open method.
         | 
| @@ -265,7 +267,7 @@ module Zip | |
| 265 267 | 
             
                # Convenience method for adding the contents of a file to the archive
         | 
| 266 268 | 
             
                def add(entry, src_path, &continue_on_exists_proc)
         | 
| 267 269 | 
             
                  continue_on_exists_proc ||= proc { ::Zip.continue_on_exists_proc }
         | 
| 268 | 
            -
                  check_entry_exists(entry, continue_on_exists_proc,  | 
| 270 | 
            +
                  check_entry_exists(entry, continue_on_exists_proc, 'add')
         | 
| 269 271 | 
             
                  new_entry = entry.kind_of?(::Zip::Entry) ? entry : ::Zip::Entry.new(@name, entry.to_s)
         | 
| 270 272 | 
             
                  new_entry.gather_fileinfo_from_srcpath(src_path)
         | 
| 271 273 | 
             
                  new_entry.dirty = true
         | 
| @@ -338,7 +340,7 @@ module Zip | |
| 338 340 | 
             
                  @entry_set.each do |e|
         | 
| 339 341 | 
             
                    return true if e.dirty
         | 
| 340 342 | 
             
                  end
         | 
| 341 | 
            -
                  @comment != @stored_comment || @entry_set != @stored_entries || @create | 
| 343 | 
            +
                  @comment != @stored_comment || @entry_set != @stored_entries || @create
         | 
| 342 344 | 
             
                end
         | 
| 343 345 |  | 
| 344 346 | 
             
                # Searches for entry with the specified name. Returns nil if
         | 
| @@ -356,9 +358,7 @@ module Zip | |
| 356 358 | 
             
                # if no entry is found.
         | 
| 357 359 | 
             
                def get_entry(entry)
         | 
| 358 360 | 
             
                  selected_entry = find_entry(entry)
         | 
| 359 | 
            -
                  unless selected_entry
         | 
| 360 | 
            -
                    raise Errno::ENOENT, entry
         | 
| 361 | 
            -
                  end
         | 
| 361 | 
            +
                  raise Errno::ENOENT, entry unless selected_entry
         | 
| 362 362 | 
             
                  selected_entry.restore_ownership   = @restore_ownership
         | 
| 363 363 | 
             
                  selected_entry.restore_permissions = @restore_permissions
         | 
| 364 364 | 
             
                  selected_entry.restore_times       = @restore_times
         | 
| @@ -367,9 +367,7 @@ module Zip | |
| 367 367 |  | 
| 368 368 | 
             
                # Creates a directory
         | 
| 369 369 | 
             
                def mkdir(entryName, permissionInt = 0755)
         | 
| 370 | 
            -
                  if find_entry(entryName)
         | 
| 371 | 
            -
                    raise Errno::EEXIST, "File exists - #{entryName}"
         | 
| 372 | 
            -
                  end
         | 
| 370 | 
            +
                  raise Errno::EEXIST, "File exists - #{entryName}" if find_entry(entryName)
         | 
| 373 371 | 
             
                  entryName = entryName.dup.to_s
         | 
| 374 372 | 
             
                  entryName << '/' unless entryName.end_with?('/')
         | 
| 375 373 | 
             
                  @entry_set << ::Zip::StreamableDirectory.new(@name, entryName, nil, permissionInt)
         | 
| @@ -377,57 +375,46 @@ module Zip | |
| 377 375 |  | 
| 378 376 | 
             
                private
         | 
| 379 377 |  | 
| 380 | 
            -
                def  | 
| 378 | 
            +
                def directory?(newEntry, srcPath)
         | 
| 381 379 | 
             
                  srcPathIsDirectory = ::File.directory?(srcPath)
         | 
| 382 | 
            -
                  if newEntry. | 
| 380 | 
            +
                  if newEntry.directory? && !srcPathIsDirectory
         | 
| 383 381 | 
             
                    raise ArgumentError,
         | 
| 384 | 
            -
                          "entry name '#{newEntry}' indicates directory entry, but " | 
| 385 | 
            -
             | 
| 386 | 
            -
                  elsif !newEntry. | 
| 387 | 
            -
                    newEntry.name +=  | 
| 382 | 
            +
                          "entry name '#{newEntry}' indicates directory entry, but " \
         | 
| 383 | 
            +
                              "'#{srcPath}' is not a directory"
         | 
| 384 | 
            +
                  elsif !newEntry.directory? && srcPathIsDirectory
         | 
| 385 | 
            +
                    newEntry.name += '/'
         | 
| 388 386 | 
             
                  end
         | 
| 389 | 
            -
                  newEntry. | 
| 387 | 
            +
                  newEntry.directory? && srcPathIsDirectory
         | 
| 390 388 | 
             
                end
         | 
| 391 389 |  | 
| 392 390 | 
             
                def check_entry_exists(entryName, continue_on_exists_proc, procedureName)
         | 
| 393 391 | 
             
                  continue_on_exists_proc ||= proc { Zip.continue_on_exists_proc }
         | 
| 394 | 
            -
                   | 
| 395 | 
            -
             | 
| 396 | 
            -
             | 
| 397 | 
            -
             | 
| 398 | 
            -
             | 
| 399 | 
            -
             | 
| 400 | 
            -
                    end
         | 
| 392 | 
            +
                  return unless @entry_set.include?(entryName)
         | 
| 393 | 
            +
                  if continue_on_exists_proc.call
         | 
| 394 | 
            +
                    remove get_entry(entryName)
         | 
| 395 | 
            +
                  else
         | 
| 396 | 
            +
                    raise ::Zip::EntryExistsError,
         | 
| 397 | 
            +
                          procedureName + " failed. Entry #{entryName} already exists"
         | 
| 401 398 | 
             
                  end
         | 
| 402 399 | 
             
                end
         | 
| 403 400 |  | 
| 404 401 | 
             
                def check_file(path)
         | 
| 405 | 
            -
                  unless ::File.readable?(path)
         | 
| 406 | 
            -
                    raise Errno::ENOENT, path
         | 
| 407 | 
            -
                  end
         | 
| 402 | 
            +
                  raise Errno::ENOENT, path unless ::File.readable?(path)
         | 
| 408 403 | 
             
                end
         | 
| 409 404 |  | 
| 410 405 | 
             
                def on_success_replace
         | 
| 411 | 
            -
                   | 
| 412 | 
            -
                   | 
| 413 | 
            -
             | 
| 414 | 
            -
             | 
| 415 | 
            -
             | 
| 416 | 
            -
             | 
| 417 | 
            -
             | 
| 418 | 
            -
             | 
| 406 | 
            +
                  dirname, basename = ::File.split(name)
         | 
| 407 | 
            +
                  ::Dir::Tmpname.create(basename, dirname) do |tmp_filename|
         | 
| 408 | 
            +
                    begin
         | 
| 409 | 
            +
                      if yield tmp_filename
         | 
| 410 | 
            +
                        ::File.rename(tmp_filename, name)
         | 
| 411 | 
            +
                        ::File.chmod(@file_permissions, name) unless @create
         | 
| 412 | 
            +
                      end
         | 
| 413 | 
            +
                    ensure
         | 
| 414 | 
            +
                      ::File.unlink(tmp_filename) if ::File.exist?(tmp_filename)
         | 
| 419 415 | 
             
                    end
         | 
| 420 416 | 
             
                  end
         | 
| 421 | 
            -
                ensure
         | 
| 422 | 
            -
                  tmpfile.unlink if tmpfile
         | 
| 423 417 | 
             
                end
         | 
| 424 | 
            -
             | 
| 425 | 
            -
                def get_tempfile
         | 
| 426 | 
            -
                  temp_file = Tempfile.new(::File.basename(name), ::File.dirname(name))
         | 
| 427 | 
            -
                  temp_file.binmode
         | 
| 428 | 
            -
                  temp_file
         | 
| 429 | 
            -
                end
         | 
| 430 | 
            -
             | 
| 431 418 | 
             
              end
         | 
| 432 419 | 
             
            end
         | 
| 433 420 |  |