Upgrade Vendored rubyzip to Version 0.9.3

This commit is contained in:
Jacques Distler 2009-12-23 02:19:16 -06:00
parent 7c51accaab
commit 1d32d45944
34 changed files with 247 additions and 36 deletions

View file

@ -1,3 +1,16 @@
= Version 0.9.3
Fixed: Added ZipEntry::name_encoding which retrieves the character
encoding of the name and comment of the entry. Also added convenience
methods ZipEntry::name_in(enc) and ZipEntry::comment_in(enc) for
getting zip entry names and comments in a specified character
encoding.
= Version 0.9.2
Fixed: Renaming an entry failed if the entry's new name was a
different length than its old name. (Diego Barros)
= Version 0.9.1 = Version 0.9.1
Added symlink support and support for unix file permissions. Reduced Added symlink support and support for unix file permissions. Reduced

View file

@ -69,4 +69,4 @@ Thomas Sondergaard (thomas at sondergaard.cc)
Technorama Ltd. (oss-ruby-zip at technorama.net) Technorama Ltd. (oss-ruby-zip at technorama.net)
extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org) extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org)

View file

@ -62,7 +62,7 @@ end
Rake::RDocTask.new do |rd| Rake::RDocTask.new do |rd|
rd.main = "README" rd.main = "README"
rd.rdoc_files.add %W{ lib/zip/*.rb README NEWS TODO ChangeLog } rd.rdoc_files.add %W{ lib/zip/*.rb README NEWS TODO ChangeLog }
rd.options << "--title 'rubyzip documentation' --webcvs http://cvs.sourceforge.net/viewcvs.py/rubyzip/rubyzip/" rd.options << "-t 'rubyzip documentation' --webcvs http://cvs.sourceforge.net/viewcvs.py/rubyzip/rubyzip/"
# rd.options << "--all" # rd.options << "--all"
end end

View file

@ -4,19 +4,20 @@ $VERBOSE = true
require 'rbconfig' require 'rbconfig'
require 'find' require 'find'
require 'ftools' require 'fileutils'
include Config include Config
files = %w{ stdrubyext.rb ioextras.rb zip.rb zipfilesystem.rb ziprequire.rb tempfile_bugfixed.rb } files = %w{ stdrubyext.rb ioextras.rb zip.rb zipfilesystem.rb ziprequire.rb tempfile_bugfixed.rb }
INSTALL_DIR = File.join(CONFIG["sitelibdir"], "zip") INSTALL_DIR = File.join(CONFIG["sitelibdir"], "zip")
File.makedirs(INSTALL_DIR) FileUtils.makedirs(INSTALL_DIR)
SOURCE_DIR = File.join(File.dirname($0), "lib/zip") SOURCE_DIR = File.join(File.dirname($0), "lib/zip")
files.each { files.each {
|filename| |filename|
installPath = File.join(INSTALL_DIR, filename) installPath = File.join(INSTALL_DIR, filename)
File::install(File.join(SOURCE_DIR, filename), installPath, 0644, true) FileUtils::install(File.join(SOURCE_DIR, filename), installPath, 0644,
:verbose => true)
} }

View file

@ -1,6 +1,6 @@
module IOExtras #:nodoc: module IOExtras #:nodoc:
CHUNK_SIZE = 32768 CHUNK_SIZE = 131072
RANGE_ALL = 0..-1 RANGE_ALL = 0..-1
@ -9,6 +9,16 @@ module IOExtras #:nodoc:
ostream.write(istream.read(CHUNK_SIZE, s)) until istream.eof? ostream.write(istream.read(CHUNK_SIZE, s)) until istream.eof?
end end
def self.copy_stream_n(ostream, istream, nbytes)
s = ''
toread = nbytes
while (toread > 0 && ! istream.eof?)
tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
ostream.write(istream.read(tr, s))
toread -= tr
end
end
# Implements kind_of? in order to pretend to be an IO object # Implements kind_of? in order to pretend to be an IO object
module FakeIO module FakeIO

View file

@ -1,4 +1,5 @@
require 'delegate' require 'delegate'
require 'iconv'
require 'singleton' require 'singleton'
require 'tempfile' require 'tempfile'
require 'fileutils' require 'fileutils'
@ -20,7 +21,7 @@ end
module Zip module Zip
VERSION = '0.9.1' VERSION = '0.9.3'
RUBY_MINOR_VERSION = RUBY_VERSION.split(".")[1].to_i RUBY_MINOR_VERSION = RUBY_VERSION.split(".")[1].to_i
@ -349,6 +350,21 @@ module Zip
attr_reader :ftype, :filepath # :nodoc: attr_reader :ftype, :filepath # :nodoc:
# Returns the character encoding used for name and comment
def name_encoding
(@gp_flags & 0b100000000000) != 0 ? "utf8" : "CP437//"
end
# Returns the name in the encoding specified by enc
def name_in(enc)
Iconv.conv(enc, name_encoding, @name)
end
# Returns the name in the encoding specified by enc
def comment_in(enc)
Iconv.conv(enc, name_encoding, @name)
end
def initialize(zipfile = "", name = "", comment = "", extra = "", def initialize(zipfile = "", name = "", comment = "", extra = "",
compressed_size = 0, crc = 0, compressed_size = 0, crc = 0,
compression_method = ZipEntry::DEFLATED, size = 0, compression_method = ZipEntry::DEFLATED, size = 0,
@ -358,6 +374,7 @@ module Zip
raise ZipEntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /" raise ZipEntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
end end
@localHeaderOffset = 0 @localHeaderOffset = 0
@local_header_size = 0
@internalFileAttributes = 1 @internalFileAttributes = 1
@externalFileAttributes = 0 @externalFileAttributes = 0
@version = 52 # this library's version @version = 52 # this library's version
@ -432,7 +449,7 @@ module Zip
# Returns +true+ if the entry is a symlink. # Returns +true+ if the entry is a symlink.
def symlink? def symlink?
raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
@ftype == :link @ftype == :symlink
end end
def name_is_directory? #:nodoc:all def name_is_directory? #:nodoc:all
@ -440,10 +457,10 @@ module Zip
end end
def local_entry_offset #:nodoc:all def local_entry_offset #:nodoc:all
localHeaderOffset + local_header_size localHeaderOffset + @local_header_size
end end
def local_header_size #:nodoc:all def calculate_local_header_size #:nodoc:all
LOCAL_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.size : 0) + (@extra ? @extra.local_size : 0) LOCAL_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.size : 0) + (@extra ? @extra.local_size : 0)
end end
@ -491,7 +508,8 @@ module Zip
LOCAL_ENTRY_SIGNATURE = 0x04034b50 LOCAL_ENTRY_SIGNATURE = 0x04034b50
LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30 LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30
LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4+4+4 LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4+4+4
VERSION_NEEDED_TO_EXTRACT = 10
def read_local_entry(io) #:nodoc:all def read_local_entry(io) #:nodoc:all
@localHeaderOffset = io.tell @localHeaderOffset = io.tell
staticSizedFieldsBuf = io.read(LOCAL_ENTRY_STATIC_HEADER_LENGTH) staticSizedFieldsBuf = io.read(LOCAL_ENTRY_STATIC_HEADER_LENGTH)
@ -516,6 +534,7 @@ module Zip
raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'" raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'"
end end
set_time(lastModDate, lastModTime) set_time(lastModDate, lastModTime)
@name = io.read(nameLength) @name = io.read(nameLength)
extra = io.read(extraLength) extra = io.read(extraLength)
@ -529,6 +548,7 @@ module Zip
@extra = ZipExtraField.new(extra) @extra = ZipExtraField.new(extra)
end end
end end
@local_header_size = calculate_local_header_size
end end
def ZipEntry.read_local_entry(io) def ZipEntry.read_local_entry(io)
@ -544,7 +564,7 @@ module Zip
io << io <<
[LOCAL_ENTRY_SIGNATURE , [LOCAL_ENTRY_SIGNATURE ,
0 , VERSION_NEEDED_TO_EXTRACT , # version needed to extract
0 , # @gp_flags , 0 , # @gp_flags ,
@compression_method , @compression_method ,
@time.to_binary_dos_time , # @lastModTime , @time.to_binary_dos_time , # @lastModTime ,
@ -615,7 +635,7 @@ module Zip
when 010 when 010
@ftype = :file @ftype = :file
when 012 when 012
@ftype = :link @ftype = :symlink
else else
raise ZipInternalError, "unknown file type #{'0%o' % (@externalFileAttributes >> 28)}" raise ZipInternalError, "unknown file type #{'0%o' % (@externalFileAttributes >> 28)}"
end end
@ -626,6 +646,7 @@ module Zip
@ftype = :file @ftype = :file
end end
end end
@local_header_size = calculate_local_header_size
end end
def ZipEntry.read_c_dir_entry(io) #:nodoc:all def ZipEntry.read_c_dir_entry(io) #:nodoc:all
@ -662,8 +683,8 @@ module Zip
# ignore setuid/setgid bits by default. honor if @restore_ownership # ignore setuid/setgid bits by default. honor if @restore_ownership
unix_perms_mask = 01777 unix_perms_mask = 01777
unix_perms_mask = 07777 if (@restore_ownership) unix_perms_mask = 07777 if (@restore_ownership)
File::chmod(@unix_perms & unix_perms_mask, destPath) if (@restore_permissions && @unix_perms) FileUtils::chmod(@unix_perms & unix_perms_mask, destPath) if (@restore_permissions && @unix_perms)
File::chown(@unix_uid, @unix_gid, destPath) if (@restore_ownership && @unix_uid && @unix_gid && Process::egid == 0) FileUtils::chown(@unix_uid, @unix_gid, destPath) if (@restore_ownership && @unix_uid && @unix_gid && Process::egid == 0)
# File::utimes() # File::utimes()
end end
end end
@ -693,7 +714,7 @@ module Zip
[CENTRAL_DIRECTORY_ENTRY_SIGNATURE, [CENTRAL_DIRECTORY_ENTRY_SIGNATURE,
@version , # version of encoding software @version , # version of encoding software
@fstype , # filesystem type @fstype , # filesystem type
0 , # @versionNeededToExtract , VERSION_NEEDED_TO_EXTRACT , # @versionNeededToExtract ,
0 , # @gp_flags , 0 , # @gp_flags ,
@compression_method , @compression_method ,
@time.to_binary_dos_time , # @lastModTime , @time.to_binary_dos_time , # @lastModTime ,
@ -849,7 +870,7 @@ module Zip
return return
elsif File.exists? destPath elsif File.exists? destPath
if block_given? && yield(self, destPath) if block_given? && yield(self, destPath)
File.rm_f destPath FileUtils::rm_f destPath
else else
raise ZipDestinationFileExistsError, raise ZipDestinationFileExistsError,
"Cannot create directory '#{destPath}'. "+ "Cannot create directory '#{destPath}'. "+
@ -967,10 +988,10 @@ module Zip
src_pos = entry.local_entry_offset src_pos = entry.local_entry_offset
entry.write_local_entry(@outputStream) entry.write_local_entry(@outputStream)
@compressor = NullCompressor.instance @compressor = NullCompressor.instance
@outputStream << entry.get_raw_input_stream { entry.get_raw_input_stream {
|is| |is|
is.seek(src_pos, IO::SEEK_SET) is.seek(src_pos, IO::SEEK_SET)
is.read(entry.compressed_size) IOExtras.copy_stream_n(@outputStream, is, entry.compressed_size)
} }
@compressor = NullCompressor.instance @compressor = NullCompressor.instance
@currentEntry = nil @currentEntry = nil
@ -981,7 +1002,7 @@ module Zip
return unless @currentEntry return unless @currentEntry
finish finish
@currentEntry.compressed_size = @outputStream.tell - @currentEntry.localHeaderOffset - @currentEntry.compressed_size = @outputStream.tell - @currentEntry.localHeaderOffset -
@currentEntry.local_header_size @currentEntry.calculate_local_header_size
@currentEntry.size = @compressor.size @currentEntry.size = @compressor.size
@currentEntry.crc = @compressor.crc @currentEntry.crc = @compressor.crc
@currentEntry = nil @currentEntry = nil
@ -1453,7 +1474,9 @@ module Zip
def rename(entry, newName, &continueOnExistsProc) def rename(entry, newName, &continueOnExistsProc)
foundEntry = get_entry(entry) foundEntry = get_entry(entry)
check_entry_exists(newName, continueOnExistsProc, "rename") check_entry_exists(newName, continueOnExistsProc, "rename")
foundEntry.name=newName @entrySet.delete(foundEntry)
foundEntry.name = newName
@entrySet << foundEntry
end end
# Replaces the specified entry with the contents of srcPath (from # Replaces the specified entry with the contents of srcPath (from
@ -1566,7 +1589,7 @@ module Zip
tmpFilename = tmpfile.path tmpFilename = tmpfile.path
tmpfile.close tmpfile.close
if yield tmpFilename if yield tmpFilename
File.move(tmpFilename, name) File.rename(tmpFilename, name)
end end
end end

View file

@ -225,6 +225,7 @@ module Zip
end end
def open(fileName, openMode = "r", &block) def open(fileName, openMode = "r", &block)
openMode.gsub!("b", "") # ignore b option
case openMode case openMode
when "r" when "r"
@mappedZip.get_input_stream(fileName, &block) @mappedZip.get_input_stream(fileName, &block)

View file

@ -3,7 +3,6 @@
$: << "../lib" $: << "../lib"
require 'zip/zipfilesystem' require 'zip/zipfilesystem'
require 'ftools'
EXAMPLE_ZIP = "filesystem.zip" EXAMPLE_ZIP = "filesystem.zip"

View file

@ -0,0 +1,150 @@
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>ZipDialogUI</class>
<widget class="QDialog">
<property name="name">
<cstring>ZipDialogUI</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>416</width>
<height>397</height>
</rect>
</property>
<property name="caption">
<string>Rubyzip</string>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<hbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QListView">
<column>
<property name="text">
<string>Entry</string>
</property>
<property name="clickable">
<bool>true</bool>
</property>
<property name="resizable">
<bool>true</bool>
</property>
</column>
<column>
<property name="text">
<string>Size</string>
</property>
<property name="clickable">
<bool>true</bool>
</property>
<property name="resizable">
<bool>true</bool>
</property>
</column>
<property name="name">
<cstring>entry_list_view</cstring>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>200</height>
</size>
</property>
<property name="resizePolicy">
<enum>Manual</enum>
</property>
<property name="selectionMode">
<enum>Extended</enum>
</property>
<property name="resizeMode">
<enum>AllColumns</enum>
</property>
</widget>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout2</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QPushButton">
<property name="name">
<cstring>add_button</cstring>
</property>
<property name="text">
<string>&amp;Add...</string>
</property>
<property name="accel">
<string>Alt+A</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton">
<property name="name">
<cstring>extract_button</cstring>
</property>
<property name="text">
<string>&amp;Extract...</string>
</property>
<property name="accel">
<string>Alt+E</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
</widget>
<spacer>
<property name="name">
<cstring>Spacer1</cstring>
</property>
<property name="orientation">
<enum>Vertical</enum>
</property>
<property name="sizeType">
<enum>Expanding</enum>
</property>
<property name="sizeHint">
<size>
<width>20</width>
<height>160</height>
</size>
</property>
</spacer>
<widget class="QPushButton">
<property name="name">
<cstring>close_button</cstring>
</property>
<property name="text">
<string>&amp;Close</string>
</property>
<property name="accel">
<string>Alt+C</string>
</property>
<property name="autoDefault">
<bool>true</bool>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</vbox>
</widget>
</hbox>
</widget>
<connections>
<connection>
<sender>close_button</sender>
<signal>clicked()</signal>
<receiver>ZipDialogUI</receiver>
<slot>accept()</slot>
</connection>
</connections>
<layoutdefaults spacing="6" margin="11"/>
</UI>

View file

@ -6,6 +6,7 @@ $: << "../lib"
require 'zip/zipfilesystem' require 'zip/zipfilesystem'
require 'test/unit' require 'test/unit'
require 'fileutils'
module ExtraAssertions module ExtraAssertions
@ -23,7 +24,7 @@ module ExtraAssertions
assert_equal(retVal, yield) # Invoke test assert_equal(retVal, yield) # Invoke test
assert_equal(expectedArgs, callArgs) assert_equal(expectedArgs, callArgs)
ensure ensure
anObject.instance_eval "alias #{method} #{method}_org" anObject.instance_eval "undef #{method}; alias #{method} #{method}_org"
end end
end end
@ -67,6 +68,15 @@ class ZipFsFileNonmutatingTest < Test::Unit::TestCase
} }
assert(blockCalled) assert(blockCalled)
blockCalled = false
@zipFile.file.open("file1", "rb") { # test binary flag is ignored
|f|
blockCalled = true
assert_equal("this is the entry 'file1' in my test archive!",
f.readline.chomp)
}
assert(blockCalled)
blockCalled = false blockCalled = false
@zipFile.dir.chdir "dir2" @zipFile.dir.chdir "dir2"
@zipFile.file.open("file21", "r") { @zipFile.file.open("file21", "r") {
@ -552,7 +562,7 @@ end
class ZipFsFileMutatingTest < Test::Unit::TestCase class ZipFsFileMutatingTest < Test::Unit::TestCase
TEST_ZIP = "zipWithDirs_copy.zip" TEST_ZIP = "zipWithDirs_copy.zip"
def setup def setup
File.copy("data/zipWithDirs.zip", TEST_ZIP) FileUtils.cp("data/zipWithDirs.zip", TEST_ZIP)
end end
def teardown def teardown
@ -579,7 +589,7 @@ class ZipFsFileMutatingTest < Test::Unit::TestCase
zf.file.read("test_open_write_entry")) zf.file.read("test_open_write_entry"))
# Test with existing entry # Test with existing entry
zf.file.open("file1", "w") { zf.file.open("file1", "wb") { #also check that 'b' option is ignored
|f| |f|
blockCalled = true blockCalled = true
f.write "This is what I'm writing too" f.write "This is what I'm writing too"
@ -640,7 +650,7 @@ class ZipFsDirectoryTest < Test::Unit::TestCase
TEST_ZIP = "zipWithDirs_copy.zip" TEST_ZIP = "zipWithDirs_copy.zip"
def setup def setup
File.copy("data/zipWithDirs.zip", TEST_ZIP) FileUtils.cp("data/zipWithDirs.zip", TEST_ZIP)
end end
def test_delete def test_delete

View file

@ -5,6 +5,7 @@ $VERBOSE = true
$: << "../lib" $: << "../lib"
require 'test/unit' require 'test/unit'
require 'fileutils'
require 'zip/zip' require 'zip/zip'
require 'gentestfiles' require 'gentestfiles'
@ -1016,7 +1017,7 @@ module CommonZipFileFixture
def setup def setup
File.delete(EMPTY_FILENAME) if File.exists?(EMPTY_FILENAME) File.delete(EMPTY_FILENAME) if File.exists?(EMPTY_FILENAME)
File.copy(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name) FileUtils.cp(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name)
end end
end end
@ -1126,7 +1127,7 @@ class ZipFileTest < Test::Unit::TestCase
def test_remove def test_remove
entryToRemove, *remainingEntries = TEST_ZIP.entry_names entryToRemove, *remainingEntries = TEST_ZIP.entry_names
File.copy(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name) FileUtils.cp(TestZipFile::TEST_ZIP2.zip_name, TEST_ZIP.zip_name)
zf = ZipFile.new(TEST_ZIP.zip_name) zf = ZipFile.new(TEST_ZIP.zip_name)
assert(zf.entries.map { |e| e.name }.include?(entryToRemove)) assert(zf.entries.map { |e| e.name }.include?(entryToRemove))
@ -1141,24 +1142,27 @@ class ZipFileTest < Test::Unit::TestCase
zfRead.close zfRead.close
end end
def test_rename def test_rename
entryToRename, *remainingEntries = TEST_ZIP.entry_names entryToRename, *remainingEntries = TEST_ZIP.entry_names
zf = ZipFile.new(TEST_ZIP.zip_name) zf = ZipFile.new(TEST_ZIP.zip_name)
assert(zf.entries.map { |e| e.name }.include?(entryToRename)) assert(zf.entries.map { |e| e.name }.include?(entryToRename))
newName = "changed name" contents = zf.read(entryToRename)
newName = "changed entry name"
assert(! zf.entries.map { |e| e.name }.include?(newName)) assert(! zf.entries.map { |e| e.name }.include?(newName))
zf.rename(entryToRename, newName) zf.rename(entryToRename, newName)
assert(zf.entries.map { |e| e.name }.include?(newName)) assert(zf.entries.map { |e| e.name }.include?(newName))
assert_equal(contents, zf.read(newName))
zf.close zf.close
zfRead = ZipFile.new(TEST_ZIP.zip_name) zfRead = ZipFile.new(TEST_ZIP.zip_name)
assert(zfRead.entries.map { |e| e.name }.include?(newName)) assert(zfRead.entries.map { |e| e.name }.include?(newName))
zfRead.close assert_equal(contents, zf.read(newName))
zfRead.close
end end
def test_renameToExistingEntry def test_renameToExistingEntry
@ -1271,12 +1275,12 @@ class ZipFileTest < Test::Unit::TestCase
# can delete the file you used to add the entry to the zip file # can delete the file you used to add the entry to the zip file
# with # with
def test_commitUseZipEntry def test_commitUseZipEntry
File.copy(TestFiles::RANDOM_ASCII_FILE1, "okToDelete.txt") FileUtils.cp(TestFiles::RANDOM_ASCII_FILE1, "okToDelete.txt")
zf = ZipFile.open(TEST_ZIP.zip_name) zf = ZipFile.open(TEST_ZIP.zip_name)
zf.add("okToDelete.txt", "okToDelete.txt") zf.add("okToDelete.txt", "okToDelete.txt")
assert_contains(zf, "okToDelete.txt") assert_contains(zf, "okToDelete.txt")
zf.commit zf.commit
File.move("okToDelete.txt", "okToDeleteMoved.txt") File.rename("okToDelete.txt", "okToDeleteMoved.txt")
assert_contains(zf, "okToDelete.txt", "okToDeleteMoved.txt") assert_contains(zf, "okToDelete.txt", "okToDeleteMoved.txt")
end end