archive-zip 0.1.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.
- data/CONTRIBUTORS +13 -0
- data/GPL +676 -0
- data/HACKING +122 -0
- data/LEGAL +8 -0
- data/LICENSE +57 -0
- data/MANIFEST +26 -0
- data/NEWS +22 -0
- data/README +130 -0
- data/lib/archive/support/io-like.rb +12 -0
- data/lib/archive/support/io.rb +14 -0
- data/lib/archive/support/iowindow.rb +123 -0
- data/lib/archive/support/stringio.rb +22 -0
- data/lib/archive/support/time.rb +85 -0
- data/lib/archive/support/zlib.rb +211 -0
- data/lib/archive/zip.rb +643 -0
- data/lib/archive/zip/codec.rb +30 -0
- data/lib/archive/zip/codec/deflate.rb +206 -0
- data/lib/archive/zip/codec/store.rb +241 -0
- data/lib/archive/zip/datadescriptor.rb +54 -0
- data/lib/archive/zip/entry.rb +991 -0
- data/lib/archive/zip/error.rb +22 -0
- data/lib/archive/zip/extrafield.rb +23 -0
- data/lib/archive/zip/extrafield/extendedtimestamp.rb +101 -0
- data/lib/archive/zip/extrafield/raw.rb +32 -0
- data/lib/archive/zip/extrafield/unix.rb +101 -0
- data/test/test_archive.rb +8 -0
- metadata +98 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
module Archive; class Zip
|
2
|
+
# Archive::Zip::Codec is a factory class for generating codec object instances
|
3
|
+
# based on the compression method and general purpose flag fields of ZIP
|
4
|
+
# entries. When adding a new codec, add a mapping in the _CODECS_ constant
|
5
|
+
# from the compression method field value reserved for the codec in the ZIP
|
6
|
+
# specification to the class implementing the codec. See the implementations
|
7
|
+
# of Archive::Zip::Codec::Deflate and Archive::Zip::Codec::Store for details
|
8
|
+
# on implementing custom codecs.
|
9
|
+
module Codec
|
10
|
+
# A Hash mapping compression methods to codec implementations. New codecs
|
11
|
+
# must add a mapping here when defined in order to be used.
|
12
|
+
CODECS = {}
|
13
|
+
|
14
|
+
# Returns a new codec instance based on _compression_method_ and
|
15
|
+
# _general_purpose_flags_.
|
16
|
+
def self.create(compression_method, general_purpose_flags)
|
17
|
+
CODECS[compression_method].new(general_purpose_flags)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns +true+ if _compression_method_ is mapped to a codec, +false+
|
21
|
+
# otherwise.
|
22
|
+
def self.supported?(compression_method)
|
23
|
+
CODECS.has_key?(compression_method)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end; end
|
27
|
+
|
28
|
+
# Load the standard codecs.
|
29
|
+
require 'archive/zip/codec/deflate'
|
30
|
+
require 'archive/zip/codec/store'
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'archive/support/zlib'
|
2
|
+
require 'archive/zip/codec'
|
3
|
+
require 'archive/zip/datadescriptor'
|
4
|
+
|
5
|
+
module Archive; class Zip; module Codec
|
6
|
+
# Archive::Zip::Codec::Deflate is a handle for the deflate-inflate codec as
|
7
|
+
# defined in Zlib which provides convenient interfaces for writing and reading
|
8
|
+
# deflated streams.
|
9
|
+
class Deflate
|
10
|
+
# Archive::Zip::Codec::Deflate::Deflate extends Zlib::ZWriter in order to
|
11
|
+
# specify the standard Zlib options required by ZIP archives and to provide
|
12
|
+
# a close method which can optionally close the delegate IO-like object. In
|
13
|
+
# addition a convenience method is provided for generating DataDescriptor
|
14
|
+
# objects based on the data which is passed through this object.
|
15
|
+
#
|
16
|
+
# Instances of this class should only be accessed via the
|
17
|
+
# Archive::Zip::Codec::Deflate#compressor method.
|
18
|
+
class Deflate < Zlib::ZWriter
|
19
|
+
# Creates a new instance of this class with the given arguments using #new
|
20
|
+
# and then passes the instance to the given block. The #close method is
|
21
|
+
# guaranteed to be called after the block completes.
|
22
|
+
#
|
23
|
+
# Equivalent to #new if no block is given.
|
24
|
+
def self.open(io, compression_level)
|
25
|
+
deflate_io = new(io, compression_level)
|
26
|
+
return deflate_io unless block_given?
|
27
|
+
|
28
|
+
begin
|
29
|
+
yield(deflate_io)
|
30
|
+
ensure
|
31
|
+
deflate_io.close unless deflate_io.closed?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates a new instance of this class using _io_ as a data sink. _io_
|
36
|
+
# must be writable and must provide a _write_ method as IO does or errors
|
37
|
+
# will be raised when performing write operations. _compression_level_
|
38
|
+
# must be one of Zlib::DEFAULT_COMPRESSION, Zlib::BEST_COMPRESSION,
|
39
|
+
# Zlib::BEST_SPEED, or Zlib::NO_COMPRESSION and specifies the amount of
|
40
|
+
# compression to be applied to the data stream.
|
41
|
+
def initialize(io, compression_level)
|
42
|
+
super(io, compression_level, -Zlib::MAX_WBITS)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Closes this object so that further write operations will fail. If
|
46
|
+
# _close_delegate_ is +true+, the delegate object used as a data sink will
|
47
|
+
# also be closed using its close method.
|
48
|
+
def close(close_delegate = true)
|
49
|
+
super()
|
50
|
+
delegate.close if close_delegate
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns an instance of Archive::Zip::Entry::DataDescriptor with
|
54
|
+
# information regarding the data which has passed through this object to
|
55
|
+
# the delegate object. The close or flush methods should be called before
|
56
|
+
# using this method in order to ensure that any possibly buffered data is
|
57
|
+
# flushed to the delegate object; otherwise, the contents of the data
|
58
|
+
# descriptor may be inaccurate.
|
59
|
+
def data_descriptor
|
60
|
+
DataDescriptor.new(crc32, compressed_size, uncompressed_size)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Archive::Zip::Codec::Deflate::Inflate extends Zlib::ZReader in order to
|
65
|
+
# specify the standard Zlib options required by ZIP archives and to provide
|
66
|
+
# a close method which can optionally close the delegate IO-like object. In
|
67
|
+
# addition a convenience method is provided for generating DataDescriptor
|
68
|
+
# objects based on the data which is passed through this object.
|
69
|
+
#
|
70
|
+
# Instances of this class should only be accessed via the
|
71
|
+
# Archive::Zip::Codec::Deflate#decompressor method.
|
72
|
+
class Inflate < Zlib::ZReader
|
73
|
+
# Creates a new instance of this class with the given arguments using #new
|
74
|
+
# and then passes the instance to the given block. The #close method is
|
75
|
+
# guaranteed to be called after the block completes.
|
76
|
+
#
|
77
|
+
# Equivalent to #new if no block is given.
|
78
|
+
def self.open(io)
|
79
|
+
inflate_io = new(io)
|
80
|
+
return inflate_io unless block_given?
|
81
|
+
|
82
|
+
begin
|
83
|
+
yield(inflate_io)
|
84
|
+
ensure
|
85
|
+
inflate_io.close unless inflate_io.closed?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Creates a new instance of this class using _io_ as a data source. _io_
|
90
|
+
# must be readable and provide a _read_ method as IO does or errors will
|
91
|
+
# be raised when performing read operations. If _io_ provides a _rewind_
|
92
|
+
# method, this class' _rewind_ method will be enabled.
|
93
|
+
def initialize(io)
|
94
|
+
super(io, -Zlib::MAX_WBITS)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Closes this object so that further read operations will fail. If
|
98
|
+
# _close_delegate_ is +true+, the delegate object used as a data source
|
99
|
+
# will also be closed using its close method.
|
100
|
+
def close(close_delegate = true)
|
101
|
+
super()
|
102
|
+
delegate.close if close_delegate
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns an instance of Archive::Zip::Entry::DataDescriptor with
|
106
|
+
# information regarding the data which has passed through this object
|
107
|
+
# from the delegate object. It is recommended to call the close method
|
108
|
+
# before calling this in order to ensure that no further read operations
|
109
|
+
# change the state of this object.
|
110
|
+
def data_descriptor
|
111
|
+
DataDescriptor.new(crc32, compressed_size, uncompressed_size)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# The numeric identifier assigned to this codec by the ZIP specification.
|
116
|
+
ID = 8
|
117
|
+
|
118
|
+
# Register this codec.
|
119
|
+
CODECS[ID] = self
|
120
|
+
|
121
|
+
# A bit mask used to denote that Zlib's default compression level should be
|
122
|
+
# used.
|
123
|
+
NORMAL = 0b000
|
124
|
+
# A bit mask used to denote that Zlib's highest/slowest compression level
|
125
|
+
# should be used.
|
126
|
+
MAXIMUM = 0b010
|
127
|
+
# A bit mask used to denote that Zlib's lowest/fastest compression level
|
128
|
+
# should be used.
|
129
|
+
FAST = 0b100
|
130
|
+
# A bit mask used to denote that Zlib should not compress data at all.
|
131
|
+
SUPER_FAST = 0b110
|
132
|
+
|
133
|
+
# This method signature is part of the interface contract expected by
|
134
|
+
# Archive::Zip::Entry for codec objects.
|
135
|
+
#
|
136
|
+
# Creates a new instance of this class using bits 1 and 2 of
|
137
|
+
# _general_purpose_flags_ to select a compression level to be used by
|
138
|
+
# #compressor to set up a compression IO object. The constants NORMAL,
|
139
|
+
# MAXIMUM, FAST, and SUPER_FAST can be used for _general_purpose_flags_ to
|
140
|
+
# manually set the compression level.
|
141
|
+
def initialize(general_purpose_flags = NORMAL)
|
142
|
+
@compression_level = general_purpose_flags & 0b110
|
143
|
+
@zlib_compression_level = case @compression_level
|
144
|
+
when NORMAL
|
145
|
+
Zlib::DEFAULT_COMPRESSION
|
146
|
+
when MAXIMUM
|
147
|
+
Zlib::BEST_COMPRESSION
|
148
|
+
when FAST
|
149
|
+
Zlib::BEST_SPEED
|
150
|
+
when SUPER_FAST
|
151
|
+
Zlib::NO_COMPRESSION
|
152
|
+
else
|
153
|
+
raise Error, 'Invalid compression level'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# This method signature is part of the interface contract expected by
|
158
|
+
# Archive::Zip::Entry for codec objects.
|
159
|
+
#
|
160
|
+
# A convenience method for creating an Archive::Zip::Codec::Deflate::Deflate
|
161
|
+
# object using that class' open method. The compression level for the open
|
162
|
+
# method is pulled from the value of the _general_purpose_flags_ argument of
|
163
|
+
# new.
|
164
|
+
def compressor(io, &b)
|
165
|
+
Deflate.open(io, @zlib_compression_level, &b)
|
166
|
+
end
|
167
|
+
|
168
|
+
# This method signature is part of the interface contract expected by
|
169
|
+
# Archive::Zip::Entry for codec objects.
|
170
|
+
#
|
171
|
+
# A convenience method for creating an Archive::Zip::Codec::Deflate::Inflate
|
172
|
+
# object using that class' open method.
|
173
|
+
def decompressor(io, &b)
|
174
|
+
Inflate.open(io, &b)
|
175
|
+
end
|
176
|
+
|
177
|
+
# This method signature is part of the interface contract expected by
|
178
|
+
# Archive::Zip::Entry for codec objects.
|
179
|
+
#
|
180
|
+
# Returns an integer which indicates the version of the official ZIP
|
181
|
+
# specification which introduced support for this codec.
|
182
|
+
def version_needed_to_extract
|
183
|
+
0x0014
|
184
|
+
end
|
185
|
+
|
186
|
+
# This method signature is part of the interface contract expected by
|
187
|
+
# Archive::Zip::Entry for codec objects.
|
188
|
+
#
|
189
|
+
# Returns an integer used to flag that this codec is used for a particular
|
190
|
+
# ZIP archive entry.
|
191
|
+
def compression_method
|
192
|
+
ID
|
193
|
+
end
|
194
|
+
|
195
|
+
# This method signature is part of the interface contract expected by
|
196
|
+
# Archive::Zip::Entry for codec objects.
|
197
|
+
#
|
198
|
+
# Returns an integer representing the general purpose flags of a ZIP archive
|
199
|
+
# entry where bits 1 and 2 are set according to the compression level
|
200
|
+
# selected for this object. All other bits are zero'd out.
|
201
|
+
def general_purpose_flags
|
202
|
+
@compression_level
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end; end; end
|
206
|
+
|
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'archive/support/io-like'
|
2
|
+
require 'archive/zip/codec'
|
3
|
+
require 'archive/zip/datadescriptor'
|
4
|
+
|
5
|
+
module Archive; class Zip; module Codec
|
6
|
+
# Archive::Zip::Codec::Store is a handle for the store-unstore (no
|
7
|
+
# compression) codec.
|
8
|
+
class Store
|
9
|
+
# Archive::Zip::Codec::Store::Store 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
|
+
class Store
|
17
|
+
include IO::Like
|
18
|
+
|
19
|
+
# Creates a new instance of this class with the given argument using #new
|
20
|
+
# and then passes the instance to the given block. The #close method is
|
21
|
+
# guaranteed to be called after the block completes.
|
22
|
+
#
|
23
|
+
# Equivalent to #new if no block is given.
|
24
|
+
def self.open(io)
|
25
|
+
store_io = new(io)
|
26
|
+
return store_io unless block_given?
|
27
|
+
|
28
|
+
begin
|
29
|
+
yield(store_io)
|
30
|
+
ensure
|
31
|
+
store_io.close unless store_io.closed?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Creates a new instance of this class using _io_ as a data sink. _io_
|
36
|
+
# must be writable and must provide a write method as IO does or errors
|
37
|
+
# will be raised when performing write operations.
|
38
|
+
#
|
39
|
+
# The _flush_size_ attribute is set to +0+ by default under the assumption
|
40
|
+
# that _io_ is already buffered.
|
41
|
+
def initialize(io)
|
42
|
+
@io = io
|
43
|
+
@crc32 = 0
|
44
|
+
@uncompressed_size = 0
|
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
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns an instance of Archive::Zip::Entry::DataDescriptor with
|
59
|
+
# information regarding the data which has passed through this object to
|
60
|
+
# the delegate object. The close or flush methods should be called before
|
61
|
+
# using this method in order to ensure that any possibly buffered data is
|
62
|
+
# flushed to the delegate object; otherwise, the contents of the data
|
63
|
+
# descriptor may be inaccurate.
|
64
|
+
def data_descriptor
|
65
|
+
DataDescriptor.new(
|
66
|
+
@crc32,
|
67
|
+
@uncompressed_size,
|
68
|
+
@uncompressed_size
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Writes _string_ to the delegate object and returns the number of bytes
|
75
|
+
# actually written. Updates the uncompressed_size and crc32 attributes as
|
76
|
+
# a side effect.
|
77
|
+
def unbuffered_write(string)
|
78
|
+
bytes_written = @io.write(string)
|
79
|
+
@uncompressed_size += bytes_written
|
80
|
+
@crc32 = Zlib.crc32(string.slice(0, bytes_written), @crc32)
|
81
|
+
bytes_written
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Archive::Zip::Codec::Store::Unstore is a readable, IO-like wrapper around
|
86
|
+
# a readable, IO-like object which provides a CRC32 checksum of the data
|
87
|
+
# read through it as well as the count of the total amount of data. A
|
88
|
+
# #close method is also provided which can optionally close the delegate
|
89
|
+
# object. In addition a convenience method is provided for generating
|
90
|
+
# DataDescriptor objects based on the data which is passed through this
|
91
|
+
# object.
|
92
|
+
class Unstore
|
93
|
+
include IO::Like
|
94
|
+
|
95
|
+
# Creates a new instance of this class with the given arguments using #new
|
96
|
+
# and then passes the instance to the given block. The #close method is
|
97
|
+
# guaranteed to be called after the block completes.
|
98
|
+
#
|
99
|
+
# Equivalent to #new if no block is given.
|
100
|
+
def self.open(io)
|
101
|
+
unstore_io = new(io)
|
102
|
+
return unstore_io unless block_given?
|
103
|
+
|
104
|
+
begin
|
105
|
+
yield(unstore_io)
|
106
|
+
ensure
|
107
|
+
unstore_io.close unless unstore_io.closed?
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Creates a new instance of this class using _io_ as a data source. _io_
|
112
|
+
# must be readable and provide a read method as IO does or errors will be
|
113
|
+
# raised when performing read operations. If _io_ provides a rewind
|
114
|
+
# method, this class' rewind method will be enabled.
|
115
|
+
#
|
116
|
+
# The _fill_size_ attribute is set to +0+ by default under the assumption
|
117
|
+
# that _io_ is already buffered.
|
118
|
+
def initialize(io)
|
119
|
+
@io = io
|
120
|
+
@crc32 = 0
|
121
|
+
@uncompressed_size = 0
|
122
|
+
# Assume that the delegate IO object is already buffered.
|
123
|
+
self.fill_size = 0
|
124
|
+
end
|
125
|
+
|
126
|
+
# Closes this object so that further read operations will fail. If
|
127
|
+
# _close_delegate_ is +true+, the delegate object used as a data source
|
128
|
+
# will also be closed using its close method.
|
129
|
+
def close(close_delegate = true)
|
130
|
+
super()
|
131
|
+
@io.close if close_delegate
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns an instance of Archive::Zip::Entry::DataDescriptor with
|
136
|
+
# information regarding the data which has passed through this object
|
137
|
+
# from the delegate object. It is recommended to call the close method
|
138
|
+
# before calling this in order to ensure that no further read operations
|
139
|
+
# change the state of this object.
|
140
|
+
def data_descriptor
|
141
|
+
DataDescriptor.new(
|
142
|
+
@crc32,
|
143
|
+
@uncompressed_size,
|
144
|
+
@uncompressed_size
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
# Returns at most _length_ bytes from the delegate object. Updates the
|
151
|
+
# uncompressed_size and crc32 attributes as a side effect.
|
152
|
+
def unbuffered_read(length)
|
153
|
+
buffer = @io.read(length)
|
154
|
+
if buffer.nil? then
|
155
|
+
raise EOFError, 'end of file reached'
|
156
|
+
else
|
157
|
+
@uncompressed_size += buffer.length
|
158
|
+
@crc32 = Zlib.crc32(buffer, @crc32)
|
159
|
+
end
|
160
|
+
buffer
|
161
|
+
end
|
162
|
+
|
163
|
+
# Allows resetting this object and the delegate object back to the
|
164
|
+
# beginning of the stream. _offset_ must be +0+ and _whence_ must be
|
165
|
+
# IO::SEEK_SET or an error will be raised. The delegate object must
|
166
|
+
# respond to the _rewind_ method or an error will be raised. The
|
167
|
+
# uncompressed_size and crc32 attributes are reinitialized as a side
|
168
|
+
# effect.
|
169
|
+
def unbuffered_seek(offset, whence = IO::SEEK_SET)
|
170
|
+
unless offset == 0 && whence == IO::SEEK_SET then
|
171
|
+
raise Errno::EINVAL, 'Invalid argument'
|
172
|
+
end
|
173
|
+
unless @io.respond_to?(:rewind) then
|
174
|
+
raise Errno::ESPIPE, 'Illegal seek'
|
175
|
+
end
|
176
|
+
@io.rewind
|
177
|
+
@crc32 = 0
|
178
|
+
@uncompressed_size = 0
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# The numeric identifier assigned to this codec by the ZIP specification.
|
183
|
+
ID = 0
|
184
|
+
|
185
|
+
# Register this codec.
|
186
|
+
CODECS[ID] = self
|
187
|
+
|
188
|
+
# This method signature is part of the interface contract expected by
|
189
|
+
# Archive::Zip::Entry for codec objects.
|
190
|
+
#
|
191
|
+
# Creates a new instance of this class. _general_purpose_flags_ is not
|
192
|
+
# used.
|
193
|
+
def initialize(general_purpose_flags = 0)
|
194
|
+
end
|
195
|
+
|
196
|
+
# This method signature is part of the interface contract expected by
|
197
|
+
# Archive::Zip::Entry for codec objects.
|
198
|
+
#
|
199
|
+
# A convenience method for creating an Archive::Zip::Codec::Store::Store
|
200
|
+
# object using that class' open method.
|
201
|
+
def compressor(io, &b)
|
202
|
+
Store.open(io, &b)
|
203
|
+
end
|
204
|
+
|
205
|
+
# This method signature is part of the interface contract expected by
|
206
|
+
# Archive::Zip::Entry for codec objects.
|
207
|
+
#
|
208
|
+
# A convenience method for creating an Archive::Zip::Codec::Store::Unstore
|
209
|
+
# object using that class' open method.
|
210
|
+
def decompressor(io, &b)
|
211
|
+
Unstore.open(io, &b)
|
212
|
+
end
|
213
|
+
|
214
|
+
# This method signature is part of the interface contract expected by
|
215
|
+
# Archive::Zip::Entry for codec objects.
|
216
|
+
#
|
217
|
+
# Returns an integer which indicates the version of the official ZIP
|
218
|
+
# specification which introduced support for this codec.
|
219
|
+
def version_needed_to_extract
|
220
|
+
0x000a
|
221
|
+
end
|
222
|
+
|
223
|
+
# This method signature is part of the interface contract expected by
|
224
|
+
# Archive::Zip::Entry for codec objects.
|
225
|
+
#
|
226
|
+
# Returns an integer used to flag that this codec is used for a particular
|
227
|
+
# ZIP archive entry.
|
228
|
+
def compression_method
|
229
|
+
ID
|
230
|
+
end
|
231
|
+
|
232
|
+
# This method signature is part of the interface contract expected by
|
233
|
+
# Archive::Zip::Entry for codec objects.
|
234
|
+
#
|
235
|
+
# Returns +0+ since this codec does not make use of general purpose flags of
|
236
|
+
# ZIP archive entries.
|
237
|
+
def general_purpose_flags
|
238
|
+
0
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end; end; end
|