rubyzip 0.9.9 → 1.0.0.beta1

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.

Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/NEWS +9 -5
  3. data/README.md +79 -21
  4. data/Rakefile +1 -1
  5. data/lib/zip.rb +52 -0
  6. data/lib/zip/central_directory.rb +135 -0
  7. data/lib/zip/constants.rb +57 -7
  8. data/lib/zip/decompressor.rb +2 -2
  9. data/lib/zip/deflater.rb +11 -12
  10. data/lib/zip/dos_time.rb +9 -9
  11. data/lib/zip/entry.rb +609 -0
  12. data/lib/zip/entry_set.rb +86 -0
  13. data/lib/zip/errors.rb +8 -0
  14. data/lib/zip/extra_field.rb +90 -0
  15. data/lib/zip/extra_field/generic.rb +43 -0
  16. data/lib/zip/extra_field/universal_time.rb +47 -0
  17. data/lib/zip/extra_field/unix.rb +39 -0
  18. data/lib/zip/{zip_file.rb → file.rb} +140 -61
  19. data/lib/zip/{zipfilesystem.rb → filesystem.rb} +12 -12
  20. data/lib/zip/inflater.rb +24 -24
  21. data/lib/zip/{zip_input_stream.rb → input_stream.rb} +11 -10
  22. data/lib/zip/ioextras.rb +145 -123
  23. data/lib/zip/null_compressor.rb +1 -1
  24. data/lib/zip/null_decompressor.rb +5 -3
  25. data/lib/zip/null_input_stream.rb +2 -2
  26. data/lib/zip/{zip_output_stream.rb → output_stream.rb} +43 -41
  27. data/lib/zip/pass_thru_compressor.rb +2 -2
  28. data/lib/zip/pass_thru_decompressor.rb +17 -16
  29. data/lib/zip/{zip_streamable_directory.rb → streamable_directory.rb} +1 -1
  30. data/lib/zip/{zip_streamable_stream.rb → streamable_stream.rb} +2 -2
  31. data/lib/zip/version.rb +3 -0
  32. data/samples/example.rb +27 -5
  33. data/samples/example_filesystem.rb +2 -2
  34. data/samples/example_recursive.rb +1 -1
  35. data/samples/gtkRubyzip.rb +1 -1
  36. data/samples/qtzip.rb +2 -2
  37. data/samples/write_simple.rb +1 -1
  38. data/samples/zipfind.rb +1 -1
  39. metadata +29 -27
  40. data/lib/zip/settings.rb +0 -10
  41. data/lib/zip/tempfile_bugfixed.rb +0 -195
  42. data/lib/zip/zip.rb +0 -56
  43. data/lib/zip/zip_central_directory.rb +0 -135
  44. data/lib/zip/zip_entry.rb +0 -638
  45. data/lib/zip/zip_entry_set.rb +0 -77
  46. data/lib/zip/zip_extra_field.rb +0 -213
@@ -1,9 +1,9 @@
1
1
  module Zip
2
2
  class Decompressor #:nodoc:all
3
3
  CHUNK_SIZE=32768
4
- def initialize(inputStream)
4
+ def initialize(input_stream)
5
5
  super()
6
- @inputStream=inputStream
6
+ @input_stream=input_stream
7
7
  end
8
8
  end
9
9
  end
@@ -1,24 +1,23 @@
1
1
  module Zip
2
2
  class Deflater < Compressor #:nodoc:all
3
- def initialize(outputStream, level = Zlib::DEFAULT_COMPRESSION)
3
+
4
+ def initialize(output_stream, level = ::Zlib::DEFAULT_COMPRESSION)
4
5
  super()
5
- @outputStream = outputStream
6
- @zlibDeflater = Zlib::Deflate.new(level, -Zlib::MAX_WBITS)
7
- @size = 0
8
- @crc = Zlib::crc32
6
+ @output_stream = output_stream
7
+ @zlib_deflater = ::Zlib::Deflate.new(level, -::Zlib::MAX_WBITS)
8
+ @size = 0
9
+ @crc = ::Zlib.crc32
9
10
  end
