archive-zip 0.12.0 → 0.13.0.pre1
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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/NEWS.md +5 -0
- data/README.md +1 -1
- data/lib/archive/support/ioextensions.rb +5 -7
- data/lib/archive/support/iowindow.rb +34 -87
- data/lib/archive/support/stringio.rb +27 -0
- data/lib/archive/support/zlib.rb +0 -435
- data/lib/archive/zip/codec/deflate/reader.rb +187 -0
- data/lib/archive/zip/codec/deflate/writer.rb +209 -0
- data/lib/archive/zip/codec/deflate.rb +92 -244
- data/lib/archive/zip/codec/null_encryption.rb +4 -184
- data/lib/archive/zip/codec/store/reader.rb +97 -0
- data/lib/archive/zip/codec/store/writer.rb +78 -0
- data/lib/archive/zip/codec/store.rb +6 -231
- data/lib/archive/zip/codec/traditional_encryption/base.rb +85 -0
- data/lib/archive/zip/codec/traditional_encryption/reader.rb +65 -0
- data/lib/archive/zip/codec/traditional_encryption/writer.rb +71 -0
- data/lib/archive/zip/codec/traditional_encryption.rb +6 -360
- data/lib/archive/zip/dos_time.rb +103 -0
- data/lib/archive/zip/entry.rb +86 -70
- data/lib/archive/zip.rb +2 -5
- metadata +35 -227
- data/.yardopts +0 -1
- data/Rakefile +0 -247
- data/lib/archive/support/binary_stringio.rb +0 -30
- data/lib/archive/support/integer.rb +0 -13
- data/lib/archive/support/io-like.rb +0 -14
- data/lib/archive/support/time.rb +0 -119
- data/lib/archive/zip/version.rb +0 -6
- data/spec/archive/dos_time_spec.rb +0 -113
- data/spec/archive/zip/archive_spec.rb +0 -54
- data/spec/archive/zip/codec/deflate/compress/checksum_spec.rb +0 -44
- data/spec/archive/zip/codec/deflate/compress/close_spec.rb +0 -45
- data/spec/archive/zip/codec/deflate/compress/crc32_spec.rb +0 -23
- data/spec/archive/zip/codec/deflate/compress/data_descriptor_spec.rb +0 -74
- data/spec/archive/zip/codec/deflate/compress/new_spec.rb +0 -39
- data/spec/archive/zip/codec/deflate/compress/open_spec.rb +0 -48
- data/spec/archive/zip/codec/deflate/compress/write_spec.rb +0 -111
- data/spec/archive/zip/codec/deflate/decompress/checksum_spec.rb +0 -20
- data/spec/archive/zip/codec/deflate/decompress/close_spec.rb +0 -34
- data/spec/archive/zip/codec/deflate/decompress/crc32_spec.rb +0 -20
- data/spec/archive/zip/codec/deflate/decompress/data_descriptor_spec.rb +0 -74
- data/spec/archive/zip/codec/deflate/decompress/new_spec.rb +0 -16
- data/spec/archive/zip/codec/deflate/decompress/open_spec.rb +0 -29
- data/spec/archive/zip/codec/deflate/fixtures/classes.rb +0 -25
- data/spec/archive/zip/codec/deflate/fixtures/compressed_file.bin +0 -1
- data/spec/archive/zip/codec/deflate/fixtures/compressed_file_nocomp.bin +0 -0
- data/spec/archive/zip/codec/deflate/fixtures/raw_file.txt +0 -10
- data/spec/archive/zip/codec/null_encryption/decrypt/close_spec.rb +0 -34
- data/spec/archive/zip/codec/null_encryption/decrypt/new_spec.rb +0 -16
- data/spec/archive/zip/codec/null_encryption/decrypt/open_spec.rb +0 -29
- data/spec/archive/zip/codec/null_encryption/decrypt/read_spec.rb +0 -26
- data/spec/archive/zip/codec/null_encryption/decrypt/rewind_spec.rb +0 -27
- data/spec/archive/zip/codec/null_encryption/decrypt/seek_spec.rb +0 -59
- data/spec/archive/zip/codec/null_encryption/decrypt/tell_spec.rb +0 -23
- data/spec/archive/zip/codec/null_encryption/encrypt/close_spec.rb +0 -34
- data/spec/archive/zip/codec/null_encryption/encrypt/new_spec.rb +0 -16
- data/spec/archive/zip/codec/null_encryption/encrypt/open_spec.rb +0 -31
- data/spec/archive/zip/codec/null_encryption/encrypt/rewind_spec.rb +0 -28
- data/spec/archive/zip/codec/null_encryption/encrypt/seek_spec.rb +0 -52
- data/spec/archive/zip/codec/null_encryption/encrypt/tell_spec.rb +0 -31
- data/spec/archive/zip/codec/null_encryption/encrypt/write_spec.rb +0 -31
- data/spec/archive/zip/codec/null_encryption/fixtures/classes.rb +0 -12
- data/spec/archive/zip/codec/null_encryption/fixtures/raw_file.txt +0 -10
- data/spec/archive/zip/codec/store/compress/close_spec.rb +0 -34
- data/spec/archive/zip/codec/store/compress/data_descriptor_spec.rb +0 -77
- data/spec/archive/zip/codec/store/compress/new_spec.rb +0 -16
- data/spec/archive/zip/codec/store/compress/open_spec.rb +0 -29
- data/spec/archive/zip/codec/store/compress/rewind_spec.rb +0 -28
- data/spec/archive/zip/codec/store/compress/seek_spec.rb +0 -52
- data/spec/archive/zip/codec/store/compress/tell_spec.rb +0 -31
- data/spec/archive/zip/codec/store/compress/write_spec.rb +0 -29
- data/spec/archive/zip/codec/store/decompress/close_spec.rb +0 -34
- data/spec/archive/zip/codec/store/decompress/data_descriptor_spec.rb +0 -75
- data/spec/archive/zip/codec/store/decompress/new_spec.rb +0 -16
- data/spec/archive/zip/codec/store/decompress/open_spec.rb +0 -29
- data/spec/archive/zip/codec/store/decompress/read_spec.rb +0 -26
- data/spec/archive/zip/codec/store/decompress/rewind_spec.rb +0 -27
- data/spec/archive/zip/codec/store/decompress/seek_spec.rb +0 -59
- data/spec/archive/zip/codec/store/decompress/tell_spec.rb +0 -23
- data/spec/archive/zip/codec/store/fixtures/classes.rb +0 -12
- data/spec/archive/zip/codec/store/fixtures/raw_file.txt +0 -10
- data/spec/archive/zip/codec/traditional_encryption/decrypt/close_spec.rb +0 -53
- data/spec/archive/zip/codec/traditional_encryption/decrypt/new_spec.rb +0 -20
- data/spec/archive/zip/codec/traditional_encryption/decrypt/open_spec.rb +0 -43
- data/spec/archive/zip/codec/traditional_encryption/decrypt/read_spec.rb +0 -127
- data/spec/archive/zip/codec/traditional_encryption/decrypt/rewind_spec.rb +0 -36
- data/spec/archive/zip/codec/traditional_encryption/decrypt/seek_spec.rb +0 -80
- data/spec/archive/zip/codec/traditional_encryption/decrypt/tell_spec.rb +0 -27
- data/spec/archive/zip/codec/traditional_encryption/encrypt/close_spec.rb +0 -53
- data/spec/archive/zip/codec/traditional_encryption/encrypt/new_spec.rb +0 -20
- data/spec/archive/zip/codec/traditional_encryption/encrypt/open_spec.rb +0 -41
- data/spec/archive/zip/codec/traditional_encryption/encrypt/rewind_spec.rb +0 -39
- data/spec/archive/zip/codec/traditional_encryption/encrypt/seek_spec.rb +0 -73
- data/spec/archive/zip/codec/traditional_encryption/encrypt/tell_spec.rb +0 -40
- data/spec/archive/zip/codec/traditional_encryption/encrypt/write_spec.rb +0 -114
- data/spec/archive/zip/codec/traditional_encryption/fixtures/classes.rb +0 -27
- data/spec/archive/zip/codec/traditional_encryption/fixtures/encrypted_file.bin +0 -0
- data/spec/archive/zip/codec/traditional_encryption/fixtures/raw_file.txt +0 -10
- data/spec/binary_stringio/new_spec.rb +0 -40
- data/spec/binary_stringio/set_encoding_spec.rb +0 -17
- data/spec/ioextensions/read_exactly_spec.rb +0 -52
- data/spec/zlib/fixtures/classes.rb +0 -65
- data/spec/zlib/fixtures/compressed_file.bin +0 -1
- data/spec/zlib/fixtures/compressed_file_gzip.bin +0 -0
- data/spec/zlib/fixtures/compressed_file_huffman.bin +0 -2
- data/spec/zlib/fixtures/compressed_file_minmem.bin +0 -0
- data/spec/zlib/fixtures/compressed_file_minwin.bin +0 -1
- data/spec/zlib/fixtures/compressed_file_nocomp.bin +0 -0
- data/spec/zlib/fixtures/compressed_file_raw.bin +0 -1
- data/spec/zlib/fixtures/raw_file.txt +0 -10
- data/spec/zlib/zreader/checksum_spec.rb +0 -42
- data/spec/zlib/zreader/close_spec.rb +0 -16
- data/spec/zlib/zreader/compressed_size_spec.rb +0 -20
- data/spec/zlib/zreader/new_spec.rb +0 -43
- data/spec/zlib/zreader/open_spec.rb +0 -51
- data/spec/zlib/zreader/read_spec.rb +0 -58
- data/spec/zlib/zreader/rewind_spec.rb +0 -25
- data/spec/zlib/zreader/seek_spec.rb +0 -57
- data/spec/zlib/zreader/tell_spec.rb +0 -23
- data/spec/zlib/zreader/uncompressed_size_spec.rb +0 -20
- data/spec/zlib/zwriter/checksum_spec.rb +0 -43
- data/spec/zlib/zwriter/close_spec.rb +0 -16
- data/spec/zlib/zwriter/compressed_size_spec.rb +0 -21
- data/spec/zlib/zwriter/new_spec.rb +0 -66
- data/spec/zlib/zwriter/open_spec.rb +0 -70
- data/spec/zlib/zwriter/rewind_spec.rb +0 -28
- data/spec/zlib/zwriter/seek_spec.rb +0 -52
- data/spec/zlib/zwriter/tell_spec.rb +0 -31
- data/spec/zlib/zwriter/uncompressed_size_spec.rb +0 -21
- data/spec/zlib/zwriter/write_spec.rb +0 -28
@@ -1,193 +1,11 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require 'archive/support/io-like'
|
4
3
|
require 'archive/zip/codec'
|
5
4
|
|
6
5
|
module Archive; class Zip; module Codec
|
7
6
|
# Archive::Zip::Codec::NullEncryption is a handle for an encryption codec
|
8
7
|
# which passes data through itself unchanged.
|
9
8
|
class NullEncryption
|
10
|
-
# Archive::Zip::Codec::NullEncryption::Encrypt is a writable, IO-like object
|
11
|
-
# which writes all data written to it directly to a delegate IO object. A
|
12
|
-
# _close_ method is also provided which can optionally closed the delegate
|
13
|
-
# object.
|
14
|
-
class Encrypt
|
15
|
-
include IO::Like
|
16
|
-
|
17
|
-
# Creates a new instance of this class with the given argument using #new
|
18
|
-
# and then passes the instance to the given block. The #close method is
|
19
|
-
# guaranteed to be called after the block completes.
|
20
|
-
#
|
21
|
-
# Equivalent to #new if no block is given.
|
22
|
-
def self.open(io)
|
23
|
-
encrypt_io = new(io)
|
24
|
-
return encrypt_io unless block_given?
|
25
|
-
|
26
|
-
begin
|
27
|
-
yield(encrypt_io)
|
28
|
-
ensure
|
29
|
-
encrypt_io.close unless encrypt_io.closed?
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# Creates a new instance of this class using _io_ as a data sink. _io_
|
34
|
-
# must be writable and must provide a write method as IO does or errors
|
35
|
-
# will be raised when performing write operations.
|
36
|
-
#
|
37
|
-
# The _flush_size_ attribute is set to <tt>0</tt> by default under the
|
38
|
-
# assumption that _io_ is already buffered.
|
39
|
-
def initialize(io)
|
40
|
-
@io = io
|
41
|
-
|
42
|
-
# Keep track of the total number of bytes written.
|
43
|
-
@total_bytes_in = 0
|
44
|
-
|
45
|
-
# Assume that the delegate IO object is already buffered.
|
46
|
-
self.flush_size = 0
|
47
|
-
end
|
48
|
-
|
49
|
-
# Closes this object so that further write operations will fail. If
|
50
|
-
# _close_delegate_ is +true+, the delegate object used as a data sink will
|
51
|
-
# also be closed using its close method.
|
52
|
-
def close(close_delegate = true)
|
53
|
-
super()
|
54
|
-
@io.close if close_delegate
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
# Allows resetting this object and the delegate object back to the
|
60
|
-
# beginning of the stream or reporting the current position in the stream.
|
61
|
-
#
|
62
|
-
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is
|
63
|
-
# either IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_
|
64
|
-
# is IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
65
|
-
# method.
|
66
|
-
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
67
|
-
unless offset == 0 &&
|
68
|
-
((whence == IO::SEEK_SET && @io.respond_to?(:rewind)) ||
|
69
|
-
whence == IO::SEEK_CUR) then
|
70
|
-
raise Errno::EINVAL
|
71
|
-
end
|
72
|
-
|
73
|
-
case whence
|
74
|
-
when IO::SEEK_SET
|
75
|
-
@io.rewind
|
76
|
-
@total_bytes_in = 0
|
77
|
-
when IO::SEEK_CUR
|
78
|
-
@total_bytes_in
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# Writes _string_ to the delegate IO object and returns the result.
|
83
|
-
def unbuffered_write(string)
|
84
|
-
bytes_written = @io.write(string)
|
85
|
-
@total_bytes_in += bytes_written
|
86
|
-
bytes_written
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# Archive::Zip::Codec::NullEncryption::Decrypt is a readable, IO-like object
|
91
|
-
# which reads data directly from a delegate IO object, making no changes. A
|
92
|
-
# _close_ method is also provided which can optionally closed the delegate
|
93
|
-
# object.
|
94
|
-
class Decrypt
|
95
|
-
include IO::Like
|
96
|
-
|
97
|
-
# Creates a new instance of this class with the given argument using #new
|
98
|
-
# and then passes the instance to the given block. The #close method is
|
99
|
-
# guaranteed to be called after the block completes.
|
100
|
-
#
|
101
|
-
# Equivalent to #new if no block is given.
|
102
|
-
def self.open(io)
|
103
|
-
decrypt_io = new(io)
|
104
|
-
return decrypt_io unless block_given?
|
105
|
-
|
106
|
-
begin
|
107
|
-
yield(decrypt_io)
|
108
|
-
ensure
|
109
|
-
decrypt_io.close unless decrypt_io.closed?
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# Creates a new instance of this class using _io_ as a data source. _io_
|
114
|
-
# must be readable and provide a _read_ method as an IO instance would or
|
115
|
-
# errors will be raised when performing read operations.
|
116
|
-
#
|
117
|
-
# This class has extremely limited seek capabilities. It is possible to
|
118
|
-
# seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
|
119
|
-
# As a result, the _pos_ and _tell_ methods also work as expected.
|
120
|
-
#
|
121
|
-
# Due to certain optimizations within IO::Like#seek and if there is data
|
122
|
-
# in the read buffer, the _seek_ method can be used to seek forward from
|
123
|
-
# the current stream position up to the end of the buffer. Unless it is
|
124
|
-
# known definitively how much data is in the buffer, it is best to avoid
|
125
|
-
# relying on this behavior.
|
126
|
-
#
|
127
|
-
# If _io_ also responds to _rewind_, then the _rewind_ method of this
|
128
|
-
# class can be used to reset the whole stream back to the beginning. Using
|
129
|
-
# _seek_ of this class to seek directly to offset <tt>0</tt> using
|
130
|
-
# <tt>IO::SEEK_SET</tt> for whence will also work in this case.
|
131
|
-
#
|
132
|
-
# Any other seeking attempts, will raise Errno::EINVAL exceptions.
|
133
|
-
#
|
134
|
-
# The _fill_size_ attribute is set to <tt>0</tt> by default under the
|
135
|
-
# assumption that _io_ is already buffered.
|
136
|
-
def initialize(io)
|
137
|
-
@io = io
|
138
|
-
|
139
|
-
# Keep track of the total number of bytes read.
|
140
|
-
@total_bytes_out = 0
|
141
|
-
|
142
|
-
# Assume that the delegate IO object is already buffered.
|
143
|
-
self.fill_size = 0
|
144
|
-
end
|
145
|
-
|
146
|
-
# Closes this object so that further write operations will fail. If
|
147
|
-
# _close_delegate_ is +true+, the delegate object used as a data source
|
148
|
-
# will also be closed using its close method.
|
149
|
-
def close(close_delegate = true)
|
150
|
-
super()
|
151
|
-
@io.close if close_delegate
|
152
|
-
end
|
153
|
-
|
154
|
-
private
|
155
|
-
|
156
|
-
# Reads and returns at most _length_ bytes from the delegate IO object.
|
157
|
-
#
|
158
|
-
# Raises EOFError if there is no data to read.
|
159
|
-
def unbuffered_read(length)
|
160
|
-
buffer = @io.read(length)
|
161
|
-
raise EOFError, 'end of file reached' if buffer.nil?
|
162
|
-
@total_bytes_out += buffer.length
|
163
|
-
|
164
|
-
buffer
|
165
|
-
end
|
166
|
-
|
167
|
-
# Allows resetting this object and the delegate object back to the
|
168
|
-
# beginning of the stream or reporting the current position in the stream.
|
169
|
-
#
|
170
|
-
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is
|
171
|
-
# either IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_
|
172
|
-
# is IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
173
|
-
# method.
|
174
|
-
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
175
|
-
unless offset == 0 &&
|
176
|
-
((whence == IO::SEEK_SET && @io.respond_to?(:rewind)) ||
|
177
|
-
whence == IO::SEEK_CUR) then
|
178
|
-
raise Errno::EINVAL
|
179
|
-
end
|
180
|
-
|
181
|
-
case whence
|
182
|
-
when IO::SEEK_SET
|
183
|
-
@io.rewind
|
184
|
-
@total_bytes_out = 0
|
185
|
-
when IO::SEEK_CUR
|
186
|
-
@total_bytes_out
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
9
|
# This method signature is part of the interface contract expected by
|
192
10
|
# Archive::Zip::Entry for encryption codec objects.
|
193
11
|
#
|
@@ -195,7 +13,8 @@ module Archive; class Zip; module Codec
|
|
195
13
|
# Archive::Zip::Codec::NullEncryption::Encrypt object using that class' open
|
196
14
|
# method.
|
197
15
|
def encryptor(io, password, &b)
|
198
|
-
|
16
|
+
return io unless block_given?
|
17
|
+
b[io]
|
199
18
|
end
|
200
19
|
|
201
20
|
# This method signature is part of the interface contract expected by
|
@@ -205,7 +24,8 @@ module Archive; class Zip; module Codec
|
|
205
24
|
# Archive::Zip::Codec::NullEncryption::Decrypt object using that class' open
|
206
25
|
# method.
|
207
26
|
def decryptor(io, password, &b)
|
208
|
-
|
27
|
+
return io unless block_given?
|
28
|
+
b[io]
|
209
29
|
end
|
210
30
|
|
211
31
|
# This method signature is part of the interface contract expected by
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'io/like_helpers/delegated_io'
|
4
|
+
|
5
|
+
require 'archive/support/zlib'
|
6
|
+
require 'archive/zip/data_descriptor'
|
7
|
+
|
8
|
+
module Archive; class Zip; module Codec; class Store
|
9
|
+
# Archive::Zip::Codec::Store::Reader is a readable, IO-like wrapper
|
10
|
+
# around a readable, IO-like object which provides a CRC32 checksum of the
|
11
|
+
# data read through it as well as the count of the total amount of data. A
|
12
|
+
# _close_ method is also provided which can optionally close the delegate
|
13
|
+
# object. In addition a convenience method is provided for generating
|
14
|
+
# DataDescriptor objects based on the data which is passed through this
|
15
|
+
# object.
|
16
|
+
#
|
17
|
+
# Instances of this class should only be accessed via the
|
18
|
+
# Archive::Zip::Codec::Store#decompressor method.
|
19
|
+
class Reader < IO::LikeHelpers::DelegatedIO
|
20
|
+
# Creates a new instance of this class using _io_ as a data source. _io_
|
21
|
+
# must be readable and provide a _read_ method as an IO instance would or
|
22
|
+
# errors will be raised when performing read operations.
|
23
|
+
#
|
24
|
+
# This class has extremely limited seek capabilities. It is possible to
|
25
|
+
# seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
|
26
|
+
# As a result, the _pos_ and _tell_ methods also work as expected.
|
27
|
+
#
|
28
|
+
# Due to certain optimizations within IO::Like#seek and if there is data
|
29
|
+
# in the read buffer, the _seek_ method can be used to seek forward from
|
30
|
+
# the current stream position up to the end of the buffer. Unless it is
|
31
|
+
# known definitively how much data is in the buffer, it is best to avoid
|
32
|
+
# relying on this behavior.
|
33
|
+
#
|
34
|
+
# If _io_ also responds to _rewind_, then the _rewind_ method of this
|
35
|
+
# class can be used to reset the whole stream back to the beginning. Using
|
36
|
+
# _seek_ of this class to seek directly to offset <tt>0</tt> using
|
37
|
+
# <tt>IO::SEEK_SET</tt> for whence will also work in this case.
|
38
|
+
#
|
39
|
+
# Any other seeking attempts, will raise Errno::EINVAL exceptions.
|
40
|
+
def initialize(delegate, autoclose: true)
|
41
|
+
super
|
42
|
+
@crc32 = 0
|
43
|
+
@uncompressed_size = 0
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns an instance of Archive::Zip::DataDescriptor with information
|
47
|
+
# regarding the data which has passed through this object from the
|
48
|
+
# delegate object. It is recommended to call the close method before
|
49
|
+
# calling this in order to ensure that no further read operations change
|
50
|
+
# the state of this object.
|
51
|
+
def data_descriptor
|
52
|
+
DataDescriptor.new(
|
53
|
+
@crc32,
|
54
|
+
@uncompressed_size,
|
55
|
+
@uncompressed_size
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns at most _length_ bytes from the delegate object. Updates the
|
60
|
+
# uncompressed_size and crc32 attributes as a side effect.
|
61
|
+
def read(length, buffer: nil, buffer_offset: 0)
|
62
|
+
result = super
|
63
|
+
return result if Symbol === result
|
64
|
+
|
65
|
+
buffer = result if buffer.nil?
|
66
|
+
@uncompressed_size += buffer.bytesize
|
67
|
+
@crc32 = Zlib.crc32(buffer, @crc32)
|
68
|
+
|
69
|
+
result
|
70
|
+
end
|
71
|
+
|
72
|
+
# Allows resetting this object and the delegate object back to the
|
73
|
+
# beginning of the stream or reporting the current position in the stream.
|
74
|
+
#
|
75
|
+
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is
|
76
|
+
# either IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_
|
77
|
+
# is IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
78
|
+
# method.
|
79
|
+
def seek(amount, whence = IO::SEEK_SET)
|
80
|
+
assert_open
|
81
|
+
raise Errno::ESPIPE if amount != 0 || whence == IO::SEEK_END
|
82
|
+
|
83
|
+
case whence
|
84
|
+
when IO::SEEK_SET
|
85
|
+
result = super
|
86
|
+
return result if Symbol === result
|
87
|
+
@crc32 = 0
|
88
|
+
@uncompressed_size = 0
|
89
|
+
result
|
90
|
+
when IO::SEEK_CUR
|
91
|
+
@uncompressed_size
|
92
|
+
else
|
93
|
+
raise Errno::EINVAL
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end; end; end; end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'io/like_helpers/delegated_io'
|
4
|
+
|
5
|
+
require 'archive/support/zlib'
|
6
|
+
require 'archive/zip/data_descriptor'
|
7
|
+
|
8
|
+
module Archive; class Zip; module Codec; class Store
|
9
|
+
# Archive::Zip::Codec::Store::Writer is simply a writable, IO-like wrapper
|
10
|
+
# around a writable, IO-like object which provides a CRC32 checksum of the
|
11
|
+
# data written through it as well as the count of the total amount of data.
|
12
|
+
# A _close_ method is also provided which can optionally close the delegate
|
13
|
+
# object. In addition a convenience method is provided for generating
|
14
|
+
# DataDescriptor objects based on the data which is passed through this
|
15
|
+
# object.
|
16
|
+
#
|
17
|
+
# Instances of this class should only be accessed via the
|
18
|
+
# Archive::Zip::Codec::Store#compressor method.
|
19
|
+
class Writer < IO::LikeHelpers::DelegatedIO
|
20
|
+
# Creates a new instance of this class using _io_ as a data sink. _io_
|
21
|
+
# must be writable and must provide a write method as IO does or errors
|
22
|
+
# will be raised when performing write operations.
|
23
|
+
def initialize(delegate, autoclose: true)
|
24
|
+
super
|
25
|
+
@crc32 = 0
|
26
|
+
@uncompressed_size = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns an instance of Archive::Zip::DataDescriptor with information
|
30
|
+
# regarding the data which has passed through this object to the delegate
|
31
|
+
# object. The close or flush methods should be called before using this
|
32
|
+
# method in order to ensure that any possibly buffered data is flushed to
|
33
|
+
# the delegate object; otherwise, the contents of the data descriptor may
|
34
|
+
# be inaccurate.
|
35
|
+
def data_descriptor
|
36
|
+
DataDescriptor.new(@crc32, @uncompressed_size, @uncompressed_size)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Allows resetting this object and the delegate object back to the
|
40
|
+
# beginning of the stream or reporting the current position in the stream.
|
41
|
+
#
|
42
|
+
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is
|
43
|
+
# either IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_
|
44
|
+
# is IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
45
|
+
# method.
|
46
|
+
def seek(amount, whence = IO::SEEK_SET)
|
47
|
+
assert_open
|
48
|
+
raise Errno::ESPIPE if amount != 0 || whence == IO::SEEK_END
|
49
|
+
|
50
|
+
case whence
|
51
|
+
when IO::SEEK_SET
|
52
|
+
result = super
|
53
|
+
return result if Symbol === result
|
54
|
+
@crc32 = 0
|
55
|
+
@uncompressed_size = 0
|
56
|
+
result
|
57
|
+
when IO::SEEK_CUR
|
58
|
+
@uncompressed_size
|
59
|
+
else
|
60
|
+
raise Errno::EINVAL
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Writes _string_ to the delegate object and returns the number of bytes
|
65
|
+
# actually written. Updates the uncompressed_size and crc32 attributes as
|
66
|
+
# a side effect.
|
67
|
+
def write(buffer, length: buffer.bytesize)
|
68
|
+
result = super
|
69
|
+
return result if Symbol === result
|
70
|
+
|
71
|
+
@uncompressed_size += result
|
72
|
+
buffer = buffer[0, result] if result < buffer.bytesize
|
73
|
+
@crc32 = Zlib.crc32(buffer, @crc32)
|
74
|
+
|
75
|
+
result
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end; end; end; end
|
@@ -1,237 +1,12 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require 'archive/
|
4
|
-
require 'archive/
|
5
|
-
require 'archive/zip/codec'
|
6
|
-
require 'archive/zip/data_descriptor'
|
3
|
+
require 'archive/zip/codec/store/reader'
|
4
|
+
require 'archive/zip/codec/store/writer'
|
7
5
|
|
8
6
|
module Archive; class Zip; module Codec
|
9
7
|
# Archive::Zip::Codec::Store is a handle for the store-unstore (no
|
10
8
|
# compression) codec.
|
11
9
|
class Store
|
12
|
-
# Archive::Zip::Codec::Store::Compress is simply a writable, IO-like wrapper
|
13
|
-
# around a writable, IO-like object which provides a CRC32 checksum of the
|
14
|
-
# data written through it as well as the count of the total amount of data.
|
15
|
-
# A _close_ method is also provided which can optionally close the delegate
|
16
|
-
# object. In addition a convenience method is provided for generating
|
17
|
-
# DataDescriptor objects based on the data which is passed through this
|
18
|
-
# object.
|
19
|
-
#
|
20
|
-
# Instances of this class should only be accessed via the
|
21
|
-
# Archive::Zip::Codec::Store#compressor method.
|
22
|
-
class Compress
|
23
|
-
include IO::Like
|
24
|
-
|
25
|
-
# Creates a new instance of this class with the given argument using #new
|
26
|
-
# and then passes the instance to the given block. The #close method is
|
27
|
-
# guaranteed to be called after the block completes.
|
28
|
-
#
|
29
|
-
# Equivalent to #new if no block is given.
|
30
|
-
def self.open(io)
|
31
|
-
store_io = new(io)
|
32
|
-
return store_io unless block_given?
|
33
|
-
|
34
|
-
begin
|
35
|
-
yield(store_io)
|
36
|
-
ensure
|
37
|
-
store_io.close unless store_io.closed?
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Creates a new instance of this class using _io_ as a data sink. _io_
|
42
|
-
# must be writable and must provide a write method as IO does or errors
|
43
|
-
# will be raised when performing write operations.
|
44
|
-
#
|
45
|
-
# The _flush_size_ attribute is set to <tt>0</tt> by default under the
|
46
|
-
# assumption that _io_ is already buffered.
|
47
|
-
def initialize(io)
|
48
|
-
@io = io
|
49
|
-
@crc32 = 0
|
50
|
-
@uncompressed_size = 0
|
51
|
-
# Assume that the delegate IO object is already buffered.
|
52
|
-
self.flush_size = 0
|
53
|
-
end
|
54
|
-
|
55
|
-
# Closes this object so that further write operations will fail. If
|
56
|
-
# _close_delegate_ is +true+, the delegate object used as a data sink will
|
57
|
-
# also be closed using its close method.
|
58
|
-
def close(close_delegate = true)
|
59
|
-
super()
|
60
|
-
@io.close if close_delegate
|
61
|
-
nil
|
62
|
-
end
|
63
|
-
|
64
|
-
# Returns an instance of Archive::Zip::DataDescriptor with information
|
65
|
-
# regarding the data which has passed through this object to the delegate
|
66
|
-
# object. The close or flush methods should be called before using this
|
67
|
-
# method in order to ensure that any possibly buffered data is flushed to
|
68
|
-
# the delegate object; otherwise, the contents of the data descriptor may
|
69
|
-
# be inaccurate.
|
70
|
-
def data_descriptor
|
71
|
-
DataDescriptor.new(
|
72
|
-
@crc32,
|
73
|
-
@uncompressed_size,
|
74
|
-
@uncompressed_size
|
75
|
-
)
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
# Allows resetting this object and the delegate object back to the
|
81
|
-
# beginning of the stream or reporting the current position in the stream.
|
82
|
-
#
|
83
|
-
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is
|
84
|
-
# either IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_
|
85
|
-
# is IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
86
|
-
# method.
|
87
|
-
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
88
|
-
unless offset == 0 &&
|
89
|
-
((whence == IO::SEEK_SET && @io.respond_to?(:rewind)) ||
|
90
|
-
whence == IO::SEEK_CUR) then
|
91
|
-
raise Errno::EINVAL
|
92
|
-
end
|
93
|
-
|
94
|
-
case whence
|
95
|
-
when IO::SEEK_SET
|
96
|
-
@io.rewind
|
97
|
-
@crc32 = 0
|
98
|
-
@uncompressed_size = 0
|
99
|
-
when IO::SEEK_CUR
|
100
|
-
@uncompressed_size
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# Writes _string_ to the delegate object and returns the number of bytes
|
105
|
-
# actually written. Updates the uncompressed_size and crc32 attributes as
|
106
|
-
# a side effect.
|
107
|
-
def unbuffered_write(string)
|
108
|
-
bytes_written = @io.write(string)
|
109
|
-
@uncompressed_size += bytes_written
|
110
|
-
@crc32 = Zlib.crc32(string.slice(0, bytes_written), @crc32)
|
111
|
-
bytes_written
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# Archive::Zip::Codec::Store::Decompress is a readable, IO-like wrapper
|
116
|
-
# around a readable, IO-like object which provides a CRC32 checksum of the
|
117
|
-
# data read through it as well as the count of the total amount of data. A
|
118
|
-
# _close_ method is also provided which can optionally close the delegate
|
119
|
-
# object. In addition a convenience method is provided for generating
|
120
|
-
# DataDescriptor objects based on the data which is passed through this
|
121
|
-
# object.
|
122
|
-
#
|
123
|
-
# Instances of this class should only be accessed via the
|
124
|
-
# Archive::Zip::Codec::Store#decompressor method.
|
125
|
-
class Decompress
|
126
|
-
include IO::Like
|
127
|
-
|
128
|
-
# Creates a new instance of this class with the given arguments using #new
|
129
|
-
# and then passes the instance to the given block. The #close method is
|
130
|
-
# guaranteed to be called after the block completes.
|
131
|
-
#
|
132
|
-
# Equivalent to #new if no block is given.
|
133
|
-
def self.open(io)
|
134
|
-
unstore_io = new(io)
|
135
|
-
return unstore_io unless block_given?
|
136
|
-
|
137
|
-
begin
|
138
|
-
yield(unstore_io)
|
139
|
-
ensure
|
140
|
-
unstore_io.close unless unstore_io.closed?
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
# Creates a new instance of this class using _io_ as a data source. _io_
|
145
|
-
# must be readable and provide a _read_ method as an IO instance would or
|
146
|
-
# errors will be raised when performing read operations.
|
147
|
-
#
|
148
|
-
# This class has extremely limited seek capabilities. It is possible to
|
149
|
-
# seek with an offset of <tt>0</tt> and a whence of <tt>IO::SEEK_CUR</tt>.
|
150
|
-
# As a result, the _pos_ and _tell_ methods also work as expected.
|
151
|
-
#
|
152
|
-
# Due to certain optimizations within IO::Like#seek and if there is data
|
153
|
-
# in the read buffer, the _seek_ method can be used to seek forward from
|
154
|
-
# the current stream position up to the end of the buffer. Unless it is
|
155
|
-
# known definitively how much data is in the buffer, it is best to avoid
|
156
|
-
# relying on this behavior.
|
157
|
-
#
|
158
|
-
# If _io_ also responds to _rewind_, then the _rewind_ method of this
|
159
|
-
# class can be used to reset the whole stream back to the beginning. Using
|
160
|
-
# _seek_ of this class to seek directly to offset <tt>0</tt> using
|
161
|
-
# <tt>IO::SEEK_SET</tt> for whence will also work in this case.
|
162
|
-
#
|
163
|
-
# Any other seeking attempts, will raise Errno::EINVAL exceptions.
|
164
|
-
#
|
165
|
-
# The _fill_size_ attribute is set to <tt>0</tt> by default under the
|
166
|
-
# assumption that _io_ is already buffered.
|
167
|
-
def initialize(io)
|
168
|
-
@io = io
|
169
|
-
@crc32 = 0
|
170
|
-
@uncompressed_size = 0
|
171
|
-
# Assume that the delegate IO object is already buffered.
|
172
|
-
self.fill_size = 0
|
173
|
-
end
|
174
|
-
|
175
|
-
# Closes this object so that further read operations will fail. If
|
176
|
-
# _close_delegate_ is +true+, the delegate object used as a data source
|
177
|
-
# will also be closed using its close method.
|
178
|
-
def close(close_delegate = true)
|
179
|
-
super()
|
180
|
-
@io.close if close_delegate
|
181
|
-
nil
|
182
|
-
end
|
183
|
-
|
184
|
-
# Returns an instance of Archive::Zip::DataDescriptor with information
|
185
|
-
# regarding the data which has passed through this object from the
|
186
|
-
# delegate object. It is recommended to call the close method before
|
187
|
-
# calling this in order to ensure that no further read operations change
|
188
|
-
# the state of this object.
|
189
|
-
def data_descriptor
|
190
|
-
DataDescriptor.new(
|
191
|
-
@crc32,
|
192
|
-
@uncompressed_size,
|
193
|
-
@uncompressed_size
|
194
|
-
)
|
195
|
-
end
|
196
|
-
|
197
|
-
private
|
198
|
-
|
199
|
-
# Returns at most _length_ bytes from the delegate object. Updates the
|
200
|
-
# uncompressed_size and crc32 attributes as a side effect.
|
201
|
-
def unbuffered_read(length)
|
202
|
-
buffer = @io.read(length)
|
203
|
-
raise EOFError, 'end of file reached' if buffer.nil?
|
204
|
-
|
205
|
-
@uncompressed_size += buffer.length
|
206
|
-
@crc32 = Zlib.crc32(buffer, @crc32)
|
207
|
-
buffer
|
208
|
-
end
|
209
|
-
|
210
|
-
# Allows resetting this object and the delegate object back to the
|
211
|
-
# beginning of the stream or reporting the current position in the stream.
|
212
|
-
#
|
213
|
-
# Raises Errno::EINVAL unless _offset_ is <tt>0</tt> and _whence_ is
|
214
|
-
# either IO::SEEK_SET or IO::SEEK_CUR. Raises Errno::EINVAL if _whence_
|
215
|
-
# is IO::SEEK_SEK and the delegate object does not respond to the _rewind_
|
216
|
-
# method.
|
217
|
-
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
218
|
-
unless offset == 0 &&
|
219
|
-
((whence == IO::SEEK_SET && @io.respond_to?(:rewind)) ||
|
220
|
-
whence == IO::SEEK_CUR) then
|
221
|
-
raise Errno::EINVAL
|
222
|
-
end
|
223
|
-
|
224
|
-
case whence
|
225
|
-
when IO::SEEK_SET
|
226
|
-
@io.rewind
|
227
|
-
@crc32 = 0
|
228
|
-
@uncompressed_size = 0
|
229
|
-
when IO::SEEK_CUR
|
230
|
-
@uncompressed_size
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
10
|
# The numeric identifier assigned to this compresion codec by the ZIP
|
236
11
|
# specification.
|
237
12
|
ID = 0
|
@@ -250,20 +25,20 @@ module Archive; class Zip; module Codec
|
|
250
25
|
# This method signature is part of the interface contract expected by
|
251
26
|
# Archive::Zip::Entry for compression codec objects.
|
252
27
|
#
|
253
|
-
# A convenience method for creating an Archive::Zip::Codec::Store::
|
28
|
+
# A convenience method for creating an Archive::Zip::Codec::Store::Writer
|
254
29
|
# object using that class' open method.
|
255
30
|
def compressor(io, &b)
|
256
|
-
|
31
|
+
Writer.open(io, &b)
|
257
32
|
end
|
258
33
|
|
259
34
|
# This method signature is part of the interface contract expected by
|
260
35
|
# Archive::Zip::Entry for compression codec objects.
|
261
36
|
#
|
262
37
|
# A convenience method for creating an
|
263
|
-
# Archive::Zip::Codec::Store::
|
38
|
+
# Archive::Zip::Codec::Store::Reader object using that class' open
|
264
39
|
# method.
|
265
40
|
def decompressor(io, &b)
|
266
|
-
|
41
|
+
Reader.open(io, &b)
|
267
42
|
end
|
268
43
|
|
269
44
|
# This method signature is part of the interface contract expected by
|