rubyzip 0.9.5 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +334 -45
  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 +61 -8
  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 +18 -14
  13. data/lib/zip/dos_time.rb +48 -0
  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} +179 -164
  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 +7 -7
  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 +275 -41
  124. data/NEWS +0 -162
  125. data/lib/zip/stdrubyext.rb +0 -77
  126. data/lib/zip/tempfile_bugfixed.rb +0 -195
  127. data/lib/zip/zip.rb +0 -54
  128. data/lib/zip/zip_central_directory.rb +0 -139
  129. data/lib/zip/zip_entry.rb +0 -639
  130. data/lib/zip/zip_entry_set.rb +0 -66
  131. data/lib/zip/zip_extra_field.rb +0 -213
  132. data/lib/zip/zip_file.rb +0 -318
  133. data/lib/zip/zip_input_stream.rb +0 -134
  134. data/lib/zip/zip_output_stream.rb +0 -172
  135. data/lib/zip/zip_streamable_stream.rb +0 -47
data/lib/zip/zip_entry.rb DELETED
@@ -1,639 +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
-
59
- attr_accessor :dirty
60
-
61
- attr_reader :ftype, :filepath # :nodoc:
62
-
63
- # Returns the character encoding used for name and comment
64
- def name_encoding
65
- (@gp_flags & 0b100000000000) != 0 ? "utf8" : "CP437//"
66
- end
67
-
68
- # Returns the name in the encoding specified by enc
69
- def name_in(enc)
70
- if RUBY_VERSION >= '1.9'
71
- @name.encode(enc)
72
- else
73
- Iconv.conv(enc, name_encoding, @name)
74
- end
75
- end
76
-
77
- # Returns the name in the encoding specified by enc
78
- def comment_in(enc)
79
- name_in(enc)
80
- end
81
-
82
- def initialize(zipfile = "", name = "", comment = "", extra = "",
83
- compressed_size = 0, crc = 0,
84
- compression_method = ZipEntry::DEFLATED, size = 0,
85
- time = Time.now)
86
- super()
87
- if name.start_with?("/")
88
- raise ZipEntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
89
- end
90
- @localHeaderOffset = 0
91
- @local_header_size = 0
92
- @internalFileAttributes = 1
93
- @externalFileAttributes = 0
94
- @version = 52 # this library's version
95
- @ftype = nil # unspecified or unknown
96
- @filepath = nil
97
- if Zip::RUNNING_ON_WINDOWS
98
- @fstype = FSTYPE_FAT
99
- else
100
- @fstype = FSTYPE_UNIX
101
- end
102
- @zipfile = zipfile
103
- @comment = comment
104
- @compressed_size = compressed_size
105
- @crc = crc
106
- @extra = extra
107
- @compression_method = compression_method
108
- @name = name
109
- @size = size
110
- @time = time
111
- @gp_flags = nil
112
-
113
- @follow_symlinks = false
114
-
115
- @restore_times = true
116
- @restore_permissions = false
117
- @restore_ownership = false
118
-
119
- # BUG: need an extra field to support uid/gid's
120
- @unix_uid = nil
121
- @unix_gid = nil
122
- @unix_perms = nil
123
- # @posix_acl = nil
124
- # @ntfs_acl = nil
125
-
126
- if name_is_directory?
127
- @ftype = :directory
128
- else
129
- @ftype = :file
130
- end
131
-
132
- unless ZipExtraField === @extra
133
- @extra = ZipExtraField.new(@extra.to_s)
134
- end
135
-
136
- @dirty = false
137
- end
138
-
139
- def time
140
- if @extra["UniversalTime"]
141
- @extra["UniversalTime"].mtime
142
- else
143
- # Atandard time field in central directory has local time
144
- # under archive creator. Then, we can't get timezone.
145
- @time
146
- end
147
- end
148
- alias :mtime :time
149
-
150
- def time=(aTime)
151
- unless @extra.member?("UniversalTime")
152
- @extra.create("UniversalTime")
153
- end
154
- @extra["UniversalTime"].mtime = aTime
155
- @time = aTime
156
- end
157
-
158
- # Returns +true+ if the entry is a directory.
159
- def directory?
160
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
161
- @ftype == :directory
162
- end
163
- alias :is_directory :directory?
164
-
165
- # Returns +true+ if the entry is a file.
166
- def file?
167
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
168
- @ftype == :file
169
- end
170
-
171
- # Returns +true+ if the entry is a symlink.
172
- def symlink?
173
- raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
174
- @ftype == :symlink
175
- end
176
-
177
- def name_is_directory? #:nodoc:all
178
- (%r{\/$} =~ @name) != nil
179
- end
180
-
181
- def local_entry_offset #:nodoc:all
182
- localHeaderOffset + @local_header_size
183
- end
184
-
185
- def calculate_local_header_size #:nodoc:all
186
- LOCAL_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.bytesize : 0) + (@extra ? @extra.local_size : 0)
187
- end
188
-
189
- def cdir_header_size #:nodoc:all
190
- CDIR_ENTRY_STATIC_HEADER_LENGTH + (@name ? @name.bytesize : 0) +
191
- (@extra ? @extra.c_dir_size : 0) + (@comment ? @comment.bytesize : 0)
192
- end
193
-
194
- def next_header_offset #:nodoc:all
195
- local_entry_offset + self.compressed_size
196
- end
197
-
198
- # Extracts entry to file destPath (defaults to @name).
199
- def extract(destPath = @name, &onExistsProc)
200
- onExistsProc ||= proc { false }
201
-
202
- if directory?
203
- create_directory(destPath, &onExistsProc)
204
- elsif file?
205
- write_file(destPath, &onExistsProc)
206
- elsif symlink?
207
- create_symlink(destPath, &onExistsProc)
208
- else
209
- raise RuntimeError, "unknown file type #{self.inspect}"
210
- end
211
-
212
- self
213
- end
214
-
215
- def to_s
216
- @name
217
- end
218
-
219
- protected
220
-
221
- def ZipEntry.read_zip_short(io) # :nodoc:
222
- io.read(2).unpack('v')[0]
223
- end
224
-
225
- def ZipEntry.read_zip_long(io) # :nodoc:
226
- io.read(4).unpack('V')[0]
227
- end
228
- public
229
-
230
- LOCAL_ENTRY_SIGNATURE = 0x04034b50
231
- LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30
232
- LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4+4+4
233
- VERSION_NEEDED_TO_EXTRACT = 10
234
-
235
- def read_local_entry(io) #:nodoc:all
236
- @localHeaderOffset = io.tell
237
- staticSizedFieldsBuf = io.read(LOCAL_ENTRY_STATIC_HEADER_LENGTH)
238
- unless (staticSizedFieldsBuf.size==LOCAL_ENTRY_STATIC_HEADER_LENGTH)
239
- raise ZipError, "Premature end of file. Not enough data for zip entry local header"
240
- end
241
-
242
- @header_signature ,
243
- @version ,
244
- @fstype ,
245
- @gp_flags ,
246
- @compression_method,
247
- lastModTime ,
248
- lastModDate ,
249
- @crc ,
250
- @compressed_size ,
251
- @size ,
252
- nameLength ,
253
- extraLength = staticSizedFieldsBuf.unpack('VCCvvvvVVVvv')
254
-
255
- unless (@header_signature == LOCAL_ENTRY_SIGNATURE)
256
- raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'"
257
- end
258
- set_time(lastModDate, lastModTime)
259
-
260
- @name = io.read(nameLength)
261
- extra = io.read(extraLength)
262
-
263
- if (extra && extra.bytesize != extraLength)
264
- raise ZipError, "Truncated local zip entry header"
265
- else
266
- if ZipExtraField === @extra
267
- @extra.merge(extra)
268
- else
269
- @extra = ZipExtraField.new(extra)
270
- end
271
- end
272
- @local_header_size = calculate_local_header_size
273
- end
274
-
275
- def ZipEntry.read_local_entry(io)
276
- entry = new(io.path)
277
- entry.read_local_entry(io)
278
- return entry
279
- rescue ZipError
280
- return nil
281
- end
282
-
283
- def write_local_entry(io) #:nodoc:all
284
- @localHeaderOffset = io.tell
285
-
286
- io <<
287
- [LOCAL_ENTRY_SIGNATURE ,
288
- VERSION_NEEDED_TO_EXTRACT , # version needed to extract
289
- 0 , # @gp_flags ,
290
- @compression_method ,
291
- @time.to_binary_dos_time , # @lastModTime ,
292
- @time.to_binary_dos_date , # @lastModDate ,
293
- @crc ,
294
- @compressed_size ,
295
- @size ,
296
- @name ? @name.bytesize : 0,
297
- @extra? @extra.local_length : 0 ].pack('VvvvvvVVVvv')
298
- io << @name
299
- io << (@extra ? @extra.to_local_bin : "")
300
- end
301
-
302
- CENTRAL_DIRECTORY_ENTRY_SIGNATURE = 0x02014b50
303
- CDIR_ENTRY_STATIC_HEADER_LENGTH = 46
304
-
305
- def read_c_dir_entry(io) #:nodoc:all
306
- staticSizedFieldsBuf = io.read(CDIR_ENTRY_STATIC_HEADER_LENGTH)
307
- unless (staticSizedFieldsBuf.size == CDIR_ENTRY_STATIC_HEADER_LENGTH)
308
- raise ZipError, "Premature end of file. Not enough data for zip cdir entry header"
309
- end
310
-
311
- @header_signature ,
312
- @version , # version of encoding software
313
- @fstype , # filesystem type
314
- @versionNeededToExtract,
315
- @gp_flags ,
316
- @compression_method ,
317
- lastModTime ,
318
- lastModDate ,
319
- @crc ,
320
- @compressed_size ,
321
- @size ,
322
- nameLength ,
323
- extraLength ,
324
- commentLength ,
325
- diskNumberStart ,
326
- @internalFileAttributes,
327
- @externalFileAttributes,
328
- @localHeaderOffset ,
329
- @name ,
330
- @extra ,
331
- @comment = staticSizedFieldsBuf.unpack('VCCvvvvvVVVvvvvvVV')
332
-
333
- unless (@header_signature == CENTRAL_DIRECTORY_ENTRY_SIGNATURE)
334
- raise ZipError, "Zip local header magic not found at location '#{localHeaderOffset}'"
335
- end
336
- set_time(lastModDate, lastModTime)
337
-
338
- @name = io.read(nameLength)
339
- if ZipExtraField === @extra
340
- @extra.merge(io.read(extraLength))
341
- else
342
- @extra = ZipExtraField.new(io.read(extraLength))
343
- end
344
- @comment = io.read(commentLength)
345
- unless (@comment && @comment.bytesize == commentLength)
346
- raise ZipError, "Truncated cdir zip entry header"
347
- end
348
-
349
- case @fstype
350
- when FSTYPE_UNIX
351
- @unix_perms = (@externalFileAttributes >> 16) & 07777
352
-
353
- case (@externalFileAttributes >> 28)
354
- when 04
355
- @ftype = :directory
356
- when 010
357
- @ftype = :file
358
- when 012
359
- @ftype = :symlink
360
- else
361
- @ftype = :unknown
362
- end
363
- else
364
- if name_is_directory?
365
- @ftype = :directory
366
- else
367
- @ftype = :file
368
- end
369
- end
370
- @local_header_size = calculate_local_header_size
371
- end
372
-
373
- def ZipEntry.read_c_dir_entry(io) #:nodoc:all
374
- entry = new(io.path)
375
- entry.read_c_dir_entry(io)
376
- return entry
377
- rescue ZipError
378
- return nil
379
- end
380
-
381
- def file_stat(path) # :nodoc:
382
- if @follow_symlinks
383
- return File::stat(path)
384
- else
385
- return File::lstat(path)
386
- end
387
- end
388
-
389
- def get_extra_attributes_from_path(path) # :nodoc:
390
- unless Zip::RUNNING_ON_WINDOWS
391
- stat = file_stat(path)
392
- @unix_uid = stat.uid
393
- @unix_gid = stat.gid
394
- @unix_perms = stat.mode & 07777
395
- end
396
- end
397
-
398
- def set_extra_attributes_on_path(destPath) # :nodoc:
399
- return unless (file? or directory?)
400
-
401
- case @fstype
402
- when FSTYPE_UNIX
403
- # BUG: does not update timestamps into account
404
- # ignore setuid/setgid bits by default. honor if @restore_ownership
405
- unix_perms_mask = 01777
406
- unix_perms_mask = 07777 if (@restore_ownership)
407
- FileUtils::chmod(@unix_perms & unix_perms_mask, destPath) if (@restore_permissions && @unix_perms)
408
- FileUtils::chown(@unix_uid, @unix_gid, destPath) if (@restore_ownership && @unix_uid && @unix_gid && Process::egid == 0)
409
- # File::utimes()
410
- end
411
- end
412
-
413
- def write_c_dir_entry(io) #:nodoc:all
414
- case @fstype
415
- when FSTYPE_UNIX
416
- ft = nil
417
- case @ftype
418
- when :file
419
- ft = 010
420
- @unix_perms ||= 0644
421
- when :directory
422
- ft = 004
423
- @unix_perms ||= 0755
424
- when :symlink
425
- ft = 012
426
- @unix_perms ||= 0755
427
- end
428
-
429
- if (!ft.nil?)
430
- @externalFileAttributes = (ft << 12 | (@unix_perms & 07777)) << 16
431
- end
432
- end
433
-
434
- io <<
435
- [CENTRAL_DIRECTORY_ENTRY_SIGNATURE,
436
- @version , # version of encoding software
437
- @fstype , # filesystem type
438
- VERSION_NEEDED_TO_EXTRACT , # @versionNeededToExtract ,
439
- 0 , # @gp_flags ,
440
- @compression_method ,
441
- @time.to_binary_dos_time , # @lastModTime ,
442
- @time.to_binary_dos_date , # @lastModDate ,
443
- @crc ,
444
- @compressed_size ,
445
- @size ,
446
- @name ? @name.bytesize : 0 ,
447
- @extra ? @extra.c_dir_length : 0 ,
448
- @comment ? @comment.bytesize : 0 ,
449
- 0 , # disk number start
450
- @internalFileAttributes , # file type (binary=0, text=1)
451
- @externalFileAttributes , # native filesystem attributes
452
- @localHeaderOffset ,
453
- @name ,
454
- @extra ,
455
- @comment ].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
-
490
- when :symlink
491
- linkpath = File::readlink(@filepath)
492
- stringio = StringIO.new(linkpath)
493
- return yield(stringio) if block_given?
494
- return stringio
495
- else
496
- raise "unknown @ftype #{@ftype}"
497
- end
498
- else
499
- zis = ZipInputStream.new(@zipfile, localHeaderOffset)
500
- zis.get_next_entry
501
- if block_given?
502
- begin
503
- return yield(zis)
504
- ensure
505
- zis.close
506
- end
507
- else
508
- return zis
509
- end
510
- end
511
- end
512
-
513
- def gather_fileinfo_from_srcpath(srcPath) # :nodoc:
514
- stat = file_stat(srcPath)
515
- case stat.ftype
516
- when 'file'
517
- if name_is_directory?
518
- raise ArgumentError,
519
- "entry name '#{newEntry}' indicates directory entry, but "+
520
- "'#{srcPath}' is not a directory"
521
- end
522
- @ftype = :file
523
- when 'directory'
524
- if ! name_is_directory?
525
- @name += "/"
526
- end
527
- @ftype = :directory
528
- when 'link'
529
- if name_is_directory?
530
- raise ArgumentError,
531
- "entry name '#{newEntry}' indicates directory entry, but "+
532
- "'#{srcPath}' is not a directory"
533
- end
534
- @ftype = :symlink
535
- else
536
- raise RuntimeError, "unknown file type: #{srcPath.inspect} #{stat.inspect}"
537
- end
538
-
539
- @filepath = srcPath
540
- get_extra_attributes_from_path(@filepath)
541
- end
542
-
543
- def write_to_zip_output_stream(aZipOutputStream) #:nodoc:all
544
- if @ftype == :directory
545
- aZipOutputStream.put_next_entry(self)
546
- elsif @filepath
547
- aZipOutputStream.put_next_entry(self)
548
- get_input_stream { |is| IOExtras.copy_stream(aZipOutputStream, is) }
549
- else
550
- aZipOutputStream.copy_raw_entry(self)
551
- end
552
- end
553
-
554
- def parent_as_string
555
- entry_name = name.chomp("/")
556
- slash_index = entry_name.rindex("/")
557
- slash_index ? entry_name.slice(0, slash_index+1) : nil
558
- end
559
-
560
- def get_raw_input_stream(&aProc)
561
- File.open(@zipfile, "rb", &aProc)
562
- end
563
-
564
- private
565
-
566
- def set_time(binaryDosDate, binaryDosTime)
567
- @time = Time.parse_binary_dos_format(binaryDosDate, binaryDosTime)
568
- rescue ArgumentError
569
- puts "Invalid date/time in zip entry"
570
- end
571
-
572
- def write_file(destPath, continueOnExistsProc = proc { false })
573
- if File.exists?(destPath) && ! yield(self, destPath)
574
- raise ZipDestinationFileExistsError,
575
- "Destination '#{destPath}' already exists"
576
- end
577
- File.open(destPath, "wb") do |os|
578
- get_input_stream do |is|
579
- set_extra_attributes_on_path(destPath)
580
-
581
- buf = ''
582
- while buf = is.sysread(Decompressor::CHUNK_SIZE, buf)
583
- os << buf
584
- end
585
- end
586
- end
587
- end
588
-
589
- def create_directory(destPath)
590
- if File.directory? destPath
591
- return
592
- elsif File.exists? destPath
593
- if block_given? && yield(self, destPath)
594
- FileUtils::rm_f destPath
595
- else
596
- raise ZipDestinationFileExistsError,
597
- "Cannot create directory '#{destPath}'. "+
598
- "A file already exists with that name"
599
- end
600
- end
601
- Dir.mkdir destPath
602
- set_extra_attributes_on_path(destPath)
603
- end
604
-
605
- # BUG: create_symlink() does not use &onExistsProc
606
- def create_symlink(destPath)
607
- stat = nil
608
- begin
609
- stat = File::lstat(destPath)
610
- rescue Errno::ENOENT
611
- end
612
-
613
- io = get_input_stream
614
- linkto = io.read
615
-
616
- if stat
617
- if stat.symlink?
618
- if File::readlink(destPath) == linkto
619
- return
620
- else
621
- raise ZipDestinationFileExistsError,
622
- "Cannot create symlink '#{destPath}'. "+
623
- "A symlink already exists with that name"
624
- end
625
- else
626
- raise ZipDestinationFileExistsError,
627
- "Cannot create symlink '#{destPath}'. "+
628
- "A file already exists with that name"
629
- end
630
- end
631
-
632
- File::symlink(linkto, destPath)
633
- end
634
- end
635
- end
636
-
637
- # Copyright (C) 2002, 2003 Thomas Sondergaard
638
- # rubyzip is free software; you can redistribute it and/or
639
- # modify it under the terms of the ruby license.
@@ -1,66 +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?(entry.to_s)
13
- end
14
-
15
- def <<(entry)
16
- @entrySet[entry.to_s] = entry
17
- end
18
- alias :push :<<
19
-
20
- def size
21
- @entrySet.size
22
- end
23
- alias :length :size
24
-
25
- def delete(entry)
26
- @entrySet.delete(entry.to_s) ? entry : nil
27
- end
28
-
29
- def each(&aProc)
30
- @entrySet.values.each(&aProc)
31
- end
32
-
33
- def entries
34
- @entrySet.values
35
- end
36
-
37
- # deep clone
38
- def dup
39
- newZipEntrySet = ZipEntrySet.new(@entrySet.values.map { |e| e.dup })
40
- end
41
-
42
- def == (other)
43
- return false unless other.kind_of?(ZipEntrySet)
44
- return @entrySet == other.entrySet
45
- end
46
-
47
- def parent(entry)
48
- @entrySet[entry.parent_as_string]
49
- end
50
-
51
- def glob(pattern, flags = File::FNM_PATHNAME|File::FNM_DOTMATCH)
52
- entries.select {
53
- |entry|
54
- File.fnmatch(pattern, entry.name.chomp('/'), flags)
55
- }
56
- end
57
-
58
- #TODO attr_accessor :auto_create_directories
59
- protected
60
- attr_accessor :entrySet
61
- end
62
- end
63
-
64
- # Copyright (C) 2002, 2003 Thomas Sondergaard
65
- # rubyzip is free software; you can redistribute it and/or
66
- # modify it under the terms of the ruby license.