rubyzip 1.0.0 → 1.2.0

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 (107) hide show
  1. checksums.yaml +6 -14
  2. data/README.md +173 -42
  3. data/Rakefile +10 -5
  4. data/TODO +0 -1
  5. data/lib/zip/central_directory.rb +55 -24
  6. data/lib/zip/compressor.rb +0 -0
  7. data/lib/zip/constants.rb +4 -2
  8. data/lib/zip/crypto/encryption.rb +11 -0
  9. data/lib/zip/crypto/null_encryption.rb +45 -0
  10. data/lib/zip/crypto/traditional_encryption.rb +99 -0
  11. data/lib/zip/decompressor.rb +2 -2
  12. data/lib/zip/deflater.rb +11 -6
  13. data/lib/zip/dos_time.rb +4 -5
  14. data/lib/zip/entry.rb +159 -97
  15. data/lib/zip/entry_set.rb +18 -18
  16. data/lib/zip/errors.rb +15 -6
  17. data/lib/zip/extra_field/generic.rb +8 -8
  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 +14 -14
  21. data/lib/zip/extra_field/unix.rb +8 -9
  22. data/lib/zip/extra_field/zip64.rb +44 -6
  23. data/lib/zip/extra_field/zip64_placeholder.rb +16 -0
  24. data/lib/zip/extra_field.rb +20 -8
  25. data/lib/zip/file.rb +126 -114
  26. data/lib/zip/filesystem.rb +140 -139
  27. data/lib/zip/inflater.rb +10 -9
  28. data/lib/zip/input_stream.rb +105 -80
  29. data/lib/zip/ioextras/abstract_input_stream.rb +15 -12
  30. data/lib/zip/ioextras/abstract_output_stream.rb +0 -2
  31. data/lib/zip/ioextras.rb +1 -3
  32. data/lib/zip/null_compressor.rb +2 -2
  33. data/lib/zip/null_decompressor.rb +4 -4
  34. data/lib/zip/null_input_stream.rb +2 -1
  35. data/lib/zip/output_stream.rb +57 -43
  36. data/lib/zip/pass_thru_compressor.rb +4 -4
  37. data/lib/zip/pass_thru_decompressor.rb +4 -5
  38. data/lib/zip/streamable_directory.rb +2 -2
  39. data/lib/zip/streamable_stream.rb +22 -13
  40. data/lib/zip/version.rb +1 -1
  41. data/lib/zip.rb +11 -2
  42. data/samples/example.rb +30 -40
  43. data/samples/example_filesystem.rb +16 -18
  44. data/samples/example_recursive.rb +35 -27
  45. data/samples/{gtkRubyzip.rb → gtk_ruby_zip.rb} +25 -27
  46. data/samples/qtzip.rb +19 -28
  47. data/samples/write_simple.rb +12 -13
  48. data/samples/zipfind.rb +29 -37
  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 +53 -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/mimetype +1 -0
  64. data/test/data/notzippedruby.rb +7 -0
  65. data/test/data/ntfs.zip +0 -0
  66. data/test/data/oddExtraField.zip +0 -0
  67. data/test/data/rubycode.zip +0 -0
  68. data/test/data/rubycode2.zip +0 -0
  69. data/test/data/test.xls +0 -0
  70. data/test/data/testDirectory.bin +0 -0
  71. data/test/data/zip64-sample.zip +0 -0
  72. data/test/data/zipWithDirs.zip +0 -0
  73. data/test/data/zipWithEncryption.zip +0 -0
  74. data/test/deflater_test.rb +65 -0
  75. data/test/encryption_test.rb +42 -0
  76. data/test/entry_set_test.rb +152 -0
  77. data/test/entry_test.rb +163 -0
  78. data/test/errors_test.rb +34 -0
  79. data/test/extra_field_test.rb +76 -0
  80. data/test/file_extract_directory_test.rb +54 -0
  81. data/test/file_extract_test.rb +83 -0
  82. data/test/file_permissions_test.rb +69 -0
  83. data/test/file_split_test.rb +57 -0
  84. data/test/file_test.rb +563 -0
  85. data/test/filesystem/dir_iterator_test.rb +58 -0
  86. data/test/filesystem/directory_test.rb +121 -0
  87. data/test/filesystem/file_mutating_test.rb +88 -0
  88. data/test/filesystem/file_nonmutating_test.rb +508 -0
  89. data/test/filesystem/file_stat_test.rb +64 -0
  90. data/test/gentestfiles.rb +122 -0
  91. data/test/inflater_test.rb +14 -0
  92. data/test/input_stream_test.rb +182 -0
  93. data/test/ioextras/abstract_input_stream_test.rb +102 -0
  94. data/test/ioextras/abstract_output_stream_test.rb +106 -0
  95. data/test/ioextras/fake_io_test.rb +18 -0
  96. data/test/local_entry_test.rb +154 -0
  97. data/test/output_stream_test.rb +128 -0
  98. data/test/pass_thru_compressor_test.rb +30 -0
  99. data/test/pass_thru_decompressor_test.rb +14 -0
  100. data/test/samples/example_recursive_test.rb +37 -0
  101. data/test/settings_test.rb +95 -0
  102. data/test/test_helper.rb +221 -0
  103. data/test/unicode_file_names_and_comments_test.rb +50 -0
  104. data/test/zip64_full_test.rb +51 -0
  105. data/test/zip64_support_test.rb +14 -0
  106. metadata +198 -22
  107. data/NEWS +0 -182
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NjQ3YjE3YmQ0MDUyYzViOThmNDBjNGVhYTRmNDdiNzAzZjYzNjZkOA==
5
- data.tar.gz: !binary |-
6
- OGI5ZjFlYTk3NmQwMGY2NmM2NmVkYWI3ZjczMTVjNDAxYzg0YzY3Zg==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- ODI3NzAwZDg5NzYyZDdjZTNlNDUyOWJjYmY0YTU0MGEzMjUwOTE5MjdkOTM3
10
- ZjkzMTFjNzQzZmRlZDA4MTllZmU2N2NjMDQyMDM5NTRjMjg5ODVmMzUyODMw
11
- ZGExYjk3MDkwNzRmYTJkYjhhYjNmMmY4YTIyYTQ2ODA4MDdiNzk=
12
- data.tar.gz: !binary |-
13
- MWM5ODRlNzdmNDNiOGE4ZjkzMWYzZTIxZTE4OTU1ZTVhZmQ4YzhhZGQ0ZWNi
14
- N2Q4N2NhZmE1ZmJiZjFjMzcxMWI3YzgzNmRiNDVlZGYwZmYyZTJiNTljY2Yx
15
- MTY4NGM1YjNhOGJiZmE2MGUyZTBjYTc2YzdjMzc0ZTE3NTIyZDc=
2
+ SHA1:
3
+ metadata.gz: 4af5fd26173e16759a74f190b293f84cc02d605b
4
+ data.tar.gz: 05666235e929fdb9bd6abe6807d3bf9583e65244
5
+ SHA512:
6
+ metadata.gz: 2f4b82040f81e517ddb65660bea4a3368ec5e150bd094051d0ae3a515184c2eef55e32bcf5f49877bd432b3331a809402977e1c4b2a045695c8d2f45ab86f43c
7
+ data.tar.gz: 31fdb0e8c66d737d341161d02faf343786d0a0d1beca058cff4532886a2cfe268b738c6307b042c22a3186909953cd6879656a7660ef607eea906f407f1aada1
data/README.md CHANGED
@@ -1,16 +1,28 @@
1
1
  # rubyzip
