nothing actually uses the zip library, ripping it out. fixes 591
git-svn-id: file:///home/svn/framework3/trunk@7663 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
c2fac74ae2
commit
b486654975
|
@ -1,72 +0,0 @@
|
||||||
= rubyzip
|
|
||||||
|
|
||||||
rubyzip is a ruby library for reading and writing zip files.
|
|
||||||
|
|
||||||
= Install
|
|
||||||
|
|
||||||
If you have rubygems you can install rubyzip directly from the gem
|
|
||||||
repository
|
|
||||||
|
|
||||||
gem install rubyzip
|
|
||||||
|
|
||||||
Otherwise obtain the source (see below) and run
|
|
||||||
|
|
||||||
ruby install.rb
|
|
||||||
|
|
||||||
To run the unit tests you need to have test::unit installed
|
|
||||||
|
|
||||||
rake test
|
|
||||||
|
|
||||||
|
|
||||||
= Documentation
|
|
||||||
|
|
||||||
There is more than one way to access or create a zip archive with
|
|
||||||
rubyzip. The basic API is modeled after the classes in
|
|
||||||
java.util.zip from the Java SDK. This means there are classes such
|
|
||||||
as Zip::ZipInputStream, Zip::ZipOutputStream and
|
|
||||||
Zip::ZipFile. Zip::ZipInputStream provides a basic interface for
|
|
||||||
iterating through the entries in a zip archive and reading from the
|
|
||||||
entries in the same way as from a regular File or IO
|
|
||||||
object. ZipOutputStream is the corresponding basic output
|
|
||||||
facility. Zip::ZipFile provides a mean for accessing the archives
|
|
||||||
central directory and provides means for accessing any entry without
|
|
||||||
having to iterate through the archive. Unlike Java's
|
|
||||||
java.util.zip.ZipFile rubyzip's Zip::ZipFile is mutable, which means
|
|
||||||
it can be used to change zip files as well.
|
|
||||||
|
|
||||||
Another way to access a zip archive with rubyzip is to use rubyzip's
|
|
||||||
Zip::ZipFileSystem API. Using this API files can be read from and
|
|
||||||
written to the archive in much the same manner as ruby's builtin
|
|
||||||
classes allows files to be read from and written to the file system.
|
|
||||||
|
|
||||||
rubyzip also features the
|
|
||||||
zip/ziprequire.rb[link:files/lib/zip/ziprequire_rb.html] module which
|
|
||||||
allows ruby to load ruby modules from zip archives.
|
|
||||||
|
|
||||||
For details about the specific behaviour of classes and methods refer
|
|
||||||
to the test suite. Finally you can generate the rdoc documentation or
|
|
||||||
visit http://rubyzip.sourceforge.net.
|
|
||||||
|
|
||||||
= License
|
|
||||||
|
|
||||||
rubyzip is distributed under the same license as ruby. See
|
|
||||||
http://www.ruby-lang.org/en/LICENSE.txt
|
|
||||||
|
|
||||||
|
|
||||||
= Website and Project Home
|
|
||||||
|
|
||||||
http://rubyzip.sourceforge.net
|
|
||||||
|
|
||||||
http://sourceforge.net/projects/rubyzip
|
|
||||||
|
|
||||||
== Download (tarballs and gems)
|
|
||||||
|
|
||||||
http://sourceforge.net/project/showfiles.php?group_id=43107&package_id=35377
|
|
||||||
|
|
||||||
= Authors
|
|
||||||
|
|
||||||
Thomas Sondergaard (thomas at sondergaard.cc)
|
|
||||||
|
|
||||||
Technorama Ltd. (oss-ruby-zip at technorama.net)
|
|
||||||
|
|
||||||
extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org)
|
|
|
@ -1,155 +0,0 @@
|
||||||
module IOExtras #:nodoc:
|
|
||||||
|
|
||||||
CHUNK_SIZE = 32768
|
|
||||||
|
|
||||||
RANGE_ALL = 0..-1
|
|
||||||
|
|
||||||
def self.copy_stream(ostream, istream)
|
|
||||||
s = ''
|
|
||||||
ostream.write(istream.read(CHUNK_SIZE, s)) until istream.eof?
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Implements kind_of? in order to pretend to be an IO object
|
|
||||||
module FakeIO
|
|
||||||
def kind_of?(object)
|
|
||||||
object == IO || super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Implements many of the convenience methods of IO
|
|
||||||
# such as gets, getc, readline and readlines
|
|
||||||
# depends on: input_finished?, produce_input and read
|
|
||||||
module AbstractInputStream
|
|
||||||
include Enumerable
|
|
||||||
include FakeIO
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super
|
|
||||||
@lineno = 0
|
|
||||||
@outputBuffer = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :lineno
|
|
||||||
|
|
||||||
def read(numberOfBytes = nil, buf = nil)
|
|
||||||
tbuf = nil
|
|
||||||
|
|
||||||
if @outputBuffer.length > 0
|
|
||||||
if numberOfBytes <= @outputBuffer.length
|
|
||||||
tbuf = @outputBuffer.slice!(0, numberOfBytes)
|
|
||||||
else
|
|
||||||
numberOfBytes -= @outputBuffer.length if (numberOfBytes)
|
|
||||||
rbuf = sysread(numberOfBytes, buf)
|
|
||||||
tbuf = @outputBuffer
|
|
||||||
tbuf << rbuf if (rbuf)
|
|
||||||
@outputBuffer = ""
|
|
||||||
end
|
|
||||||
else
|
|
||||||
tbuf = sysread(numberOfBytes, buf)
|
|
||||||
end
|
|
||||||
|
|
||||||
return nil unless (tbuf)
|
|
||||||
|
|
||||||
if buf
|
|
||||||
buf.replace(tbuf)
|
|
||||||
else
|
|
||||||
buf = tbuf
|
|
||||||
end
|
|
||||||
|
|
||||||
buf
|
|
||||||
end
|
|
||||||
|
|
||||||
def readlines(aSepString = $/)
|
|
||||||
retVal = []
|
|
||||||
each_line(aSepString) { |line| retVal << line }
|
|
||||||
return retVal
|
|
||||||
end
|
|
||||||
|
|
||||||
def gets(aSepString=$/)
|
|
||||||
@lineno = @lineno.next
|
|
||||||
return read if aSepString == nil
|
|
||||||
aSepString="#{$/}#{$/}" if aSepString == ""
|
|
||||||
|
|
||||||
bufferIndex=0
|
|
||||||
while ((matchIndex = @outputBuffer.index(aSepString, bufferIndex)) == nil)
|
|
||||||
bufferIndex=@outputBuffer.length
|
|
||||||
if input_finished?
|
|
||||||
return @outputBuffer.empty? ? nil : flush
|
|
||||||
end
|
|
||||||
@outputBuffer << produce_input
|
|
||||||
end
|
|
||||||
sepIndex=matchIndex + aSepString.length
|
|
||||||
return @outputBuffer.slice!(0...sepIndex)
|
|
||||||
end
|
|
||||||
|
|
||||||
def flush
|
|
||||||
retVal=@outputBuffer
|
|
||||||
@outputBuffer=""
|
|
||||||
return retVal
|
|
||||||
end
|
|
||||||
|
|
||||||
def readline(aSepString = $/)
|
|
||||||
retVal = gets(aSepString)
|
|
||||||
raise EOFError if retVal == nil
|
|
||||||
return retVal
|
|
||||||
end
|
|
||||||
|
|
||||||
def each_line(aSepString = $/)
|
|
||||||
while true
|
|
||||||
yield readline(aSepString)
|
|
||||||
end
|
|
||||||
rescue EOFError
|
|
||||||
end
|
|
||||||
|
|
||||||
alias_method :each, :each_line
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Implements many of the output convenience methods of IO.
|
|
||||||
# relies on <<
|
|
||||||
module AbstractOutputStream
|
|
||||||
include FakeIO
|
|
||||||
|
|
||||||
def write(data)
|
|
||||||
self << data
|
|
||||||
data.to_s.length
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def print(*params)
|
|
||||||
self << params.to_s << $\.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def printf(aFormatString, *params)
|
|
||||||
self << sprintf(aFormatString, *params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def putc(anObject)
|
|
||||||
self << case anObject
|
|
||||||
when Fixnum then anObject.chr
|
|
||||||
when String then anObject
|
|
||||||
else raise TypeError, "putc: Only Fixnum and String supported"
|
|
||||||
end
|
|
||||||
anObject
|
|
||||||
end
|
|
||||||
|
|
||||||
def puts(*params)
|
|
||||||
params << "\n" if params.empty?
|
|
||||||
params.flatten.each {
|
|
||||||
|element|
|
|
||||||
val = element.to_s
|
|
||||||
self << val
|
|
||||||
self << "\n" unless val[-1,1] == "\n"
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end # IOExtras namespace module
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Copyright (C) 2002-2004 Thomas Sondergaard
|
|
||||||
# rubyzip is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the ruby license.
|
|
|
@ -1,111 +0,0 @@
|
||||||
unless Enumerable.method_defined?(:inject)
|
|
||||||
module Enumerable #:nodoc:all
|
|
||||||
def inject(n = 0)
|
|
||||||
each { |value| n = yield(n, value) }
|
|
||||||
n
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
module Enumerable #:nodoc:all
|
|
||||||
# returns a new array of all the return values not equal to nil
|
|
||||||
# This implementation could be faster
|
|
||||||
def select_map(&aProc)
|
|
||||||
map(&aProc).reject { |e| e.nil? }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
unless Object.method_defined?(:object_id)
|
|
||||||
class Object #:nodoc:all
|
|
||||||
# Using object_id which is the new thing, so we need
|
|
||||||
# to make that work in versions prior to 1.8.0
|
|
||||||
alias object_id id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
unless File.respond_to?(:read)
|
|
||||||
class File # :nodoc:all
|
|
||||||
# singleton method read does not exist in 1.6.x
|
|
||||||
def self.read(fileName)
|
|
||||||
open(fileName) { |f| f.read }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class String #:nodoc:all
|
|
||||||
def starts_with(aString)
|
|
||||||
rindex(aString, 0) == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def ends_with(aString)
|
|
||||||
index(aString, -aString.size)
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_end(aString)
|
|
||||||
ends_with(aString) ? self : self + aString
|
|
||||||
end
|
|
||||||
|
|
||||||
def lchop
|
|
||||||
slice(1, length)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Time #:nodoc:all
|
|
||||||
|
|
||||||
#MS-DOS File Date and Time format as used in Interrupt 21H Function 57H:
|
|
||||||
#
|
|
||||||
# Register CX, the Time:
|
|
||||||
# Bits 0-4 2 second increments (0-29)
|
|
||||||
# Bits 5-10 minutes (0-59)
|
|
||||||
# bits 11-15 hours (0-24)
|
|
||||||
#
|
|
||||||
# Register DX, the Date:
|
|
||||||
# Bits 0-4 day (1-31)
|
|
||||||
# bits 5-8 month (1-12)
|
|
||||||
# bits 9-15 year (four digit year minus 1980)
|
|
||||||
|
|
||||||
|
|
||||||
def to_binary_dos_time
|
|
||||||
(sec/2) +
|
|
||||||
(min << 5) +
|
|
||||||
(hour << 11)
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_binary_dos_date
|
|
||||||
(day) +
|
|
||||||
(month << 5) +
|
|
||||||
((year - 1980) << 9)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Dos time is only stored with two seconds accuracy
|
|
||||||
def dos_equals(other)
|
|
||||||
to_i/2 == other.to_i/2
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.parse_binary_dos_format(binaryDosDate, binaryDosTime)
|
|
||||||
second = 2 * ( 0b11111 & binaryDosTime)
|
|
||||||
minute = ( 0b11111100000 & binaryDosTime) >> 5
|
|
||||||
hour = (0b1111100000000000 & binaryDosTime) >> 11
|
|
||||||
day = ( 0b11111 & binaryDosDate)
|
|
||||||
month = ( 0b111100000 & binaryDosDate) >> 5
|
|
||||||
year = ((0b1111111000000000 & binaryDosDate) >> 9) + 1980
|
|
||||||
begin
|
|
||||||
return Time.local(year, month, day, hour, minute, second)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class Module #:nodoc:all
|
|
||||||
def forward_message(forwarder, *messagesToForward)
|
|
||||||
methodDefs = messagesToForward.map {
|
|
||||||
|msg|
|
|
||||||
"def #{msg}; #{forwarder}(:#{msg}); end"
|
|
||||||
}
|
|
||||||
module_eval(methodDefs.join("\n"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
||||||
# rubyzip is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the ruby license.
|
|
|
@ -1,195 +0,0 @@
|
||||||
#
|
|
||||||
# tempfile - manipulates temporary files
|
|
||||||
#
|
|
||||||
# $Id: tempfile_bugfixed.rb,v 1.2 2005/02/19 20:30:33 thomas Exp $
|
|
||||||
#
|
|
||||||
|
|
||||||
require 'delegate'
|
|
||||||
require 'tmpdir'
|
|
||||||
|
|
||||||
module BugFix #:nodoc:all
|
|
||||||
|
|
||||||
# A class for managing temporary files. This library is written to be
|
|
||||||
# thread safe.
|
|
||||||
class Tempfile < DelegateClass(File)
|
|
||||||
MAX_TRY = 10
|
|
||||||
@@cleanlist = []
|
|
||||||
|
|
||||||
# Creates a temporary file of mode 0600 in the temporary directory
|
|
||||||
# whose name is basename.pid.n and opens with mode "w+". A Tempfile
|
|
||||||
# object works just like a File object.
|
|
||||||
#
|
|
||||||
# If tmpdir is omitted, the temporary directory is determined by
|
|
||||||
# Dir::tmpdir provided by 'tmpdir.rb'.
|
|
||||||
# When $SAFE > 0 and the given tmpdir is tainted, it uses
|
|
||||||
# /tmp. (Note that ENV values are tainted by default)
|
|
||||||
def initialize(basename, tmpdir=Dir::tmpdir)
|
|
||||||
if $SAFE > 0 and tmpdir.tainted?
|
|
||||||
tmpdir = '/tmp'
|
|
||||||
end
|
|
||||||
|
|
||||||
lock = nil
|
|
||||||
n = failure = 0
|
|
||||||
|
|
||||||
begin
|
|
||||||
Thread.critical = true
|
|
||||||
|
|
||||||
begin
|
|
||||||
tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n)
|
|
||||||
lock = tmpname + '.lock'
|
|
||||||
n += 1
|
|
||||||
end while @@cleanlist.include?(tmpname) or
|
|
||||||
File.exist?(lock) or File.exist?(tmpname)
|
|
||||||
|
|
||||||
Dir.mkdir(lock)
|
|
||||||
rescue
|
|
||||||
failure += 1
|
|
||||||
retry if failure < MAX_TRY
|
|
||||||
raise "cannot generate tempfile `%s'" % tmpname
|
|
||||||
ensure
|
|
||||||
Thread.critical = false
|
|
||||||
end
|
|
||||||
|
|
||||||
@data = [tmpname]
|
|
||||||
@clean_proc = Tempfile.callback(@data)
|
|
||||||
ObjectSpace.define_finalizer(self, @clean_proc)
|
|
||||||
|
|
||||||
@tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
|
|
||||||
@tmpname = tmpname
|
|
||||||
@@cleanlist << @tmpname
|
|
||||||
@data[1] = @tmpfile
|
|
||||||
@data[2] = @@cleanlist
|
|
||||||
|
|
||||||
super(@tmpfile)
|
|
||||||
|
|
||||||
# Now we have all the File/IO methods defined, you must not
|
|
||||||
# carelessly put bare puts(), etc. after this.
|
|
||||||
|
|
||||||
Dir.rmdir(lock)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Opens or reopens the file with mode "r+".
|
|
||||||
def open
|
|
||||||
@tmpfile.close if @tmpfile
|
|
||||||
@tmpfile = File.open(@tmpname, 'r+')
|
|
||||||
@data[1] = @tmpfile
|
|
||||||
__setobj__(@tmpfile)
|
|
||||||
end
|
|
||||||
|
|
||||||
def _close # :nodoc:
|
|
||||||
@tmpfile.close if @tmpfile
|
|
||||||
@data[1] = @tmpfile = nil
|
|
||||||
end
|
|
||||||
protected :_close
|
|
||||||
|
|
||||||
# Closes the file. If the optional flag is true, unlinks the file
|
|
||||||
# after closing.
|
|
||||||
#
|
|
||||||
# If you don't explicitly unlink the temporary file, the removal
|
|
||||||
# will be delayed until the object is finalized.
|
|
||||||
def close(unlink_now=false)
|
|
||||||
if unlink_now
|
|
||||||
close!
|
|
||||||
else
|
|
||||||
_close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Closes and unlinks the file.
|
|
||||||
def close!
|
|
||||||
_close
|
|
||||||
@clean_proc.call
|
|
||||||
ObjectSpace.undefine_finalizer(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Unlinks the file. On UNIX-like systems, it is often a good idea
|
|
||||||
# to unlink a temporary file immediately after creating and opening
|
|
||||||
# it, because it leaves other programs zero chance to access the
|
|
||||||
# file.
|
|
||||||
def unlink
|
|
||||||
# keep this order for thread safeness
|
|
||||||
File.unlink(@tmpname) if File.exist?(@tmpname)
|
|
||||||
@@cleanlist.delete(@tmpname) if @@cleanlist
|
|
||||||
end
|
|
||||||
alias delete unlink
|
|
||||||
|
|
||||||
if RUBY_VERSION > '1.8.0'
|
|
||||||
def __setobj__(obj)
|
|
||||||
@_dc_obj = obj
|
|
||||||
end
|
|
||||||
else
|
|
||||||
def __setobj__(obj)
|
|
||||||
@obj = obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the full path name of the temporary file.
|
|
||||||
def path
|
|
||||||
@tmpname
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the size of the temporary file. As a side effect, the IO
|
|
||||||
# buffer is flushed before determining the size.
|
|
||||||
def size
|
|
||||||
if @tmpfile
|
|
||||||
@tmpfile.flush
|
|
||||||
@tmpfile.stat.size
|
|
||||||
else
|
|
||||||
0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
alias length size
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def callback(data) # :nodoc:
|
|
||||||
pid = $$
|
|
||||||
lambda{
|
|
||||||
if pid == $$
|
|
||||||
path, tmpfile, cleanlist = *data
|
|
||||||
|
|
||||||
print "removing ", path, "..." if $DEBUG
|
|
||||||
|
|
||||||
tmpfile.close if tmpfile
|
|
||||||
|
|
||||||
# keep this order for thread safeness
|
|
||||||
File.unlink(path) if File.exist?(path)
|
|
||||||
cleanlist.delete(path) if cleanlist
|
|
||||||
|
|
||||||
print "done\n" if $DEBUG
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
# If no block is given, this is a synonym for new().
|
|
||||||
#
|
|
||||||
# If a block is given, it will be passed tempfile as an argument,
|
|
||||||
# and the tempfile will automatically be closed when the block
|
|
||||||
# terminates. In this case, open() returns nil.
|
|
||||||
def open(*args)
|
|
||||||
tempfile = new(*args)
|
|
||||||
|
|
||||||
if block_given?
|
|
||||||
begin
|
|
||||||
yield(tempfile)
|
|
||||||
ensure
|
|
||||||
tempfile.close
|
|
||||||
end
|
|
||||||
|
|
||||||
nil
|
|
||||||
else
|
|
||||||
tempfile
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end # module BugFix
|
|
||||||
if __FILE__ == $0
|
|
||||||
# $DEBUG = true
|
|
||||||
f = Tempfile.new("foo")
|
|
||||||
f.print("foo\n")
|
|
||||||
f.close
|
|
||||||
f.open
|
|
||||||
p f.gets # => "foo\n"
|
|
||||||
f.close!
|
|
||||||
end
|
|
1847
lib/zip/zip.rb
1847
lib/zip/zip.rb
File diff suppressed because it is too large
Load Diff
|
@ -1,609 +0,0 @@
|
||||||
require 'zip/zip'
|
|
||||||
|
|
||||||
module Zip
|
|
||||||
|
|
||||||
# The ZipFileSystem API provides an API for accessing entries in
|
|
||||||
# a zip archive that is similar to ruby's builtin File and Dir
|
|
||||||
# classes.
|
|
||||||
#
|
|
||||||
# Requiring 'zip/zipfilesystem' includes this module in ZipFile
|
|
||||||
# making the methods in this module available on ZipFile objects.
|
|
||||||
#
|
|
||||||
# Using this API the following example creates a new zip file
|
|
||||||
# <code>my.zip</code> containing a normal entry with the name
|
|
||||||
# <code>first.txt</code>, a directory entry named <code>mydir</code>
|
|
||||||
# and finally another normal entry named <code>second.txt</code>
|
|
||||||
#
|
|
||||||
# require 'zip/zipfilesystem'
|
|
||||||
#
|
|
||||||
# Zip::ZipFile.open("my.zip", Zip::ZipFile::CREATE) {
|
|
||||||
# |zipfile|
|
|
||||||
# zipfile.file.open("first.txt", "w") { |f| f.puts "Hello world" }
|
|
||||||
# zipfile.dir.mkdir("mydir")
|
|
||||||
# zipfile.file.open("mydir/second.txt", "w") { |f| f.puts "Hello again" }
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# Reading is as easy as writing, as the following example shows. The
|
|
||||||
# example writes the contents of <code>first.txt</code> from zip archive
|
|
||||||
# <code>my.zip</code> to standard out.
|
|
||||||
#
|
|
||||||
# require 'zip/zipfilesystem'
|
|
||||||
#
|
|
||||||
# Zip::ZipFile.open("my.zip") {
|
|
||||||
# |zipfile|
|
|
||||||
# puts zipfile.file.read("first.txt")
|
|
||||||
# }
|
|
||||||
|
|
||||||
module ZipFileSystem
|
|
||||||
|
|
||||||
def initialize # :nodoc:
|
|
||||||
mappedZip = ZipFileNameMapper.new(self)
|
|
||||||
@zipFsDir = ZipFsDir.new(mappedZip)
|
|
||||||
@zipFsFile = ZipFsFile.new(mappedZip)
|
|
||||||
@zipFsDir.file = @zipFsFile
|
|
||||||
@zipFsFile.dir = @zipFsDir
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a ZipFsDir which is much like ruby's builtin Dir (class)
|
|
||||||
# object, except it works on the ZipFile on which this method is
|
|
||||||
# invoked
|
|
||||||
def dir
|
|
||||||
@zipFsDir
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a ZipFsFile which is much like ruby's builtin File (class)
|
|
||||||
# object, except it works on the ZipFile on which this method is
|
|
||||||
# invoked
|
|
||||||
def file
|
|
||||||
@zipFsFile
|
|
||||||
end
|
|
||||||
|
|
||||||
# Instances of this class are normally accessed via the accessor
|
|
||||||
# ZipFile::file. An instance of ZipFsFile behaves like ruby's
|
|
||||||
# builtin File (class) object, except it works on ZipFile entries.
|
|
||||||
#
|
|
||||||
# The individual methods are not documented due to their
|
|
||||||
# similarity with the methods in File
|
|
||||||
class ZipFsFile
|
|
||||||
|
|
||||||
attr_writer :dir
|
|
||||||
# protected :dir
|
|
||||||
|
|
||||||
class ZipFsStat
|
|
||||||
def initialize(zipFsFile, entryName)
|
|
||||||
@zipFsFile = zipFsFile
|
|
||||||
@entryName = entryName
|
|
||||||
end
|
|
||||||
|
|
||||||
def forward_invoke(msg)
|
|
||||||
@zipFsFile.send(msg, @entryName)
|
|
||||||
end
|
|
||||||
|
|
||||||
def kind_of?(t)
|
|
||||||
super || t == ::File::Stat
|
|
||||||
end
|
|
||||||
|
|
||||||
forward_message :forward_invoke, :file?, :directory?, :pipe?, :chardev?
|
|
||||||
forward_message :forward_invoke, :symlink?, :socket?, :blockdev?
|
|
||||||
forward_message :forward_invoke, :readable?, :readable_real?
|
|
||||||
forward_message :forward_invoke, :writable?, :writable_real?
|
|
||||||
forward_message :forward_invoke, :executable?, :executable_real?
|
|
||||||
forward_message :forward_invoke, :sticky?, :owned?, :grpowned?
|
|
||||||
forward_message :forward_invoke, :setuid?, :setgid?
|
|
||||||
forward_message :forward_invoke, :zero?
|
|
||||||
forward_message :forward_invoke, :size, :size?
|
|
||||||
forward_message :forward_invoke, :mtime, :atime, :ctime
|
|
||||||
|
|
||||||
def blocks; nil; end
|
|
||||||
|
|
||||||
def get_entry
|
|
||||||
@zipFsFile.__send__(:get_entry, @entryName)
|
|
||||||
end
|
|
||||||
private :get_entry
|
|
||||||
|
|
||||||
def gid
|
|
||||||
e = get_entry
|
|
||||||
if e.extra.member? "IUnix"
|
|
||||||
e.extra["IUnix"].gid || 0
|
|
||||||
else
|
|
||||||
0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def uid
|
|
||||||
e = get_entry
|
|
||||||
if e.extra.member? "IUnix"
|
|
||||||
e.extra["IUnix"].uid || 0
|
|
||||||
else
|
|
||||||
0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ino; 0; end
|
|
||||||
|
|
||||||
def dev; 0; end
|
|
||||||
|
|
||||||
def rdev; 0; end
|
|
||||||
|
|
||||||
def rdev_major; 0; end
|
|
||||||
|
|
||||||
def rdev_minor; 0; end
|
|
||||||
|
|
||||||
def ftype
|
|
||||||
if file?
|
|
||||||
return "file"
|
|
||||||
elsif directory?
|
|
||||||
return "directory"
|
|
||||||
else
|
|
||||||
raise StandardError, "Unknown file type"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def nlink; 1; end
|
|
||||||
|
|
||||||
def blksize; nil; end
|
|
||||||
|
|
||||||
def mode
|
|
||||||
e = get_entry
|
|
||||||
if e.fstype == 3
|
|
||||||
e.externalFileAttributes >> 16
|
|
||||||
else
|
|
||||||
33206 # 33206 is equivalent to -rw-rw-rw-
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(mappedZip)
|
|
||||||
@mappedZip = mappedZip
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_entry(fileName)
|
|
||||||
if ! exists?(fileName)
|
|
||||||
raise Errno::ENOENT, "No such file or directory - #{fileName}"
|
|
||||||
end
|
|
||||||
@mappedZip.find_entry(fileName)
|
|
||||||
end
|
|
||||||
private :get_entry
|
|
||||||
|
|
||||||
def unix_mode_cmp(fileName, mode)
|
|
||||||
begin
|
|
||||||
e = get_entry(fileName)
|
|
||||||
e.fstype == 3 && ((e.externalFileAttributes >> 16) & mode ) != 0
|
|
||||||
rescue Errno::ENOENT
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
private :unix_mode_cmp
|
|
||||||
|
|
||||||
def exists?(fileName)
|
|
||||||
expand_path(fileName) == "/" || @mappedZip.find_entry(fileName) != nil
|
|
||||||
end
|
|
||||||
alias :exist? :exists?
|
|
||||||
|
|
||||||
# Permissions not implemented, so if the file exists it is accessible
|
|
||||||
alias owned? exists?
|
|
||||||
alias grpowned? exists?
|
|
||||||
|
|
||||||
def readable?(fileName)
|
|
||||||
unix_mode_cmp(fileName, 0444)
|
|
||||||
end
|
|
||||||
alias readable_real? readable?
|
|
||||||
|
|
||||||
def writable?(fileName)
|
|
||||||
unix_mode_cmp(fileName, 0222)
|
|
||||||
end
|
|
||||||
alias writable_real? writable?
|
|
||||||
|
|
||||||
def executable?(fileName)
|
|
||||||
unix_mode_cmp(fileName, 0111)
|
|
||||||
end
|
|
||||||
alias executable_real? executable?
|
|
||||||
|
|
||||||
def setuid?(fileName)
|
|
||||||
unix_mode_cmp(fileName, 04000)
|
|
||||||
end
|
|
||||||
|
|
||||||
def setgid?(fileName)
|
|
||||||
unix_mode_cmp(fileName, 02000)
|
|
||||||
end
|
|
||||||
|
|
||||||
def sticky?(fileName)
|
|
||||||
unix_mode_cmp(fileName, 01000)
|
|
||||||
end
|
|
||||||
|
|
||||||
def umask(*args)
|
|
||||||
::File.umask(*args)
|
|
||||||
end
|
|
||||||
|
|
||||||
def truncate(fileName, len)
|
|
||||||
raise StandardError, "truncate not supported"
|
|
||||||
end
|
|
||||||
|
|
||||||
def directory?(fileName)
|
|
||||||
entry = @mappedZip.find_entry(fileName)
|
|
||||||
expand_path(fileName) == "/" || (entry != nil && entry.directory?)
|
|
||||||
end
|
|
||||||
|
|
||||||
def open(fileName, openMode = "r", &block)
|
|
||||||
case openMode
|
|
||||||
when "r"
|
|
||||||
@mappedZip.get_input_stream(fileName, &block)
|
|
||||||
when "w"
|
|
||||||
@mappedZip.get_output_stream(fileName, &block)
|
|
||||||
else
|
|
||||||
raise StandardError, "openmode '#{openMode} not supported" unless openMode == "r"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def new(fileName, openMode = "r")
|
|
||||||
open(fileName, openMode)
|
|
||||||
end
|
|
||||||
|
|
||||||
def size(fileName)
|
|
||||||
@mappedZip.get_entry(fileName).size
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns nil for not found and nil for directories
|
|
||||||
def size?(fileName)
|
|
||||||
entry = @mappedZip.find_entry(fileName)
|
|
||||||
return (entry == nil || entry.directory?) ? nil : entry.size
|
|
||||||
end
|
|
||||||
|
|
||||||
def chown(ownerInt, groupInt, *filenames)
|
|
||||||
filenames.each { |fileName|
|
|
||||||
e = get_entry(fileName)
|
|
||||||
unless e.extra.member?("IUnix")
|
|
||||||
e.extra.create("IUnix")
|
|
||||||
end
|
|
||||||
e.extra["IUnix"].uid = ownerInt
|
|
||||||
e.extra["IUnix"].gid = groupInt
|
|
||||||
}
|
|
||||||
filenames.size
|
|
||||||
end
|
|
||||||
|
|
||||||
def chmod (modeInt, *filenames)
|
|
||||||
filenames.each { |fileName|
|
|
||||||
e = get_entry(fileName)
|
|
||||||
e.fstype = 3 # force convertion filesystem type to unix
|
|
||||||
e.externalFileAttributes = modeInt << 16
|
|
||||||
}
|
|
||||||
filenames.size
|
|
||||||
end
|
|
||||||
|
|
||||||
def zero?(fileName)
|
|
||||||
sz = size(fileName)
|
|
||||||
sz == nil || sz == 0
|
|
||||||
rescue Errno::ENOENT
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def file?(fileName)
|
|
||||||
entry = @mappedZip.find_entry(fileName)
|
|
||||||
entry != nil && entry.file?
|
|
||||||
end
|
|
||||||
|
|
||||||
def dirname(fileName)
|
|
||||||
::File.dirname(fileName)
|
|
||||||
end
|
|
||||||
|
|
||||||
def basename(fileName)
|
|
||||||
::File.basename(fileName)
|
|
||||||
end
|
|
||||||
|
|
||||||
def split(fileName)
|
|
||||||
::File.split(fileName)
|
|
||||||
end
|
|
||||||
|
|
||||||
def join(*fragments)
|
|
||||||
::File.join(*fragments)
|
|
||||||
end
|
|
||||||
|
|
||||||
def utime(modifiedTime, *fileNames)
|
|
||||||
fileNames.each { |fileName|
|
|
||||||
get_entry(fileName).time = modifiedTime
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def mtime(fileName)
|
|
||||||
@mappedZip.get_entry(fileName).mtime
|
|
||||||
end
|
|
||||||
|
|
||||||
def atime(fileName)
|
|
||||||
e = get_entry(fileName)
|
|
||||||
if e.extra.member? "UniversalTime"
|
|
||||||
e.extra["UniversalTime"].atime
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ctime(fileName)
|
|
||||||
e = get_entry(fileName)
|
|
||||||
if e.extra.member? "UniversalTime"
|
|
||||||
e.extra["UniversalTime"].ctime
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pipe?(filename)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def blockdev?(filename)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def chardev?(filename)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def symlink?(fileName)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def socket?(fileName)
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def ftype(fileName)
|
|
||||||
@mappedZip.get_entry(fileName).directory? ? "directory" : "file"
|
|
||||||
end
|
|
||||||
|
|
||||||
def readlink(fileName)
|
|
||||||
raise NotImplementedError, "The readlink() function is not implemented"
|
|
||||||
end
|
|
||||||
|
|
||||||
def symlink(fileName, symlinkName)
|
|
||||||
raise NotImplementedError, "The symlink() function is not implemented"
|
|
||||||
end
|
|
||||||
|
|
||||||
def link(fileName, symlinkName)
|
|
||||||
raise NotImplementedError, "The link() function is not implemented"
|
|
||||||
end
|
|
||||||
|
|
||||||
def pipe
|
|
||||||
raise NotImplementedError, "The pipe() function is not implemented"
|
|
||||||
end
|
|
||||||
|
|
||||||
def stat(fileName)
|
|
||||||
if ! exists?(fileName)
|
|
||||||
raise Errno::ENOENT, fileName
|
|
||||||
end
|
|
||||||
ZipFsStat.new(self, fileName)
|
|
||||||
end
|
|
||||||
|
|
||||||
alias lstat stat
|
|
||||||
|
|
||||||
def readlines(fileName)
|
|
||||||
open(fileName) { |is| is.readlines }
|
|
||||||
end
|
|
||||||
|
|
||||||
def read(fileName)
|
|
||||||
@mappedZip.read(fileName)
|
|
||||||
end
|
|
||||||
|
|
||||||
def popen(*args, &aProc)
|
|
||||||
File.popen(*args, &aProc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def foreach(fileName, aSep = $/, &aProc)
|
|
||||||
open(fileName) { |is| is.each_line(aSep, &aProc) }
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete(*args)
|
|
||||||
args.each {
|
|
||||||
|fileName|
|
|
||||||
if directory?(fileName)
|
|
||||||
raise Errno::EISDIR, "Is a directory - \"#{fileName}\""
|
|
||||||
end
|
|
||||||
@mappedZip.remove(fileName)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def rename(fileToRename, newName)
|
|
||||||
@mappedZip.rename(fileToRename, newName) { true }
|
|
||||||
end
|
|
||||||
|
|
||||||
alias :unlink :delete
|
|
||||||
|
|
||||||
def expand_path(aPath)
|
|
||||||
@mappedZip.expand_path(aPath)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Instances of this class are normally accessed via the accessor
|
|
||||||
# ZipFile::dir. An instance of ZipFsDir behaves like ruby's
|
|
||||||
# builtin Dir (class) object, except it works on ZipFile entries.
|
|
||||||
#
|
|
||||||
# The individual methods are not documented due to their
|
|
||||||
# similarity with the methods in Dir
|
|
||||||
class ZipFsDir
|
|
||||||
|
|
||||||
def initialize(mappedZip)
|
|
||||||
@mappedZip = mappedZip
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_writer :file
|
|
||||||
|
|
||||||
def new(aDirectoryName)
|
|
||||||
ZipFsDirIterator.new(entries(aDirectoryName))
|
|
||||||
end
|
|
||||||
|
|
||||||
def open(aDirectoryName)
|
|
||||||
dirIt = new(aDirectoryName)
|
|
||||||
if block_given?
|
|
||||||
begin
|
|
||||||
yield(dirIt)
|
|
||||||
return nil
|
|
||||||
ensure
|
|
||||||
dirIt.close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
dirIt
|
|
||||||
end
|
|
||||||
|
|
||||||
def pwd; @mappedZip.pwd; end
|
|
||||||
alias getwd pwd
|
|
||||||
|
|
||||||
def chdir(aDirectoryName)
|
|
||||||
unless @file.stat(aDirectoryName).directory?
|
|
||||||
raise Errno::EINVAL, "Invalid argument - #{aDirectoryName}"
|
|
||||||
end
|
|
||||||
@mappedZip.pwd = @file.expand_path(aDirectoryName)
|
|
||||||
end
|
|
||||||
|
|
||||||
def entries(aDirectoryName)
|
|
||||||
entries = []
|
|
||||||
foreach(aDirectoryName) { |e| entries << e }
|
|
||||||
entries
|
|
||||||
end
|
|
||||||
|
|
||||||
def foreach(aDirectoryName)
|
|
||||||
unless @file.stat(aDirectoryName).directory?
|
|
||||||
raise Errno::ENOTDIR, aDirectoryName
|
|
||||||
end
|
|
||||||
path = @file.expand_path(aDirectoryName).ensure_end("/")
|
|
||||||
|
|
||||||
subDirEntriesRegex = Regexp.new("^#{path}([^/]+)$", nil, 'n')
|
|
||||||
@mappedZip.each {
|
|
||||||
|fileName|
|
|
||||||
match = subDirEntriesRegex.match(fileName)
|
|
||||||
yield(match[1]) unless match == nil
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete(entryName)
|
|
||||||
unless @file.stat(entryName).directory?
|
|
||||||
raise Errno::EINVAL, "Invalid argument - #{entryName}"
|
|
||||||
end
|
|
||||||
@mappedZip.remove(entryName)
|
|
||||||
end
|
|
||||||
alias rmdir delete
|
|
||||||
alias unlink delete
|
|
||||||
|
|
||||||
def mkdir(entryName, permissionInt = 0755)
|
|
||||||
@mappedZip.mkdir(entryName, permissionInt)
|
|
||||||
end
|
|
||||||
|
|
||||||
def chroot(*args)
|
|
||||||
raise NotImplementedError, "The chroot() function is not implemented"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class ZipFsDirIterator # :nodoc:all
|
|
||||||
include Enumerable
|
|
||||||
|
|
||||||
def initialize(arrayOfFileNames)
|
|
||||||
@fileNames = arrayOfFileNames
|
|
||||||
@index = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def close
|
|
||||||
@fileNames = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def each(&aProc)
|
|
||||||
raise IOError, "closed directory" if @fileNames == nil
|
|
||||||
@fileNames.each(&aProc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def read
|
|
||||||
raise IOError, "closed directory" if @fileNames == nil
|
|
||||||
@fileNames[(@index+=1)-1]
|
|
||||||
end
|
|
||||||
|
|
||||||
def rewind
|
|
||||||
raise IOError, "closed directory" if @fileNames == nil
|
|
||||||
@index = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def seek(anIntegerPosition)
|
|
||||||
raise IOError, "closed directory" if @fileNames == nil
|
|
||||||
@index = anIntegerPosition
|
|
||||||
end
|
|
||||||
|
|
||||||
def tell
|
|
||||||
raise IOError, "closed directory" if @fileNames == nil
|
|
||||||
@index
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# All access to ZipFile from ZipFsFile and ZipFsDir goes through a
|
|
||||||
# ZipFileNameMapper, which has one responsibility: ensure
|
|
||||||
class ZipFileNameMapper # :nodoc:all
|
|
||||||
include Enumerable
|
|
||||||
|
|
||||||
def initialize(zipFile)
|
|
||||||
@zipFile = zipFile
|
|
||||||
@pwd = "/"
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :pwd
|
|
||||||
|
|
||||||
def find_entry(fileName)
|
|
||||||
@zipFile.find_entry(expand_to_entry(fileName))
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_entry(fileName)
|
|
||||||
@zipFile.get_entry(expand_to_entry(fileName))
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_input_stream(fileName, &aProc)
|
|
||||||
@zipFile.get_input_stream(expand_to_entry(fileName), &aProc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_output_stream(fileName, &aProc)
|
|
||||||
@zipFile.get_output_stream(expand_to_entry(fileName), &aProc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def read(fileName)
|
|
||||||
@zipFile.read(expand_to_entry(fileName))
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove(fileName)
|
|
||||||
@zipFile.remove(expand_to_entry(fileName))
|
|
||||||
end
|
|
||||||
|
|
||||||
def rename(fileName, newName, &continueOnExistsProc)
|
|
||||||
@zipFile.rename(expand_to_entry(fileName), expand_to_entry(newName),
|
|
||||||
&continueOnExistsProc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def mkdir(fileName, permissionInt = 0755)
|
|
||||||
@zipFile.mkdir(expand_to_entry(fileName), permissionInt)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Turns entries into strings and adds leading /
|
|
||||||
# and removes trailing slash on directories
|
|
||||||
def each
|
|
||||||
@zipFile.each {
|
|
||||||
|e|
|
|
||||||
yield("/"+e.to_s.chomp("/"))
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def expand_path(aPath)
|
|
||||||
expanded = aPath.starts_with("/") ? aPath : @pwd.ensure_end("/") + aPath
|
|
||||||
expanded.gsub!(/\/\.(\/|$)/, "")
|
|
||||||
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, "")
|
|
||||||
expanded.empty? ? "/" : expanded
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def expand_to_entry(aPath)
|
|
||||||
expand_path(aPath).lchop
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class ZipFile
|
|
||||||
include ZipFileSystem
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
|
||||||
# rubyzip is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the ruby license.
|
|
|
@ -1,90 +0,0 @@
|
||||||
# With ziprequire you can load ruby modules from a zip file. This means
|
|
||||||
# ruby's module include path can include zip-files.
|
|
||||||
#
|
|
||||||
# The following example creates a zip file with a single entry
|
|
||||||
# <code>log/simplelog.rb</code> that contains a single function
|
|
||||||
# <code>simpleLog</code>:
|
|
||||||
#
|
|
||||||
# require 'zip/zipfilesystem'
|
|
||||||
#
|
|
||||||
# Zip::ZipFile.open("my.zip", true) {
|
|
||||||
# |zf|
|
|
||||||
# zf.file.open("log/simplelog.rb", "w") {
|
|
||||||
# |f|
|
|
||||||
# f.puts "def simpleLog(v)"
|
|
||||||
# f.puts ' Kernel.puts "INFO: #{v}"'
|
|
||||||
# f.puts "end"
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
# To use the ruby module stored in the zip archive simply require
|
|
||||||
# <code>zip/ziprequire</code> and include the <code>my.zip</code> zip
|
|
||||||
# file in the module search path. The following command shows one
|
|
||||||
# way to do this:
|
|
||||||
#
|
|
||||||
# ruby -rzip/ziprequire -Imy.zip -e " require 'log/simplelog'; simpleLog 'Hello world' "
|
|
||||||
|
|
||||||
#$: << 'data/rubycode.zip' << 'data/rubycode2.zip'
|
|
||||||
|
|
||||||
|
|
||||||
require 'zip/zip'
|
|
||||||
|
|
||||||
class ZipList #:nodoc:all
|
|
||||||
def initialize(zipFileList)
|
|
||||||
@zipFileList = zipFileList
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_input_stream(entry, &aProc)
|
|
||||||
@zipFileList.each {
|
|
||||||
|zfName|
|
|
||||||
Zip::ZipFile.open(zfName) {
|
|
||||||
|zf|
|
|
||||||
begin
|
|
||||||
return zf.get_input_stream(entry, &aProc)
|
|
||||||
rescue Errno::ENOENT
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
raise Errno::ENOENT,
|
|
||||||
"No matching entry found in zip files '#{@zipFileList.join(', ')}' "+
|
|
||||||
" for '#{entry}'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
module Kernel #:nodoc:all
|
|
||||||
alias :oldRequire :require
|
|
||||||
|
|
||||||
def require(moduleName)
|
|
||||||
zip_require(moduleName) || oldRequire(moduleName)
|
|
||||||
end
|
|
||||||
|
|
||||||
def zip_require(moduleName)
|
|
||||||
return false if already_loaded?(moduleName)
|
|
||||||
get_resource(ensure_rb_extension(moduleName)) {
|
|
||||||
|zis|
|
|
||||||
eval(zis.read); $" << moduleName
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
rescue Errno::ENOENT => ex
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_resource(resourceName, &aProc)
|
|
||||||
zl = ZipList.new($:.grep(/\.zip$/))
|
|
||||||
zl.get_input_stream(resourceName, &aProc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def already_loaded?(moduleName)
|
|
||||||
moduleRE = Regexp.new("^"+moduleName+"(\.rb|\.so|\.dll|\.o)?$", nil, 'n')
|
|
||||||
$".detect { |e| e =~ moduleRE } != nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_rb_extension(aString)
|
|
||||||
aString.sub(/(\.rb)?$/i, ".rb")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Copyright (C) 2002 Thomas Sondergaard
|
|
||||||
# rubyzip is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the ruby license.
|
|
Loading…
Reference in New Issue