rubyzip 2.4.rc1 → 3.0.0.alpha
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/Changelog.md +368 -0
- data/README.md +112 -37
- data/Rakefile +11 -7
- data/lib/zip/central_directory.rb +164 -118
- data/lib/zip/compressor.rb +3 -1
- data/lib/zip/constants.rb +25 -21
- data/lib/zip/crypto/decrypted_io.rb +3 -1
- data/lib/zip/crypto/encryption.rb +4 -2
- data/lib/zip/crypto/null_encryption.rb +5 -3
- data/lib/zip/crypto/traditional_encryption.rb +5 -3
- data/lib/zip/decompressor.rb +4 -3
- data/lib/zip/deflater.rb +10 -8
- data/lib/zip/dirtyable.rb +32 -0
- data/lib/zip/dos_time.rb +32 -3
- data/lib/zip/entry.rb +263 -199
- data/lib/zip/entry_set.rb +9 -7
- data/lib/zip/errors.rb +115 -16
- data/lib/zip/extra_field/generic.rb +3 -10
- data/lib/zip/extra_field/ntfs.rb +4 -2
- data/lib/zip/extra_field/old_unix.rb +3 -1
- data/lib/zip/extra_field/universal_time.rb +3 -1
- data/lib/zip/extra_field/unix.rb +5 -3
- data/lib/zip/extra_field/unknown.rb +33 -0
- data/lib/zip/extra_field/zip64.rb +12 -5
- data/lib/zip/extra_field.rb +15 -21
- data/lib/zip/file.rb +143 -264
- data/lib/zip/file_split.rb +97 -0
- data/lib/zip/filesystem/dir.rb +86 -0
- data/lib/zip/filesystem/directory_iterator.rb +48 -0
- data/lib/zip/filesystem/file.rb +262 -0
- data/lib/zip/filesystem/file_stat.rb +110 -0
- data/lib/zip/filesystem/zip_file_name_mapper.rb +81 -0
- data/lib/zip/filesystem.rb +26 -595
- data/lib/zip/inflater.rb +7 -5
- data/lib/zip/input_stream.rb +44 -39
- data/lib/zip/ioextras/abstract_input_stream.rb +14 -9
- data/lib/zip/ioextras/abstract_output_stream.rb +5 -3
- data/lib/zip/ioextras.rb +6 -6
- data/lib/zip/null_compressor.rb +3 -1
- data/lib/zip/null_decompressor.rb +3 -1
- data/lib/zip/null_input_stream.rb +3 -1
- data/lib/zip/output_stream.rb +47 -48
- data/lib/zip/pass_thru_compressor.rb +3 -1
- data/lib/zip/pass_thru_decompressor.rb +4 -2
- data/lib/zip/streamable_directory.rb +3 -1
- data/lib/zip/streamable_stream.rb +3 -0
- data/lib/zip/version.rb +3 -1
- data/lib/zip.rb +15 -16
- data/rubyzip.gemspec +38 -0
- data/samples/example.rb +8 -3
- data/samples/example_filesystem.rb +2 -1
- data/samples/example_recursive.rb +3 -1
- data/samples/gtk_ruby_zip.rb +4 -2
- data/samples/qtzip.rb +6 -5
- data/samples/write_simple.rb +1 -0
- data/samples/zipfind.rb +1 -0
- metadata +81 -46
- data/TODO +0 -15
- data/lib/zip/extra_field/zip64_placeholder.rb +0 -15
    
        data/lib/zip/input_stream.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Zip
         | 
| 2 4 | 
             
              # InputStream is the basic class for reading zip entries in a
         | 
| 3 5 | 
             
              # zip file. It is possible to create a InputStream object directly,
         | 
| @@ -49,30 +51,30 @@ module Zip | |
| 49 51 | 
             
                #
         | 
| 50 52 | 
             
                # @param context [String||IO||StringIO] file path or IO/StringIO object
         | 
| 51 53 | 
             
                # @param offset [Integer] offset in the IO/StringIO
         | 