2
- [![Build Status](https://secure.travis-ci.org/rubyzip/rubyzip.png)](http://travis-ci.org/rubyzip/rubyzip)
3
- [![Code Climate](https://codeclimate.com/github/rubyzip/rubyzip.png)](https://codeclimate.com/github/rubyzip/rubyzip)
4
- [![Coverage Status](https://coveralls.io/repos/rubyzip/rubyzip/badge.png?branch=master)](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
2
+ [![Gem Version](https://badge.fury.io/rb/rubyzip.svg)](http://badge.fury.io/rb/rubyzip)
3
+ [![Build Status](https://secure.travis-ci.org/rubyzip/rubyzip.svg)](http://travis-ci.org/rubyzip/rubyzip)
4
+ [![Code Climate](https://codeclimate.com/github/rubyzip/rubyzip.svg)](https://codeclimate.com/github/rubyzip/rubyzip)
5
+ [![Coverage Status](https://img.shields.io/coveralls/rubyzip/rubyzip.svg)](https://coveralls.io/r/rubyzip/rubyzip?branch=master)
5
6
 
6
- rubyzip is a ruby library for reading and writing zip files.
7
+ Rubyzip is a ruby library for reading and writing zip files.
7
8
 
8
9
  ## Important note
9
10
 
10
- Rubyzip interface changed!!! No need to do `require "zip/zip"` and `Zip` prefix in class names removed.
11
+ The Rubyzip interface has changed!!! No need to do `require "zip/zip"` and `Zip` prefix in class names removed.
12
+
13
+ If you have issues with any third-party gems that require an old version of rubyzip, you can use this workaround:
14
+
15
+ ```ruby
16
+ gem 'rubyzip', '>= 1.0.0' # will load new rubyzip version
17
+ gem 'zip-zip' # will load compatibility for old rubyzip API.
18
+ ```
19
+
20
+ ## Requirements
21
+
22
+ * Ruby 1.9.2 or greater
11
23
 
12
24
  ## Installation
13
- rubyzip is available on RubyGems, so:
25
+ Rubyzip is available on RubyGems:
14
26
 
15
27
  ```
16
28
  gem install rubyzip
@@ -42,25 +54,148 @@ Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
42
54
  # - The original file, including the path to find it
43
55
  zipfile.add(filename, folder + '/' + filename)
44
56
  end
57
+ zipfile.get_output_stream("myFile") { |os| os.write "myFile contains just this" }
45
58
  end
46
59
  ```
47
60
 
48
61
  ### Zipping a directory recursively
62
+ Copy from [here](https://github.com/rubyzip/rubyzip/blob/05916bf89181e1955118fd3ea059f18acac28cc8/samples/example_recursive.rb )
49
63
 
50
64
  ```ruby
51
65
  require 'rubygems'
52
66
  require 'zip'
67
+ # This is a simple example which uses rubyzip to
68
+ # recursively generate a zip file from the contents of
69
+ # a specified directory. The directory itself is not
70
+ # included in the archive, rather just its contents.
71
+ #
72
+ # Usage:
73
+ # require /path/to/the/ZipFileGenerator/Class
74
+ # directoryToZip = "/tmp/input"
75
+ # outputFile = "/tmp/out.zip"
76
+ # zf = ZipFileGenerator.new(directoryToZip, outputFile)
77
+ # zf.write()
78
+
79
+ class ZipFileGenerator
80
+ # Initialize with the directory to zip and the location of the output archive.
81
+ def initialize(input_dir, output_file)
82
+ @input_dir = input_dir
83
+ @output_file = output_file
84
+ end
53
85
 
54
- directory = '/Users/me/Desktop/directory_to_zip/'
55
- zipfile_name = '/Users/me/Desktop/recursive_directory.zip'
86
+ # Zip the input directory.
87
+ def write
88
+ entries = Dir.entries(@input_dir) - %w(. ..)
56
89
 
57
- Zip::File.open(zipfile_name, Zip::File::CREATE) do |zipfile|
58
- Dir[File.join(directory, '**', '**')].each do |file|
59
- zipfile.add(file.sub(directory, ''), file)
60
- end
90
+ ::Zip::File.open(@output_file, ::Zip::File::CREATE) do |io|
91
+ write_entries entries, '', io
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ # A helper method to make the recursion work.
98
+ def write_entries(entries, path, io)
99
+ entries.each do |e|
100
+ zip_file_path = path == '' ? e : File.join(path, e)
101
+ disk_file_path = File.join(@input_dir, zip_file_path)
102
+ puts "Deflating #{disk_file_path}"
103
+
104
+ if File.directory? disk_file_path
105
+ recursively_deflate_directory(disk_file_path, io, zip_file_path)
106
+ else
107
+ put_into_archive(disk_file_path, io, zip_file_path)
108
+ end
109
+ end
110
+ end
111
+
112
+ def recursively_deflate_directory(disk_file_path, io, zip_file_path)
113
+ io.mkdir zip_file_path
114
+ subdir = Dir.entries(disk_file_path) - %w(. ..)
115
+ write_entries subdir, zip_file_path, io
116
+ end
117
+
118
+ def put_into_archive(disk_file_path, io, zip_file_path)
119
+ io.get_output_stream(zip_file_path) do |f|
120
+ f.puts(File.open(disk_file_path, 'rb').read)
121
+ end
122
+ end
123
+ end
124
+ ```
125
+
126
+ ### Save zip archive entries in sorted by name state
127
+
128
+ To save zip archives in sorted order like below, you need to set `::Zip.sort_entries` to `true`
129
+
130
+ ```
131
+ Vegetable/
132
+ Vegetable/bean
133
+ Vegetable/carrot
134
+ Vegetable/celery
135
+ fruit/
136
+ fruit/apple
137
+ fruit/kiwi
138
+ fruit/mango
139
+ fruit/orange
140
+ ```
141
+
142
+ After this, entries in the zip archive will be saved in ordered state.
143
+
144
+ ### Default permissions of zip archives
145
+
146
+ On Posix file systems the default file permissions applied to a new archive
147
+ are (0666 - umask), which mimics the behavior of standard tools such as `touch`.
148
+
149
+ On Windows the default file permissions are set to 0644 as suggested by the
150
+ [Ruby File documentation](http://ruby-doc.org/core-2.2.2/File.html).
151
+
152
+ When modifying a zip archive the file permissions of the archive are preserved.
153
+
154
+ ### Reading a Zip file
155
+
156
+ ```ruby
157
+ Zip::File.open('foo.zip') do |zip_file|
158
+ # Handle entries one by one
159
+ zip_file.each do |entry|
160
+ # Extract to file/directory/symlink
161
+ puts "Extracting #{entry.name}"
162
+ entry.extract(dest_file)
163
+
164
+ # Read into memory
165
+ content = entry.get_input_stream.read
166
+ end
167
+
168
+ # Find specific entry
169
+ entry = zip_file.glob('*.csv').first
170
+ puts entry.get_input_stream.read
61
171
  end
62
172
  ```
63
173
 
174
+ #### Notice about ::Zip::InputStream
175
+
176
+ `::Zip::InputStream` usable for fast reading zip file content because it not read Central directory.
177
+
178
+ But there is one exception when it is not working - General Purpose Flag Bit 3.
179
+
180
+ ```
181
+ 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
182
+ ```
183
+
184
+ If `::Zip::InputStream` finds such entry in the zip archive it will raise an exception.
185
+
186
+ ### Password Protection (Experimental)
187
+
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.:
189
+
190
+ ```ruby
191
+ Zip::OutputStream.write_buffer(::StringIO.new(''), Zip::TraditionalEncrypter.new('password')) do |out|
192
+ out.put_next_entry("my_file.txt")
193
+ out.write my_data
194
+ end.string
195
+ ```
196
+
197
+ This is an experimental feature and the interface for encryption may change in future versions.
198
+
64
199
  ## Known issues
65
200
 
66
201
  ### Modify docx file with rubyzip
@@ -86,32 +221,6 @@ end
86
221
  File.open(new_path, "w") {|f| f.write(buffer.string) }
87
222
  ```
88
223
 
89
- ## Further Documentation
90
-
91
- There is more than one way to access or create a zip archive with
92
- rubyzip. The basic API is modeled after the classes in
93
- java.util.zip from the Java SDK. This means there are classes such
94
- as Zip::InputStream, Zip::OutputStream and
95
- Zip::File. Zip::InputStream provides a basic interface for
96
- iterating through the entries in a zip archive and reading from the
97
- entries in the same way as from a regular File or IO
98
- object. OutputStream is the corresponding basic output
99
- facility. Zip::File provides a mean for accessing the archives
100
- central directory and provides means for accessing any entry without
101
- having to iterate through the archive. Unlike Java's
102
- java.util.zip.ZipFile rubyzip's Zip::File is mutable, which means
103
- it can be used to change zip files as well.
104
-
105
- Another way to access a zip archive with rubyzip is to use rubyzip's
106
- Zip::FileSystem API. Using this API files can be read from and
107
- written to the archive in much the same manner as ruby's builtin
108
- classes allows files to be read from and written to the file system.
109
-
110
- For details about the specific behaviour of classes and methods refer
111
- to the test suite. Finally you can generate the rdoc documentation or
112
- visit http://rubyzip.sourceforge.net.
113
-
114
-
115
224
  ## Configuration
116
225
 
117
226
  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:
@@ -128,25 +237,47 @@ Additionally, if you want to configure rubyzip to overwrite existing files while
128
237
  Zip.continue_on_exists_proc = true
129
238
  ```
130
239
 
131
- If you want to store non english names and want to open properly file on Windows(pre 7) you need to set next option:
240
+ If you want to store non-english names and want to open them on Windows(pre 7) you need to set this option:
132
241
 
133
242
  ```ruby
134
243
  Zip.unicode_names = true
135
244
  ```
136
245
 
137
- All settings in same time
246
+ Some zip files might have an invalid date format, which will raise a warning. You can hide this warning with the following setting:
247
+
248
+ ```ruby
249
+ Zip.warn_invalid_date = false
250
+ ```
251
+
252
+ You can set the default compression level like so:
253
+
254
+ ```ruby
255
+ Zip.default_compression = Zlib::DEFAULT_COMPRESSION
256
+ ```
257
+ It defaults to `Zlib::DEFAULT_COMPRESSION`. Possible values are `Zlib::BEST_COMPRESSION`, `Zlib::DEFAULT_COMPRESSION` and `Zlib::NO_COMPRESSION`
258
+
259
+ You can set multiple settings at the same time by using a block:
138
260
 
139
261
  ```ruby
140
262
  Zip.setup do |c|
141
263
  c.on_exists_proc = true
142
264
  c.continue_on_exists_proc = true
143
265
  c.unicode_names = true
266
+ c.default_compression = Zlib::BEST_COMPRESSION
144
267
  end
145
268
  ```
146
269
 
270
+ By default, Zip64 support is disabled for writing. To enable it do this:
271
+
272
+ ```ruby
273
+ Zip.write_zip64_support = true
274
+ ```
275
+
276
+ _NOTE_: If you will enable Zip64 writing then you will need zip extractor with Zip64 support to extract archive.
277
+
147
278
  ## Developing
148
279
 
149
- To run tests you need run next commands:
280
+ To run the test you need to do this:
150
281
 
151
282
  ```
152
283
  bundle install
@@ -173,5 +304,5 @@ extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org)
173
304
 
174
305
  ## License
175
306
 
176
- rubyzip is distributed under the same license as ruby. See
307
+ Rubyzip is distributed under the same license as ruby. See
177
308
  http://www.ruby-lang.org/en/LICENSE.txt
data/Rakefile CHANGED
@@ -1,13 +1,18 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rake/testtask'
3
3
 
4
- task :default => :test
4
+ task default: :test
5
5
 
6
6
  Rake::TestTask.new(:test) do |test|
7
- test.libs << File.join(File.dirname(__FILE__), 'lib')
8
- test.libs << File.join(File.dirname(__FILE__), 'test')
9
- test.pattern = File.join(File.dirname(__FILE__), 'test/alltests.rb')
7
+ test.libs << 'lib'
8
+ test.libs << 'test'
9
+ test.pattern = 'test/**/*_test.rb'
10
10
  test.verbose = true
11
-
12
11
  end
13
12
 
13
+ # Rake::TestTask.new(:zip64_full_test) do |test|
14
+ # test.libs << File.join(File.dirname(__FILE__), 'lib')
15
+ # test.libs << File.join(File.dirname(__FILE__), 'test')
16
+ # test.pattern = File.join(File.dirname(__FILE__), 'test/zip64_full_test.rb')
17
+ # test.verbose = true
18
+ # end
data/TODO CHANGED
@@ -4,7 +4,6 @@
4
4
  * Suggestion: Add ZipFile/ZipInputStream example that demonstrates extracting all entries.
5
5
  * Suggestion: ZipFile#extract destination should default to "."
6
6
  * Suggestion: ZipEntry should have extract(), get_input_stream() methods etc
7
- * Suggestion: ZipInputStream/ZipOutputStream should accept an IO object in addition to a filename.
8
7
  * (is buffering used anywhere with write?)
9
8
  * Inflater.sysread should pass the buffer to produce_input.
10
9
  * Implement ZipFsDir.glob
@@ -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 = 65536 + 18
8
+ MAX_END_OF_CDS_SIZE = 65_536 + 18
9
9
  STATIC_EOCD_SIZE = 22
10
10
 
11
11
  attr_reader :comment
@@ -22,21 +22,31 @@ module Zip
22
22
  end
23
23
 
24
24
  def write_to_stream(io) #:nodoc:
25
- offset = io.tell
25
+ cdir_offset = io.tell
26
26
  @entry_set.each { |entry| entry.write_c_dir_entry(io) }
27
- write_e_o_c_d(io, offset)
27
+ eocd_offset = io.tell
28
+ cdir_size = eocd_offset - cdir_offset
29
+ if ::Zip.write_zip64_support
30
+ need_zip64_eocd = cdir_offset > 0xFFFFFFFF || cdir_size > 0xFFFFFFFF || @entry_set.size > 0xFFFF
31
+ need_zip64_eocd ||= @entry_set.any? { |entry| entry.extra['Zip64'] }
32
+ if need_zip64_eocd
33
+ write_64_e_o_c_d(io, cdir_offset, cdir_size)
34
+ write_64_eocd_locator(io, eocd_offset)
35
+ end
36
+ end
37
+ write_e_o_c_d(io, cdir_offset, cdir_size)
28
38
  end
29
39
 
30
- def write_e_o_c_d(io, offset) #:nodoc:
40
+ def write_e_o_c_d(io, offset, cdir_size) #:nodoc:
31
41
  tmp = [
32
42
  END_OF_CDS,
33
43
  0, # @numberOfThisDisk
34
44
  0, # @numberOfDiskWithStartOfCDir
35
- @entry_set ? @entry_set.size : 0,
36
- @entry_set ? @entry_set.size : 0,
37
- cdir_size,
38
- offset,
39
- @comment ? @comment.length : 0
45
+ @entry_set ? [@entry_set.size, 0xFFFF].min : 0,
46
+ @entry_set ? [@entry_set.size, 0xFFFF].min : 0,
47
+ [cdir_size, 0xFFFFFFFF].min,
48
+ [offset, 0xFFFFFFFF].min,
49
+ @comment ? @comment.bytesize : 0
40
50
  ]
41
51
  io << tmp.pack('VvvvvVVv')
42
52
  io << @comment
@@ -44,14 +54,35 @@ module Zip
44
54
 
45
55
  private :write_e_o_c_d
46
56
 
47
- def cdir_size #:nodoc:
48
- # does not include eocd
49
- @entry_set.inject(0) do |value, entry|
50
- entry.cdir_header_size + value
51
- end
57
+ def write_64_e_o_c_d(io, offset, cdir_size) #:nodoc:
58
+ tmp = [
59
+ ZIP64_END_OF_CDS,
60
+ 44, # size of zip64 end of central directory record (excludes signature and field itself)
61
+ VERSION_MADE_BY,
62
+ VERSION_NEEDED_TO_EXTRACT_ZIP64,
63
+ 0, # @numberOfThisDisk
64
+ 0, # @numberOfDiskWithStartOfCDir
65
+ @entry_set ? @entry_set.size : 0, # number of entries on this disk
66
+ @entry_set ? @entry_set.size : 0, # number of entries total
67
+ cdir_size, # size of central directory
68
+ offset, # offset of start of central directory in its disk
69
+ ]
70
+ io << tmp.pack('VQ<vvVVQ<Q<Q<Q<')
71
+ end
72
+
73
+ private :write_64_e_o_c_d
74
+
75
+ def write_64_eocd_locator(io, zip64_eocd_offset)
76
+ tmp = [
77
+ ZIP64_EOCD_LOCATOR,
78
+ 0, # number of disk containing the start of zip64 eocd record
79
+ zip64_eocd_offset, # offset of the start of zip64 eocd record in its disk
80
+ 1 # total number of disks
81
+ ]
82
+ io << tmp.pack('VVQ<V')
52
83
  end
53
84
 
54
- private :cdir_size
85
+ private :write_64_eocd_locator
55
86
 
56
87
  def read_64_e_o_c_d(buf) #:nodoc:
57
88
  buf = get_64_e_o_c_d(buf)
@@ -65,7 +96,7 @@ module Zip
65
96
  @size_in_bytes = Entry.read_zip_64_long(buf)
66
97
  @cdir_offset = Entry.read_zip_64_long(buf)
67
98
  @zip_64_extensible = buf.slice!(0, buf.bytesize)
68
- raise ZipError, "Zip consistency problem while reading eocd structure" unless buf.size == 0
99
+ raise Error, 'Zip consistency problem while reading eocd structure' unless buf.size == 0
69
100
  end
70
101
 
71
102
  def read_e_o_c_d(buf) #:nodoc:
@@ -77,19 +108,19 @@ module Zip
77
108
  @size_in_bytes = Entry.read_zip_long(buf)
78
109
  @cdir_offset = Entry.read_zip_long(buf)
79
110
  comment_length = Entry.read_zip_short(buf)
80
- @comment = if comment_length <= 0
111
+ @comment = if comment_length.to_i <= 0
81
112
  buf.slice!(0, buf.size)
82
113
  else
83
114
  buf.read(comment_length)
84
115
  end
85
- raise ZipError, "Zip consistency problem while reading eocd structure" unless buf.size == 0
116
+ raise Error, 'Zip consistency problem while reading eocd structure' unless buf.size == 0
86
117
  end
87
118
 
88
119
  def read_central_directory_entries(io) #:nodoc:
89
120
  begin
90
121
  io.seek(@cdir_offset, IO::SEEK_SET)
91
122
  rescue Errno::EINVAL
92
- raise ZipError, "Zip consistency problem while reading central directory entry"
123
+ raise Error, 'Zip consistency problem while reading central directory entry'
93
124
  end
94
125
  @entry_set = EntrySet.new
95
126
  @size.times do
@@ -109,7 +140,7 @@ module Zip
109
140
 
110
141
  def get_e_o_c_d(buf) #:nodoc:
111
142
  sig_index = buf.rindex([END_OF_CDS].pack('V'))
112
- raise ZipError, "Zip end of central directory signature not found" unless sig_index
143
+ raise Error, 'Zip end of central directory signature not found' unless sig_index
113
144
  buf = buf.slice!((sig_index + 4)..(buf.bytesize))
114
145
 
115
146
  def buf.read(count)
@@ -134,9 +165,9 @@ module Zip
134
165
 
135
166
  def get_64_e_o_c_d(buf) #:nodoc:
136
167
  zip_64_start = buf.rindex([ZIP64_END_OF_CDS].pack('V'))
137
- raise ZipError, "Zip64 end of central directory signature not found" unless zip_64_start
168
+ raise Error, 'Zip64 end of central directory signature not found' unless zip_64_start
138
169
  zip_64_locator = buf.rindex([ZIP64_EOCD_LOCATOR].pack('V'))
139
- raise ZipError, "Zip64 end of central directory signature locator not found" unless zip_64_locator
170
+ raise Error, 'Zip64 end of central directory signature locator not found' unless zip_64_locator
140
171
  buf = buf.slice!((zip_64_start + 4)..zip_64_locator)
141
172
 
142
173
  def buf.read(count)
@@ -151,7 +182,7 @@ module Zip
151
182
  @entry_set.each(&proc)
152
183
  end
153
184
 
154
- # Returns the number of entries in the central directory (and
185
+ # Returns the number of entries in the central directory (and
155
186
  # consequently in the zip archive).
156
187
  def size
157
188
  @entry_set.size
@@ -161,7 +192,7 @@ module Zip
161
192
  cdir = new
162
193
  cdir.read_from_stream(io)
163
194
  return cdir
164
- rescue ZipError
195
+ rescue Error
165
196
  return nil
166
197
  end
167
198
 
File without changes
data/lib/zip/constants.rb CHANGED
@@ -6,8 +6,10 @@ 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
+ VERSION_MADE_BY = 52 # this library's version
10
11
  VERSION_NEEDED_TO_EXTRACT = 20
12
+ VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45
11
13
 
12
14
  FILE_TYPE_FILE = 010
13
15
  FILE_TYPE_DIR = 004
@@ -56,6 +58,6 @@ module Zip
56
58
  FSTYPE_TANDEM => 'Tandem NSK'.freeze,
57
59
  FSTYPE_THEOS => 'Theos'.freeze,
58
60
  FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.freeze,
59
- FSTYPE_ATHEOS => 'AtheOS'.freeze,
61
+ FSTYPE_ATHEOS => 'AtheOS'.freeze
60
62
  }.freeze
61
63
  end
@@ -0,0 +1,11 @@
1
+ module Zip
2
+ class Encrypter #:nodoc:all
3
+ end
4
+
5
+ class Decrypter
6
+ end
7
+ end
8
+
9
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
10
+ # rubyzip is free software; you can redistribute it and/or
11
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,45 @@
1
+ module Zip
2
+ module NullEncryption
3
+ def header_bytesize
4
+ 0
5
+ end
6
+
7
+ def gp_flags
8
+ 0
9
+ end
10
+ end
11
+
12
+ class NullEncrypter < Encrypter
13
+ include NullEncryption
14
+
15
+ def header(_mtime)
16
+ ''
17
+ end
18
+
19
+ def encrypt(data)
20
+ data
21
+ end
22
+
23
+ def data_descriptor(_crc32, _compressed_size, _uncomprssed_size)
24
+ ''
25
+ end
26
+
27
+ def reset!
28
+ end
29
+ end
30
+
31
+ class NullDecrypter < Decrypter
32
+ include NullEncryption
33
+
34
+ def decrypt(data)
35
+ data
36
+ end
37
+
38
+ def reset!(_header)
39
+ end
40
+ end
41
+ end
42
+
43
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
44
+ # rubyzip is free software; you can redistribute it and/or
45
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,99 @@
1
+ module Zip
2
+ module TraditionalEncryption
3
+ def initialize(password)
4
+ @password = password
5
+ reset_keys!
6
+ end
7
+
8
+ def header_bytesize
9
+ 12
10
+ end
11
+
12
+ def gp_flags
13
+ 0x0001 | 0x0008
14
+ end
15
+
16
+ protected
17
+
18
+ def reset_keys!
19
+ @key0 = 0x12345678
20
+ @key1 = 0x23456789
21
+ @key2 = 0x34567890
22
+ @password.each_byte do |byte|
23
+ update_keys(byte.chr)
24
+ end
25
+ end
26
+
27
+ def update_keys(n)
28
+ @key0 = ~Zlib.crc32(n, ~@key0)
29
+ @key1 = ((@key1 + (@key0 & 0xff)) * 134_775_813 + 1) & 0xffffffff
30
+ @key2 = ~Zlib.crc32((@key1 >> 24).chr, ~@key2)
31
+ end
32
+
33
+ def decrypt_byte
34
+ temp = (@key2 & 0xffff) | 2
35
+ ((temp * (temp ^ 1)) >> 8) & 0xff
36
+ end
37
+ end
38
+
39
+ class TraditionalEncrypter < Encrypter
40
+ include TraditionalEncryption
41
+
42
+ def header(mtime)
43
+ [].tap do |header|
44
+ (header_bytesize - 2).times do
45
+ header << Random.rand(0..255)
46
+ end
47
+ header << (mtime.to_binary_dos_time & 0xff)
48
+ header << (mtime.to_binary_dos_time >> 8)
49
+ end.map { |x| encode x }.pack('C*')
50
+ end
51
+
52
+ def encrypt(data)
53
+ data.unpack('C*').map { |x| encode x }.pack('C*')
54
+ end
55
+
56
+ def data_descriptor(crc32, compressed_size, uncomprssed_size)
57
+ [0x08074b50, crc32, compressed_size, uncomprssed_size].pack('VVVV')
58
+ end
59
+
60
+ def reset!
61
+ reset_keys!
62
+ end
63
+
64
+ private
65
+
66
+ def encode(n)
67
+ t = decrypt_byte
68
+ update_keys(n.chr)
69
+ t ^ n
70
+ end
71
+ end
72
+
73
+ class TraditionalDecrypter < Decrypter
74
+ include TraditionalEncryption
75
+
76
+ def decrypt(data)
77
+ data.unpack('C*').map { |x| decode x }.pack('C*')
78
+ end
79
+
80
+ def reset!(header)
81
+ reset_keys!
82
+ header.each_byte do |x|
83
+ decode x
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def decode(n)
90
+ n ^= decrypt_byte
91
+ update_keys(n.chr)
92
+ n
93
+ end
94
+ end
95
+ end
96
+
97
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
98
+ # rubyzip is free software; you can redistribute it and/or
99
+ # modify it under the terms of the ruby license.
@@ -1,9 +1,9 @@
1
1
  module Zip
2
2
  class Decompressor #:nodoc:all
3
- CHUNK_SIZE = 32768
3
+ CHUNK_SIZE = 32_768
4
4
  def initialize(input_stream)
5
5
  super()
6
- @input_stream=input_stream
6
+ @input_stream = input_stream
7
7
  end
8
8
  end
9
9
  end