rubyzip 0.9.9 → 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 +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
@@ -1,213 +0,0 @@
1
- module Zip
2
- class ZipExtraField < Hash
3
- ID_MAP = {}
4
-
5
- # Meta class for extra fields
6
- class Generic
7
- def self.register_map
8
- if self.const_defined?(:HEADER_ID)
9
- ID_MAP[self.const_get(:HEADER_ID)] = self
10
- end
11
- end
12
-
13
- def self.name
14
- self.to_s.split("::")[-1]
15
- end
16
-
17
- # return field [size, content] or false
18
- def initial_parse(binstr)
19
- if ! binstr
20
- # If nil, start with empty.
21
- return false
22
- elsif binstr[0,2] != self.class.const_get(:HEADER_ID)
23
- $stderr.puts "Warning: weired extra feild header ID. skip parsing"
24
- return false
25
- end
26
- [binstr[2,2].unpack("v")[0], binstr[4..-1]]
27
- end
28
-
29
- def ==(other)
30
- return false if self.class != other.class
31
- each do |k, v|
32
- v != other[k] and return false
33
- end
34
- true
35
- end
36
-
37
- def to_local_bin
38
- s = pack_for_local
39
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack("v") + s
40
- end
41
-
42
- def to_c_dir_bin
43
- s = pack_for_c_dir
44
- self.class.const_get(:HEADER_ID) + [s.bytesize].pack("v") + s
45
- end
46
- end
47
-
48
- # Info-ZIP Additional timestamp field
49
- class UniversalTime < Generic
50
- HEADER_ID = "UT"
51
- register_map
52
-
53
- def initialize(binstr = nil)
54
- @ctime = nil
55
- @mtime = nil
56
- @atime = nil
57
- @flag = nil
58
- binstr and merge(binstr)
59
- end
60
- attr_accessor :atime, :ctime, :mtime, :flag
61
-
62
- def merge(binstr)
63
- return if binstr.empty?
64
- size, content = initial_parse(binstr)
65
- size or return
66
- @flag, mtime, atime, ctime = content.unpack("CVVV")
67
- mtime and @mtime ||= DOSTime.at(mtime)
68
- atime and @atime ||= DOSTime.at(atime)
69
- ctime and @ctime ||= DOSTime.at(ctime)
70
- end
71
-
72
- def ==(other)
73
- @mtime == other.mtime &&
74
- @atime == other.atime &&
75
- @ctime == other.ctime
76
- end
77
-
78
- def pack_for_local
79
- s = [@flag].pack("C")
80
- @flag & 1 != 0 and s << [@mtime.to_i].pack("V")
81
- @flag & 2 != 0 and s << [@atime.to_i].pack("V")
82
- @flag & 4 != 0 and s << [@ctime.to_i].pack("V")
83
- s
84
- end
85
-
86
- def pack_for_c_dir
87
- s = [@flag].pack("C")
88
- @flag & 1 == 1 and s << [@mtime.to_i].pack("V")
89
- s
90
- end
91
- end
92
-
93
- # Info-ZIP Extra for UNIX uid/gid
94
- class IUnix < Generic
95
- HEADER_ID = "Ux"
96
- register_map
97
-
98
- def initialize(binstr = nil)
99
- @uid = 0
100
- @gid = 0
101
- binstr and merge(binstr)
102
- end
103
- attr_accessor :uid, :gid
104
-
105
- def merge(binstr)
106
- return if binstr.empty?
107
- size, content = initial_parse(binstr)
108
- # size: 0 for central directory. 4 for local header
109
- return if(!size || size == 0)
110
- uid, gid = content.unpack("vv")
111
- @uid ||= uid
112
- @gid ||= gid
113
- end
114
-
115
- def ==(other)
116
- @uid == other.uid &&
117
- @gid == other.gid
118
- end
119
-
120
- def pack_for_local
121
- [@uid, @gid].pack("vv")
122
- end
123
-
124
- def pack_for_c_dir
125
- ""
126
- end
127
- end
128
-
129
- ## start main of ZipExtraField < Hash
130
- def initialize(binstr = nil)
131
- binstr and merge(binstr)
132
- end
133
-
134
- def merge(binstr)
135
- return if binstr.empty?
136
- i = 0
137
- while i < binstr.bytesize
138
- id = binstr[i,2]
139
- len = binstr[i + 2,2].to_s.unpack("v")[0]
140
- if id && ID_MAP.member?(id)
141
- field_name = ID_MAP[id].name
142
- if self.member?(field_name)
143
- self[field_name].mergea(binstr[i, len + 4])
144
- else
145
- field_obj = ID_MAP[id].new(binstr[i, len + 4])
146
- self[field_name] = field_obj
147
- end
148
- elsif id
149
- unless self["Unknown"]
150
- s = ""
151
- class << s
152
- alias_method :to_c_dir_bin, :to_s
153
- alias_method :to_local_bin, :to_s
154
- end
155
- self["Unknown"] = s
156
- end
157
- if !len || len + 4 > binstr[i..-1].bytesize
158
- self["Unknown"] << binstr[i..-1]
159
- break
160
- end
161
- self["Unknown"] << binstr[i, len + 4]
162
- end
163
- i += len + 4
164
- end
165
- end
166
-
167
- def create(name)
168
- field_class = nil
169
- ID_MAP.each { |id, klass|
170
- if klass.name == name
171
- field_class = klass
172
- break
173
- end
174
- }
175
- if ! field_class
176
- raise ZipError, "Unknown extra field '#{name}'"
177
- end
178
- self[name] = field_class.new()
179
- end
180
-
181
- def to_local_bin
182
- s = ""
183
- each do |k, v|
184
- s << v.to_local_bin
185
- end
186
- s
187
- end
188
- alias :to_s :to_local_bin
189
-
190
- def to_c_dir_bin
191
- s = ""
192
- each do |k, v|
193
- s << v.to_c_dir_bin
194
- end
195
- s
196
- end
197
-
198
- def c_dir_length
199
- to_c_dir_bin.bytesize
200
- end
201
- def local_length
202
- to_local_bin.bytesize
203
- end
204
- alias :c_dir_size :c_dir_length
205
- alias :local_size :local_length
206
- alias :length :local_length
207
- alias :size :local_length
208
- end
209
- end
210
-
211
- # Copyright (C) 2002, 2003 Thomas Sondergaard
212
- # rubyzip is free software; you can redistribute it and/or
213
- # modify it under the terms of the ruby license.
data/lib/zip/zip_file.rb DELETED
@@ -1,340 +0,0 @@
1
- module Zip
2
- # ZipFile is modeled after java.util.zip.ZipFile from the Java SDK.
3
- # The most important methods are those inherited from
4
- # ZipCentralDirectory for accessing information about the entries in
5
- # the archive and methods such as get_input_stream and
6
- # get_output_stream for reading from and writing entries to the
7
- # archive. The class includes a few convenience methods such as
8
- # #extract for extracting entries to the filesystem, and #remove,
9
- # #replace, #rename and #mkdir for making simple modifications to
10
- # the archive.
11
- #
12
- # Modifications to a zip archive are not committed until #commit or
13
- # #close is called. The method #open accepts a block following
14
- # the pattern from File.open offering a simple way to
15
- # automatically close the archive when the block returns.
16
- #
17
- # The following example opens zip archive <code>my.zip</code>
18
- # (creating it if it doesn't exist) and adds an entry
19
- # <code>first.txt</code> and a directory entry <code>a_dir</code>
20
- # to it.
21
- #
22
- # require 'zip/zip'
23
- #
24
- # Zip::ZipFile.open("my.zip", Zip::ZipFile::CREATE) {
25
- # |zipfile|
26
- # zipfile.get_output_stream("first.txt") { |f| f.puts "Hello from ZipFile" }
27
- # zipfile.mkdir("a_dir")
28
- # }
29
- #
30
- # The next example reopens <code>my.zip</code> writes the contents of
31
- # <code>first.txt</code> to standard out and deletes the entry from
32
- # the archive.
33
- #
34
- # require 'zip/zip'
35
- #
36
- # Zip::ZipFile.open("my.zip", Zip::ZipFile::CREATE) {
37
- # |zipfile|
38
- # puts zipfile.read("first.txt")
39
- # zipfile.remove("first.txt")
40
- # }
41
- #
42
- # ZipFileSystem offers an alternative API that emulates ruby's
43
- # interface for accessing the filesystem, ie. the File and Dir classes.
44
-
45
- class ZipFile < ZipCentralDirectory
46
-
47
- CREATE = 1
48
-
49
- attr_reader :name
50
-
51
- # default -> false
52
- attr_accessor :restore_ownership
53
- # default -> false
54
- attr_accessor :restore_permissions
55
- # default -> true
56
- attr_accessor :restore_times
57
-
58
- # Opens a zip archive. Pass true as the second parameter to create
59
- # a new archive if it doesn't exist already.
60
- def initialize(fileName, create = nil, buffer = false)
61
- super()
62
- @name = fileName
63
- @comment = ""
64
- case
65
- when ::File.exists?(fileName) && !buffer
66
- ::File.open(name, "rb") do |f|
67
- read_from_stream(f)
68
- end
69
- when create
70
- @entrySet = ZipEntrySet.new
71
- else
72
- raise ZipError, "File #{fileName} not found"
73
- end
74
- @create = create
75
- @storedEntries = @entrySet.dup
76
- @storedComment = @comment
77
- @restore_ownership = false
78
- @restore_permissions = false
79
- @restore_times = true
80
- end
81
-
82
- class << self
83
- # Same as #new. If a block is passed the ZipFile object is passed
84
- # to the block and is automatically closed afterwards just as with
85
- # ruby's builtin File.open method.
86
- def open(fileName, create = nil)
87
- zf = ZipFile.new(fileName, create)
88
- if block_given?
89
- begin
90
- yield zf
91
- ensure
92
- zf.close
93
- end
94
- else
95
- zf
96
- end
97
- end
98
-
99
- # Same as #open. But outputs data to a buffer instead of a file
100
- def add_buffer
101
- zf = ZipFile.new('', true, true)
102
- yield zf
103
- zf.write_buffer
104
- end
105
-
106
- # Like #open, but reads zip archive contents from a String or open IO
107
- # stream, and outputs data to a buffer.
108
- # (This can be used to extract data from a
109
- # downloaded zip archive without first saving it to disk.)
110
- def open_buffer(io)
111
- zf = ZipFile.new('',true,true)
112
- if io.is_a? IO
113
- zf.read_from_stream(io)
114
- elsif io.is_a? String
115
- require 'stringio'
116
- zf.read_from_stream(StringIO.new(io))
117
- else
118
- raise "Zip::ZipFile.open_buffer expects an argument of class String or IO. Found: #{io.class}"
119
- end
120
- yield zf
121
- zf.write_buffer
122
- end
123
-
124
- # Iterates over the contents of the ZipFile. This is more efficient
125
- # than using a ZipInputStream since this methods simply iterates
126
- # through the entries in the central directory structure in the archive
127
- # whereas ZipInputStream jumps through the entire archive accessing the
128
- # local entry headers (which contain the same information as the
129
- # central directory).
130
- def foreach(aZipFileName, &block)
131
- open(aZipFileName) do |zipFile|
132
- zipFile.each(&block)
133
- end
134
- end
135
- end
136
-
137
- # Returns the zip files comment, if it has one
138
- attr_accessor :comment
139
-
140
- # Returns an input stream to the specified entry. If a block is passed
141
- # the stream object is passed to the block and the stream is automatically
142
- # closed afterwards just as with ruby's builtin File.open method.
143
- def get_input_stream(entry, &aProc)
144
- get_entry(entry).get_input_stream(&aProc)
145
- end
146
-
147
- # Returns an output stream to the specified entry. If a block is passed
148
- # the stream object is passed to the block and the stream is automatically
149
- # closed afterwards just as with ruby's builtin File.open method.
150
- def get_output_stream(entry, permissionInt = nil, &aProc)
151
- newEntry = entry.kind_of?(ZipEntry) ? entry : ZipEntry.new(@name, entry.to_s)
152
- if newEntry.directory?
153
- raise ArgumentError,
154
- "cannot open stream to directory entry - '#{newEntry}'"
155
- end
156
- newEntry.unix_perms = permissionInt
157
- zipStreamableEntry = ZipStreamableStream.new(newEntry)
158
- @entrySet << zipStreamableEntry
159
- zipStreamableEntry.get_output_stream(&aProc)
160
- end
161
-
162
- # Returns the name of the zip archive
163
- def to_s
164
- @name
165
- end
166
-
167
- # Returns a string containing the contents of the specified entry
168
- def read(entry)
169
- get_input_stream(entry) { |is| is.read }
170
- end
171
-
172
- # Convenience method for adding the contents of a file to the archive
173
- def add(entry, srcPath, &continueOnExistsProc)
174
- continueOnExistsProc ||= proc { Zip.options[:continue_on_exists_proc] }
175
- check_entry_exists(entry, continueOnExistsProc, "add")
176
- newEntry = entry.kind_of?(ZipEntry) ? entry : ZipEntry.new(@name, entry.to_s)
177
- newEntry.gather_fileinfo_from_srcpath(srcPath)
178
- @entrySet << newEntry
179
- end
180
-
181
- # Removes the specified entry.
182
- def remove(entry)
183
- @entrySet.delete(get_entry(entry))
184
- end
185
-
186
- # Renames the specified entry.
187
- def rename(entry, newName, &continueOnExistsProc)
188
- foundEntry = get_entry(entry)
189
- check_entry_exists(newName, continueOnExistsProc, "rename")
190
- @entrySet.delete(foundEntry)
191
- foundEntry.name = newName
192
- @entrySet << foundEntry
193
- end
194
-
195
- # Replaces the specified entry with the contents of srcPath (from
196
- # the file system).
197
- def replace(entry, srcPath)
198
- check_file(srcPath)
199
- remove(entry)
200
- add(entry, srcPath)
201
- end
202
-
203
- # Extracts entry to file destPath.
204
- def extract(entry, destPath, &onExistsProc)
205
- onExistsProc ||= proc { Zip.options[:on_exists_proc] }
206
- foundEntry = get_entry(entry)
207
- foundEntry.extract(destPath, &onExistsProc)
208
- end
209
-
210
- # Commits changes that has been made since the previous commit to
211
- # the zip archive.
212
- def commit
213
- return if !commit_required?
214
- on_success_replace(name) {
215
- |tmpFile|
216
- ZipOutputStream.open(tmpFile) {
217
- |zos|
218
-
219
- @entrySet.each {
220
- |e|
221
- e.write_to_zip_output_stream(zos)
222
- e.dirty = false
223
- }
224
- zos.comment = comment
225
- }
226
- true
227
- }
228
- initialize(name)
229
- end
230
-
231
- # Write buffer write changes to buffer and return
232
- def write_buffer
233
- buffer = ZipOutputStream.write_buffer do |zos|
234
- @entrySet.each { |e| e.write_to_zip_output_stream(zos) }
235
- zos.comment = comment
236
- end
237
- return buffer
238
- end
239
-
240
- # Closes the zip file committing any changes that has been made.
241
- def close
242
- commit
243
- end
244
-
245
- # Returns true if any changes has been made to this archive since
246
- # the previous commit
247
- def commit_required?
248
- @entrySet.each do |e|
249
- return true if e.dirty
250
- end
251
- @comment != @storedComment || @entrySet != @storedEntries || @create == ZipFile::CREATE
252
- end
253
-
254
- # Searches for entry with the specified name. Returns nil if
255
- # no entry is found. See also get_entry
256
- def find_entry(entry_name)
257
- @entrySet.find_entry(entry_name)
258
- end
259
-
260
- # Searches for entries given a glob
261
- def glob(*args,&block)
262
- @entrySet.glob(*args,&block)
263
- end
264
-
265
- # Searches for an entry just as find_entry, but throws Errno::ENOENT
266
- # if no entry is found.
267
- def get_entry(entry)
268
- selectedEntry = find_entry(entry)
269
- unless selectedEntry
270
- raise Errno::ENOENT, entry
271
- end
272
- selectedEntry.restore_ownership = @restore_ownership
273
- selectedEntry.restore_permissions = @restore_permissions
274
- selectedEntry.restore_times = @restore_times
275
- selectedEntry
276
- end
277
-
278
- # Creates a directory
279
- def mkdir(entryName, permissionInt = 0755)
280
- if find_entry(entryName)
281
- raise Errno::EEXIST, "File exists - #{entryName}"
282
- end
283
- entryName = entryName.dup.to_s
284
- entryName << '/' unless entryName.end_with?('/')
285
- @entrySet << ZipStreamableDirectory.new(@name, entryName, nil, permissionInt)
286
- end
287
-
288
- private
289
-
290
- def is_directory(newEntry, srcPath)
291
- srcPathIsDirectory = ::File.directory?(srcPath)
292
- if newEntry.is_directory && ! srcPathIsDirectory
293
- raise ArgumentError,
294
- "entry name '#{newEntry}' indicates directory entry, but "+
295
- "'#{srcPath}' is not a directory"
296
- elsif !newEntry.is_directory && srcPathIsDirectory
297
- newEntry.name += "/"
298
- end
299
- newEntry.is_directory && srcPathIsDirectory
300
- end
301
-
302
- def check_entry_exists(entryName, continueOnExistsProc, procedureName)
303
- continueOnExistsProc ||= proc { Zip.options[:continue_on_exists_proc] }
304
- if @entrySet.include?(entryName)
305
- if continueOnExistsProc.call
306
- remove get_entry(entryName)
307
- else
308
- raise ZipEntryExistsError,
309
- procedureName + " failed. Entry #{entryName} already exists"
310
- end
311
- end
312
- end
313
-
314
- def check_file(path)
315
- unless ::File.readable?(path)
316
- raise Errno::ENOENT, path
317
- end
318
- end
319
-
320
- def on_success_replace(aFilename)
321
- tmpfile = get_tempfile
322
- tmpFilename = tmpfile.path
323
- tmpfile.close
324
- if yield tmpFilename
325
- ::File.rename(tmpFilename, name)
326
- end
327
- end
328
-
329
- def get_tempfile
330
- tempFile = Tempfile.new(::File.basename(name), ::File.dirname(name))
331
- tempFile.binmode
332
- tempFile
333
- end
334
-
335
- end
336
- end
337
-
338
- # Copyright (C) 2002, 2003 Thomas Sondergaard
339
- # rubyzip is free software; you can redistribute it and/or
340
- # modify it under the terms of the ruby license.
@@ -1,144 +0,0 @@
1
- module Zip
2
- # ZipInputStream is the basic class for reading zip entries in a
3
- # zip file. It is possible to create a ZipInputStream object directly,
4
- # passing the zip file name to the constructor, but more often than not
5
- # the ZipInputStream will be obtained from a ZipFile (perhaps using the
6
- # ZipFileSystem interface) object for a particular entry in the zip
7
- # archive.
8
- #
9
- # A ZipInputStream inherits IOExtras::AbstractInputStream in order
10
- # to provide an IO-like interface for reading from a single zip
11
- # entry. Beyond methods for mimicking an IO-object it contains
12
- # the method get_next_entry for iterating through the entries of
13
- # an archive. get_next_entry returns a ZipEntry object that describes
14
- # the zip entry the ZipInputStream is currently reading from.
15
- #
16
- # Example that creates a zip archive with ZipOutputStream and reads it
17
- # back again with a ZipInputStream.
18
- #
19
- # require 'zip/zip'
20
- #
21
- # Zip::ZipOutputStream::open("my.zip") {
22
- # |io|
23
- #
24
- # io.put_next_entry("first_entry.txt")
25
- # io.write "Hello world!"
26
- #
27
- # io.put_next_entry("adir/first_entry.txt")
28
- # io.write "Hello again!"
29
- # }
30
- #
31
- #
32
- # Zip::ZipInputStream::open("my.zip") {
33
- # |io|
34
- #
35
- # while (entry = io.get_next_entry)
36
- # puts "Contents of #{entry.name}: '#{io.read}'"
37
- # end
38
- # }
39
- #
40
- # java.util.zip.ZipInputStream is the original inspiration for this
41
- # class.
42
-
43
- class ZipInputStream
44
- include IOExtras::AbstractInputStream
45
-
46
- # Opens the indicated zip file. An exception is thrown
47
- # if the specified offset in the specified filename is
48
- # not a local zip entry header.
49
- def initialize(filename, offset = 0, io = nil)
50
- super()
51
- if (io.nil?)
52
- @archiveIO = ::File.open(filename, "rb")
53
- @archiveIO.seek(offset, IO::SEEK_SET)
54
- else
55
- @archiveIO = io
56
- end
57
- @decompressor = NullDecompressor.instance
58
- @currentEntry = nil
59
- end
60
-
61
- def close
62
- @archiveIO.close
63
- end
64
-
65
- # Same as #initialize but if a block is passed the opened
66
- # stream is passed to the block and closed when the block
67
- # returns.
68
- def ZipInputStream.open(filename)
69
- return new(filename) unless block_given?
70
-
71
- zio = new(filename)
72
- yield zio
73
- ensure
74
- zio.close if zio
75
- end
76
-
77
- def ZipInputStream.open_buffer(io)
78
- return new('',0,io) unless block_given?
79
- zio = new('',0,io)
80
- yield zio
81
- ensure
82
- zio.close if zio
83
- end
84
-
85
- # Returns a ZipEntry object. It is necessary to call this
86
- # method on a newly created ZipInputStream before reading from
87
- # the first entry in the archive. Returns nil when there are
88
- # no more entries.
89
-
90
- def get_next_entry
91
- @archiveIO.seek(@currentEntry.next_header_offset, IO::SEEK_SET) if @currentEntry
92
- open_entry
93
- end
94
-
95
- # Rewinds the stream to the beginning of the current entry
96
- def rewind
97
- return if @currentEntry.nil?
98
- @lineno = 0
99
- @archiveIO.seek(@currentEntry.localHeaderOffset,
100
- IO::SEEK_SET)
101
- open_entry
102
- end
103
-
104
- # Modeled after IO.sysread
105
- def sysread(numberOfBytes = nil, buf = nil)
106
- @decompressor.sysread(numberOfBytes, buf)
107
- end
108
-
109
- def eof
110
- @outputBuffer.empty? && @decompressor.eof
111
- end
112
- alias :eof? :eof
113
-
114
- protected
115
-
116
- def open_entry
117
- @currentEntry = ZipEntry.read_local_entry(@archiveIO)
118
- if @currentEntry.nil?
119
- @decompressor = NullDecompressor.instance
120
- elsif @currentEntry.compression_method == ZipEntry::STORED
121
- @decompressor = PassThruDecompressor.new(@archiveIO, @currentEntry.size)
122
- elsif @currentEntry.compression_method == ZipEntry::DEFLATED
123
- @decompressor = Inflater.new(@archiveIO)
124
- else
125
- raise ZipCompressionMethodError,
126
- "Unsupported compression method #{@currentEntry.compression_method}"
127
- end
128
- flush
129
- return @currentEntry
130
- end
131
-
132
- def produce_input
133
- @decompressor.produce_input
134
- end
135
-
136
- def input_finished?
137
- @decompressor.input_finished?
138
- end
139
- end
140
- end
141
-
142
- # Copyright (C) 2002, 2003 Thomas Sondergaard
143
- # rubyzip is free software; you can redistribute it and/or
144
- # modify it under the terms of the ruby license.