rubyzip 0.9.9 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +284 -41
  3. data/Rakefile +11 -6
  4. data/TODO +0 -1
  5. data/lib/zip/central_directory.rb +208 -0
  6. data/lib/zip/compressor.rb +1 -2
  7. data/lib/zip/constants.rb +59 -7
  8. data/lib/zip/crypto/encryption.rb +11 -0
  9. data/lib/zip/crypto/null_encryption.rb +43 -0
  10. data/lib/zip/crypto/traditional_encryption.rb +99 -0
  11. data/lib/zip/decompressor.rb +4 -4
  12. data/lib/zip/deflater.rb +17 -13
  13. data/lib/zip/dos_time.rb +13 -14
  14. data/lib/zip/entry.rb +700 -0
  15. data/lib/zip/entry_set.rb +86 -0
  16. data/lib/zip/errors.rb +18 -0
  17. data/lib/zip/extra_field/generic.rb +43 -0
  18. data/lib/zip/extra_field/ntfs.rb +90 -0
  19. data/lib/zip/extra_field/old_unix.rb +44 -0
  20. data/lib/zip/extra_field/universal_time.rb +47 -0
  21. data/lib/zip/extra_field/unix.rb +37 -0
  22. data/lib/zip/extra_field/zip64.rb +68 -0
  23. data/lib/zip/extra_field/zip64_placeholder.rb +15 -0
  24. data/lib/zip/extra_field.rb +101 -0
  25. data/lib/zip/file.rb +443 -0
  26. data/lib/zip/{zipfilesystem.rb → filesystem.rb} +162 -157
  27. data/lib/zip/inflater.rb +29 -28
  28. data/lib/zip/input_stream.rb +173 -0
  29. data/lib/zip/ioextras/abstract_input_stream.rb +111 -0
  30. data/lib/zip/ioextras/abstract_output_stream.rb +43 -0
  31. data/lib/zip/ioextras.rb +21 -149
  32. data/lib/zip/null_compressor.rb +2 -2
  33. data/lib/zip/null_decompressor.rb +8 -6
  34. data/lib/zip/null_input_stream.rb +3 -2
  35. data/lib/zip/output_stream.rb +189 -0
  36. data/lib/zip/pass_thru_compressor.rb +6 -6
  37. data/lib/zip/pass_thru_decompressor.rb +19 -19
  38. data/lib/zip/{zip_streamable_directory.rb → streamable_directory.rb} +3 -3
  39. data/lib/zip/streamable_stream.rb +56 -0
  40. data/lib/zip/version.rb +3 -0
  41. data/lib/zip.rb +71 -0
  42. data/samples/example.rb +44 -32
  43. data/samples/example_filesystem.rb +16 -18
  44. data/samples/example_recursive.rb +33 -28
  45. data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +26 -28
  46. data/samples/qtzip.rb +22 -31
  47. data/samples/write_simple.rb +12 -13
  48. data/samples/zipfind.rb +31 -39
  49. data/test/basic_zip_file_test.rb +60 -0
  50. data/test/case_sensitivity_test.rb +69 -0
  51. data/test/central_directory_entry_test.rb +69 -0
  52. data/test/central_directory_test.rb +100 -0
  53. data/test/crypto/null_encryption_test.rb +57 -0
  54. data/test/crypto/traditional_encryption_test.rb +80 -0
  55. data/test/data/WarnInvalidDate.zip +0 -0
  56. data/test/data/file1.txt +46 -0
  57. data/test/data/file1.txt.deflatedData +0 -0
  58. data/test/data/file2.txt +1504 -0
  59. data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
  60. data/test/data/globTest/foo.txt +0 -0
  61. data/test/data/globTest/food.txt +0 -0
  62. data/test/data/globTest.zip +0 -0
  63. data/test/data/gpbit3stored.zip +0 -0
  64. data/test/data/mimetype +1 -0
  65. data/test/data/notzippedruby.rb +7 -0
  66. data/test/data/ntfs.zip +0 -0
  67. data/test/data/oddExtraField.zip +0 -0
  68. data/test/data/path_traversal/Makefile +10 -0
  69. data/test/data/path_traversal/jwilk/README.md +5 -0
  70. data/test/data/path_traversal/jwilk/absolute1.zip +0 -0
  71. data/test/data/path_traversal/jwilk/absolute2.zip +0 -0
  72. data/test/data/path_traversal/jwilk/dirsymlink.zip +0 -0
  73. data/test/data/path_traversal/jwilk/dirsymlink2a.zip +0 -0
  74. data/test/data/path_traversal/jwilk/dirsymlink2b.zip +0 -0
  75. data/test/data/path_traversal/jwilk/relative0.zip +0 -0
  76. data/test/data/path_traversal/jwilk/relative2.zip +0 -0
  77. data/test/data/path_traversal/jwilk/symlink.zip +0 -0
  78. data/test/data/path_traversal/relative1.zip +0 -0
  79. data/test/data/path_traversal/tilde.zip +0 -0
  80. data/test/data/path_traversal/tuzovakaoff/README.md +3 -0
  81. data/test/data/path_traversal/tuzovakaoff/absolutepath.zip +0 -0
  82. data/test/data/path_traversal/tuzovakaoff/symlink.zip +0 -0
  83. data/test/data/rubycode.zip +0 -0
  84. data/test/data/rubycode2.zip +0 -0
  85. data/test/data/test.xls +0 -0
  86. data/test/data/testDirectory.bin +0 -0
  87. data/test/data/zip64-sample.zip +0 -0
  88. data/test/data/zipWithDirs.zip +0 -0
  89. data/test/data/zipWithEncryption.zip +0 -0
  90. data/test/deflater_test.rb +65 -0
  91. data/test/encryption_test.rb +42 -0
  92. data/test/entry_set_test.rb +163 -0
  93. data/test/entry_test.rb +154 -0
  94. data/test/errors_test.rb +35 -0
  95. data/test/extra_field_test.rb +76 -0
  96. data/test/file_extract_directory_test.rb +54 -0
  97. data/test/file_extract_test.rb +145 -0
  98. data/test/file_permissions_test.rb +65 -0
  99. data/test/file_split_test.rb +57 -0
  100. data/test/file_test.rb +666 -0
  101. data/test/filesystem/dir_iterator_test.rb +58 -0
  102. data/test/filesystem/directory_test.rb +139 -0
  103. data/test/filesystem/file_mutating_test.rb +87 -0
  104. data/test/filesystem/file_nonmutating_test.rb +508 -0
  105. data/test/filesystem/file_stat_test.rb +64 -0
  106. data/test/gentestfiles.rb +126 -0
  107. data/test/inflater_test.rb +14 -0
  108. data/test/input_stream_test.rb +182 -0
  109. data/test/ioextras/abstract_input_stream_test.rb +102 -0
  110. data/test/ioextras/abstract_output_stream_test.rb +106 -0
  111. data/test/ioextras/fake_io_test.rb +18 -0
  112. data/test/local_entry_test.rb +154 -0
  113. data/test/output_stream_test.rb +128 -0
  114. data/test/pass_thru_compressor_test.rb +30 -0
  115. data/test/pass_thru_decompressor_test.rb +14 -0
  116. data/test/path_traversal_test.rb +141 -0
  117. data/test/samples/example_recursive_test.rb +37 -0
  118. data/test/settings_test.rb +95 -0
  119. data/test/test_helper.rb +234 -0
  120. data/test/unicode_file_names_and_comments_test.rb +62 -0
  121. data/test/zip64_full_test.rb +51 -0
  122. data/test/zip64_support_test.rb +14 -0
  123. metadata +274 -41
  124. data/NEWS +0 -172
  125. data/lib/zip/settings.rb +0 -10
  126. data/lib/zip/tempfile_bugfixed.rb +0 -195
  127. data/lib/zip/zip.rb +0 -56
  128. data/lib/zip/zip_central_directory.rb +0 -135
  129. data/lib/zip/zip_entry.rb +0 -638
  130. data/lib/zip/zip_entry_set.rb +0 -77
  131. data/lib/zip/zip_extra_field.rb +0 -213
  132. data/lib/zip/zip_file.rb +0 -340
  133. data/lib/zip/zip_input_stream.rb +0 -144
  134. data/lib/zip/zip_output_stream.rb +0 -173
  135. data/lib/zip/zip_streamable_stream.rb +0 -47