10
-
11
+
11
12
  def << (data)
12
- val = data.to_s
13
- @crc = Zlib::crc32(val, @crc)
13
+ val = data.to_s
14
+ @crc = Zlib::crc32(val, @crc)
14
15
  @size += val.bytesize
15
- @outputStream << @zlibDeflater.deflate(data)
16
+ @output_stream << @zlib_deflater.deflate(data)
16
17
  end
17
18
 
18
19
  def finish
19
- until @zlibDeflater.finished?
20
- @outputStream << @zlibDeflater.finish
21
- end
20
+ @output_stream << @zlib_deflater.finish until @zlib_deflater.finished?
22
21
  end
23
22
 
24
23
  attr_reader :size, :crc
@@ -15,14 +15,14 @@ module Zip
15
15
 
16
16
  def to_binary_dos_time
17
17
  (sec/2) +
18
- (min << 5) +
19
- (hour << 11)
18
+ (min << 5) +
19
+ (hour << 11)
20
20
  end
21
21
 
22
22
  def to_binary_dos_date
23
23
  (day) +
24
- (month << 5) +
25
- ((year - 1980) << 9)
24
+ (month << 5) +
25
+ ((year - 1980) << 9)
26
26
  end
27
27
 
28
28
  # Dos time is only stored with two seconds accuracy
@@ -31,14 +31,14 @@ module Zip
31
31
  end
32
32
 
33
33
  def self.parse_binary_dos_format(binaryDosDate, binaryDosTime)
34
- second = 2 * ( 0b11111 & binaryDosTime)
35
- minute = ( 0b11111100000 & binaryDosTime) >> 5
34
+ second = 2 * (0b11111 & binaryDosTime)
35
+ minute = (0b11111100000 & binaryDosTime) >> 5
36
36
  hour = (0b1111100000000000 & binaryDosTime) >> 11
37
- day = ( 0b11111 & binaryDosDate)
38
- month = ( 0b111100000 & binaryDosDate) >> 5
37
+ day = (0b11111 & binaryDosDate)
38
+ month = (0b111100000 & binaryDosDate) >> 5
39
39
  year = ((0b1111111000000000 & binaryDosDate) >> 9) + 1980
40
40
  begin
41
- return self.local(year, month, day, hour, minute, second)
41
+ self.local(year, month, day, hour, minute, second)
42
42
  end
43
43
  end
44
44
  end
