rubyzip 0.9.1 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +354 -0
  3. data/Rakefile +15 -104
  4. data/TODO +0 -1
  5. data/lib/zip/central_directory.rb +212 -0
  6. data/lib/zip/compressor.rb +9 -0
  7. data/lib/zip/constants.rb +115 -0
  8. data/lib/zip/crypto/decrypted_io.rb +40 -0
  9. data/lib/zip/crypto/encryption.rb +11 -0
  10. data/lib/zip/crypto/null_encryption.rb +43 -0
  11. data/lib/zip/crypto/traditional_encryption.rb +99 -0
  12. data/lib/zip/decompressor.rb +31 -0
  13. data/lib/zip/deflater.rb +34 -0
  14. data/lib/zip/dos_time.rb +53 -0
  15. data/lib/zip/entry.rb +719 -0
  16. data/lib/zip/entry_set.rb +88 -0
  17. data/lib/zip/errors.rb +19 -0
  18. data/lib/zip/extra_field/generic.rb +44 -0
  19. data/lib/zip/extra_field/ntfs.rb +94 -0
  20. data/lib/zip/extra_field/old_unix.rb +46 -0
  21. data/lib/zip/extra_field/universal_time.rb +77 -0
  22. data/lib/zip/extra_field/unix.rb +39 -0
  23. data/lib/zip/extra_field/zip64.rb +70 -0
  24. data/lib/zip/extra_field/zip64_placeholder.rb +15 -0
  25. data/lib/zip/extra_field.rb +103 -0
  26. data/lib/zip/file.rb +468 -0
  27. data/lib/zip/filesystem.rb +643 -0
  28. data/lib/zip/inflater.rb +54 -0
  29. data/lib/zip/input_stream.rb +180 -0
  30. data/lib/zip/ioextras/abstract_input_stream.rb +122 -0
  31. data/lib/zip/ioextras/abstract_output_stream.rb +43 -0
  32. data/lib/zip/ioextras.rb +21 -140
  33. data/lib/zip/null_compressor.rb +15 -0
  34. data/lib/zip/null_decompressor.rb +19 -0
  35. data/lib/zip/null_input_stream.rb +10 -0
  36. data/lib/zip/output_stream.rb +198 -0
  37. data/lib/zip/pass_thru_compressor.rb +23 -0
  38. data/lib/zip/pass_thru_decompressor.rb +31 -0
  39. data/lib/zip/streamable_directory.rb +15 -0
  40. data/lib/zip/streamable_stream.rb +52 -0
  41. data/lib/zip/version.rb +3 -0
  42. data/lib/zip.rb +72 -0
  43. data/samples/example.rb +44 -32
  44. data/samples/example_filesystem.rb +16 -19
  45. data/samples/example_recursive.rb +54 -0
  46. data/samples/gtk_ruby_zip.rb +84 -0
  47. data/samples/qtzip.rb +25 -34
  48. data/samples/write_simple.rb +10 -13
  49. data/samples/zipfind.rb +38 -45
  50. metadata +182 -91
  51. data/ChangeLog +0 -1504
  52. data/NEWS +0 -144
  53. data/README +0 -72
  54. data/install.rb +0 -22
  55. data/lib/download_quizzes.rb +0 -119
  56. data/lib/quiz1/t/solutions/Bill Guindon/solitaire.rb +0 -205
  57. data/lib/quiz1/t/solutions/Carlos/solitaire.rb +0 -111
  58. data/lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb +0 -111
  59. data/lib/quiz1/t/solutions/Florian Gross/solitaire.rb +0 -301
  60. data/lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb +0 -268
  61. data/lib/quiz1/t/solutions/James Edward Gray II/solitaire.rb +0 -132
  62. data/lib/quiz1/t/solutions/Jamis Buck/bin/main.rb +0 -13
  63. data/lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb +0 -230
  64. data/lib/quiz1/t/solutions/Jamis Buck/lib/cli.rb +0 -24
  65. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_deck.rb +0 -30
  66. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_key-stream.rb +0 -19
  67. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_keying-algorithms.rb +0 -31
  68. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_solitaire-cipher.rb +0 -66
  69. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_unkeyed-algorithm.rb +0 -17
  70. data/lib/quiz1/t/solutions/Jamis Buck/test/tests.rb +0 -2
  71. data/lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb +0 -204
  72. data/lib/quiz1/t/solutions/Jim Menard/test.rb +0 -47
  73. data/lib/quiz1/t/solutions/Moses Hohman/cipher.rb +0 -97
  74. data/lib/quiz1/t/solutions/Moses Hohman/deck.rb +0 -140
  75. data/lib/quiz1/t/solutions/Moses Hohman/solitaire.rb +0 -14
  76. data/lib/quiz1/t/solutions/Moses Hohman/test_cipher.rb +0 -68
  77. data/lib/quiz1/t/solutions/Moses Hohman/test_deck.rb +0 -146
  78. data/lib/quiz1/t/solutions/Moses Hohman/test_util.rb +0 -38
  79. data/lib/quiz1/t/solutions/Moses Hohman/testsuite.rb +0 -5
  80. data/lib/quiz1/t/solutions/Moses Hohman/util.rb +0 -27
  81. data/lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb +0 -151
  82. data/lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb +0 -198
  83. data/lib/zip/stdrubyext.rb +0 -111
  84. data/lib/zip/tempfile_bugfixed.rb +0 -195
  85. data/lib/zip/zip.rb +0 -1847
  86. data/lib/zip/zipfilesystem.rb +0 -609
  87. data/lib/zip/ziprequire.rb +0 -90
  88. data/samples/gtkRubyzip.rb +0 -86
  89. data/test/alltests.rb +0 -9
  90. data/test/data/file1.txt +0 -46
  91. data/test/data/file1.txt.deflatedData +0 -0
  92. data/test/data/file2.txt +0 -1504
  93. data/test/data/notzippedruby.rb +0 -7
  94. data/test/data/rubycode.zip +0 -0
  95. data/test/data/rubycode2.zip +0 -0
  96. data/test/data/testDirectory.bin +0 -0
  97. data/test/data/zipWithDirs.zip +0 -0
  98. data/test/gentestfiles.rb +0 -157
  99. data/test/ioextrastest.rb +0 -208
  100. data/test/stdrubyexttest.rb +0 -52
  101. data/test/zipfilesystemtest.rb +0 -831
  102. data/test/ziprequiretest.rb +0 -43
  103. data/test/ziptest.rb +0 -1599
