rubyzip 1.1.7 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +137 -54
- data/Rakefile +6 -4
- data/lib/zip/central_directory.rb +17 -13
- data/lib/zip/compressor.rb +1 -2
- data/lib/zip/constants.rb +57 -5
- data/lib/zip/crypto/decrypted_io.rb +40 -0
- data/lib/zip/crypto/null_encryption.rb +4 -6
- data/lib/zip/crypto/traditional_encryption.rb +14 -14
- data/lib/zip/decompressor.rb +22 -4
- data/lib/zip/deflater.rb +8 -6
- data/lib/zip/dos_time.rb +17 -13
- data/lib/zip/entry.rb +171 -148
- data/lib/zip/entry_set.rb +16 -14
- data/lib/zip/errors.rb +3 -0
- data/lib/zip/extra_field/generic.rb +14 -13
- data/lib/zip/extra_field/ntfs.rb +18 -16
- data/lib/zip/extra_field/old_unix.rb +12 -11
- data/lib/zip/extra_field/universal_time.rb +46 -16
- data/lib/zip/extra_field/unix.rb +10 -9
- data/lib/zip/extra_field/zip64.rb +15 -12
- data/lib/zip/extra_field/zip64_placeholder.rb +1 -2
- data/lib/zip/extra_field.rb +18 -16
- data/lib/zip/file.rb +147 -115
- data/lib/zip/filesystem.rb +289 -272
- data/lib/zip/inflater.rb +24 -36
- data/lib/zip/input_stream.rb +44 -28
- data/lib/zip/ioextras/abstract_input_stream.rb +24 -17
- data/lib/zip/ioextras/abstract_output_stream.rb +4 -6
- data/lib/zip/ioextras.rb +2 -4
- data/lib/zip/null_compressor.rb +2 -2
- data/lib/zip/null_decompressor.rb +3 -11
- data/lib/zip/null_input_stream.rb +0 -0
- data/lib/zip/output_stream.rb +25 -17
- data/lib/zip/pass_thru_compressor.rb +6 -6
- data/lib/zip/pass_thru_decompressor.rb +14 -24
- data/lib/zip/streamable_directory.rb +3 -3
- data/lib/zip/streamable_stream.rb +7 -11
- data/lib/zip/version.rb +1 -1
- data/lib/zip.rb +15 -6
- data/samples/example.rb +29 -39
- data/samples/example_filesystem.rb +16 -18
- data/samples/example_recursive.rb +31 -25
- data/samples/gtk_ruby_zip.rb +84 -0
- data/samples/qtzip.rb +23 -32
- data/samples/write_simple.rb +10 -13
- data/samples/zipfind.rb +33 -40
- metadata +50 -141
- data/samples/gtkRubyzip.rb +0 -86
- data/test/basic_zip_file_test.rb +0 -64
- data/test/central_directory_entry_test.rb +0 -73
- data/test/central_directory_test.rb +0 -104
- data/test/crypto/null_encryption_test.rb +0 -53
- data/test/crypto/traditional_encryption_test.rb +0 -80
- data/test/data/WarnInvalidDate.zip +0 -0
- data/test/data/file1.txt +0 -46
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +0 -1504
- data/test/data/globTest/foo/bar/baz/foo.txt +0 -0
- data/test/data/globTest/foo.txt +0 -0
- data/test/data/globTest/food.txt +0 -0
- data/test/data/globTest.zip +0 -0
- data/test/data/mimetype +0 -1
- data/test/data/notzippedruby.rb +0 -7
- data/test/data/ntfs.zip +0 -0
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zip64-sample.zip +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/data/zipWithEncryption.zip +0 -0
- data/test/deflater_test.rb +0 -67
- data/test/encryption_test.rb +0 -42
- data/test/entry_set_test.rb +0 -138
- data/test/entry_test.rb +0 -165
- data/test/errors_test.rb +0 -36
- data/test/extra_field_test.rb +0 -78
- data/test/file_extract_directory_test.rb +0 -56
- data/test/file_extract_test.rb +0 -90
- data/test/file_split_test.rb +0 -60
- data/test/file_test.rb +0 -559
- data/test/filesystem/dir_iterator_test.rb +0 -62
- data/test/filesystem/directory_test.rb +0 -131
- data/test/filesystem/file_mutating_test.rb +0 -100
- data/test/filesystem/file_nonmutating_test.rb +0 -514
- data/test/filesystem/file_stat_test.rb +0 -66
- data/test/gentestfiles.rb +0 -134
- data/test/inflater_test.rb +0 -14
- data/test/input_stream_test.rb +0 -170
- data/test/ioextras/abstract_input_stream_test.rb +0 -103
- data/test/ioextras/abstract_output_stream_test.rb +0 -106
- data/test/ioextras/fake_io_test.rb +0 -18
- data/test/local_entry_test.rb +0 -156
- data/test/output_stream_test.rb +0 -129
- data/test/pass_thru_compressor_test.rb +0 -31
- data/test/pass_thru_decompressor_test.rb +0 -15
- data/test/settings_test.rb +0 -92
- data/test/test_helper.rb +0 -228
- data/test/unicode_file_names_and_comments_test.rb +0 -52
- data/test/zip64_full_test.rb +0 -53
- data/test/zip64_support_test.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 35bd078119c42cd2250fadd127a0feae3299184b0bf90804c3ff0bc28d1c427f
|
4
|
+
data.tar.gz: 98e034b50a428ff970f25b28348993d938a88c5d5c93506561761f260062c059
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 421a8884fbfe6f720e2e0da35f34e4208b96f83529faf5cba03501aa2693d95d51b9c19e04e4567801de1822120a0e14faf1c4d0991a164b8f0d011eaa6c0f7b
|
7
|
+
data.tar.gz: 59f29c6b49a14c777605224b351d8d14f7fdfe88a2ffc75a5f2120f51152831ed9afa04d8daf1f971bad982c3bcdd86e17d5616c8c9d57ddff7509b7f59e58b1
|
data/README.md
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
# rubyzip
|
2
|
+
|
2
3
|
[![Gem Version](https://badge.fury.io/rb/rubyzip.svg)](http://badge.fury.io/rb/rubyzip)
|
3
4
|
[![Build Status](https://secure.travis-ci.org/rubyzip/rubyzip.svg)](http://travis-ci.org/rubyzip/rubyzip)
|
4
5
|
[![Code Climate](https://codeclimate.com/github/rubyzip/rubyzip.svg)](https://codeclimate.com/github/rubyzip/rubyzip)
|
5
6
|
[![Coverage Status](https://img.shields.io/coveralls/rubyzip/rubyzip.svg)](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
|
6
7
|
|
7
|
-
|
8
|
+
Rubyzip is a ruby library for reading and writing zip files.
|
8
9
|
|
9
10
|
## Important note
|
10
11
|
|
11
|
-
Rubyzip interface changed!!! No need to do `require "zip/zip"` and `Zip` prefix in class names removed.
|
12
|
+
The Rubyzip interface has changed!!! No need to do `require "zip/zip"` and `Zip` prefix in class names removed.
|
12
13
|
|
13
14
|
If you have issues with any third-party gems that require an old version of rubyzip, you can use this workaround:
|
14
15
|
|
@@ -19,10 +20,11 @@ gem 'zip-zip' # will load compatibility for old rubyzip API.
|
|
19
20
|
|
20
21
|
## Requirements
|
21
22
|
|
22
|
-
|
23
|
+
- Ruby 2.4 or greater (for rubyzip 2.0; use 1.x for older rubies)
|
23
24
|
|
24
25
|
## Installation
|
25
|
-
|
26
|
+
|
27
|
+
Rubyzip is available on RubyGems:
|
26
28
|
|
27
29
|
```
|
28
30
|
gem install rubyzip
|
@@ -52,65 +54,76 @@ Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
|
|
52
54
|
# Two arguments:
|
53
55
|
# - The name of the file as it will appear in the archive
|
54
56
|
# - The original file, including the path to find it
|
55
|
-
zipfile.add(filename, folder
|
57
|
+
zipfile.add(filename, File.join(folder, filename))
|
56
58
|
end
|
57
|
-
zipfile.get_output_stream("myFile") { |
|
59
|
+
zipfile.get_output_stream("myFile") { |f| f.write "myFile contains just this" }
|
58
60
|
end
|
59
61
|
```
|
60
62
|
|
61
63
|
### Zipping a directory recursively
|
62
|
-
|
64
|
+
|
65
|
+
Copy from [here](https://github.com/rubyzip/rubyzip/blob/9d891f7353e66052283562d3e252fe380bb4b199/samples/example_recursive.rb)
|
63
66
|
|
64
67
|
```ruby
|
65
|
-
require 'rubygems'
|
66
68
|
require 'zip'
|
69
|
+
|
67
70
|
# This is a simple example which uses rubyzip to
|
68
71
|
# recursively generate a zip file from the contents of
|
69
72
|
# a specified directory. The directory itself is not
|
70
73
|
# included in the archive, rather just its contents.
|
71
74
|
#
|
72
75
|
# Usage:
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
# zf.write()
|
78
|
-
|
76
|
+
# directory_to_zip = "/tmp/input"
|
77
|
+
# output_file = "/tmp/out.zip"
|
78
|
+
# zf = ZipFileGenerator.new(directory_to_zip, output_file)
|
79
|
+
# zf.write()
|
79
80
|
class ZipFileGenerator
|
80
81
|
# Initialize with the directory to zip and the location of the output archive.
|
81
|
-
def initialize(
|
82
|
-
@
|
83
|
-
@
|
82
|
+
def initialize(input_dir, output_file)
|
83
|
+
@input_dir = input_dir
|
84
|
+
@output_file = output_file
|
84
85
|
end
|
86
|
+
|
85
87
|
# Zip the input directory.
|
86
|
-
def write
|
87
|
-
entries = Dir.entries(@
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
def write
|
89
|
+
entries = Dir.entries(@input_dir) - %w[. ..]
|
90
|
+
|
91
|
+
::Zip::File.open(@output_file, ::Zip::File::CREATE) do |zipfile|
|
92
|
+
write_entries entries, '', zipfile
|
93
|
+
end
|
91
94
|
end
|
92
|
-
|
95
|
+
|
93
96
|
private
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
97
|
+
|
98
|
+
# A helper method to make the recursion work.
|
99
|
+
def write_entries(entries, path, zipfile)
|
100
|
+
entries.each do |e|
|
101
|
+
zipfile_path = path == '' ? e : File.join(path, e)
|
102
|
+
disk_file_path = File.join(@input_dir, zipfile_path)
|
103
|
+
|
104
|
+
if File.directory? disk_file_path
|
105
|
+
recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
|
103
106
|
else
|
104
|
-
|
107
|
+
put_into_archive(disk_file_path, zipfile, zipfile_path)
|
105
108
|
end
|
106
|
-
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def recursively_deflate_directory(disk_file_path, zipfile, zipfile_path)
|
113
|
+
zipfile.mkdir zipfile_path
|
114
|
+
subdir = Dir.entries(disk_file_path) - %w[. ..]
|
115
|
+
write_entries subdir, zipfile_path, zipfile
|
116
|
+
end
|
117
|
+
|
118
|
+
def put_into_archive(disk_file_path, zipfile, zipfile_path)
|
119
|
+
zipfile.add(zipfile_path, disk_file_path)
|
107
120
|
end
|
108
121
|
end
|
109
122
|
```
|
110
123
|
|
111
124
|
### Save zip archive entries in sorted by name state
|
112
125
|
|
113
|
-
To
|
126
|
+
To save zip archives in sorted order like below, you need to set `::Zip.sort_entries` to `true`
|
114
127
|
|
115
128
|
```
|
116
129
|
Vegetable/
|
@@ -124,17 +137,30 @@ fruit/mango
|
|
124
137
|
fruit/orange
|
125
138
|
```
|
126
139
|
|
127
|
-
After this entries in zip archive will be saved in ordered state.
|
140
|
+
After this, entries in the zip archive will be saved in ordered state.
|
141
|
+
|
142
|
+
### Default permissions of zip archives
|
143
|
+
|
144
|
+
On Posix file systems the default file permissions applied to a new archive
|
145
|
+
are (0666 - umask), which mimics the behavior of standard tools such as `touch`.
|
146
|
+
|
147
|
+
On Windows the default file permissions are set to 0644 as suggested by the
|
148
|
+
[Ruby File documentation](http://ruby-doc.org/core-2.2.2/File.html).
|
149
|
+
|
150
|
+
When modifying a zip archive the file permissions of the archive are preserved.
|
128
151
|
|
129
152
|
### Reading a Zip file
|
130
153
|
|
131
154
|
```ruby
|
155
|
+
MAX_SIZE = 1024**2 # 1MiB (but of course you can increase this)
|
132
156
|
Zip::File.open('foo.zip') do |zip_file|
|
133
157
|
# Handle entries one by one
|
134
158
|
zip_file.each do |entry|
|
135
|
-
# Extract to file/directory/symlink
|
136
159
|
puts "Extracting #{entry.name}"
|
137
|
-
entry.
|
160
|
+
raise 'File too large when extracted' if entry.size > MAX_SIZE
|
161
|
+
|
162
|
+
# Extract to file or directory based on name in the archive
|
163
|
+
entry.extract
|
138
164
|
|
139
165
|
# Read into memory
|
140
166
|
content = entry.get_input_stream.read
|
@@ -142,13 +168,24 @@ Zip::File.open('foo.zip') do |zip_file|
|
|
142
168
|
|
143
169
|
# Find specific entry
|
144
170
|
entry = zip_file.glob('*.csv').first
|
171
|
+
raise 'File too large when extracted' if entry.size > MAX_SIZE
|
145
172
|
puts entry.get_input_stream.read
|
146
173
|
end
|
147
174
|
```
|
148
175
|
|
176
|
+
#### Notice about ::Zip::InputStream
|
177
|
+
|
178
|
+
`::Zip::InputStream` usable for fast reading zip file content because it not read Central directory.
|
179
|
+
|
180
|
+
But there is one exception when it is not working - General Purpose Flag Bit 3.
|
181
|
+
|
182
|
+
> If bit 3 (0x08) of the general-purpose flags field is set, then the CRC-32 and file sizes are not known when the header is written. The fields in the local header are filled with zero, and the CRC-32 and size are appended in a 12-byte structure (optionally preceded by a 4-byte signature) immediately after the compressed data
|
183
|
+
|
184
|
+
If `::Zip::InputStream` finds such entry in the zip archive it will raise an exception.
|
185
|
+
|
149
186
|
### Password Protection (Experimental)
|
150
187
|
|
151
|
-
|
188
|
+
Rubyzip supports reading/writing zip files with traditional zip encryption (a.k.a. "ZipCrypto"). AES encryption is not yet supported. It can be used with buffer streams, e.g.:
|
152
189
|
|
153
190
|
```ruby
|
154
191
|
Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |out|
|
@@ -181,12 +218,14 @@ buffer = Zip::OutputStream.write_buffer do |out|
|
|
181
218
|
out.write rels.to_xml(:indent => 0).gsub("\n","")
|
182
219
|
end
|
183
220
|
|
184
|
-
File.open(new_path, "
|
221
|
+
File.open(new_path, "wb") {|f| f.write(buffer.string) }
|
185
222
|
```
|
186
223
|
|
187
224
|
## Configuration
|
188
225
|
|
189
|
-
|
226
|
+
### Existing Files
|
227
|
+
|
228
|
+
By default, rubyzip will not overwrite files if they already exist inside of the extracted path. To change this behavior, you may specify a configuration option like so:
|
190
229
|
|
191
230
|
```ruby
|
192
231
|
Zip.on_exists_proc = true
|
@@ -200,26 +239,78 @@ Additionally, if you want to configure rubyzip to overwrite existing files while
|
|
200
239
|
Zip.continue_on_exists_proc = true
|
201
240
|
```
|
202
241
|
|
203
|
-
|
242
|
+
### Non-ASCII Names
|
243
|
+
|
244
|
+
If you want to store non-english names and want to open them on Windows(pre 7) you need to set this option:
|
204
245
|
|
205
246
|
```ruby
|
206
247
|
Zip.unicode_names = true
|
207
248
|
```
|
208
249
|
|
209
|
-
|
250
|
+
Sometimes file names inside zip contain non-ASCII characters. If you can assume which encoding was used for such names and want to be able to find such entries using `find_entry` then you can force assumed encoding like so:
|
251
|
+
|
252
|
+
```ruby
|
253
|
+
Zip.force_entry_names_encoding = 'UTF-8'
|
254
|
+
```
|
255
|
+
|
256
|
+
Allowed encoding names are the same as accepted by `String#force_encoding`
|
257
|
+
|
258
|
+
### Date Validation
|
259
|
+
|
260
|
+
Some zip files might have an invalid date format, which will raise a warning. You can hide this warning with the following setting:
|
210
261
|
|
211
262
|
```ruby
|
212
263
|
Zip.warn_invalid_date = false
|
213
264
|
```
|
214
265
|
|
266
|
+
### Size Validation
|
267
|
+
|
268
|
+
By default (in rubyzip >= 2.0), rubyzip's `extract` method checks that an entry's reported uncompressed size is not (significantly) smaller than its actual size. This is to help you protect your application against [zip bombs](https://en.wikipedia.org/wiki/Zip_bomb). Before `extract`ing an entry, you should check that its size is in the range you expect. For example, if your application supports processing up to 100 files at once, each up to 10MiB, your zip extraction code might look like:
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
MAX_FILE_SIZE = 10 * 1024**2 # 10MiB
|
272
|
+
MAX_FILES = 100
|
273
|
+
Zip::File.open('foo.zip') do |zip_file|
|
274
|
+
num_files = 0
|
275
|
+
zip_file.each do |entry|
|
276
|
+
num_files += 1 if entry.file?
|
277
|
+
raise 'Too many extracted files' if num_files > MAX_FILES
|
278
|
+
raise 'File too large when extracted' if entry.size > MAX_FILE_SIZE
|
279
|
+
entry.extract
|
280
|
+
end
|
281
|
+
end
|
282
|
+
```
|
283
|
+
|
284
|
+
If you need to extract zip files that report incorrect uncompressed sizes and you really trust them not too be too large, you can disable this setting with
|
285
|
+
```ruby
|
286
|
+
Zip.validate_entry_sizes = false
|
287
|
+
```
|
288
|
+
|
289
|
+
Note that if you use the lower level `Zip::InputStream` interface, `rubyzip` does *not* check the entry `size`s. In this case, the caller is responsible for making sure it does not read more data than expected from the input stream.
|
290
|
+
|
291
|
+
### Default Compression
|
292
|
+
|
215
293
|
You can set the default compression level like so:
|
216
294
|
|
217
295
|
```ruby
|
218
296
|
Zip.default_compression = Zlib::DEFAULT_COMPRESSION
|
219
297
|
```
|
298
|
+
|
220
299
|
It defaults to `Zlib::DEFAULT_COMPRESSION`. Possible values are `Zlib::BEST_COMPRESSION`, `Zlib::DEFAULT_COMPRESSION` and `Zlib::NO_COMPRESSION`
|
221
300
|
|
222
|
-
|
301
|
+
### Zip64 Support
|
302
|
+
|
303
|
+
By default, Zip64 support is disabled for writing. To enable it do this:
|
304
|
+
|
305
|
+
```ruby
|
306
|
+
Zip.write_zip64_support = true
|
307
|
+
```
|
308
|
+
|
309
|
+
_NOTE_: If you will enable Zip64 writing then you will need zip extractor with Zip64 support to extract archive.
|
310
|
+
|
311
|
+
### Block Form
|
312
|
+
|
313
|
+
You can set multiple settings at the same time by using a block:
|
223
314
|
|
224
315
|
```ruby
|
225
316
|
Zip.setup do |c|
|
@@ -230,17 +321,9 @@ All settings in same time
|
|
230
321
|
end
|
231
322
|
```
|
232
323
|
|
233
|
-
By default Zip64 support is disabled for writing. To enable it do next:
|
234
|
-
|
235
|
-
```ruby
|
236
|
-
Zip.write_zip64_support = true
|
237
|
-
```
|
238
|
-
|
239
|
-
_NOTE_: If you will enable Zip64 writing then you will need zip extractor with Zip64 support to extract archive.
|
240
|
-
|
241
324
|
## Developing
|
242
325
|
|
243
|
-
To run
|
326
|
+
To run the test you need to do this:
|
244
327
|
|
245
328
|
```
|
246
329
|
bundle install
|
@@ -267,5 +350,5 @@ extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org)
|
|
267
350
|
|
268
351
|
## License
|
269
352
|
|
270
|
-
|
353
|
+
Rubyzip is distributed under the same license as ruby. See
|
271
354
|
http://www.ruby-lang.org/en/LICENSE.txt
|
data/Rakefile
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
require 'rake/testtask'
|
3
|
+
require 'rubocop/rake_task'
|
3
4
|
|
4
|
-
task :
|
5
|
+
task default: :test
|
5
6
|
|
6
7
|
Rake::TestTask.new(:test) do |test|
|
7
8
|
test.libs << 'lib'
|
@@ -10,10 +11,11 @@ Rake::TestTask.new(:test) do |test|
|
|
10
11
|
test.verbose = true
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
# Rake::TestTask.new(:zip64_full_test) do |test|
|
14
17
|
# test.libs << File.join(File.dirname(__FILE__), 'lib')
|
15
18
|
# test.libs << File.join(File.dirname(__FILE__), 'test')
|
16
19
|
# test.pattern = File.join(File.dirname(__FILE__), 'test/zip64_full_test.rb')
|
17
20
|
# test.verbose = true
|
18
|
-
#end
|
19
|
-
|
21
|
+
# end
|
@@ -5,7 +5,7 @@ module Zip
|
|
5
5
|
END_OF_CDS = 0x06054b50
|
6
6
|
ZIP64_END_OF_CDS = 0x06064b50
|
7
7
|
ZIP64_EOCD_LOCATOR = 0x07064b50
|
8
|
-
MAX_END_OF_CDS_SIZE =
|
8
|
+
MAX_END_OF_CDS_SIZE = 65_536 + 18
|
9
9
|
STATIC_EOCD_SIZE = 22
|
10
10
|
|
11
11
|
attr_reader :comment
|
@@ -65,7 +65,7 @@ module Zip
|
|
65
65
|
@entry_set ? @entry_set.size : 0, # number of entries on this disk
|
66
66
|
@entry_set ? @entry_set.size : 0, # number of entries total
|
67
67
|
cdir_size, # size of central directory
|
68
|
-
offset
|
68
|
+
offset # offset of start of central directory in its disk
|
69
69
|
]
|
70
70
|
io << tmp.pack('VQ<vvVVQ<Q<Q<Q<')
|
71
71
|
end
|
@@ -96,7 +96,7 @@ module Zip
|
|
96
96
|
@size_in_bytes = Entry.read_zip_64_long(buf)
|
97
97
|
@cdir_offset = Entry.read_zip_64_long(buf)
|
98
98
|
@zip_64_extensible = buf.slice!(0, buf.bytesize)
|
99
|
-
raise Error,
|
99
|
+
raise Error, 'Zip consistency problem while reading eocd structure' unless buf.empty?
|
100
100
|
end
|
101
101
|
|
102
102
|
def read_e_o_c_d(buf) #:nodoc:
|
@@ -113,14 +113,14 @@ module Zip
|
|
113
113
|
else
|
114
114
|
buf.read(comment_length)
|
115
115
|
end
|
116
|
-
raise Error,
|
116
|
+
raise Error, 'Zip consistency problem while reading eocd structure' unless buf.empty?
|
117
117
|
end
|
118
118
|
|
119
119
|
def read_central_directory_entries(io) #:nodoc:
|
120
120
|
begin
|
121
121
|
io.seek(@cdir_offset, IO::SEEK_SET)
|
122
122
|
rescue Errno::EINVAL
|
123
|
-
raise Error,
|
123
|
+
raise Error, 'Zip consistency problem while reading central directory entry'
|
124
124
|
end
|
125
125
|
@entry_set = EntrySet.new
|
126
126
|
@size.times do
|
@@ -130,7 +130,7 @@ module Zip
|
|
130
130
|
|
131
131
|
def read_from_stream(io) #:nodoc:
|
132
132
|
buf = start_buf(io)
|
133
|
-
if
|
133
|
+
if zip64_file?(buf)
|
134
134
|
read_64_e_o_c_d(buf)
|
135
135
|
else
|
136
136
|
read_e_o_c_d(buf)
|
@@ -140,7 +140,8 @@ module Zip
|
|
140
140
|
|
141
141
|
def get_e_o_c_d(buf) #:nodoc:
|
142
142
|
sig_index = buf.rindex([END_OF_CDS].pack('V'))
|
143
|
-
raise Error,
|
143
|
+
raise Error, 'Zip end of central directory signature not found' unless sig_index
|
144
|
+
|
144
145
|
buf = buf.slice!((sig_index + 4)..(buf.bytesize))
|
145
146
|
|
146
147
|
def buf.read(count)
|
@@ -165,9 +166,11 @@ module Zip
|
|
165
166
|
|
166
167
|
def get_64_e_o_c_d(buf) #:nodoc:
|
167
168
|
zip_64_start = buf.rindex([ZIP64_END_OF_CDS].pack('V'))
|
168
|
-
raise Error,
|
169
|
+
raise Error, 'Zip64 end of central directory signature not found' unless zip_64_start
|
170
|
+
|
169
171
|
zip_64_locator = buf.rindex([ZIP64_EOCD_LOCATOR].pack('V'))
|
170
|
-
raise Error,
|
172
|
+
raise Error, 'Zip64 end of central directory signature locator not found' unless zip_64_locator
|
173
|
+
|
171
174
|
buf = buf.slice!((zip_64_start + 4)..zip_64_locator)
|
172
175
|
|
173
176
|
def buf.read(count)
|
@@ -178,8 +181,8 @@ module Zip
|
|
178
181
|
end
|
179
182
|
|
180
183
|
# For iterating over the entries.
|
181
|
-
def each(&
|
182
|
-
@entry_set.each(&
|
184
|
+
def each(&a_proc)
|
185
|
+
@entry_set.each(&a_proc)
|
183
186
|
end
|
184
187
|
|
185
188
|
# Returns the number of entries in the central directory (and
|
@@ -191,13 +194,14 @@ module Zip
|
|
191
194
|
def self.read_from_stream(io) #:nodoc:
|
192
195
|
cdir = new
|
193
196
|
cdir.read_from_stream(io)
|
194
|
-
|
197
|
+
cdir
|
195
198
|
rescue Error
|
196
|
-
|
199
|
+
nil
|
197
200
|
end
|
198
201
|
|
199
202
|
def ==(other) #:nodoc:
|
200
203
|
return false unless other.kind_of?(CentralDirectory)
|
204
|
+
|
201
205
|
@entry_set.entries.sort == other.entries.sort && comment == other.comment
|
202
206
|
end
|
203
207
|
end
|
data/lib/zip/compressor.rb
CHANGED
data/lib/zip/constants.rb
CHANGED
@@ -6,14 +6,14 @@ module Zip
|
|
6
6
|
|
7
7
|
LOCAL_ENTRY_SIGNATURE = 0x04034b50
|
8
8
|
LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30
|
9
|
-
LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4+4+4
|
9
|
+
LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4 + 4 + 4
|
10
10
|
VERSION_MADE_BY = 52 # this library's version
|
11
11
|
VERSION_NEEDED_TO_EXTRACT = 20
|
12
12
|
VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45
|
13
13
|
|
14
|
-
FILE_TYPE_FILE =
|
15
|
-
FILE_TYPE_DIR =
|
16
|
-
FILE_TYPE_SYMLINK =
|
14
|
+
FILE_TYPE_FILE = 0o10
|
15
|
+
FILE_TYPE_DIR = 0o04
|
16
|
+
FILE_TYPE_SYMLINK = 0o12
|
17
17
|
|
18
18
|
FSTYPE_FAT = 0
|
19
19
|
FSTYPE_AMIGA = 1
|
@@ -58,6 +58,58 @@ module Zip
|
|
58
58
|
FSTYPE_TANDEM => 'Tandem NSK'.freeze,
|
59
59
|
FSTYPE_THEOS => 'Theos'.freeze,
|
60
60
|
FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.freeze,
|
61
|
-
FSTYPE_ATHEOS => 'AtheOS'.freeze
|
61
|
+
FSTYPE_ATHEOS => 'AtheOS'.freeze
|
62
|
+
}.freeze
|
63
|
+
|
64
|
+
COMPRESSION_METHOD_STORE = 0
|
65
|
+
COMPRESSION_METHOD_SHRINK = 1
|
66
|
+
COMPRESSION_METHOD_REDUCE_1 = 2
|
67
|
+
COMPRESSION_METHOD_REDUCE_2 = 3
|
68
|
+
COMPRESSION_METHOD_REDUCE_3 = 4
|
69
|
+
COMPRESSION_METHOD_REDUCE_4 = 5
|
70
|
+
COMPRESSION_METHOD_IMPLODE = 6
|
71
|
+
# RESERVED = 7
|
72
|
+
COMPRESSION_METHOD_DEFLATE = 8
|
73
|
+
COMPRESSION_METHOD_DEFLATE_64 = 9
|
74
|
+
COMPRESSION_METHOD_PKWARE_DCLI = 10
|
75
|
+
# RESERVED = 11
|
76
|
+
COMPRESSION_METHOD_BZIP2 = 12
|
77
|
+
# RESERVED = 13
|
78
|
+
COMPRESSION_METHOD_LZMA = 14
|
79
|
+
# RESERVED = 15
|
80
|
+
COMPRESSION_METHOD_IBM_CMPSC = 16
|
81
|
+
# RESERVED = 17
|
82
|
+
COMPRESSION_METHOD_IBM_TERSE = 18
|
83
|
+
COMPRESSION_METHOD_IBM_LZ77 = 19
|
84
|
+
COMPRESSION_METHOD_JPEG = 96
|
85
|
+
COMPRESSION_METHOD_WAVPACK = 97
|
86
|
+
COMPRESSION_METHOD_PPMD = 98
|
87
|
+
COMPRESSION_METHOD_AES = 99
|
88
|
+
|
89
|
+
COMPRESSION_METHODS = {
|
90
|
+
COMPRESSION_METHOD_STORE => 'Store (no compression)',
|
91
|
+
COMPRESSION_METHOD_SHRINK => 'Shrink',
|
92
|
+
COMPRESSION_METHOD_REDUCE_1 => 'Reduce with compression factor 1',
|
93
|
+
COMPRESSION_METHOD_REDUCE_2 => 'Reduce with compression factor 2',
|
94
|
+
COMPRESSION_METHOD_REDUCE_3 => 'Reduce with compression factor 3',
|
95
|
+
COMPRESSION_METHOD_REDUCE_4 => 'Reduce with compression factor 4',
|
96
|
+
COMPRESSION_METHOD_IMPLODE => 'Implode',
|
97
|
+
# RESERVED = 7
|
98
|
+
COMPRESSION_METHOD_DEFLATE => 'Deflate',
|
99
|
+
COMPRESSION_METHOD_DEFLATE_64 => 'Deflate64(tm)',
|
100
|
+
COMPRESSION_METHOD_PKWARE_DCLI => 'PKWARE Data Compression Library Imploding (old IBM TERSE)',
|
101
|
+
# RESERVED = 11
|
102
|
+
COMPRESSION_METHOD_BZIP2 => 'BZIP2',
|
103
|
+
# RESERVED = 13
|
104
|
+
COMPRESSION_METHOD_LZMA => 'LZMA',
|
105
|
+
# RESERVED = 15
|
106
|
+
COMPRESSION_METHOD_IBM_CMPSC => 'IBM z/OS CMPSC Compression',
|
107
|
+
# RESERVED = 17
|
108
|
+
COMPRESSION_METHOD_IBM_TERSE => 'IBM TERSE (new)',
|
109
|
+
COMPRESSION_METHOD_IBM_LZ77 => 'IBM LZ77 z Architecture (PFS)',
|
110
|
+
COMPRESSION_METHOD_JPEG => 'JPEG variant',
|
111
|
+
COMPRESSION_METHOD_WAVPACK => 'WavPack compressed data',
|
112
|
+
COMPRESSION_METHOD_PPMD => 'PPMd version I, Rev 1',
|
113
|
+
COMPRESSION_METHOD_AES => 'AES encryption'
|
62
114
|
}.freeze
|
63
115
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Zip
|
2
|
+
class DecryptedIo #:nodoc:all
|
3
|
+
CHUNK_SIZE = 32_768
|
4
|
+
|
5
|
+
def initialize(io, decrypter)
|
6
|
+
@io = io
|
7
|
+
@decrypter = decrypter
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(length = nil, outbuf = +'')
|
11
|
+
return (length.nil? || length.zero? ? '' : nil) if eof
|
12
|
+
|
13
|
+
while length.nil? || (buffer.bytesize < length)
|
14
|
+
break if input_finished?
|
15
|
+
|
16
|
+
buffer << produce_input
|
17
|
+
end
|
18
|
+
|
19
|
+
outbuf.replace(buffer.slice!(0...(length || output_buffer.bytesize)))
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def eof
|
25
|
+
buffer.empty? && input_finished?
|
26
|
+
end
|
27
|
+
|
28
|
+
def buffer
|
29
|
+
@buffer ||= +''
|
30
|
+
end
|
31
|
+
|
32
|
+
def input_finished?
|
33
|
+
@io.eof
|
34
|
+
end
|
35
|
+
|
36
|
+
def produce_input
|
37
|
+
@decrypter.decrypt(@io.read(CHUNK_SIZE))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -12,7 +12,7 @@ module Zip
|
|
12
12
|
class NullEncrypter < Encrypter
|
13
13
|
include NullEncryption
|
14
14
|
|
15
|
-
def header(
|
15
|
+
def header(_mtime)
|
16
16
|
''
|
17
17
|
end
|
18
18
|
|
@@ -20,12 +20,11 @@ module Zip
|
|
20
20
|
data
|
21
21
|
end
|
22
22
|
|
23
|
-
def data_descriptor(
|
23
|
+
def data_descriptor(_crc32, _compressed_size, _uncomprssed_size)
|
24
24
|
''
|
25
25
|
end
|
26
26
|
|
27
|
-
def reset
|
28
|
-
end
|
27
|
+
def reset!; end
|
29
28
|
end
|
30
29
|
|
31
30
|
class NullDecrypter < Decrypter
|
@@ -35,8 +34,7 @@ module Zip
|
|
35
34
|
data
|
36
35
|
end
|
37
36
|
|
38
|
-
def reset!(
|
39
|
-
end
|
37
|
+
def reset!(_header); end
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|