@@ -0,0 +1,609 @@
1
+ module Zip
2
+ class Entry
3
+ STORED = 0
4
+ DEFLATED = 8
5
+ # Language encoding flag (EFS) bit
6
+ EFS = 0b100000000000
7
+
8
+ attr_accessor :comment, :compressed_size, :crc, :extra, :compression_method,
9
+ :name, :size, :local_header_offset, :zipfile, :fstype, :external_file_attributes,
10
+ :gp_flags, :header_signature, :follow_symlinks,
11
+ :restore_times, :restore_permissions, :restore_ownership,
12
+ :unix_uid, :unix_gid, :unix_perms,
13
+ :dirty
14
+ attr_reader :ftype, :filepath # :nodoc:
15
+
16
+ def set_default_vars_values
17
+ @local_header_offset = 0
18
+ @local_header_size = 0
19
+ @internal_file_attributes = 1
20
+ @external_file_attributes = 0
21
+ @header_signature = ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
22
+
23
+ @version_needed_to_extract = VERSION_NEEDED_TO_EXTRACT
24
+ @version = 52 # this library's version
25
+
26
+ @ftype = nil # unspecified or unknown
27
+ @filepath = nil
28
+ @gp_flags = 0
29
+ if ::Zip.unicode_names
30
+ @gp_flags |= EFS
31
+ @version = 63
32
+ end
33
+ @follow_symlinks = false
34
+
35
+ @restore_times = true
36
+ @restore_permissions = false
37
+ @restore_ownership = false
38
+ # BUG: need an extra field to support uid/gid's
39
+ @unix_uid = nil
40
+ @unix_gid = nil
41
+ @unix_perms = nil
42
+ #@posix_acl = nil
43
+ #@ntfs_acl = nil
44
+ @dirty = false
45
+ end
46
+
47
+ def check_name(name)
48
+ if name.start_with?('/')
49
+ raise ::Zip::ZipEntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
50
+ end
51
+ end
52
+
53
+ def initialize(*args)
54
+ name = args[1] || ''
55
+ check_name(name)
56
+
57
+ set_default_vars_values
58
+ @fstype = ::Zip::RUNNING_ON_WINDOWS ? ::Zip::FSTYPE_FAT : ::Zip::FSTYPE_UNIX
59
+
60
+ @zipfile = args[0] || ''
61
+ @name = name
62
+ @comment = args[2] || ''
63
+ @extra = args[3] || ''
64
+ @compressed_size = args[4] || 0
65
+ @crc = args[5] || 0
66
+ @compression_method = args[6] || ::Zip::Entry::DEFLATED
67
+ @size = args[7] || 0
68
+ @time = args[8] || ::Zip::DOSTime.now
69
+
70
+ @ftype = name_is_directory? ? :directory : :file
71
+ @extra = ::Zip::ExtraField.new(@extra.to_s) unless ::Zip::ExtraField === @extra
72
+ end
73
+
74
+ def time
75
+ if @extra['UniversalTime']
76
+ @extra['UniversalTime'].mtime
77
+ else
78
+ # Standard time field in central directory has local time
79
+ # under archive creator. Then, we can't get timezone.
80
+ @time
81
+ end
82
+ end
83
+
84
+ alias :mtime :time
85
+
86
+ def time=(value)
87
+ unless @extra.member?('UniversalTime')
88
+ @extra.create('UniversalTime')
89
+ end
90
+ @extra['UniversalTime'].mtime = value
91
+ @time = value
92
+ end
93
+
94
+ def file_type_is?(type)
95
+ raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
96
+ @ftype == type
97
+ end
98
+
99
+ # Dynamic checkers
100
+ %w(directory file symlink).each do |k|
101
+ define_method "#{k}?" do
102
+ file_type_is?(k.to_sym)
103
+ end
104
+ end
105
+
106
+ def name_is_directory? #:nodoc:all
107
+ @name.end_with?('/')
108
+ end
109
+
110
+ def local_entry_offset #:nodoc:all
111
+ local_header_offset + @local_header_size
112
+ end
113
+
114
+ def name_size
115
+ @name ? @name.bytesize : 0
116
+ end
117
+
118
+ def extra_size
119
+ @extra ? @extra.local_size : 0
120
+ end
121
+
122
+ def comment_size
123
+ @comment ? @comment.bytesize : 0
124
+ end
125
+
126
+ def calculate_local_header_size #:nodoc:all
127
+ LOCAL_ENTRY_STATIC_HEADER_LENGTH + name_size + extra_size
128
+ end
129
+
130
+ def cdir_header_size #:nodoc:all
131
+ CDIR_ENTRY_STATIC_HEADER_LENGTH + name_size +
132
+ (@extra ? @extra.c_dir_size : 0) + comment_size
133
+ end
134
+
135
+ def next_header_offset #:nodoc:all
136
+ local_entry_offset + self.compressed_size
137
+ end
138
+
139
+ # Extracts entry to file dest_path (defaults to @name).
140
+ def extract(dest_path = @name, &block)
141
+ block ||= proc { ::Zip.on_exists_proc }
142
+
143
+ if directory? || file? || symlink?
144
+ self.__send__("create_#{@ftype}", dest_path, &block)
145
+ else
146
+ raise RuntimeError, "unknown file type #{self.inspect}"
147
+ end
148
+
149
+ self
150
+ end
151
+
152
+ def to_s
153
+ @name
154
+ end
155
+
156
+ protected
157
+
158
+ class << self
159
+ def read_zip_short(io) # :nodoc:
160
+ io.read(2).unpack('v')[0]
161
+ end
162
+
163
+ def read_zip_long(io) # :nodoc:
164
+ io.read(4).unpack('V')[0]
165
+ end
166
+
167
+ def read_c_dir_entry(io) #:nodoc:all
168
+ entry = new(io.path)
169
+ entry.read_c_dir_entry(io)
170
+ entry
171
+ rescue ZipError
172
+ nil
173
+ end
174
+
175
+ def read_local_entry(io)
176
+ entry = new(io.path)
177
+ entry.read_local_entry(io)
178
+ entry
179
+ rescue ZipError
180
+ nil
181
+ end
182
+
183
+ end
184
+
185
+ public
186
+
187
+ def unpack_local_entry(buf)
188
+ @header_signature,
189
+ @version,
190
+ @fstype,
191
+ @gp_flags,
192
+ @compression_method,
193
+ @last_mod_time,
194
+ @last_mod_date,
195
+ @crc,
196
+ @compressed_size,
197
+ @size,
198
+ @name_length,
199
+ @extra_length = buf.unpack('VCCvvvvVVVvv')
200
+ end
201
+
202
+ def read_local_entry(io) #:nodoc:all
203
+ @local_header_offset = io.tell
204
+
205
+ static_sized_fields_buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH)
206
+
207
+ unless static_sized_fields_buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
208
+ raise ZipError, "Premature end of file. Not enough data for zip entry local header"
209
+ end
210
+
211
+ unpack_local_entry(static_sized_fields_buf)
212
+
213
+ unless @header_signature == ::Zip::LOCAL_ENTRY_SIGNATURE
214
+ raise ::Zip::ZipError, "Zip local header magic not found at location '#{local_header_offset}'"
215
+ end
216
+ set_time(@last_mod_date, @last_mod_time)
217
+
218
+ @name = io.read(@name_length)
219
+ extra = io.read(@extra_length)
220
+
221
+ @name.gsub!('\\', '/')
222
+
223
+ if extra && extra.bytesize != @extra_length
224
+ raise ::Zip::ZipError, "Truncated local zip entry header"
225
+ else
226
+ if ::Zip::ExtraField === @extra
227
+ @extra.merge(extra)
228
+ else
229
+ @extra = ::Zip::ExtraField.new(extra)
230
+ end
231
+ end
232
+ @local_header_size = calculate_local_header_size
233
+ end
234
+
235
+ def pack_local_entry
236
+ [::Zip::LOCAL_ENTRY_SIGNATURE,
237
+ @version_needed_to_extract, # version needed to extract
238
+ @gp_flags, # @gp_flags ,
239
+ @compression_method,
240
+ @time.to_binary_dos_time, # @last_mod_time ,
241
+ @time.to_binary_dos_date, # @last_mod_date ,
242
+ @crc,
243
+ @compressed_size,
244
+ @size,
245
+ name_size,
246
+ @extra ? @extra.local_length : 0].pack('VvvvvvVVVvv')
247
+ end
248
+
249
+ def write_local_entry(io) #:nodoc:all
250
+ @local_header_offset = io.tell
251
+
252
+ io << pack_local_entry
253
+
254
+ io << @name
255
+ io << (@extra ? @extra.to_local_bin : '')
256
+ end
257
+
258
+ def unpack_c_dir_entry(buf)
259
+ @header_signature,
260
+ @version, # version of encoding software
261
+ @fstype, # filesystem type
262
+ @version_needed_to_extract,
263
+ @gp_flags,
264
+ @compression_method,
265
+ @last_mod_time,
266
+ @last_mod_date,
267
+ @crc,
268
+ @compressed_size,
269
+ @size,
270
+ @name_length,
271
+ @extra_length,
272
+ @comment_length,
273
+ _, # diskNumberStart
274
+ @internal_file_attributes,
275
+ @external_file_attributes,
276
+ @local_header_offset,
277
+ @name,
278
+ @extra,
279
+ @comment = buf.unpack('VCCvvvvvVVVvvvvvVV')
280
+ end
281
+
282
+ def set_ftype_from_c_dir_entry
283
+ @ftype = case @fstype
284
+ when ::Zip::FSTYPE_UNIX
285
+ @unix_perms = (@external_file_attributes >> 16) & 07777
286
+ case (@external_file_attributes >> 28)
287
+ when ::Zip::FILE_TYPE_DIR
288
+ :directory
289
+ when ::Zip::FILE_TYPE_FILE
290
+ :file
291
+ when ::Zip::FILE_TYPE_SYMLINK
292
+ :symlink
293
+ else
294
+ #best case guess for whether it is a file or not
295
+ #Otherwise this would be set to unknown and that entry would never be able to extracted
296
+ if name_is_directory?
297
+ :directory
298
+ else
299
+ :file
300
+ end
301
+ end
302
+ else
303
+ if name_is_directory?
304
+ :directory
305
+ else
306
+ :file
307
+ end
308
+ end
309
+ end
310
+
311
+ def check_c_dir_entry_static_header_length(buf)
312
+ unless buf.bytesize == ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
313
+ raise ZipError, 'Premature end of file. Not enough data for zip cdir entry header'
314
+ end
315
+ end
316
+
317
+ def check_c_dir_entry_signature
318
+ unless header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
319
+ raise ZipError, "Zip local header magic not found at location '#{local_header_offset}'"
320
+ end
321
+ end
322
+
323
+ def check_c_dir_entry_comment_size
324
+ unless @comment && @comment.bytesize == @comment_length
325
+ raise ::Zip::ZipError, "Truncated cdir zip entry header"
326
+ end
327
+ end
328
+
329
+ def read_c_dir_extra_field(io)
330
+ if @extra.is_a?(::Zip::ExtraField)
331
+ @extra.merge(io.read(@extra_length))
332
+ else
333
+ @extra = ::Zip::ExtraField.new(io.read(@extra_length))
334
+ end
335
+ end
336
+
337
+ def read_c_dir_entry(io) #:nodoc:all
338
+ static_sized_fields_buf = io.read(::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH)
339
+ check_c_dir_entry_static_header_length(static_sized_fields_buf)
340
+ unpack_c_dir_entry(static_sized_fields_buf)
341
+ check_c_dir_entry_signature
342
+ set_time(@last_mod_date, @last_mod_time)
343
+ @name = io.read(@name_length).gsub('\\', '/')
344
+ read_c_dir_extra_field(io)
345
+ @comment = io.read(@comment_length)
346
+ check_c_dir_entry_comment_size
347
+ set_ftype_from_c_dir_entry
348
+ @local_header_size = calculate_local_header_size
349
+ end
350
+
351
+ def file_stat(path) # :nodoc:
352
+ if @follow_symlinks
353
+ ::File::stat(path)
354
+ else
355
+ ::File::lstat(path)
356
+ end
357
+ end
358
+
359
+ def get_extra_attributes_from_path(path) # :nodoc:
360
+ unless Zip::RUNNING_ON_WINDOWS
361
+ stat = file_stat(path)
362
+ @unix_uid = stat.uid
363
+ @unix_gid = stat.gid
364
+ @unix_perms = stat.mode & 07777
365
+ end
366
+ end
367
+
368
+ def set_unix_permissions_on_path(dest_path)
369
+ # BUG: does not update timestamps into account
370
+ # ignore setuid/setgid bits by default. honor if @restore_ownership
371
+ unix_perms_mask = 01777
372
+ unix_perms_mask = 07777 if @restore_ownership
373
+ ::FileUtils.chmod(@unix_perms & unix_perms_mask, dest_path) if @restore_permissions && @unix_perms
374
+ ::FileUtils.chown(@unix_uid, @unix_gid, dest_path) if @restore_ownership && @unix_uid && @unix_gid && ::Process.egid == 0
375
+ # File::utimes()
376
+ end
377
+
378
+ def set_extra_attributes_on_path(dest_path) # :nodoc:
379
+ return unless (file? || directory?)
380
+
381
+ case @fstype
382
+ when ::Zip::FSTYPE_UNIX
383
+ set_unix_permissions_on_path(dest_path)
384
+ end
385
+ end
386
+
387
+ def pack_c_dir_entry
388
+ [
389
+ @header_signature,
390
+ @version, # version of encoding software
391
+ @fstype, # filesystem type
392
+ @version_needed_to_extract, # @versionNeededToExtract ,
393
+ @gp_flags, # @gp_flags ,
394
+ @compression_method,
395
+ @time.to_binary_dos_time, # @last_mod_time ,
396
+ @time.to_binary_dos_date, # @last_mod_date ,
397
+ @crc,
398
+ @compressed_size,
399
+ @size,
400
+ name_size,
401
+ @extra ? @extra.c_dir_length : 0,
402
+ comment_size,
403
+ 0, # disk number start
404
+ @internal_file_attributes, # file type (binary=0, text=1)
405
+ @external_file_attributes, # native filesystem attributes
406
+ @local_header_offset,
407
+ @name,
408
+ @extra,
409
+ @comment
410
+ ].pack('VCCvvvvvVVVvvvvvVV')
411
+ end
412
+
413
+ def write_c_dir_entry(io) #:nodoc:all
414
+ case @fstype
415
+ when ::Zip::FSTYPE_UNIX
416
+ ft = case @ftype
417
+ when :file
418
+ @unix_perms ||= 0644
419
+ ::Zip::FILE_TYPE_FILE
420
+ when :directory
421
+ @unix_perms ||= 0755
422
+ ::Zip::FILE_TYPE_DIR
423
+ when :symlink
424
+ @unix_perms ||= 0755
425
+ ::Zip::FILE_TYPE_SYMLINK
426
+ end
427
+
428
+ unless ft.nil?
429
+ @external_file_attributes = (ft << 12 | (@unix_perms & 07777)) << 16
430
+ end
431
+ end
432
+
433
+ io << pack_c_dir_entry
434
+
435
+ io << @name
436
+ io << (@extra ? @extra.to_c_dir_bin : '')
437
+ io << @comment
438
+ end
439
+
440
+ def ==(other)
441
+ return false unless other.class == self.class
442
+ # Compares contents of local entry and exposed fields
443
+ keys_equal = %w(compression_method crc compressed_size size name extra filepath).all? do |k|
444
+ other.__send__(k.to_sym) == self.__send__(k.to_sym)
445
+ end
446
+ keys_equal && self.time.dos_equals(other.time)
447
+ end
448
+
449
+ def <=> (other)
450
+ self.to_s <=> other.to_s
451
+ end
452
+
453
+ # Returns an IO like object for the given ZipEntry.
454
+ # Warning: may behave weird with symlinks.
455
+ def get_input_stream(&block)
456
+ if @ftype == :directory
457
+ yield(::Zip::NullInputStream.instance) if block_given?
458
+ ::Zip::NullInputStream.instance
459
+ elsif @filepath
460
+ case @ftype
461
+ when :file
462
+ ::File.open(@filepath, 'rb', &block)
463
+ when :symlink
464
+ linkpath = ::File.readlink(@filepath)
465
+ stringio = ::StringIO.new(linkpath)
466
+ yield(stringio) if block_given?
467
+ stringio
468
+ else
469
+ raise "unknown @file_type #{@ftype}"
470
+ end
471
+ else
472
+ zis = ::Zip::InputStream.new(@zipfile, local_header_offset)
473
+ zis.get_next_entry
474
+ if block_given?
475
+ begin
476
+ yield(zis)
477
+ ensure
478
+ zis.close
479
+ end
480
+ else
481
+ zis
482
+ end
483
+ end
484
+ end
485
+
486
+ def gather_fileinfo_from_srcpath(src_path) # :nodoc:
487
+ stat = file_stat(src_path)
488
+ @ftype = case stat.ftype
489
+ when 'file'
490
+ if name_is_directory?
491
+ raise ArgumentError,
492
+ "entry name '#{newEntry}' indicates directory entry, but "+
493
+ "'#{src_path}' is not a directory"
494
+ end
495
+ :file
496
+ when 'directory'
497
+ @name += "/" unless name_is_directory?
498
+ :directory
499
+ when 'link'
500
+ if name_is_directory?
501
+ raise ArgumentError,
502
+ "entry name '#{newEntry}' indicates directory entry, but "+
503
+ "'#{src_path}' is not a directory"
504
+ end
505
+ :symlink
506
+ else
507
+ raise RuntimeError, "unknown file type: #{src_path.inspect} #{stat.inspect}"
508
+ end
509
+
510
+ @filepath = src_path
511
+ get_extra_attributes_from_path(@filepath)
512
+ end
513
+
514
+ def write_to_zip_output_stream(zip_output_stream) #:nodoc:all
515
+ if @ftype == :directory
516
+ zip_output_stream.put_next_entry(self)
517
+ elsif @filepath
518
+ zip_output_stream.put_next_entry(self, nil, nil, nil)
519
+ get_input_stream { |is| ::Zip::IOExtras.copy_stream(zip_output_stream, is) }
520
+ else
521
+ zip_output_stream.copy_raw_entry(self)
522
+ end
523
+ end
524
+
525
+ def parent_as_string
526
+ entry_name = name.chomp('/')
527
+ slash_index = entry_name.rindex('/')
528
+ slash_index ? entry_name.slice(0, slash_index+1) : nil
529
+ end
530
+
531
+ def get_raw_input_stream(&block)
532
+ ::File.open(@zipfile, "rb", &block)
533
+ end
534
+
535
+ private
536
+
537
+ def set_time(binary_dos_date, binary_dos_time)
538
+ @time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time)
539
+ rescue ArgumentError
540
+ puts "Invalid date/time in zip entry"
541
+ end
542
+
543
+ def create_file(dest_path, continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
544
+ if ::File.exists?(dest_path) && !yield(self, dest_path)
545
+ raise ::Zip::ZipDestinationFileExistsError,
546
+ "Destination '#{dest_path}' already exists"
547
+ end
548
+ ::File.open(dest_path, "wb") do |os|
549
+ get_input_stream do |is|
550
+ set_extra_attributes_on_path(dest_path)
551
+
552
+ buf = ''
553
+ while buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf)
554
+ os << buf
555
+ end
556
+ end
557
+ end
558
+ end
559
+
560
+ def create_directory(dest_path)
561
+ return if ::File.directory?(dest_path)
562
+ if ::File.exists?(dest_path)
563
+ if block_given? && yield(self, dest_path)
564
+ ::FileUtils::rm_f dest_path
565
+ else
566
+ raise ::Zip::ZipDestinationFileExistsError,
567
+ "Cannot create directory '#{dest_path}'. "+
568
+ "A file already exists with that name"
569
+ end
570
+ end
571
+ ::FileUtils.mkdir_p(dest_path)
572
+ set_extra_attributes_on_path(dest_path)
573
+ end
574
+
575
+ # BUG: create_symlink() does not use &block
576
+ def create_symlink(dest_path)
577
+ stat = nil
578
+ begin
579
+ stat = ::File.lstat(dest_path)
580
+ rescue Errno::ENOENT
581
+ end
582
+
583
+ io = get_input_stream
584
+ linkto = io.read
585
+
586
+ if stat
587
+ if stat.symlink?
588
+ if ::File.readlink(dest_path) == linkto
589
+ return
590
+ else
591
+ raise ZipDestinationFileExistsError,
592
+ "Cannot create symlink '#{dest_path}'. "+
593
+ "A symlink already exists with that name"
594
+ end
595
+ else
596
+ raise ZipDestinationFileExistsError,
597
+ "Cannot create symlink '#{dest_path}'. "+
598
+ "A file already exists with that name"
599
+ end
600
+ end
601
+
602
+ ::File.symlink(linkto, dest_path)
603
+ end
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.