rubyzip 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubyzip might be problematic. Click here for more details.
- data/ChangeLog +1265 -0
- data/NEWS +106 -0
- data/README +69 -0
- data/Rakefile +110 -0
- data/TODO +9 -0
- data/install.rb +22 -0
- data/lib/zip/ioextras.rb +117 -0
- data/lib/zip/stdrubyext.rb +111 -0
- data/lib/zip/tempfile_bugfixed.rb +195 -0
- data/lib/zip/zip.rb +1543 -0
- data/lib/zip/zipfilesystem.rb +609 -0
- data/lib/zip/ziprequire.rb +90 -0
- data/samples/example.rb +69 -0
- data/samples/example_filesystem.rb +34 -0
- data/samples/gtkRubyzip.rb +86 -0
- data/samples/write_simple.rb +13 -0
- data/samples/zipfind.rb +74 -0
- data/test/alltests.rb +9 -0
- data/test/data/file1.txt +46 -0
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +1504 -0
- data/test/data/notzippedruby.rb +7 -0
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/gentestfiles.rb +155 -0
- data/test/ioextrastest.rb +208 -0
- data/test/stdrubyexttest.rb +52 -0
- data/test/zipfilesystemtest.rb +829 -0
- data/test/ziprequiretest.rb +43 -0
- data/test/ziptest.rb +1557 -0
- metadata +68 -0
@@ -0,0 +1,609 @@
|
|
1
|
+
require 'zip/zip'
|
2
|
+
|
3
|
+
module Zip
|
4
|
+
|
5
|
+
# The ZipFileSystem API provides an API for accessing entries in
|
6
|
+
# a zip archive that is similar to ruby's builtin File and Dir
|
7
|
+
# classes.
|
8
|
+
#
|
9
|
+
# Requiring 'zip/zipfilesystem' includes this module in ZipFile
|
10
|
+
# making the methods in this module available on ZipFile objects.
|
11
|
+
#
|
12
|
+
# Using this API the following example creates a new zip file
|
13
|
+
# <code>my.zip</code> containing a normal entry with the name
|
14
|
+
# <code>first.txt</code>, a directory entry named <code>mydir</code>
|
15
|
+
# and finally another normal entry named <code>second.txt</code>
|
16
|
+
#
|
17
|
+
# require 'zip/zipfilesystem'
|
18
|
+
#
|
19
|
+
# Zip::ZipFile.open("my.zip", Zip::ZipFile::CREATE) {
|
20
|
+
# |zipfile|
|
21
|
+
# zipfile.file.open("first.txt", "w") { |f| f.puts "Hello world" }
|
22
|
+
# zipfile.dir.mkdir("mydir")
|
23
|
+
# zipfile.file.open("mydir/second.txt", "w") { |f| f.puts "Hello again" }
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# Reading is as easy as writing, as the following example shows. The
|
27
|
+
# example writes the contents of <code>first.txt</code> from zip archive
|
28
|
+
# <code>my.zip</code> to standard out.
|
29
|
+
#
|
30
|
+
# require 'zip/zipfilesystem'
|
31
|
+
#
|
32
|
+
# Zip::ZipFile.open("my.zip") {
|
33
|
+
# |zipfile|
|
34
|
+
# puts zipfile.file.read("first.txt")
|
35
|
+
# }
|
36
|
+
|
37
|
+
module ZipFileSystem
|
38
|
+
|
39
|
+
def initialize # :nodoc:
|
40
|
+
mappedZip = ZipFileNameMapper.new(self)
|
41
|
+
@zipFsDir = ZipFsDir.new(mappedZip)
|
42
|
+
@zipFsFile = ZipFsFile.new(mappedZip)
|
43
|
+
@zipFsDir.file = @zipFsFile
|
44
|
+
@zipFsFile.dir = @zipFsDir
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns a ZipFsDir which is much like ruby's builtin Dir (class)
|
48
|
+
# object, except it works on the ZipFile on which this method is
|
49
|
+
# invoked
|
50
|
+
def dir
|
51
|
+
@zipFsDir
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns a ZipFsFile which is much like ruby's builtin File (class)
|
55
|
+
# object, except it works on the ZipFile on which this method is
|
56
|
+
# invoked
|
57
|
+
def file
|
58
|
+
@zipFsFile
|
59
|
+
end
|
60
|
+
|
61
|
+
# Instances of this class are normally accessed via the accessor
|
62
|
+
# ZipFile::file. An instance of ZipFsFile behaves like ruby's
|
63
|
+
# builtin File (class) object, except it works on ZipFile entries.
|
64
|
+
#
|
65
|
+
# The individual methods are not documented due to their
|
66
|
+
# similarity with the methods in File
|
67
|
+
class ZipFsFile
|
68
|
+
|
69
|
+
attr_writer :dir
|
70
|
+
# protected :dir
|
71
|
+
|
72
|
+
class ZipFsStat
|
73
|
+
def initialize(zipFsFile, entryName)
|
74
|
+
@zipFsFile = zipFsFile
|
75
|
+
@entryName = entryName
|
76
|
+
end
|
77
|
+
|
78
|
+
def forward_invoke(msg)
|
79
|
+
@zipFsFile.send(msg, @entryName)
|
80
|
+
end
|
81
|
+
|
82
|
+
def kind_of?(t)
|
83
|
+
super || t == ::File::Stat
|
84
|
+
end
|
85
|
+
|
86
|
+
forward_message :forward_invoke, :file?, :directory?, :pipe?, :chardev?
|
87
|
+
forward_message :forward_invoke, :symlink?, :socket?, :blockdev?
|
88
|
+
forward_message :forward_invoke, :readable?, :readable_real?
|
89
|
+
forward_message :forward_invoke, :writable?, :writable_real?
|
90
|
+
forward_message :forward_invoke, :executable?, :executable_real?
|
91
|
+
forward_message :forward_invoke, :sticky?, :owned?, :grpowned?
|
92
|
+
forward_message :forward_invoke, :setuid?, :setgid?
|
93
|
+
forward_message :forward_invoke, :zero?
|
94
|
+
forward_message :forward_invoke, :size, :size?
|
95
|
+
forward_message :forward_invoke, :mtime, :atime, :ctime
|
96
|
+
|
97
|
+
def blocks; nil; end
|
98
|
+
|
99
|
+
def get_entry
|
100
|
+
@zipFsFile.__send__(:get_entry, @entryName)
|
101
|
+
end
|
102
|
+
private :get_entry
|
103
|
+
|
104
|
+
def gid
|
105
|
+
e = get_entry
|
106
|
+
if e.extra.member? "IUnix"
|
107
|
+
e.extra["IUnix"].gid || 0
|
108
|
+
else
|
109
|
+
0
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def uid
|
114
|
+
e = get_entry
|
115
|
+
if e.extra.member? "IUnix"
|
116
|
+
e.extra["IUnix"].uid || 0
|
117
|
+
else
|
118
|
+
0
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def ino; 0; end
|
123
|
+
|
124
|
+
def dev; 0; end
|
125
|
+
|
126
|
+
def rdev; 0; end
|
127
|
+
|
128
|
+
def rdev_major; 0; end
|
129
|
+
|
130
|
+
def rdev_minor; 0; end
|
131
|
+
|
132
|
+
def ftype
|
133
|
+
if file?
|
134
|
+
return "file"
|
135
|
+
elsif directory?
|
136
|
+
return "directory"
|
137
|
+
else
|
138
|
+
raise StandardError, "Unknown file type"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def nlink; 1; end
|
143
|
+
|
144
|
+
def blksize; nil; end
|
145
|
+
|
146
|
+
def mode
|
147
|
+
e = get_entry
|
148
|
+
if e.fstype == 3
|
149
|
+
e.externalFileAttributes >> 16
|
150
|
+
else
|
151
|
+
33206 # 33206 is equivalent to -rw-rw-rw-
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def initialize(mappedZip)
|
157
|
+
@mappedZip = mappedZip
|
158
|
+
end
|
159
|
+
|
160
|
+
def get_entry(fileName)
|
161
|
+
if ! exists?(fileName)
|
162
|
+
raise Errno::ENOENT, "No such file or directory - #{fileName}"
|
163
|
+
end
|
164
|
+
@mappedZip.find_entry(fileName)
|
165
|
+
end
|
166
|
+
private :get_entry
|
167
|
+
|
168
|
+
def unix_mode_cmp(fileName, mode)
|
169
|
+
begin
|
170
|
+
e = get_entry(fileName)
|
171
|
+
e.fstype == 3 && ((e.externalFileAttributes >> 16) & mode ) != 0
|
172
|
+
rescue Errno::ENOENT
|
173
|
+
false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
private :unix_mode_cmp
|
177
|
+
|
178
|
+
def exists?(fileName)
|
179
|
+
expand_path(fileName) == "/" || @mappedZip.find_entry(fileName) != nil
|
180
|
+
end
|
181
|
+
alias :exist? :exists?
|
182
|
+
|
183
|
+
# Permissions not implemented, so if the file exists it is accessible
|
184
|
+
alias owned? exists?
|
185
|
+
alias grpowned? exists?
|
186
|
+
|
187
|
+
def readable?(fileName)
|
188
|
+
unix_mode_cmp(fileName, 0444)
|
189
|
+
end
|
190
|
+
alias readable_real? readable?
|
191
|
+
|
192
|
+
def writable?(fileName)
|
193
|
+
unix_mode_cmp(fileName, 0222)
|
194
|
+
end
|
195
|
+
alias writable_real? writable?
|
196
|
+
|
197
|
+
def executable?(fileName)
|
198
|
+
unix_mode_cmp(fileName, 0111)
|
199
|
+
end
|
200
|
+
alias executable_real? executable?
|
201
|
+
|
202
|
+
def setuid?(fileName)
|
203
|
+
unix_mode_cmp(fileName, 04000)
|
204
|
+
end
|
205
|
+
|
206
|
+
def setgid?(fileName)
|
207
|
+
unix_mode_cmp(fileName, 02000)
|
208
|
+
end
|
209
|
+
|
210
|
+
def sticky?(fileName)
|
211
|
+
unix_mode_cmp(fileName, 01000)
|
212
|
+
end
|
213
|
+
|
214
|
+
def umask(*args)
|
215
|
+
::File.umask(*args)
|
216
|
+
end
|
217
|
+
|
218
|
+
def truncate(fileName, len)
|
219
|
+
raise StandardError, "truncate not supported"
|
220
|
+
end
|
221
|
+
|
222
|
+
def directory?(fileName)
|
223
|
+
entry = @mappedZip.find_entry(fileName)
|
224
|
+
expand_path(fileName) == "/" || (entry != nil && entry.directory?)
|
225
|
+
end
|
226
|
+
|
227
|
+
def open(fileName, openMode = "r", &block)
|
228
|
+
case openMode
|
229
|
+
when "r"
|
230
|
+
@mappedZip.get_input_stream(fileName, &block)
|
231
|
+
when "w"
|
232
|
+
@mappedZip.get_output_stream(fileName, &block)
|
233
|
+
else
|
234
|
+
raise StandardError, "openmode '#{openMode} not supported" unless openMode == "r"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def new(fileName, openMode = "r")
|
239
|
+
open(fileName, openMode)
|
240
|
+
end
|
241
|
+
|
242
|
+
def size(fileName)
|
243
|
+
@mappedZip.get_entry(fileName).size
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns nil for not found and nil for directories
|
247
|
+
def size?(fileName)
|
248
|
+
entry = @mappedZip.find_entry(fileName)
|
249
|
+
return (entry == nil || entry.directory?) ? nil : entry.size
|
250
|
+
end
|
251
|
+
|
252
|
+
def chown(ownerInt, groupInt, *filenames)
|
253
|
+
filenames.each { |fileName|
|
254
|
+
e = get_entry(fileName)
|
255
|
+
unless e.extra.member?("IUnix")
|
256
|
+
e.extra.create("IUnix")
|
257
|
+
end
|
258
|
+
e.extra["IUnix"].uid = ownerInt
|
259
|
+
e.extra["IUnix"].gid = groupInt
|
260
|
+
}
|
261
|
+
filenames.size
|
262
|
+
end
|
263
|
+
|
264
|
+
def chmod (modeInt, *filenames)
|
265
|
+
filenames.each { |fileName|
|
266
|
+
e = get_entry(fileName)
|
267
|
+
e.fstype = 3 # force convertion filesystem type to unix
|
268
|
+
e.externalFileAttributes = modeInt << 16
|
269
|
+
}
|
270
|
+
filenames.size
|
271
|
+
end
|
272
|
+
|
273
|
+
def zero?(fileName)
|
274
|
+
sz = size(fileName)
|
275
|
+
sz == nil || sz == 0
|
276
|
+
rescue Errno::ENOENT
|
277
|
+
false
|
278
|
+
end
|
279
|
+
|
280
|
+
def file?(fileName)
|
281
|
+
entry = @mappedZip.find_entry(fileName)
|
282
|
+
entry != nil && entry.file?
|
283
|
+
end
|
284
|
+
|
285
|
+
def dirname(fileName)
|
286
|
+
::File.dirname(fileName)
|
287
|
+
end
|
288
|
+
|
289
|
+
def basename(fileName)
|
290
|
+
::File.basename(fileName)
|
291
|
+
end
|
292
|
+
|
293
|
+
def split(fileName)
|
294
|
+
::File.split(fileName)
|
295
|
+
end
|
296
|
+
|
297
|
+
def join(*fragments)
|
298
|
+
::File.join(*fragments)
|
299
|
+
end
|
300
|
+
|
301
|
+
def utime(modifiedTime, *fileNames)
|
302
|
+
fileNames.each { |fileName|
|
303
|
+
get_entry(fileName).time = modifiedTime
|
304
|
+
}
|
305
|
+
end
|
306
|
+
|
307
|
+
def mtime(fileName)
|
308
|
+
@mappedZip.get_entry(fileName).mtime
|
309
|
+
end
|
310
|
+
|
311
|
+
def atime(fileName)
|
312
|
+
e = get_entry(fileName)
|
313
|
+
if e.extra.member? "UniversalTime"
|
314
|
+
e.extra["UniversalTime"].atime
|
315
|
+
else
|
316
|
+
nil
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def ctime(fileName)
|
321
|
+
e = get_entry(fileName)
|
322
|
+
if e.extra.member? "UniversalTime"
|
323
|
+
e.extra["UniversalTime"].ctime
|
324
|
+
else
|
325
|
+
nil
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
def pipe?(filename)
|
330
|
+
false
|
331
|
+
end
|
332
|
+
|
333
|
+
def blockdev?(filename)
|
334
|
+
false
|
335
|
+
end
|
336
|
+
|
337
|
+
def chardev?(filename)
|
338
|
+
false
|
339
|
+
end
|
340
|
+
|
341
|
+
def symlink?(fileName)
|
342
|
+
false
|
343
|
+
end
|
344
|
+
|
345
|
+
def socket?(fileName)
|
346
|
+
false
|
347
|
+
end
|
348
|
+
|
349
|
+
def ftype(fileName)
|
350
|
+
@mappedZip.get_entry(fileName).directory? ? "directory" : "file"
|
351
|
+
end
|
352
|
+
|
353
|
+
def readlink(fileName)
|
354
|
+
raise NotImplementedError, "The readlink() function is not implemented"
|
355
|
+
end
|
356
|
+
|
357
|
+
def symlink(fileName, symlinkName)
|
358
|
+
raise NotImplementedError, "The symlink() function is not implemented"
|
359
|
+
end
|
360
|
+
|
361
|
+
def link(fileName, symlinkName)
|
362
|
+
raise NotImplementedError, "The link() function is not implemented"
|
363
|
+
end
|
364
|
+
|
365
|
+
def pipe
|
366
|
+
raise NotImplementedError, "The pipe() function is not implemented"
|
367
|
+
end
|
368
|
+
|
369
|
+
def stat(fileName)
|
370
|
+
if ! exists?(fileName)
|
371
|
+
raise Errno::ENOENT, fileName
|
372
|
+
end
|
373
|
+
ZipFsStat.new(self, fileName)
|
374
|
+
end
|
375
|
+
|
376
|
+
alias lstat stat
|
377
|
+
|
378
|
+
def readlines(fileName)
|
379
|
+
open(fileName) { |is| is.readlines }
|
380
|
+
end
|
381
|
+
|
382
|
+
def read(fileName)
|
383
|
+
@mappedZip.read(fileName)
|
384
|
+
end
|
385
|
+
|
386
|
+
def popen(*args, &aProc)
|
387
|
+
File.popen(*args, &aProc)
|
388
|
+
end
|
389
|
+
|
390
|
+
def foreach(fileName, aSep = $/, &aProc)
|
391
|
+
open(fileName) { |is| is.each_line(aSep, &aProc) }
|
392
|
+
end
|
393
|
+
|
394
|
+
def delete(*args)
|
395
|
+
args.each {
|
396
|
+
|fileName|
|
397
|
+
if directory?(fileName)
|
398
|
+
raise Errno::EISDIR, "Is a directory - \"#{fileName}\""
|
399
|
+
end
|
400
|
+
@mappedZip.remove(fileName)
|
401
|
+
}
|
402
|
+
end
|
403
|
+
|
404
|
+
def rename(fileToRename, newName)
|
405
|
+
@mappedZip.rename(fileToRename, newName) { true }
|
406
|
+
end
|
407
|
+
|
408
|
+
alias :unlink :delete
|
409
|
+
|
410
|
+
def expand_path(aPath)
|
411
|
+
@mappedZip.expand_path(aPath)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
# Instances of this class are normally accessed via the accessor
|
416
|
+
# ZipFile::dir. An instance of ZipFsDir behaves like ruby's
|
417
|
+
# builtin Dir (class) object, except it works on ZipFile entries.
|
418
|
+
#
|
419
|
+
# The individual methods are not documented due to their
|
420
|
+
# similarity with the methods in Dir
|
421
|
+
class ZipFsDir
|
422
|
+
|
423
|
+
def initialize(mappedZip)
|
424
|
+
@mappedZip = mappedZip
|
425
|
+
end
|
426
|
+
|
427
|
+
attr_writer :file
|
428
|
+
|
429
|
+
def new(aDirectoryName)
|
430
|
+
ZipFsDirIterator.new(entries(aDirectoryName))
|
431
|
+
end
|
432
|
+
|
433
|
+
def open(aDirectoryName)
|
434
|
+
dirIt = new(aDirectoryName)
|
435
|
+
if block_given?
|
436
|
+
begin
|
437
|
+
yield(dirIt)
|
438
|
+
return nil
|
439
|
+
ensure
|
440
|
+
dirIt.close
|
441
|
+
end
|
442
|
+
end
|
443
|
+
dirIt
|
444
|
+
end
|
445
|
+
|
446
|
+
def pwd; @mappedZip.pwd; end
|
447
|
+
alias getwd pwd
|
448
|
+
|
449
|
+
def chdir(aDirectoryName)
|
450
|
+
unless @file.stat(aDirectoryName).directory?
|
451
|
+
raise Errno::EINVAL, "Invalid argument - #{aDirectoryName}"
|
452
|
+
end
|
453
|
+
@mappedZip.pwd = @file.expand_path(aDirectoryName)
|
454
|
+
end
|
455
|
+
|
456
|
+
def entries(aDirectoryName)
|
457
|
+
entries = []
|
458
|
+
foreach(aDirectoryName) { |e| entries << e }
|
459
|
+
entries
|
460
|
+
end
|
461
|
+
|
462
|
+
def foreach(aDirectoryName)
|
463
|
+
unless @file.stat(aDirectoryName).directory?
|
464
|
+
raise Errno::ENOTDIR, aDirectoryName
|
465
|
+
end
|
466
|
+
path = @file.expand_path(aDirectoryName).ensure_end("/")
|
467
|
+
|
468
|
+
subDirEntriesRegex = Regexp.new("^#{path}([^/]+)$")
|
469
|
+
@mappedZip.each {
|
470
|
+
|fileName|
|
471
|
+
match = subDirEntriesRegex.match(fileName)
|
472
|
+
yield(match[1]) unless match == nil
|
473
|
+
}
|
474
|
+
end
|
475
|
+
|
476
|
+
def delete(entryName)
|
477
|
+
unless @file.stat(entryName).directory?
|
478
|
+
raise Errno::EINVAL, "Invalid argument - #{entryName}"
|
479
|
+
end
|
480
|
+
@mappedZip.remove(entryName)
|
481
|
+
end
|
482
|
+
alias rmdir delete
|
483
|
+
alias unlink delete
|
484
|
+
|
485
|
+
def mkdir(entryName, permissionInt = 0)
|
486
|
+
@mappedZip.mkdir(entryName, permissionInt)
|
487
|
+
end
|
488
|
+
|
489
|
+
def chroot(*args)
|
490
|
+
raise NotImplementedError, "The chroot() function is not implemented"
|
491
|
+
end
|
492
|
+
|
493
|
+
end
|
494
|
+
|
495
|
+
class ZipFsDirIterator # :nodoc:all
|
496
|
+
include Enumerable
|
497
|
+
|
498
|
+
def initialize(arrayOfFileNames)
|
499
|
+
@fileNames = arrayOfFileNames
|
500
|
+
@index = 0
|
501
|
+
end
|
502
|
+
|
503
|
+
def close
|
504
|
+
@fileNames = nil
|
505
|
+
end
|
506
|
+
|
507
|
+
def each(&aProc)
|
508
|
+
raise IOError, "closed directory" if @fileNames == nil
|
509
|
+
@fileNames.each(&aProc)
|
510
|
+
end
|
511
|
+
|
512
|
+
def read
|
513
|
+
raise IOError, "closed directory" if @fileNames == nil
|
514
|
+
@fileNames[(@index+=1)-1]
|
515
|
+
end
|
516
|
+
|
517
|
+
def rewind
|
518
|
+
raise IOError, "closed directory" if @fileNames == nil
|
519
|
+
@index = 0
|
520
|
+
end
|
521
|
+
|
522
|
+
def seek(anIntegerPosition)
|
523
|
+
raise IOError, "closed directory" if @fileNames == nil
|
524
|
+
@index = anIntegerPosition
|
525
|
+
end
|
526
|
+
|
527
|
+
def tell
|
528
|
+
raise IOError, "closed directory" if @fileNames == nil
|
529
|
+
@index
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
# All access to ZipFile from ZipFsFile and ZipFsDir goes through a
|
534
|
+
# ZipFileNameMapper, which has one responsibility: ensure
|
535
|
+
class ZipFileNameMapper # :nodoc:all
|
536
|
+
include Enumerable
|
537
|
+
|
538
|
+
def initialize(zipFile)
|
539
|
+
@zipFile = zipFile
|
540
|
+
@pwd = "/"
|
541
|
+
end
|
542
|
+
|
543
|
+
attr_accessor :pwd
|
544
|
+
|
545
|
+
def find_entry(fileName)
|
546
|
+
@zipFile.find_entry(expand_to_entry(fileName))
|
547
|
+
end
|
548
|
+
|
549
|
+
def get_entry(fileName)
|
550
|
+
@zipFile.get_entry(expand_to_entry(fileName))
|
551
|
+
end
|
552
|
+
|
553
|
+
def get_input_stream(fileName, &aProc)
|
554
|
+
@zipFile.get_input_stream(expand_to_entry(fileName), &aProc)
|
555
|
+
end
|
556
|
+
|
557
|
+
def get_output_stream(fileName, &aProc)
|
558
|
+
@zipFile.get_output_stream(expand_to_entry(fileName), &aProc)
|
559
|
+
end
|
560
|
+
|
561
|
+
def read(fileName)
|
562
|
+
@zipFile.read(expand_to_entry(fileName))
|
563
|
+
end
|
564
|
+
|
565
|
+
def remove(fileName)
|
566
|
+
@zipFile.remove(expand_to_entry(fileName))
|
567
|
+
end
|
568
|
+
|
569
|
+
def rename(fileName, newName, &continueOnExistsProc)
|
570
|
+
@zipFile.rename(expand_to_entry(fileName), expand_to_entry(newName),
|
571
|
+
&continueOnExistsProc)
|
572
|
+
end
|
573
|
+
|
574
|
+
def mkdir(fileName, permissionInt = 0)
|
575
|
+
@zipFile.mkdir(expand_to_entry(fileName), permissionInt)
|
576
|
+
end
|
577
|
+
|
578
|
+
# Turns entries into strings and adds leading /
|
579
|
+
# and removes trailing slash on directories
|
580
|
+
def each
|
581
|
+
@zipFile.each {
|
582
|
+
|e|
|
583
|
+
yield("/"+e.to_s.chomp("/"))
|
584
|
+
}
|
585
|
+
end
|
586
|
+
|
587
|
+
def expand_path(aPath)
|
588
|
+
expanded = aPath.starts_with("/") ? aPath : @pwd.ensure_end("/") + aPath
|
589
|
+
expanded.gsub!(/\/\.(\/|$)/, "")
|
590
|
+
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, "")
|
591
|
+
expanded.empty? ? "/" : expanded
|
592
|
+
end
|
593
|
+
|
594
|
+
private
|
595
|
+
|
596
|
+
def expand_to_entry(aPath)
|
597
|
+
expand_path(aPath).lchop
|
598
|
+
end
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
class ZipFile
|
603
|
+
include ZipFileSystem
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
# Copyright (C) 2002, 2003 Thomas Sondergaard
|
608
|
+
# rubyzip is free software; you can redistribute it and/or
|
609
|
+
# modify it under the terms of the ruby license.
|