| 52 | 
            -
                def initialize(context,  | 
| 54 | 
            +
                def initialize(context, offset: 0, decrypter: nil)
         | 
| 53 55 | 
             
                  super()
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                   | 
| 56 | 
            -
             | 
| 57 | 
            -
                  end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  offset         = dep_offset if offset.zero?
         | 
| 60 | 
            -
                  @archive_io    = get_io(context, offset)
         | 
| 61 | 
            -
                  @decompressor  = ::Zip::NullDecompressor
         | 
| 62 | 
            -
                  @decrypter     = decrypter || dep_decrypter || ::Zip::NullDecrypter.new
         | 
| 56 | 
            +
                  @archive_io = get_io(context, offset)
         | 
| 57 | 
            +
                  @decompressor = ::Zip::NullDecompressor
         | 
| 58 | 
            +
                  @decrypter = decrypter || ::Zip::NullDecrypter.new
         | 
| 63 59 | 
             
                  @current_entry = nil
         | 
| 60 | 
            +
                  @complete_entry = nil
         | 
| 64 61 | 
             
                end
         | 
| 65 62 |  | 
| 66 63 | 
             
                def close
         | 
| 67 64 | 
             
                  @archive_io.close
         | 
| 68 65 | 
             
                end
         | 
| 69 66 |  | 
| 70 | 
            -
                # Returns  | 
| 71 | 
            -
                # method on a newly created | 
| 72 | 
            -
                # the first entry in the archive. | 
| 73 | 
            -
                # no more entries.
         | 
| 67 | 
            +
                # Returns an Entry object and positions the stream at the beginning of
         | 
| 68 | 
            +
                # the entry data. It is necessary to call this method on a newly created
         | 
| 69 | 
            +
                # InputStream before reading from the first entry in the archive.
         | 
| 70 | 
            +
                # Returns nil when there are no more entries.
         | 
| 74 71 | 
             
                def get_next_entry
         | 
| 75 | 
            -
                  @ | 
| 72 | 
            +
                  unless @current_entry.nil?
         | 
| 73 | 
            +
                    raise StreamingError, @current_entry if @current_entry.incomplete?
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    @archive_io.seek(@current_entry.next_header_offset, IO::SEEK_SET)
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 76 78 | 
             
                  open_entry
         | 
| 77 79 | 
             
                end
         | 
| 78 80 |  | 
| @@ -91,18 +93,19 @@ module Zip | |
| 91 93 | 
             
                  @decompressor.read(length, outbuf)
         | 
| 92 94 | 
             
                end
         | 
| 93 95 |  | 
| 96 | 
            +
                # Returns the size of the current entry, or `nil` if there isn't one.
         | 
| 97 | 
            +
                def size
         | 
| 98 | 
            +
                  return if @current_entry.nil?
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  @current_entry.size
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 94 103 | 
             
                class << self
         | 
| 95 104 | 
             
                  # Same as #initialize but if a block is passed the opened
         | 
| 96 105 | 
             
                  # stream is passed to the block and closed when the block
         | 
| 97 106 | 
             
                  # returns.
         | 
| 98 | 
            -
                  def open(filename_or_io,  | 
| 99 | 
            -
                     | 
| 100 | 
            -
                      Zip.warn_about_v3_api('Zip::InputStream.new')
         | 
| 101 | 
            -
                    end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                    offset = dep_offset if offset.zero?
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                    zio = new(filename_or_io, offset: offset, decrypter: decrypter || dep_decrypter)
         | 
| 107 | 
            +
                  def open(filename_or_io, offset: 0, decrypter: nil)
         | 
| 108 | 
            +
                    zio = new(filename_or_io, offset: offset, decrypter: decrypter)
         | 
| 106 109 | 
             
                    return zio unless block_given?
         | 
| 107 110 |  | 
| 108 111 | 
             
                    begin
         | 
| @@ -112,10 +115,9 @@ module Zip | |
| 112 115 | 
             
                    end
         | 
| 113 116 | 
             
                  end
         | 
| 114 117 |  | 
| 115 | 
            -
                  def open_buffer(filename_or_io, offset  | 
| 116 | 
            -
                     | 
| 117 | 
            -
             | 
| 118 | 
            -
                    ::Zip::InputStream.open(filename_or_io, offset)
         | 
| 118 | 
            +
                  def open_buffer(filename_or_io, offset: 0)
         | 
| 119 | 
            +
                    warn 'open_buffer is deprecated!!! Use open instead!'
         | 
| 120 | 
            +
                    ::Zip::InputStream.open(filename_or_io, offset: offset)
         | 
| 119 121 | 
             
                  end
         | 
| 120 122 | 
             
                end
         | 
| 121 123 |  | 
| @@ -135,17 +137,18 @@ module Zip | |
| 135 137 |  | 
| 136 138 | 
             
                def open_entry
         | 
| 137 139 | 
             
                  @current_entry = ::Zip::Entry.read_local_entry(@archive_io)
         | 
| 138 | 
            -
                  if @current_entry | 
| 139 | 
            -
             | 
| 140 | 
            +
                  return if @current_entry.nil?
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  if @current_entry.encrypted? && @decrypter.kind_of?(NullDecrypter)
         | 
| 143 | 
            +
                    raise Error,
         | 
| 144 | 
            +
                          'A password is required to decode this zip file'
         | 
| 140 145 | 
             
                  end
         | 
| 141 146 |  | 
| 142 | 
            -
                  if @current_entry | 
| 143 | 
            -
                    &&  | 
| 144 | 
            -
                     | 
| 145 | 
            -
                    raise GPFBit3Error,
         | 
| 146 | 
            -
                          'General purpose flag Bit 3 is set so not possible to get proper info from local header.' \
         | 
| 147 | 
            -
                          'Please use ::Zip::File instead of ::Zip::InputStream'
         | 
| 147 | 
            +
                  if @current_entry.incomplete? && @current_entry.compressed_size == 0 \
         | 
| 148 | 
            +
                    && !@complete_entry
         | 
| 149 | 
            +
                    raise StreamingError, @current_entry
         | 
| 148 150 | 
             
                  end
         | 
| 151 | 
            +
             | 
| 149 152 | 
             
                  @decrypted_io = get_decrypted_io
         | 
| 150 153 | 
             
                  @decompressor = get_decompressor
         | 
| 151 154 | 
             
                  flush
         | 
| @@ -163,16 +166,18 @@ module Zip | |
| 163 166 | 
             
                  return ::Zip::NullDecompressor if @current_entry.nil?
         | 
| 164 167 |  | 
| 165 168 | 
             
                  decompressed_size =
         | 
| 166 | 
            -
                    if @current_entry.incomplete? && @current_entry.crc == 0  | 
| 169 | 
            +
                    if @current_entry.incomplete? && @current_entry.crc == 0 \
         | 
| 170 | 
            +
                       && @current_entry.size == 0 && @complete_entry
         | 
| 167 171 | 
             
                      @complete_entry.size
         | 
| 168 172 | 
             
                    else
         | 
| 169 173 | 
             
                      @current_entry.size
         | 
| 170 174 | 
             
                    end
         | 
| 171 175 |  | 
| 172 | 
            -
                  decompressor_class = ::Zip::Decompressor.find_by_compression_method( | 
| 176 | 
            +
                  decompressor_class = ::Zip::Decompressor.find_by_compression_method(
         | 
| 177 | 
            +
                    @current_entry.compression_method
         | 
| 178 | 
            +
                  )
         | 
| 173 179 | 
             
                  if decompressor_class.nil?
         | 
| 174 | 
            -
                    raise ::Zip::CompressionMethodError,
         | 
| 175 | 
            -
                          "Unsupported compression method #{@current_entry.compression_method}"
         | 
| 180 | 
            +
                    raise ::Zip::CompressionMethodError, @current_entry.compression_method
         | 
| 176 181 | 
             
                  end
         | 
| 177 182 |  | 
| 178 183 | 
             
                  decompressor_class.new(@decrypted_io, decompressed_size)
         | 
| @@ -1,9 +1,11 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Zip
         | 
| 2 | 
            -
              module IOExtras
         | 
| 4 | 
            +
              module IOExtras # :nodoc:
         | 
| 3 5 | 
             
                # Implements many of the convenience methods of IO
         | 
| 4 6 | 
             
                # such as gets, getc, readline and readlines
         | 
| 5 7 | 
             
                # depends on: input_finished?, produce_input and read
         | 
| 6 | 
            -
                module AbstractInputStream
         | 
| 8 | 
            +
                module AbstractInputStream # :nodoc:
         | 
| 7 9 | 
             
                  include Enumerable
         | 
| 8 10 | 
             
                  include FakeIO
         | 
| 9 11 |  | 
| @@ -11,22 +13,22 @@ module Zip | |
| 11 13 | 
             
                    super
         | 
| 12 14 | 
             
                    @lineno        = 0
         | 
| 13 15 | 
             
                    @pos           = 0
         | 
| 14 | 
            -
                    @output_buffer = '' | 
| 16 | 
            +
                    @output_buffer = +''
         | 
| 15 17 | 
             
                  end
         | 
| 16 18 |  | 
| 17 19 | 
             
                  attr_accessor :lineno
         | 
| 18 20 | 
             
                  attr_reader :pos
         | 
| 19 21 |  | 
| 20 | 
            -
                  def read(number_of_bytes = nil, buf = '' | 
| 22 | 
            +
                  def read(number_of_bytes = nil, buf = +'')
         | 
| 21 23 | 
             
                    tbuf = if @output_buffer.bytesize > 0
         | 
| 22 | 
            -
                             if number_of_bytes <= @output_buffer.bytesize
         | 
| 24 | 
            +
                             if number_of_bytes && number_of_bytes <= @output_buffer.bytesize
         | 
| 23 25 | 
             
                               @output_buffer.slice!(0, number_of_bytes)
         | 
| 24 26 | 
             
                             else
         | 
| 25 27 | 
             
                               number_of_bytes -= @output_buffer.bytesize if number_of_bytes
         | 
| 26 28 | 
             
                               rbuf = sysread(number_of_bytes, buf)
         | 
| 27 29 | 
             
                               out  = @output_buffer
         | 
| 28 30 | 
             
                               out << rbuf if rbuf
         | 
| 29 | 
            -
                               @output_buffer = '' | 
| 31 | 
            +
                               @output_buffer = ''
         | 
| 30 32 | 
             
                               out
         | 
| 31 33 | 
             
                             end
         | 
| 32 34 | 
             
                           else
         | 
| @@ -34,7 +36,7 @@ module Zip | |
| 34 36 | 
             
                           end
         | 
| 35 37 |  | 
| 36 38 | 
             
                    if tbuf.nil? || tbuf.empty?
         | 
| 37 | 
            -
                      return nil if number_of_bytes
         | 
| 39 | 
            +
                      return nil if number_of_bytes&.positive?
         | 
| 38 40 |  | 
| 39 41 | 
             
                      return ''
         | 
| 40 42 | 
             
                    end
         | 
| @@ -82,7 +84,10 @@ module Zip | |
| 82 84 | 
             
                      @output_buffer << produce_input
         | 
| 83 85 | 
             
                      over_limit = (number_of_bytes && @output_buffer.bytesize >= number_of_bytes)
         | 
| 84 86 | 
             
                    end
         | 
| 85 | 
            -
                    sep_index = [ | 
| 87 | 
            +
                    sep_index = [
         | 
| 88 | 
            +
                      match_index + a_sep_string.bytesize,
         | 
| 89 | 
            +
                      number_of_bytes || @output_buffer.bytesize
         | 
| 90 | 
            +
                    ].min
         | 
| 86 91 | 
             
                    @pos += sep_index
         | 
| 87 92 | 
             
                    @output_buffer.slice!(0...sep_index)
         | 
| 88 93 | 
             
                  end
         | 
| @@ -93,7 +98,7 @@ module Zip | |
| 93 98 |  | 
| 94 99 | 
             
                  def flush
         | 
| 95 100 | 
             
                    ret_val        = @output_buffer
         | 
| 96 | 
            -
                    @output_buffer = '' | 
| 101 | 
            +
                    @output_buffer = +''
         | 
| 97 102 | 
             
                    ret_val
         | 
| 98 103 | 
             
                  end
         | 
| 99 104 |  | 
| @@ -1,8 +1,10 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Zip
         | 
| 2 | 
            -
              module IOExtras
         | 
| 4 | 
            +
              module IOExtras # :nodoc:
         | 
| 3 5 | 
             
                # Implements many of the output convenience methods of IO.
         | 
| 4 6 | 
             
                # relies on <<
         | 
| 5 | 
            -
                module AbstractOutputStream
         | 
| 7 | 
            +
                module AbstractOutputStream # :nodoc:
         | 
| 6 8 | 
             
                  include FakeIO
         | 
| 7 9 |  | 
| 8 10 | 
             
                  def write(data)
         | 
| @@ -11,7 +13,7 @@ module Zip | |
| 11 13 | 
             
                  end
         | 
| 12 14 |  | 
| 13 15 | 
             
                  def print(*params)
         | 
| 14 | 
            -
                    self << params.join | 
| 16 | 
            +
                    self << params.join << $OUTPUT_RECORD_SEPARATOR.to_s
         | 
| 15 17 | 
             
                  end
         | 
| 16 18 |  | 
| 17 19 | 
             
                  def printf(a_format_string, *params)
         | 
    
        data/lib/zip/ioextras.rb
    CHANGED
    
    | @@ -1,26 +1,26 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Zip
         | 
| 2 | 
            -
              module IOExtras  | 
| 4 | 
            +
              module IOExtras # :nodoc:
         | 
| 3 5 | 
             
                CHUNK_SIZE = 131_072
         | 
| 4 6 |  | 
| 5 | 
            -
                RANGE_ALL = 0..-1
         | 
| 6 | 
            -
             | 
| 7 7 | 
             
                class << self
         | 
| 8 8 | 
             
                  def copy_stream(ostream, istream)
         | 
| 9 | 
            -
                    ostream.write(istream.read(CHUNK_SIZE, '' | 
| 9 | 
            +
                    ostream.write(istream.read(CHUNK_SIZE, +'')) until istream.eof?
         | 
| 10 10 | 
             
                  end
         | 
| 11 11 |  | 
| 12 12 | 
             
                  def copy_stream_n(ostream, istream, nbytes)
         | 
| 13 13 | 
             
                    toread = nbytes
         | 
| 14 14 | 
             
                    while toread > 0 && !istream.eof?
         | 
| 15 15 | 
             
                      tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
         | 
| 16 | 
            -
                      ostream.write(istream.read(tr, '' | 
| 16 | 
            +
                      ostream.write(istream.read(tr, +''))
         | 
| 17 17 | 
             
                      toread -= tr
         | 
| 18 18 | 
             
                    end
         | 
| 19 19 | 
             
                  end
         | 
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 22 | 
             
                # Implements kind_of? in order to pretend to be an IO object
         | 
| 23 | 
            -
                module FakeIO
         | 
| 23 | 
            +
                module FakeIO # :nodoc:
         | 
| 24 24 | 
             
                  def kind_of?(object)
         | 
| 25 25 | 
             
                    object == IO || super
         | 
| 26 26 | 
             
                  end
         | 
    
        data/lib/zip/null_compressor.rb
    CHANGED
    
    
    
        data/lib/zip/output_stream.rb
    CHANGED
    
    | @@ -1,3 +1,7 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'forwardable'
         | 
| 4 | 
            +
             | 
| 1 5 | 
             
            module Zip
         | 
| 2 6 | 
             
              # ZipOutputStream is the basic class for writing zip files. It is
         | 
| 3 7 | 
             
              # possible to create a ZipOutputStream object directly, passing
         | 
| @@ -18,55 +22,48 @@ module Zip | |
| 18 22 | 
             
              # class.
         | 
| 19 23 |  | 
| 20 24 | 
             
              class OutputStream
         | 
| 25 | 
            +
                extend Forwardable
         | 
| 21 26 | 
             
                include ::Zip::IOExtras::AbstractOutputStream
         | 
| 22 27 |  | 
| 23 | 
            -
                 | 
| 28 | 
            +
                def_delegators :@cdir, :comment, :comment=
         | 
| 24 29 |  | 
| 25 30 | 
             
                # Opens the indicated zip file. If a file with that name already
         | 
| 26 31 | 
             
                # exists it will be overwritten.
         | 
| 27 | 
            -
                def initialize(file_name,  | 
| 32 | 
            +
                def initialize(file_name, stream: false, encrypter: nil)
         | 
| 28 33 | 
             
                  super()
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                  Zip.warn_about_v3_api('Zip::OutputStream.new') if dep_stream || !dep_encrypter.nil?
         | 
| 31 | 
            -
             | 
| 32 34 | 
             
                  @file_name = file_name
         | 
| 33 | 
            -
                  @output_stream = if stream | 
| 34 | 
            -
                                     iostream = @file_name.dup
         | 
| 35 | 
            +
                  @output_stream = if stream
         | 
| 36 | 
            +
                                     iostream = Zip::RUNNING_ON_WINDOWS ? @file_name : @file_name.dup
         | 
| 35 37 | 
             
                                     iostream.reopen(@file_name)
         | 
| 36 38 | 
             
                                     iostream.rewind
         | 
| 37 39 | 
             
                                     iostream
         | 
| 38 40 | 
             
                                   else
         | 
| 39 41 | 
             
                                     ::File.new(@file_name, 'wb')
         | 
| 40 42 | 
             
                                   end
         | 
| 41 | 
            -
                  @ | 
| 43 | 
            +
                  @cdir = ::Zip::CentralDirectory.new
         | 
| 42 44 | 
             
                  @compressor = ::Zip::NullCompressor.instance
         | 
| 43 | 
            -
                  @encrypter = encrypter ||  | 
| 45 | 
            +
                  @encrypter = encrypter || ::Zip::NullEncrypter.new
         | 
| 44 46 | 
             
                  @closed = false
         | 
| 45 47 | 
             
                  @current_entry = nil
         | 
| 46 | 
            -
                  @comment = nil
         | 
| 47 48 | 
             
                end
         | 
| 48 49 |  | 
| 49 50 | 
             
                # Same as #initialize but if a block is passed the opened
         | 
| 50 51 | 
             
                # stream is passed to the block and closed when the block
         | 
| 51 52 | 
             
                # returns.
         | 
| 52 53 | 
             
                class << self
         | 
| 53 | 
            -
                  def open(file_name,  | 
| 54 | 
            +
                  def open(file_name, encrypter: nil)
         | 
| 54 55 | 
             
                    return new(file_name) unless block_given?
         | 
| 55 56 |  | 
| 56 | 
            -
                     | 
| 57 | 
            -
             | 
| 58 | 
            -
                    zos = new(file_name, stream: false, encrypter: (encrypter || dep_encrypter))
         | 
| 57 | 
            +
                    zos = new(file_name, stream: false, encrypter: encrypter)
         | 
| 59 58 | 
             
                    yield zos
         | 
| 60 59 | 
             
                  ensure
         | 
| 61 60 | 
             
                    zos.close if zos
         | 
| 62 61 | 
             
                  end
         | 
| 63 62 |  | 
| 64 63 | 
             
                  # Same as #open but writes to a filestream instead
         | 
| 65 | 
            -
                  def write_buffer(io = ::StringIO.new,  | 
| 66 | 
            -
                    Zip.warn_about_v3_api('Zip::OutputStream.write_buffer') unless dep_encrypter.nil?
         | 
| 67 | 
            -
             | 
| 64 | 
            +
                  def write_buffer(io = ::StringIO.new, encrypter: nil)
         | 
| 68 65 | 
             
                    io.binmode if io.respond_to?(:binmode)
         | 
| 69 | 
            -
                    zos = new(io, stream: true, encrypter:  | 
| 66 | 
            +
                    zos = new(io, stream: true, encrypter: encrypter)
         | 
| 70 67 | 
             
                    yield zos
         | 
| 71 68 | 
             
                    zos.close_buffer
         | 
| 72 69 | 
             
                  end
         | 
| @@ -78,7 +75,7 @@ module Zip | |
| 78 75 |  | 
| 79 76 | 
             
                  finalize_current_entry
         | 
| 80 77 | 
             
                  update_local_headers
         | 
| 81 | 
            -
                   | 
| 78 | 
            +
                  @cdir.write_to_stream(@output_stream)
         | 
| 82 79 | 
             
                  @output_stream.close
         | 
| 83 80 | 
             
                  @closed = true
         | 
| 84 81 | 
             
                end
         | 
| @@ -89,27 +86,31 @@ module Zip | |
| 89 86 |  | 
| 90 87 | 
             
                  finalize_current_entry
         | 
| 91 88 | 
             
                  update_local_headers
         | 
| 92 | 
            -
                   | 
| 89 | 
            +
                  @cdir.write_to_stream(@output_stream)
         | 
| 93 90 | 
             
                  @closed = true
         | 
| 91 | 
            +
                  @output_stream.flush
         | 
| 94 92 | 
             
                  @output_stream
         | 
| 95 93 | 
             
                end
         | 
| 96 94 |  | 
| 97 95 | 
             
                # Closes the current entry and opens a new for writing.
         | 
| 98 96 | 
             
                # +entry+ can be a ZipEntry object or a string.
         | 
| 99 | 
            -
                def put_next_entry( | 
| 97 | 
            +
                def put_next_entry(
         | 
| 98 | 
            +
                  entry_name, comment = '', extra = ExtraField.new,
         | 
| 99 | 
            +
                  compression_method = Entry::DEFLATED, level = Zip.default_compression
         | 
| 100 | 
            +
                )
         | 
| 100 101 | 
             
                  raise Error, 'zip stream is closed' if @closed
         | 
| 101 102 |  | 
| 102 | 
            -
                  new_entry = | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
                  init_next_entry(new_entry | 
| 103 | 
            +
                  new_entry =
         | 
| 104 | 
            +
                    if entry_name.kind_of?(Entry) || entry_name.kind_of?(StreamableStream)
         | 
| 105 | 
            +
                      entry_name
         | 
| 106 | 
            +
                    else
         | 
| 107 | 
            +
                      Entry.new(
         | 
| 108 | 
            +
                        @file_name, entry_name.to_s, comment: comment, extra: extra,
         | 
| 109 | 
            +
                        compression_method: compression_method, compression_level: level
         | 
| 110 | 
            +
                      )
         | 
| 111 | 
            +
                    end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  init_next_entry(new_entry)
         | 
| 113 114 | 
             
                  @current_entry = new_entry
         | 
| 114 115 | 
             
                end
         | 
| 115 116 |  | 
| @@ -119,7 +120,7 @@ module Zip | |
| 119 120 | 
             
                  raise Error, 'entry is not a ZipEntry' unless entry.kind_of?(Entry)
         | 
| 120 121 |  | 
| 121 122 | 
             
                  finalize_current_entry
         | 
| 122 | 
            -
                  @ | 
| 123 | 
            +
                  @cdir << entry
         | 
| 123 124 | 
             
                  src_pos = entry.local_header_offset
         | 
| 124 125 | 
             
                  entry.write_local_entry(@output_stream)
         | 
| 125 126 | 
             
                  @compressor = NullCompressor.instance
         | 
| @@ -143,47 +144,45 @@ module Zip | |
| 143 144 | 
             
                                                   @current_entry.calculate_local_header_size
         | 
| 144 145 | 
             
                  @current_entry.size = @compressor.size
         | 
| 145 146 | 
             
                  @current_entry.crc = @compressor.crc
         | 
| 146 | 
            -
                  @output_stream << @encrypter.data_descriptor( | 
| 147 | 
            +
                  @output_stream << @encrypter.data_descriptor(
         | 
| 148 | 
            +
                    @current_entry.crc,
         | 
| 149 | 
            +
                    @current_entry.compressed_size,
         | 
| 150 | 
            +
                    @current_entry.size
         | 
| 151 | 
            +
                  )
         | 
| 147 152 | 
             
                  @current_entry.gp_flags |= @encrypter.gp_flags
         | 
| 148 153 | 
             
                  @current_entry = nil
         | 
| 149 154 | 
             
                  @compressor = ::Zip::NullCompressor.instance
         | 
| 150 155 | 
             
                end
         | 
| 151 156 |  | 
| 152 | 
            -
                def init_next_entry(entry | 
| 157 | 
            +
                def init_next_entry(entry)
         | 
| 153 158 | 
             
                  finalize_current_entry
         | 
| 154 | 
            -
                  @ | 
| 159 | 
            +
                  @cdir << entry
         | 
| 155 160 | 
             
                  entry.write_local_entry(@output_stream)
         | 
| 156 161 | 
             
                  @encrypter.reset!
         | 
| 157 162 | 
             
                  @output_stream << @encrypter.header(entry.mtime)
         | 
| 158 | 
            -
                  @compressor = get_compressor(entry | 
| 163 | 
            +
                  @compressor = get_compressor(entry)
         | 
| 159 164 | 
             
                end
         | 
| 160 165 |  | 
| 161 | 
            -
                def get_compressor(entry | 
| 166 | 
            +
                def get_compressor(entry)
         | 
| 162 167 | 
             
                  case entry.compression_method
         | 
| 163 168 | 
             
                  when Entry::DEFLATED
         | 
| 164 | 
            -
                    ::Zip::Deflater.new(@output_stream,  | 
| 169 | 
            +
                    ::Zip::Deflater.new(@output_stream, entry.compression_level, @encrypter)
         | 
| 165 170 | 
             
                  when Entry::STORED
         | 
| 166 171 | 
             
                    ::Zip::PassThruCompressor.new(@output_stream)
         | 
| 167 172 | 
             
                  else
         | 
| 168 | 
            -
                    raise ::Zip::CompressionMethodError,
         | 
| 169 | 
            -
                          "Invalid compression method: '#{entry.compression_method}'"
         | 
| 173 | 
            +
                    raise ::Zip::CompressionMethodError, entry.compression_method
         | 
| 170 174 | 
             
                  end
         | 
| 171 175 | 
             
                end
         | 
| 172 176 |  | 
| 173 177 | 
             
                def update_local_headers
         | 
| 174 178 | 
             
                  pos = @output_stream.pos
         | 
| 175 | 
            -
                  @ | 
| 179 | 
            +
                  @cdir.each do |entry|
         | 
| 176 180 | 
             
                    @output_stream.pos = entry.local_header_offset
         | 
| 177 | 
            -
                    entry.write_local_entry(@output_stream, true)
         | 
| 181 | 
            +
                    entry.write_local_entry(@output_stream, rewrite: true)
         | 
| 178 182 | 
             
                  end
         | 
| 179 183 | 
             
                  @output_stream.pos = pos
         | 
| 180 184 | 
             
                end
         | 
| 181 185 |  | 
| 182 | 
            -
                def write_central_directory
         | 
| 183 | 
            -
                  cdir = CentralDirectory.new(@entry_set, @comment)
         | 
| 184 | 
            -
                  cdir.write_to_stream(@output_stream)
         | 
| 185 | 
            -
                end
         | 
| 186 | 
            -
             | 
| 187 186 | 
             
                protected
         | 
| 188 187 |  | 
| 189 188 | 
             
                def finish
         | 
| @@ -1,11 +1,13 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Zip
         | 
| 2 | 
            -
              class PassThruDecompressor < Decompressor  | 
| 4 | 
            +
              class PassThruDecompressor < Decompressor # :nodoc:all
         | 
| 3 5 | 
             
                def initialize(*args)
         | 
| 4 6 | 
             
                  super
         | 
| 5 7 | 
             
                  @read_so_far = 0
         | 
| 6 8 | 
             
                end
         | 
| 7 9 |  | 
| 8 | 
            -
                def read(length = nil, outbuf = '' | 
| 10 | 
            +
                def read(length = nil, outbuf = +'')
         | 
| 9 11 | 
             
                  return (length.nil? || length.zero? ? '' : nil) if eof
         | 
| 10 12 |  | 
| 11 13 | 
             
                  if length.nil? || (@read_so_far + length) > decompressed_size
         | 
    
        data/lib/zip/version.rb
    CHANGED
    
    
    
        data/lib/zip.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require 'English'
         | 
| 2 4 | 
             
            require 'delegate'
         | 
| 3 5 | 
             
            require 'singleton'
         | 
| @@ -33,22 +35,12 @@ require 'zip/streamable_stream' | |
| 33 35 | 
             
            require 'zip/streamable_directory'
         | 
| 34 36 | 
             
            require 'zip/errors'
         | 
| 35 37 |  | 
| 38 | 
            +
            # Rubyzip is a ruby module for reading and writing zip files.
         | 
| 39 | 
            +
            #
         | 
| 40 | 
            +
            # The main entry points are File, InputStream and OutputStream. For a
         | 
| 41 | 
            +
            # file/directory interface in the style of the standard ruby ::File and
         | 
| 42 | 
            +
            # ::Dir APIs then `require 'zip/filesystem'` and see FileSystem.
         | 
| 36 43 | 
             
            module Zip
         | 
| 37 | 
            -
              V3_API_WARNING_MSG = <<~END_MSG
         | 
| 38 | 
            -
                You have called '%s' which is changing or deprecated
         | 
| 39 | 
            -
                in version 3.0.0. Please see
         | 
| 40 | 
            -
                  https://github.com/rubyzip/rubyzip/wiki/Updating-to-version-3.x
         | 
| 41 | 
            -
                for more information.
         | 
| 42 | 
            -
              END_MSG
         | 
| 43 | 
            -
             | 
| 44 | 
            -
              def self.warn_about_v3_api(method)
         | 
| 45 | 
            -
                warn V3_API_WARNING_MSG % method if ENV['RUBYZIP_V3_API_WARN']
         | 
| 46 | 
            -
              end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
              if RUBY_VERSION < '3.0'
         | 
| 49 | 
            -
                warn 'RubyZip 3.0 will require Ruby 3.0 or later.' if ENV['RUBYZIP_V3_API_WARN']
         | 
| 50 | 
            -
              end
         | 
| 51 | 
            -
             | 
| 52 44 | 
             
              extend self
         | 
| 53 45 | 
             
              attr_accessor :unicode_names,
         | 
| 54 46 | 
             
                            :on_exists_proc,
         | 
| @@ -61,6 +53,12 @@ module Zip | |
| 61 53 | 
             
                            :force_entry_names_encoding,
         | 
| 62 54 | 
             
                            :validate_entry_sizes
         | 
| 63 55 |  | 
| 56 | 
            +
              DEFAULT_RESTORE_OPTIONS = {
         | 
| 57 | 
            +
                restore_ownership:   false,
         | 
| 58 | 
            +
                restore_permissions: true,
         | 
| 59 | 
            +
                restore_times:       true
         | 
| 60 | 
            +
              }.freeze
         | 
| 61 | 
            +
             | 
| 64 62 | 
             
              def reset!
         | 
| 65 63 | 
             
                @_ran_once = false
         | 
| 66 64 | 
             
                @unicode_names = false
         | 
| @@ -68,9 +66,10 @@ module Zip | |
| 68 66 | 
             
                @continue_on_exists_proc = false
         | 
| 69 67 | 
             
                @sort_entries = false
         | 
| 70 68 | 
             
                @default_compression = ::Zlib::DEFAULT_COMPRESSION
         | 
| 71 | 
            -
                @write_zip64_support =  | 
| 69 | 
            +
                @write_zip64_support = true
         | 
| 72 70 | 
             
                @warn_invalid_date = true
         | 
| 73 71 | 
             
                @case_insensitive_match = false
         | 
| 72 | 
            +
                @force_entry_names_encoding = nil
         | 
| 74 73 | 
             
                @validate_entry_sizes = true
         | 
| 75 74 | 
             
              end
         | 
| 76 75 |  | 
    
        data/rubyzip.gemspec
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative 'lib/zip/version'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Gem::Specification.new do |s|
         | 
| 6 | 
            +
              s.name          = 'rubyzip'
         | 
| 7 | 
            +
              s.version       = ::Zip::VERSION
         | 
| 8 | 
            +
              s.authors       = ['Robert Haines', 'John Lees-Miller', 'Alexander Simonov']
         | 
| 9 | 
            +
              s.email         = [
         | 
| 10 | 
            +
                'hainesr@gmail.com', 'jdleesmiller@gmail.com', 'alex@simonov.me'
         | 
| 11 | 
            +
              ]
         | 
| 12 | 
            +
              s.homepage      = 'http://github.com/rubyzip/rubyzip'
         | 
| 13 | 
            +
              s.platform      = Gem::Platform::RUBY
         | 
| 14 | 
            +
              s.summary       = 'rubyzip is a ruby module for reading and writing zip files'
         | 
| 15 | 
            +
              s.files         = Dir.glob('{samples,lib}/**/*.rb') +
         | 
| 16 | 
            +
                                %w[README.md Changelog.md Rakefile rubyzip.gemspec]
         | 
| 17 | 
            +
              s.require_paths = ['lib']
         | 
| 18 | 
            +
              s.license       = 'BSD-2-Clause'
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              s.metadata      = {
         | 
| 21 | 
            +
                'bug_tracker_uri'   => 'https://github.com/rubyzip/rubyzip/issues',
         | 
| 22 | 
            +
                'changelog_uri'     => "https://github.com/rubyzip/rubyzip/blob/v#{s.version}/Changelog.md",
         | 
| 23 | 
            +
                'documentation_uri' => "https://www.rubydoc.info/gems/rubyzip/#{s.version}",
         | 
| 24 | 
            +
                'source_code_uri'   => "https://github.com/rubyzip/rubyzip/tree/v#{s.version}",
         | 
| 25 | 
            +
                'wiki_uri'          => 'https://github.com/rubyzip/rubyzip/wiki'
         | 
| 26 | 
            +
              }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              s.required_ruby_version = '>= 2.5'
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              s.add_development_dependency 'minitest', '~> 5.4'
         | 
| 31 | 
            +
              s.add_development_dependency 'rake', '~> 12.3.3'
         | 
| 32 | 
            +
              s.add_development_dependency 'rdoc', '~> 6.4.0'
         | 
| 33 | 
            +
              s.add_development_dependency 'rubocop', '~> 1.12.0'
         | 
| 34 | 
            +
              s.add_development_dependency 'rubocop-performance', '~> 1.10.0'
         | 
| 35 | 
            +
              s.add_development_dependency 'rubocop-rake', '~> 0.5.0'
         | 
| 36 | 
            +
              s.add_development_dependency 'simplecov', '~> 0.18.0'
         | 
| 37 | 
            +
              s.add_development_dependency 'simplecov-lcov', '~> 0.8'
         | 
| 38 | 
            +
            end
         |