@@ -0,0 +1,643 @@
1
+ require 'zip'
2
+
3
+ module Zip
4
+ # The ZipFileSystem API provides an API for accessing entries in
5
+ # a zip archive that is similar to ruby's builtin File and Dir
6
+ # classes.
7
+ #
8
+ # Requiring 'zip/filesystem' includes this module in Zip::File
9
+ # making the methods in this module available on Zip::File objects.
10
+ #
11
+ # Using this API the following example creates a new zip file
12
+ # <code>my.zip</code> containing a normal entry with the name
13
+ # <code>first.txt</code>, a directory entry named <code>mydir</code>
14
+ # and finally another normal entry named <code>second.txt</code>
15
+ #
16
+ # require 'zip/filesystem'
17
+ #
18
+ # Zip::File.open("my.zip", Zip::File::CREATE) {
19
+ # |zipfile|
20
+ # zipfile.file.open("first.txt", "w") { |f| f.puts "Hello world" }
21
+ # zipfile.dir.mkdir("mydir")
22
+ # zipfile.file.open("mydir/second.txt", "w") { |f| f.puts "Hello again" }
23
+ # }
24
+ #
25
+ # Reading is as easy as writing, as the following example shows. The
26
+ # example writes the contents of <code>first.txt</code> from zip archive
27
+ # <code>my.zip</code> to standard out.
28
+ #
29
+ # require 'zip/filesystem'
30
+ #
31
+ # Zip::File.open("my.zip") {
32
+ # |zipfile|
33
+ # puts zipfile.file.read("first.txt")
34
+ # }
35
+
36
+ module FileSystem
37
+ def initialize # :nodoc:
38
+ mapped_zip = ZipFileNameMapper.new(self)
39
+ @zip_fs_dir = ZipFsDir.new(mapped_zip)
40
+ @zip_fs_file = ZipFsFile.new(mapped_zip)
41
+ @zip_fs_dir.file = @zip_fs_file
42
+ @zip_fs_file.dir = @zip_fs_dir
43
+ end
44
+
45
+ # Returns a ZipFsDir which is much like ruby's builtin Dir (class)
46
+ # object, except it works on the Zip::File on which this method is
47
+ # invoked
48
+ def dir
49
+ @zip_fs_dir
50
+ end
51
+
52
+ # Returns a ZipFsFile which is much like ruby's builtin File (class)
53
+ # object, except it works on the Zip::File on which this method is
54
+ # invoked
55
+ def file
56
+ @zip_fs_file
57
+ end
58
+
59
+ # Instances of this class are normally accessed via the accessor
60
+ # Zip::File::file. An instance of ZipFsFile behaves like ruby's
61
+ # builtin File (class) object, except it works on Zip::File entries.
62
+ #
63
+ # The individual methods are not documented due to their
64
+ # similarity with the methods in File
65
+ class ZipFsFile
66
+ attr_writer :dir
67
+ # protected :dir
68
+
69
+ class ZipFsStat
70
+ class << self
71
+ def delegate_to_fs_file(*methods)
72
+ methods.each do |method|
73
+ class_eval <<-END_EVAL, __FILE__, __LINE__ + 1
74
+ def #{method} # def file?
75
+ @zip_fs_file.#{method}(@entry_name) # @zip_fs_file.file?(@entry_name)
76
+ end # end
77
+ END_EVAL
78
+ end
79
+ end
80
+ end
81
+
82
+ def initialize(zip_fs_file, entry_name)
83
+ @zip_fs_file = zip_fs_file
84
+ @entry_name = entry_name
85
+ end
86
+
87
+ def kind_of?(type)
88
+ super || type == ::File::Stat
89
+ end
90
+
91
+ delegate_to_fs_file :file?, :directory?, :pipe?, :chardev?, :symlink?,
92
+ :socket?, :blockdev?, :readable?, :readable_real?, :writable?, :ctime,
93
+ :writable_real?, :executable?, :executable_real?, :sticky?, :owned?,
94
+ :grpowned?, :setuid?, :setgid?, :zero?, :size, :size?, :mtime, :atime
95
+
96
+ def blocks
97
+ nil
98
+ end
99
+
100
+ def get_entry
101
+ @zip_fs_file.__send__(:get_entry, @entry_name)
102
+ end
103
+ private :get_entry
104
+
105
+ def gid
106
+ e = get_entry
107
+ if e.extra.member? 'IUnix'
108
+ e.extra['IUnix'].gid || 0
109
+ else
110
+ 0
111
+ end
112
+ end
113
+
114
+ def uid
115
+ e = get_entry
116
+ if e.extra.member? 'IUnix'
117
+ e.extra['IUnix'].uid || 0
118
+ else
119
+ 0
120
+ end
121
+ end
122
+
123
+ def ino
124
+ 0
125
+ end
126
+
127
+ def dev
128
+ 0
129
+ end
130
+
131
+ def rdev
132
+ 0
133
+ end
134
+
135
+ def rdev_major
136
+ 0
137
+ end
138
+
139
+ def rdev_minor
140
+ 0
141
+ end
142
+
143
+ def ftype
144
+ if file?
145
+ 'file'
146
+ elsif directory?
147
+ 'directory'
148
+ else
149
+ raise StandardError, 'Unknown file type'
150
+ end
151
+ end
152
+
153
+ def nlink
154
+ 1
155
+ end
156
+
157
+ def blksize
158
+ nil
159
+ end
160
+
161
+ def mode
162
+ e = get_entry
163
+ if e.fstype == 3
164
+ e.external_file_attributes >> 16
165
+ else
166
+ 33_206 # 33206 is equivalent to -rw-rw-rw-
167
+ end
168
+ end
169
+ end
170
+
171
+ def initialize(mapped_zip)
172
+ @mapped_zip = mapped_zip
173
+ end
174
+
175
+ def get_entry(filename)
176
+ unless exists?(filename)
177
+ raise Errno::ENOENT, "No such file or directory - #{filename}"
178
+ end
179
+
180
+ @mapped_zip.find_entry(filename)
181
+ end
182
+ private :get_entry
183
+
184
+ def unix_mode_cmp(filename, mode)
185
+ e = get_entry(filename)
186
+ e.fstype == 3 && ((e.external_file_attributes >> 16) & mode) != 0
187
+ rescue Errno::ENOENT
188
+ false
189
+ end
190
+ private :unix_mode_cmp
191
+
192
+ def exists?(filename)
193
+ expand_path(filename) == '/' || !@mapped_zip.find_entry(filename).nil?
194
+ end
195
+ alias exist? exists?
196
+
197
+ # Permissions not implemented, so if the file exists it is accessible
198
+ alias owned? exists?
199
+ alias grpowned? exists?
200
+
201
+ def readable?(filename)
202
+ unix_mode_cmp(filename, 0o444)
203
+ end
204
+ alias readable_real? readable?
205
+
206
+ def writable?(filename)
207
+ unix_mode_cmp(filename, 0o222)
208
+ end
209
+ alias writable_real? writable?
210
+
211
+ def executable?(filename)
212
+ unix_mode_cmp(filename, 0o111)
213
+ end
214
+ alias executable_real? executable?
215
+
216
+ def setuid?(filename)
217
+ unix_mode_cmp(filename, 0o4000)
218
+ end
219
+
220
+ def setgid?(filename)
221
+ unix_mode_cmp(filename, 0o2000)
222
+ end
223
+
224
+ def sticky?(filename)
225
+ unix_mode_cmp(filename, 0o1000)
226
+ end
227
+
228
+ def umask(*args)
229
+ ::File.umask(*args)
230
+ end
231
+
232
+ def truncate(_filename, _len)
233
+ raise StandardError, 'truncate not supported'
234
+ end
235
+
236
+ def directory?(filename)
237
+ entry = @mapped_zip.find_entry(filename)
238
+ expand_path(filename) == '/' || (!entry.nil? && entry.directory?)
239
+ end
240
+
241
+ def open(filename, mode = 'r', permissions = 0o644, &block)
242
+ mode.delete!('b') # ignore b option
243
+ case mode
244
+ when 'r'
245
+ @mapped_zip.get_input_stream(filename, &block)
246
+ when 'w'
247
+ @mapped_zip.get_output_stream(filename, permissions, &block)
248
+ else
249
+ raise StandardError, "openmode '#{mode} not supported" unless mode == 'r'
250
+ end
251
+ end
252
+
253
+ def new(filename, mode = 'r')
254
+ self.open(filename, mode)
255
+ end
256
+
257
+ def size(filename)
258
+ @mapped_zip.get_entry(filename).size
259
+ end
260
+
261
+ # Returns nil for not found and nil for directories
262
+ def size?(filename)
263
+ entry = @mapped_zip.find_entry(filename)
264
+ entry.nil? || entry.directory? ? nil : entry.size
265
+ end
266
+
267
+ def chown(owner, group, *filenames)
268
+ filenames.each do |filename|
269
+ e = get_entry(filename)
270
+ e.extra.create('IUnix') unless e.extra.member?('IUnix')
271
+ e.extra['IUnix'].uid = owner
272
+ e.extra['IUnix'].gid = group
273
+ end
274
+ filenames.size
275
+ end
276
+
277
+ def chmod(mode, *filenames)
278
+ filenames.each do |filename|
279
+ e = get_entry(filename)
280
+ e.fstype = 3 # force convertion filesystem type to unix
281
+ e.unix_perms = mode
282
+ e.external_file_attributes = mode << 16
283
+ e.dirty = true
284
+ end
285
+ filenames.size
286
+ end
287
+
288
+ def zero?(filename)
289
+ sz = size(filename)
290
+ sz.nil? || sz == 0
291
+ rescue Errno::ENOENT
292
+ false
293
+ end
294
+
295
+ def file?(filename)
296
+ entry = @mapped_zip.find_entry(filename)
297
+ !entry.nil? && entry.file?
298
+ end
299
+
300
+ def dirname(filename)
301
+ ::File.dirname(filename)
302
+ end
303
+
304
+ def basename(filename)
305
+ ::File.basename(filename)
306
+ end
307
+
308
+ def split(filename)
309
+ ::File.split(filename)
310
+ end
311
+
312
+ def join(*fragments)
313
+ ::File.join(*fragments)
314
+ end
315
+
316
+ def utime(modified_time, *filenames)
317
+ filenames.each do |filename|
318
+ get_entry(filename).time = modified_time
319
+ end
320
+ end
321
+
322
+ def mtime(filename)
323
+ @mapped_zip.get_entry(filename).mtime
324
+ end
325
+
326
+ def atime(filename)
327
+ e = get_entry(filename)
328
+ if e.extra.member? 'UniversalTime'
329
+ e.extra['UniversalTime'].atime
330
+ elsif e.extra.member? 'NTFS'
331
+ e.extra['NTFS'].atime
332
+ end
333
+ end
334
+
335
+ def ctime(filename)
336
+ e = get_entry(filename)
337
+ if e.extra.member? 'UniversalTime'
338
+ e.extra['UniversalTime'].ctime
339
+ elsif e.extra.member? 'NTFS'
340
+ e.extra['NTFS'].ctime
341
+ end
342
+ end
343
+
344
+ def pipe?(_filename)
345
+ false
346
+ end
347
+
348
+ def blockdev?(_filename)
349
+ false
350
+ end
351
+
352
+ def chardev?(_filename)
353
+ false
354
+ end
355
+
356
+ def symlink?(_filename)
357
+ false
358
+ end
359
+
360
+ def socket?(_filename)
361
+ false
362
+ end
363
+
364
+ def ftype(filename)
365
+ @mapped_zip.get_entry(filename).directory? ? 'directory' : 'file'
366
+ end
367
+
368
+ def readlink(_filename)
369
+ raise NotImplementedError, 'The readlink() function is not implemented'
370
+ end
371
+
372
+ def symlink(_filename, _symlink_name)
373
+ raise NotImplementedError, 'The symlink() function is not implemented'
374
+ end
375
+
376
+ def link(_filename, _symlink_name)
377
+ raise NotImplementedError, 'The link() function is not implemented'
378
+ end
379
+
380
+ def pipe
381
+ raise NotImplementedError, 'The pipe() function is not implemented'
382
+ end
383
+
384
+ def stat(filename)
385
+ raise Errno::ENOENT, filename unless exists?(filename)
386
+
387
+ ZipFsStat.new(self, filename)
388
+ end
389
+
390
+ alias lstat stat
391
+
392
+ def readlines(filename)
393
+ self.open(filename, &:readlines)
394
+ end
395
+
396
+ def read(filename)
397
+ @mapped_zip.read(filename)
398
+ end
399
+
400
+ def popen(*args, &a_proc)
401
+ ::File.popen(*args, &a_proc)
402
+ end
403
+
404
+ def foreach(filename, sep = $INPUT_RECORD_SEPARATOR, &a_proc)
405
+ self.open(filename) { |is| is.each_line(sep, &a_proc) }
406
+ end
407
+
408
+ def delete(*args)
409
+ args.each do |filename|
410
+ if directory?(filename)
411
+ raise Errno::EISDIR, "Is a directory - \"#{filename}\""
412
+ end
413
+
414
+ @mapped_zip.remove(filename)
415
+ end
416
+ end
417
+
418
+ def rename(file_to_rename, new_name)
419
+ @mapped_zip.rename(file_to_rename, new_name) { true }
420
+ end
421
+
422
+ alias unlink delete
423
+
424
+ def expand_path(path)
425
+ @mapped_zip.expand_path(path)
426
+ end
427
+ end
428
+
429
+ # Instances of this class are normally accessed via the accessor
430
+ # ZipFile::dir. An instance of ZipFsDir behaves like ruby's
431
+ # builtin Dir (class) object, except it works on ZipFile entries.
432
+ #
433
+ # The individual methods are not documented due to their
434
+ # similarity with the methods in Dir
435
+ class ZipFsDir
436
+ def initialize(mapped_zip)
437
+ @mapped_zip = mapped_zip
438
+ end
439
+
440
+ attr_writer :file
441
+
442
+ def new(directory_name)
443
+ ZipFsDirIterator.new(entries(directory_name))
444
+ end
445
+
446
+ def open(directory_name)
447
+ dir_iter = new(directory_name)
448
+ if block_given?
449
+ begin
450
+ yield(dir_iter)
451
+ return nil
452
+ ensure
453
+ dir_iter.close
454
+ end
455
+ end
456
+ dir_iter
457
+ end
458
+
459
+ def pwd
460
+ @mapped_zip.pwd
461
+ end
462
+ alias getwd pwd
463
+
464
+ def chdir(directory_name)
465
+ unless @file.stat(directory_name).directory?
466
+ raise Errno::EINVAL, "Invalid argument - #{directory_name}"
467
+ end
468
+
469
+ @mapped_zip.pwd = @file.expand_path(directory_name)
470
+ end
471
+
472
+ def entries(directory_name)
473
+ entries = []
474
+ foreach(directory_name) { |e| entries << e }
475
+ entries
476
+ end
477
+
478
+ def glob(*args, &block)
479
+ @mapped_zip.glob(*args, &block)
480
+ end
481
+
482
+ def foreach(directory_name)
483
+ unless @file.stat(directory_name).directory?
484
+ raise Errno::ENOTDIR, directory_name
485
+ end
486
+
487
+ path = @file.expand_path(directory_name)
488
+ path << '/' unless path.end_with?('/')
489
+ path = Regexp.escape(path)
490
+ subdir_entry_regex = Regexp.new("^#{path}([^/]+)$")
491
+ @mapped_zip.each do |filename|
492
+ match = subdir_entry_regex.match(filename)
493
+ yield(match[1]) unless match.nil?
494
+ end
495
+ end
496
+
497
+ def delete(entry_name)
498
+ unless @file.stat(entry_name).directory?
499
+ raise Errno::EINVAL, "Invalid argument - #{entry_name}"
500
+ end
501
+
502
+ @mapped_zip.remove(entry_name)
503
+ end
504
+ alias rmdir delete
505
+ alias unlink delete
506
+
507
+ def mkdir(entry_name, permissions = 0o755)
508
+ @mapped_zip.mkdir(entry_name, permissions)
509
+ end
510
+
511
+ def chroot(*_args)
512
+ raise NotImplementedError, 'The chroot() function is not implemented'
513
+ end
514
+ end
515
+
516
+ class ZipFsDirIterator # :nodoc:all
517
+ include Enumerable
518
+
519
+ def initialize(filenames)
520
+ @filenames = filenames
521
+ @index = 0
522
+ end
523
+
524
+ def close
525
+ @filenames = nil
526
+ end
527
+
528
+ def each(&a_proc)
529
+ raise IOError, 'closed directory' if @filenames.nil?
530
+
531
+ @filenames.each(&a_proc)
532
+ end
533
+
534
+ def read
535
+ raise IOError, 'closed directory' if @filenames.nil?
536
+
537
+ @filenames[(@index += 1) - 1]
538
+ end
539
+
540
+ def rewind
541
+ raise IOError, 'closed directory' if @filenames.nil?
542
+
543
+ @index = 0
544
+ end
545
+
546
+ def seek(position)
547
+ raise IOError, 'closed directory' if @filenames.nil?
548
+
549
+ @index = position
550
+ end
551
+
552
+ def tell
553
+ raise IOError, 'closed directory' if @filenames.nil?
554
+
555
+ @index
556
+ end
557
+ end
558
+
559
+ # All access to Zip::File from ZipFsFile and ZipFsDir goes through a
560
+ # ZipFileNameMapper, which has one responsibility: ensure
561
+ class ZipFileNameMapper # :nodoc:all
562
+ include Enumerable
563
+
564
+ def initialize(zip_file)
565
+ @zip_file = zip_file
566
+ @pwd = '/'
567
+ end
568
+
569
+ attr_accessor :pwd
570
+
571
+ def find_entry(filename)
572
+ @zip_file.find_entry(expand_to_entry(filename))
573
+ end
574
+
575
+ def get_entry(filename)
576
+ @zip_file.get_entry(expand_to_entry(filename))
577
+ end
578
+
579
+ def get_input_stream(filename, &a_proc)
580
+ @zip_file.get_input_stream(expand_to_entry(filename), &a_proc)
581
+ end
582
+
583
+ def get_output_stream(filename, permissions = nil, &a_proc)
584
+ @zip_file.get_output_stream(
585
+ expand_to_entry(filename), permissions, &a_proc
586
+ )
587
+ end
588
+
589
+ def glob(pattern, *flags, &block)
590
+ @zip_file.glob(expand_to_entry(pattern), *flags, &block)
591
+ end
592
+
593
+ def read(filename)
594
+ @zip_file.read(expand_to_entry(filename))
595
+ end
596
+
597
+ def remove(filename)
598
+ @zip_file.remove(expand_to_entry(filename))
599
+ end
600
+
601
+ def rename(filename, new_name, &continue_on_exists_proc)
602
+ @zip_file.rename(
603
+ expand_to_entry(filename),
604
+ expand_to_entry(new_name),
605
+ &continue_on_exists_proc
606
+ )
607
+ end
608
+
609
+ def mkdir(filename, permissions = 0o755)
610
+ @zip_file.mkdir(expand_to_entry(filename), permissions)
611
+ end
612
+
613
+ # Turns entries into strings and adds leading /
614
+ # and removes trailing slash on directories
615
+ def each
616
+ @zip_file.each do |e|
617
+ yield('/' + e.to_s.chomp('/'))
618
+ end
619
+ end
620
+
621
+ def expand_path(path)
622
+ expanded = path.start_with?('/') ? path : ::File.join(@pwd, path)
623
+ expanded.gsub!(/\/\.(\/|$)/, '')
624
+ expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, '')
625
+ expanded.empty? ? '/' : expanded
626
+ end
627
+
628
+ private
629
+
630
+ def expand_to_entry(path)
631
+ expand_path(path)[1..-1]
632
+ end
633
+ end
634
+ end
635
+
636
+ class File
637
+ include FileSystem
638
+ end
639
+ end
640
+
641
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
642
+ # rubyzip is free software; you can redistribute it and/or
643
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,54 @@
1
+ module Zip
2
+ class Inflater < Decompressor #:nodoc:all
3
+ def initialize(*args)
4
+ super
5
+
6
+ @buffer = +''
7
+ @zlib_inflater = ::Zlib::Inflate.new(-Zlib::MAX_WBITS)
8
+ end
9
+
10
+ def read(length = nil, outbuf = '')
11
+ return (length.nil? || length.zero? ? '' : nil) if eof
12
+
13
+ while length.nil? || (@buffer.bytesize < length)
14
+ break if input_finished?
15
+
16
+ @buffer << produce_input
17
+ end
18
+
19
+ outbuf.replace(@buffer.slice!(0...(length || @buffer.bytesize)))
20
+ end
21
+
22
+ def eof
23
+ @buffer.empty? && input_finished?
24
+ end
25
+
26
+ alias eof? eof
27
+
28
+ private
29
+
30
+ def produce_input
31
+ retried = 0
32
+ begin
33
+ @zlib_inflater.inflate(input_stream.read(Decompressor::CHUNK_SIZE))
34
+ rescue Zlib::BufError
35
+ raise if retried >= 5 # how many times should we retry?
36
+
37
+ retried += 1
38
+ retry
39
+ end
40
+ rescue Zlib::Error
41
+ raise(::Zip::DecompressionError, 'zlib error while inflating')
42
+ end
43
+
44
+ def input_finished?
45
+ @zlib_inflater.finished?
46
+ end
47
+ end
48
+
49
+ ::Zip::Decompressor.register(::Zip::COMPRESSION_METHOD_DEFLATE, ::Zip::Inflater)
50
+ end
51
+
52
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
53
+ # rubyzip is free software; you can redistribute it and/or
54
+ # modify it under the terms of the ruby license.