data/lib/zip/zip_entry.rb DELETED
@@ -1,638 +0,0 @@
1
- module Zip
2
- class ZipEntry
3
- STORED = 0
4
- DEFLATED = 8
5
-
6
- FSTYPE_FAT = 0
7
- FSTYPE_AMIGA = 1
8
- FSTYPE_VMS = 2
9
- FSTYPE_UNIX = 3
10
- FSTYPE_VM_CMS = 4
11
- FSTYPE_ATARI = 5
12
- FSTYPE_HPFS = 6
13
- FSTYPE_MAC = 7
14
- FSTYPE_Z_SYSTEM = 8
15
- FSTYPE_CPM = 9
16
- FSTYPE_TOPS20 = 10
17
- FSTYPE_NTFS = 11
18
- FSTYPE_QDOS = 12
19
- FSTYPE_ACORN = 13
20
- FSTYPE_VFAT = 14
21
- FSTYPE_MVS = 15
22
- FSTYPE_BEOS = 16
23
- FSTYPE_TANDEM = 17
24
- FSTYPE_THEOS = 18
25
- FSTYPE_MAC_OSX = 19
26
- FSTYPE_ATHEOS = 30
27
-
28
- FSTYPES = {
29
- FSTYPE_FAT => 'FAT'.freeze,
30
- FSTYPE_AMIGA => 'Amiga'.freeze,
31
- FSTYPE_VMS => 'VMS (Vax or Alpha AXP)'.freeze,
32
- FSTYPE_UNIX => 'Unix'.freeze,
33
- FSTYPE_VM_CMS => 'VM/CMS'.freeze,
34
- FSTYPE_ATARI => 'Atari ST'.freeze,
35
- FSTYPE_HPFS => 'OS/2 or NT HPFS'.freeze,
36
- FSTYPE_MAC => 'Macintosh'.freeze,
37
- FSTYPE_Z_SYSTEM => 'Z-System'.freeze,
38
- FSTYPE_CPM => 'CP/M'.freeze,
39
- FSTYPE_TOPS20 => 'TOPS-20'.freeze,
40
- FSTYPE_NTFS => 'NTFS'.freeze,
41
- FSTYPE_QDOS => 'SMS/QDOS'.freeze,
42
- FSTYPE_ACORN => 'Acorn RISC OS'.freeze,
43
- FSTYPE_VFAT => 'Win32 VFAT'.freeze,
44
- FSTYPE_MVS => 'MVS'.freeze,
45
- FSTYPE_BEOS => 'BeOS'.freeze,
46
- FSTYPE_TANDEM => 'Tandem NSK'.freeze,
47
- FSTYPE_THEOS => 'Theos'.freeze,
48
- FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.freeze,
49
- FSTYPE_ATHEOS => 'AtheOS'.freeze,
50
- }.freeze
51
-
52
- attr_accessor :comment, :compressed_size, :crc, :extra, :compression_method,
53
- :name, :size, :localHeaderOffset, :zipfile, :fstype, :externalFileAttributes, :gp_flags, :header_signature
54
-
55
- attr_accessor :follow_symlinks
56
- attr_accessor :restore_times, :restore_permissions, :restore_ownership
57
- attr_accessor :unix_uid, :unix_gid, :unix_perms
58
- attr_accessor :dirty
59
- attr_reader :ftype, :filepath # :nodoc:
60
-
61
- def initialize(zipfile = "", name = "", comment = "", extra = "",
62
- compressed_size = 0, crc = 0,
63
- compression_method = ZipEntry::DEFLATED, size = 0,
64
- time = DOSTime.now)
65
- super()
66
- if name.start_with?("/")
67
- raise ZipEntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
68
- end
69
- @localHeaderOffset = 0
70
- @local_header_size = 0
71
- @internalFileAttributes = 1
72
- @externalFileAttributes = 0
73
- @header_signature = CENTRAL_DIRECTORY_ENTRY_SIGNATURE
74
- @versionNeededToExtract = VERSION_NEEDED_TO_EXTRACT
75
- @version = 52 # this library's version
76
- @ftype = nil # unspecified or unknown
77
- @filepath = nil
78
- if Zip::RUNNING_ON_WINDOWS
79
- @fstype = FSTYPE_FAT
80
- else
81
- @fstype = FSTYPE_UNIX
82
- end
83
- @zipfile = zipfile
84
- @comment = comment
85
- @compressed_size = compressed_size
86
- @crc = crc
87
- @extra = extra
88
- @compression_method = compression_method
89
- @name = name
90
- @size = size
91
- @time = time
92
- @gp_flags = 0
93
-
94
- @follow_symlinks = false
95
-
96
- @restore_times = true
97
- @restore_permissions = false
98
- @restore_ownership = false
99
-
100
- # BUG: need an extra field to support uid/gid's
101
- @unix_uid = nil
102
- @unix_gid = nil
103
- @unix_perms = nil
104
- # @posix_acl = nil
105
- # @ntfs_acl = nil
106
-
107
- if name_is_directory?
108
- @ftype = :directory
109
- else
110
- @ftype = :file
111
- end
112
-
113
- unless ZipExtraField === @extra
114
- @extra = ZipExtraField.new(@extra.to_s)
115
- end
116
-
117
- @dirty = false
118
- end
119
-
120
- def time
121
- if @extra["UniversalTime"]
122
- @extra["UniversalTime"].mtime
123
- else
124
- # Standard time field in central directory has local time
125
- # under archive creator. Then, we can't get timezone.
126
- @time
127
- end
128
- end
129
- alias :mtime :time
130
-
131
- def time=(aTime)
132
- unless @extra.member?("UniversalTime")
133
- @extra.create("UniversalTime")
134
- end
135
- @extra["UniversalTime"].mtime = aTime
136
- @time = aTime
137
- end
138
-
139
- # Returns +true+ if the entry is a directory.
140
- def directory?
141
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
142
- @ftype == :directory
143
- end
144
- alias :is_directory :directory?
145
-
146
- # Returns +true+ if the entry is a file.
147
- def file?
148
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
149
- @ftype == :file
150
- end
151
-
152
- # Returns +true+ if the entry is a symlink.
153
- def symlink?
154
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
155
- @ftype == :symlink
156
- end
157
-
158
- def name_is_directory? #:nodoc:all
159
- (%r{\/$} =~ @name) != nil
160
- end
161
-
162
- def local_entry_offset #:nodoc:all
163
- localHeaderOffset + @local_header_size
164
- end
165
-
166
- def calculate_local_header_size #:nodoc:all
167
- LOCAL_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.bytesize : 0) + (@extra ? @extra.local_size : 0)
168
- end
169
-
170
- def cdir_header_size #:nodoc:all
171
- CDIR_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.bytesize : 0) +
172
- (@extra ? @extra.c_dir_size : 0) + (@comment ? @comment.bytesize : 0)
173
- end
174
-
175
- def next_header_offset #:nodoc:all
176
- local_entry_offset + self.compressed_size
177
- end
178
-
179
- # Extracts entry to file destPath (defaults to @name).
180
- def extract(destPath = @name, &onExistsProc)
181
- onExistsProc ||= proc { Zip.options[:on_exists_proc] }
182
-
183
- if directory?
184
- create_directory(destPath, &onExistsProc)
185
- elsif file?
186
- write_file(destPath, &onExistsProc)
187
- elsif symlink?
188
- create_symlink(destPath, &onExistsProc)
189
- else
190
- raise RuntimeError, "unknown file type #{self.inspect}"
191
- end
192
-
193
- self
194
- end
195
-
196
- def to_s
197
- @name
198
- end
199
-
200
- protected
201
-
202
- class << self
203
- def read_zip_short(io) # :nodoc:
204
- io.read(2).unpack('v')[0]
205
- end
206
-
207
- def read_zip_long(io) # :nodoc:
208
- io.read(4).unpack('V')[0]
209
- end
210
-
211
- def read_c_dir_entry(io) #:nodoc:all
212
- entry = new(io.path)
213
- entry.read_c_dir_entry(io)
214
- entry
215
- rescue ZipError
216
- nil
217
- end
218
-
219
- def read_local_entry(io)
220
- entry = new(io.path)
221
- entry.read_local_entry(io)
222
- entry
223
- rescue ZipError
224
- nil
225
- end
226
-
227
- end
228
-
229
- public
230
-
231
- LOCAL_ENTRY_SIGNATURE = 0x04034b50
232
- LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30
233
- LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4+4+4
234
- VERSION_NEEDED_TO_EXTRACT = 20
235
-
236
- def read_local_entry(io) #:nodoc:all
237
- @localHeaderOffset = io.tell
238
- staticSizedFieldsBuf = io.read(LOCAL_ENTRY_STATIC_HEADER_LENGTH)
239
- unless (staticSizedFieldsBuf.size == LOCAL_ENTRY_STATIC_HEADER_LENGTH)
240
- raise ZipError, "Premature end of file. Not enough data for zip entry local header"
241
- end
242
-
243
- @header_signature ,
244
- @version ,
245
- @fstype ,
246
- @gp_flags ,
247
- @compression_method,
248
- lastModTime ,
249
- lastModDate ,
250
- @crc ,
251
- @compressed_size ,
252
- @size ,
253
- nameLength ,
254
- extraLength = staticSizedFieldsBuf.unpack('VCCvvvvVVVvv')
255
-
256
- unless (@header_signature == LOCAL_ENTRY_SIGNATURE)
257
- raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'"
258
- end
259
- set_time(lastModDate, lastModTime)
260
-
261
- @name = io.read(nameLength)
262
- extra = io.read(extraLength)
263
- until @name.sub!('\\', '/') == nil do end # some zip files use backslashes instead of slashes as path separators
264
- if (extra && extra.bytesize != extraLength)
265
- raise ZipError, "Truncated local zip entry header"
266
- else
267
- if ZipExtraField === @extra
268
- @extra.merge(extra)
269
- else
270
- @extra = ZipExtraField.new(extra)
271
- end
272
- end
273
- @local_header_size = calculate_local_header_size
274
- end
275
-
276
-
277
-
278
- def write_local_entry(io) #:nodoc:all
279
- @localHeaderOffset = io.tell
280
-
281
- io <<
282
- [LOCAL_ENTRY_SIGNATURE ,
283
- @versionNeededToExtract , # version needed to extract
284
- @gp_flags , # @gp_flags ,
285
- @compression_method ,
286
- @time.to_binary_dos_time , # @lastModTime ,
287
- @time.to_binary_dos_date , # @lastModDate ,
288
- @crc ,
289
- @compressed_size ,
290
- @size ,
291
- @name ? @name.bytesize : 0,
292
- @extra? @extra.local_length : 0 ].pack('VvvvvvVVVvv')
293
- io << @name
294
- io << (@extra ? @extra.to_local_bin : "")
295
- end
296
-
297
- CENTRAL_DIRECTORY_ENTRY_SIGNATURE = 0x02014b50
298
- CDIR_ENTRY_STATIC_HEADER_LENGTH = 46
299
-
300
- def read_c_dir_entry(io) #:nodoc:all
301
- staticSizedFieldsBuf = io.read(CDIR_ENTRY_STATIC_HEADER_LENGTH)
302
- unless (staticSizedFieldsBuf.bytesize == CDIR_ENTRY_STATIC_HEADER_LENGTH)
303
- raise ZipError, "Premature end of file. Not enough data for zip cdir entry header"
304
- end
305
-
306
-
307
- @header_signature ,
308
- @version , # version of encoding software
309
- @fstype , # filesystem type
310
- @versionNeededToExtract ,
311
- @gp_flags ,
312
- @compression_method ,
313
- lastModTime ,
314
- lastModDate ,
315
- @crc ,
316
- @compressed_size ,
317
- @size ,
318
- nameLength ,
319
- extraLength ,
320
- commentLength ,
321
- diskNumberStart ,
322
- @internalFileAttributes ,
323
- @externalFileAttributes ,
324
- @localHeaderOffset ,
325
- @name ,
326
- @extra ,
327
- @comment = staticSizedFieldsBuf.unpack('VCCvvvvvVVVvvvvvVV')
328
-
329
- unless (@header_signature == CENTRAL_DIRECTORY_ENTRY_SIGNATURE)
330
- raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'"
331
- end
332
- set_time(lastModDate, lastModTime)
333
-
334
- @name = io.read(nameLength)
335
- until @name.sub!('\\', '/') == nil do end # some zip files use backslashes instead of slashes as path separators
336
- if ZipExtraField === @extra
337
- @extra.merge(io.read(extraLength))
338
- else
339
- @extra = ZipExtraField.new(io.read(extraLength))
340
- end
341
- @comment = io.read(commentLength)
342
- unless (@comment && @comment.bytesize == commentLength)
343
- raise ZipError, "Truncated cdir zip entry header"
344
- end
345
-
346
- case @fstype
347
- when FSTYPE_UNIX
348
- @unix_perms = (@externalFileAttributes >> 16) & 07777
349
-
350
- case (@externalFileAttributes >> 28)
351
- when 04
352
- @ftype = :directory
353
- when 010
354
- @ftype = :file
355
- when 012
356
- @ftype = :symlink
357
- else
358
- #best case guess for whether it is a file or not
359
- #Otherwise this would be set to unknown and that entry would never be able to extracted
360
- if name_is_directory?
361
- @ftype = :directory
362
- else
363
- @ftype = :file
364
- end
365
- end
366
- else
367
- if name_is_directory?
368
- @ftype = :directory
369
- else
370
- @ftype = :file
371
- end
372
- end
373
- @local_header_size = calculate_local_header_size
374
- end
375
-
376
-
377
-
378
- def file_stat(path) # :nodoc:
379
- if @follow_symlinks
380
- return File::stat(path)
381
- else
382
- return File::lstat(path)
383
- end
384
- end
385
-
386
- def get_extra_attributes_from_path(path) # :nodoc:
387
- unless Zip::RUNNING_ON_WINDOWS
388
- stat = file_stat(path)
389
- @unix_uid = stat.uid
390
- @unix_gid = stat.gid
391
- @unix_perms = stat.mode & 07777
392
- end
393
- end
394
-
395
- def set_extra_attributes_on_path(destPath) # :nodoc:
396
- return unless (file? or directory?)
397
-
398
- case @fstype
399
- when FSTYPE_UNIX
400
- # BUG: does not update timestamps into account
401
- # ignore setuid/setgid bits by default. honor if @restore_ownership
402
- unix_perms_mask = 01777
403
- unix_perms_mask = 07777 if (@restore_ownership)
404
- FileUtils::chmod(@unix_perms & unix_perms_mask, destPath) if (@restore_permissions && @unix_perms)
405
- FileUtils::chown(@unix_uid, @unix_gid, destPath) if (@restore_ownership && @unix_uid && @unix_gid && Process::egid == 0)
406
- # File::utimes()
407
- end
408
- end
409
-
410
- def write_c_dir_entry(io) #:nodoc:all
411
- case @fstype
412
- when FSTYPE_UNIX
413
- ft = nil
414
- case @ftype
415
- when :file
416
- ft = 010
417
- @unix_perms ||= 0644
418
- when :directory
419
- ft = 004
420
- @unix_perms ||= 0755
421
- when :symlink
422
- ft = 012
423
- @unix_perms ||= 0755
424
- end
425
-
426
- if (!ft.nil?)
427
- @externalFileAttributes = (ft << 12 | (@unix_perms & 07777)) << 16
428
- end
429
- end
430
-
431
- tmp = [
432
- @header_signature,
433
- @version , # version of encoding software
434
- @fstype , # filesystem type
435
- @versionNeededToExtract , # @versionNeededToExtract ,
436
- @gp_flags , # @gp_flags ,
437
- @compression_method ,
438
- @time.to_binary_dos_time , # @lastModTime ,
439
- @time.to_binary_dos_date , # @lastModDate ,
440
- @crc ,
441
- @compressed_size ,
442
- @size ,
443
- @name ? @name.bytesize : 0 ,
444
- @extra ? @extra.c_dir_length : 0 ,
445
- @comment ? @comment.bytesize : 0 ,
446
- 0 , # disk number start
447
- @internalFileAttributes , # file type (binary=0, text=1)
448
- @externalFileAttributes , # native filesystem attributes
449
- @localHeaderOffset ,
450
- @name ,
451
- @extra ,
452
- @comment
453
- ]
454
-
455
- io << tmp.pack('VCCvvvvvVVVvvvvvVV')
456
-
457
- io << @name
458
- io << (@extra ? @extra.to_c_dir_bin : "")
459
- io << @comment
460
- end
461
-
462
- def == (other)
463
- return false unless other.class == self.class
464
- # Compares contents of local entry and exposed fields
465
- (@compression_method == other.compression_method &&
466
- @crc == other.crc &&
467
- @compressed_size == other.compressed_size &&
468
- @size == other.size &&
469
- @name == other.name &&
470
- @extra == other.extra &&
471
- @filepath == other.filepath &&
472
- self.time.dos_equals(other.time))
473
- end
474
-
475
- def <=> (other)
476
- return to_s <=> other.to_s
477
- end
478
-
479
- # Returns an IO like object for the given ZipEntry.
480
- # Warning: may behave weird with symlinks.
481
- def get_input_stream(&aProc)
482
- if @ftype == :directory
483
- return yield(NullInputStream.instance) if block_given?
484
- return NullInputStream.instance
485
- elsif @filepath
486
- case @ftype
487
- when :file
488
- return ::File.open(@filepath, "rb", &aProc)
489
- when :symlink
490
- linkpath = ::File::readlink(@filepath)
491
- stringio = StringIO.new(linkpath)
492
- return yield(stringio) if block_given?
493
- return stringio
494
- else
495
- raise "unknown @ftype #{@ftype}"
496
- end
497
- else
498
- zis = ZipInputStream.new(@zipfile, localHeaderOffset)
499
- zis.get_next_entry
500
- if block_given?
501
- begin
502
- return yield(zis)
503
- ensure
504
- zis.close
505
- end
506
- else
507
- return zis
508
- end
509
- end
510
- end
511
-
512
- def gather_fileinfo_from_srcpath(srcPath) # :nodoc:
513
- stat = file_stat(srcPath)
514
- case stat.ftype
515
- when 'file'
516
- if name_is_directory?
517
- raise ArgumentError,
518
- "entry name '#{newEntry}' indicates directory entry, but "+
519
- "'#{srcPath}' is not a directory"
520
- end
521
- @ftype = :file
522
- when 'directory'
523
- if ! name_is_directory?
524
- @name += "/"
525
- end
526
- @ftype = :directory
527
- when 'link'
528
- if name_is_directory?
529
- raise ArgumentError,
530
- "entry name '#{newEntry}' indicates directory entry, but "+
531
- "'#{srcPath}' is not a directory"
532
- end
533
- @ftype = :symlink
534
- else
535
- raise RuntimeError, "unknown file type: #{srcPath.inspect} #{stat.inspect}"
536
- end
537
-
538
- @filepath = srcPath
539
- get_extra_attributes_from_path(@filepath)
540
- end
541
-
542
- def write_to_zip_output_stream(aZipOutputStream) #:nodoc:all
543
- if @ftype == :directory
544
- aZipOutputStream.put_next_entry(self)
545
- elsif @filepath
546
- aZipOutputStream.put_next_entry(self)
547
- get_input_stream { |is| IOExtras.copy_stream(aZipOutputStream, is) }
548
- else
549
- aZipOutputStream.copy_raw_entry(self)
550
- end
551
- end
552
-
553
- def parent_as_string
554
- entry_name = name.chomp("/")
555
- slash_index = entry_name.rindex("/")
556
- slash_index ? entry_name.slice(0, slash_index+1) : nil
557
- end
558
-
559
- def get_raw_input_stream(&aProc)
560
- ::File.open(@zipfile, "rb", &aProc)
561
- end
562
-
563
- private
564
-
565
- def set_time(binaryDosDate, binaryDosTime)
566
- @time = DOSTime.parse_binary_dos_format(binaryDosDate, binaryDosTime)
567
- rescue ArgumentError
568
- puts "Invalid date/time in zip entry"
569
- end
570
-
571
- def write_file(destPath, continueOnExistsProc = proc { Zip.options[:continue_on_exists_proc] })
572
- if ::File.exists?(destPath) && ! yield(self, destPath)
573
- raise ZipDestinationFileExistsError,
574
- "Destination '#{destPath}' already exists"
575
- end
576
- ::File.open(destPath, "wb") do |os|
577
- get_input_stream do |is|
578
- set_extra_attributes_on_path(destPath)
579
-
580
- buf = ''
581
- while buf = is.sysread(Decompressor::CHUNK_SIZE, buf)
582
- os << buf
583
- end
584
- end
585
- end
586
- end
587
-
588
- def create_directory(destPath)
589
- if ::File.directory?(destPath)
590
- return
591
- elsif ::File.exists?(destPath)
592
- if block_given? && yield(self, destPath)
593
- FileUtils::rm_f destPath
594
- else
595
- raise ZipDestinationFileExistsError,
596
- "Cannot create directory '#{destPath}'. "+
597
- "A file already exists with that name"
598
- end
599
- end
600
- Dir.mkdir destPath
601
- set_extra_attributes_on_path(destPath)
602
- end
603
-
604
- # BUG: create_symlink() does not use &onExistsProc
605
- def create_symlink(destPath)
606
- stat = nil
607
- begin
608
- stat = ::File::lstat(destPath)
609
- rescue Errno::ENOENT
610
- end
611
-
612
- io = get_input_stream
613
- linkto = io.read
614
-
615
- if stat
616
- if stat.symlink?
617
- if ::File::readlink(destPath) == linkto
618
- return
619
- else
620
- raise ZipDestinationFileExistsError,
621
- "Cannot create symlink '#{destPath}'. "+
622
- "A symlink already exists with that name"
623
- end
624
- else
625
- raise ZipDestinationFileExistsError,
626
- "Cannot create symlink '#{destPath}'. "+
627
- "A file already exists with that name"
628
- end
629
- end
630
-
631
- ::File::symlink(linkto, destPath)
632
- end
633
- end
634
- end
635
-
636
- # Copyright (C) 2002, 2003 Thomas Sondergaard
637
- # rubyzip is free software; you can redistribute it and/or
638
- # modify it under the terms of the ruby license.
@@ -1,77 +0,0 @@
1
- module Zip
2
- class ZipEntrySet #:nodoc:all
3
- include Enumerable
4
-
5
- def initialize(anEnumerable = [])
6
- super()
7
- @entrySet = {}
8
- anEnumerable.each { |o| push(o) }
9
- end
10
-
11
- def include?(entry)
12
- @entrySet.include?(to_key(entry))
13
- end
14
-
15
- def find_entry(entry)
16
- @entrySet[to_key(entry)]
17
- end
18
-
19
- def <<(entry)
20
- @entrySet[to_key(entry)] = entry
21
- end
22
- alias :push :<<
23
-
24
- def size
25
- @entrySet.size
26
- end
27
-
28
- alias :length :size
29
-
30
- def delete(entry)
31
- @entrySet.delete(to_key(entry)) ? entry : nil
32
- end
33
-
34
- def each(&aProc)
35
- @entrySet.values.each(&aProc)
36
- end
37
-
38
- def entries
39
- @entrySet.values
40
- end
41
-
42
- # deep clone
43
- def dup
44
- ZipEntrySet.new(@entrySet.values.map { |e| e.dup })
45
- end
46
-
47
- def ==(other)
48
- return false unless other.kind_of?(ZipEntrySet)
49
- @entrySet == other.entrySet
50
- end
51
-
52
- def parent(entry)
53
- @entrySet[to_key(entry.parent_as_string)]
54
- end
55
-
56
- def glob(pattern, flags = ::File::FNM_PATHNAME|::File::FNM_DOTMATCH)
57
- entries.map do |entry|
58
- next nil unless ::File.fnmatch(pattern, entry.name.chomp('/'), flags)
59
- yield(entry) if block_given?
60
- entry
61
- end.compact
62
- end
63
-
64
- #TODO attr_accessor :auto_create_directories
65
- protected
66
- attr_accessor :entrySet
67
-
68
- private
69
- def to_key(entry)
70
- entry.to_s.sub(/\/$/, "")
71
- end
72
- end
73
- end
74
-
75
- # Copyright (C) 2002, 2003 Thomas Sondergaard
76
- # rubyzip is free software; you can redistribute it and/or
77
- # modify it under the terms of the ruby license.