rubyzip 0.9.1 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +354 -0
  3. data/Rakefile +15 -104
  4. data/TODO +0 -1
  5. data/lib/zip/central_directory.rb +212 -0
  6. data/lib/zip/compressor.rb +9 -0
  7. data/lib/zip/constants.rb +115 -0
  8. data/lib/zip/crypto/decrypted_io.rb +40 -0
  9. data/lib/zip/crypto/encryption.rb +11 -0
  10. data/lib/zip/crypto/null_encryption.rb +43 -0
  11. data/lib/zip/crypto/traditional_encryption.rb +99 -0
  12. data/lib/zip/decompressor.rb +31 -0
  13. data/lib/zip/deflater.rb +34 -0
  14. data/lib/zip/dos_time.rb +53 -0
  15. data/lib/zip/entry.rb +719 -0
  16. data/lib/zip/entry_set.rb +88 -0
  17. data/lib/zip/errors.rb +19 -0
  18. data/lib/zip/extra_field/generic.rb +44 -0
  19. data/lib/zip/extra_field/ntfs.rb +94 -0
  20. data/lib/zip/extra_field/old_unix.rb +46 -0
  21. data/lib/zip/extra_field/universal_time.rb +77 -0
  22. data/lib/zip/extra_field/unix.rb +39 -0
  23. data/lib/zip/extra_field/zip64.rb +70 -0
  24. data/lib/zip/extra_field/zip64_placeholder.rb +15 -0
  25. data/lib/zip/extra_field.rb +103 -0
  26. data/lib/zip/file.rb +468 -0
  27. data/lib/zip/filesystem.rb +643 -0
  28. data/lib/zip/inflater.rb +54 -0
  29. data/lib/zip/input_stream.rb +180 -0
  30. data/lib/zip/ioextras/abstract_input_stream.rb +122 -0
  31. data/lib/zip/ioextras/abstract_output_stream.rb +43 -0
  32. data/lib/zip/ioextras.rb +21 -140
  33. data/lib/zip/null_compressor.rb +15 -0
  34. data/lib/zip/null_decompressor.rb +19 -0
  35. data/lib/zip/null_input_stream.rb +10 -0
  36. data/lib/zip/output_stream.rb +198 -0
  37. data/lib/zip/pass_thru_compressor.rb +23 -0
  38. data/lib/zip/pass_thru_decompressor.rb +31 -0
  39. data/lib/zip/streamable_directory.rb +15 -0
  40. data/lib/zip/streamable_stream.rb +52 -0
  41. data/lib/zip/version.rb +3 -0
  42. data/lib/zip.rb +72 -0
  43. data/samples/example.rb +44 -32
  44. data/samples/example_filesystem.rb +16 -19
  45. data/samples/example_recursive.rb +54 -0
  46. data/samples/gtk_ruby_zip.rb +84 -0
  47. data/samples/qtzip.rb +25 -34
  48. data/samples/write_simple.rb +10 -13
  49. data/samples/zipfind.rb +38 -45
  50. metadata +182 -91
  51. data/ChangeLog +0 -1504
  52. data/NEWS +0 -144
  53. data/README +0 -72
  54. data/install.rb +0 -22
  55. data/lib/download_quizzes.rb +0 -119
  56. data/lib/quiz1/t/solutions/Bill Guindon/solitaire.rb +0 -205
  57. data/lib/quiz1/t/solutions/Carlos/solitaire.rb +0 -111
  58. data/lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb +0 -111
  59. data/lib/quiz1/t/solutions/Florian Gross/solitaire.rb +0 -301
  60. data/lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb +0 -268
  61. data/lib/quiz1/t/solutions/James Edward Gray II/solitaire.rb +0 -132
  62. data/lib/quiz1/t/solutions/Jamis Buck/bin/main.rb +0 -13
  63. data/lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb +0 -230
  64. data/lib/quiz1/t/solutions/Jamis Buck/lib/cli.rb +0 -24
  65. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_deck.rb +0 -30
  66. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_key-stream.rb +0 -19
  67. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_keying-algorithms.rb +0 -31
  68. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_solitaire-cipher.rb +0 -66
  69. data/lib/quiz1/t/solutions/Jamis Buck/test/tc_unkeyed-algorithm.rb +0 -17
  70. data/lib/quiz1/t/solutions/Jamis Buck/test/tests.rb +0 -2
  71. data/lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb +0 -204
  72. data/lib/quiz1/t/solutions/Jim Menard/test.rb +0 -47
  73. data/lib/quiz1/t/solutions/Moses Hohman/cipher.rb +0 -97
  74. data/lib/quiz1/t/solutions/Moses Hohman/deck.rb +0 -140
  75. data/lib/quiz1/t/solutions/Moses Hohman/solitaire.rb +0 -14
  76. data/lib/quiz1/t/solutions/Moses Hohman/test_cipher.rb +0 -68
  77. data/lib/quiz1/t/solutions/Moses Hohman/test_deck.rb +0 -146
  78. data/lib/quiz1/t/solutions/Moses Hohman/test_util.rb +0 -38
  79. data/lib/quiz1/t/solutions/Moses Hohman/testsuite.rb +0 -5
  80. data/lib/quiz1/t/solutions/Moses Hohman/util.rb +0 -27
  81. data/lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb +0 -151
  82. data/lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb +0 -198
  83. data/lib/zip/stdrubyext.rb +0 -111
  84. data/lib/zip/tempfile_bugfixed.rb +0 -195
  85. data/lib/zip/zip.rb +0 -1847
  86. data/lib/zip/zipfilesystem.rb +0 -609
  87. data/lib/zip/ziprequire.rb +0 -90
  88. data/samples/gtkRubyzip.rb +0 -86
  89. data/test/alltests.rb +0 -9
  90. data/test/data/file1.txt +0 -46
  91. data/test/data/file1.txt.deflatedData +0 -0
  92. data/test/data/file2.txt +0 -1504
  93. data/test/data/notzippedruby.rb +0 -7
  94. data/test/data/rubycode.zip +0 -0
  95. data/test/data/rubycode2.zip +0 -0
  96. data/test/data/testDirectory.bin +0 -0
  97. data/test/data/zipWithDirs.zip +0 -0
  98. data/test/gentestfiles.rb +0 -157
  99. data/test/ioextrastest.rb +0 -208
  100. data/test/stdrubyexttest.rb +0 -52
  101. data/test/zipfilesystemtest.rb +0 -831
  102. data/test/ziprequiretest.rb +0 -43
  103. data/test/ziptest.rb +0 -1599
@@ -0,0 +1,212 @@
1
+ module Zip
2
+ class CentralDirectory
3
+ include Enumerable
4
+
5
+ END_OF_CDS = 0x06054b50
6
+ ZIP64_END_OF_CDS = 0x06064b50
7
+ ZIP64_EOCD_LOCATOR = 0x07064b50
8
+ MAX_END_OF_CDS_SIZE = 65_536 + 18
9
+ STATIC_EOCD_SIZE = 22
10
+
11
+ attr_reader :comment
12
+
13
+ # Returns an Enumerable containing the entries.
14
+ def entries
15
+ @entry_set.entries
16
+ end
17
+
18
+ def initialize(entries = EntrySet.new, comment = '') #:nodoc:
19
+ super()
20
+ @entry_set = entries.kind_of?(EntrySet) ? entries : EntrySet.new(entries)
21
+ @comment = comment
22
+ end
23
+
24
+ def write_to_stream(io) #:nodoc:
25
+ cdir_offset = io.tell
26
+ @entry_set.each { |entry| entry.write_c_dir_entry(io) }
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)
38
+ end
39
+
40
+ def write_e_o_c_d(io, offset, cdir_size) #:nodoc:
41
+ tmp = [
42
+ END_OF_CDS,
43
+ 0, # @numberOfThisDisk
44
+ 0, # @numberOfDiskWithStartOfCDir
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
50
+ ]
51
+ io << tmp.pack('VvvvvVVv')
52
+ io << @comment
53
+ end
54
+
55
+ private :write_e_o_c_d
56
+
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')
83
+ end
84
+
85
+ private :write_64_eocd_locator
86
+
87
+ def read_64_e_o_c_d(buf) #:nodoc:
88
+ buf = get_64_e_o_c_d(buf)
89
+ @size_of_zip64_e_o_c_d = Entry.read_zip_64_long(buf)
90
+ @version_made_by = Entry.read_zip_short(buf)
91
+ @version_needed_for_extract = Entry.read_zip_short(buf)
92
+ @number_of_this_disk = Entry.read_zip_long(buf)
93
+ @number_of_disk_with_start_of_cdir = Entry.read_zip_long(buf)
94
+ @total_number_of_entries_in_cdir_on_this_disk = Entry.read_zip_64_long(buf)
95
+ @size = Entry.read_zip_64_long(buf)
96
+ @size_in_bytes = Entry.read_zip_64_long(buf)
97
+ @cdir_offset = Entry.read_zip_64_long(buf)
98
+ @zip_64_extensible = buf.slice!(0, buf.bytesize)
99
+ raise Error, 'Zip consistency problem while reading eocd structure' unless buf.empty?
100
+ end
101
+
102
+ def read_e_o_c_d(buf) #:nodoc:
103
+ buf = get_e_o_c_d(buf)
104
+ @number_of_this_disk = Entry.read_zip_short(buf)
105
+ @number_of_disk_with_start_of_cdir = Entry.read_zip_short(buf)
106
+ @total_number_of_entries_in_cdir_on_this_disk = Entry.read_zip_short(buf)
107
+ @size = Entry.read_zip_short(buf)
108
+ @size_in_bytes = Entry.read_zip_long(buf)
109
+ @cdir_offset = Entry.read_zip_long(buf)
110
+ comment_length = Entry.read_zip_short(buf)
111
+ @comment = if comment_length.to_i <= 0
112
+ buf.slice!(0, buf.size)
113
+ else
114
+ buf.read(comment_length)
115
+ end
116
+ raise Error, 'Zip consistency problem while reading eocd structure' unless buf.empty?
117
+ end
118
+
119
+ def read_central_directory_entries(io) #:nodoc:
120
+ begin
121
+ io.seek(@cdir_offset, IO::SEEK_SET)
122
+ rescue Errno::EINVAL
123
+ raise Error, 'Zip consistency problem while reading central directory entry'
124
+ end
125
+ @entry_set = EntrySet.new
126
+ @size.times do
127
+ @entry_set << Entry.read_c_dir_entry(io)
128
+ end
129
+ end
130
+
131
+ def read_from_stream(io) #:nodoc:
132
+ buf = start_buf(io)
133
+ if zip64_file?(buf)
134
+ read_64_e_o_c_d(buf)
135
+ else
136
+ read_e_o_c_d(buf)
137
+ end
138
+ read_central_directory_entries(io)
139
+ end
140
+
141
+ def get_e_o_c_d(buf) #:nodoc:
142
+ sig_index = buf.rindex([END_OF_CDS].pack('V'))
143
+ raise Error, 'Zip end of central directory signature not found' unless sig_index
144
+
145
+ buf = buf.slice!((sig_index + 4)..(buf.bytesize))
146
+
147
+ def buf.read(count)
148
+ slice!(0, count)
149
+ end
150
+
151
+ buf
152
+ end
153
+
154
+ def zip64_file?(buf)
155
+ buf.rindex([ZIP64_END_OF_CDS].pack('V')) && buf.rindex([ZIP64_EOCD_LOCATOR].pack('V'))
156
+ end
157
+
158
+ def start_buf(io)
159
+ begin
160
+ io.seek(-MAX_END_OF_CDS_SIZE, IO::SEEK_END)
161
+ rescue Errno::EINVAL
162
+ io.seek(0, IO::SEEK_SET)
163
+ end
164
+ io.read
165
+ end
166
+
167
+ def get_64_e_o_c_d(buf) #:nodoc:
168
+ zip_64_start = buf.rindex([ZIP64_END_OF_CDS].pack('V'))
169
+ raise Error, 'Zip64 end of central directory signature not found' unless zip_64_start
170
+
171
+ zip_64_locator = buf.rindex([ZIP64_EOCD_LOCATOR].pack('V'))
172
+ raise Error, 'Zip64 end of central directory signature locator not found' unless zip_64_locator
173
+
174
+ buf = buf.slice!((zip_64_start + 4)..zip_64_locator)
175
+
176
+ def buf.read(count)
177
+ slice!(0, count)
178
+ end
179
+
180
+ buf
181
+ end
182
+
183
+ # For iterating over the entries.
184
+ def each(&a_proc)
185
+ @entry_set.each(&a_proc)
186
+ end
187
+
188
+ # Returns the number of entries in the central directory (and
189
+ # consequently in the zip archive).
190
+ def size
191
+ @entry_set.size
192
+ end
193
+
194
+ def self.read_from_stream(io) #:nodoc:
195
+ cdir = new
196
+ cdir.read_from_stream(io)
197
+ cdir
198
+ rescue Error
199
+ nil
200
+ end
201
+
202
+ def ==(other) #:nodoc:
203
+ return false unless other.kind_of?(CentralDirectory)
204
+
205
+ @entry_set.entries.sort == other.entries.sort && comment == other.comment
206
+ end
207
+ end
208
+ end
209
+
210
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
211
+ # rubyzip is free software; you can redistribute it and/or
212
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,9 @@
1
+ module Zip
2
+ class Compressor #:nodoc:all
3
+ def finish; end
4
+ end
5
+ end
6
+
7
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
8
+ # rubyzip is free software; you can redistribute it and/or
9
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,115 @@
1
+ module Zip
2
+ RUNNING_ON_WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/i
3
+
4
+ CENTRAL_DIRECTORY_ENTRY_SIGNATURE = 0x02014b50
5
+ CDIR_ENTRY_STATIC_HEADER_LENGTH = 46
6
+
7
+ LOCAL_ENTRY_SIGNATURE = 0x04034b50
8
+ LOCAL_ENTRY_STATIC_HEADER_LENGTH = 30
9
+ LOCAL_ENTRY_TRAILING_DESCRIPTOR_LENGTH = 4 + 4 + 4
10
+ VERSION_MADE_BY = 52 # this library's version
11
+ VERSION_NEEDED_TO_EXTRACT = 20
12
+ VERSION_NEEDED_TO_EXTRACT_ZIP64 = 45
13
+
14
+ FILE_TYPE_FILE = 0o10
15
+ FILE_TYPE_DIR = 0o04
16
+ FILE_TYPE_SYMLINK = 0o12
17
+
18
+ FSTYPE_FAT = 0
19
+ FSTYPE_AMIGA = 1
20
+ FSTYPE_VMS = 2
21
+ FSTYPE_UNIX = 3
22
+ FSTYPE_VM_CMS = 4
23
+ FSTYPE_ATARI = 5
24
+ FSTYPE_HPFS = 6
25
+ FSTYPE_MAC = 7
26
+ FSTYPE_Z_SYSTEM = 8
27
+ FSTYPE_CPM = 9
28
+ FSTYPE_TOPS20 = 10
29
+ FSTYPE_NTFS = 11
30
+ FSTYPE_QDOS = 12
31
+ FSTYPE_ACORN = 13
32
+ FSTYPE_VFAT = 14
33
+ FSTYPE_MVS = 15
34
+ FSTYPE_BEOS = 16
35
+ FSTYPE_TANDEM = 17
36
+ FSTYPE_THEOS = 18
37
+ FSTYPE_MAC_OSX = 19
38
+ FSTYPE_ATHEOS = 30
39
+
40
+ FSTYPES = {
41
+ FSTYPE_FAT => 'FAT'.freeze,
42
+ FSTYPE_AMIGA => 'Amiga'.freeze,
43
+ FSTYPE_VMS => 'VMS (Vax or Alpha AXP)'.freeze,
44
+ FSTYPE_UNIX => 'Unix'.freeze,
45
+ FSTYPE_VM_CMS => 'VM/CMS'.freeze,
46
+ FSTYPE_ATARI => 'Atari ST'.freeze,
47
+ FSTYPE_HPFS => 'OS/2 or NT HPFS'.freeze,
48
+ FSTYPE_MAC => 'Macintosh'.freeze,
49
+ FSTYPE_Z_SYSTEM => 'Z-System'.freeze,
50
+ FSTYPE_CPM => 'CP/M'.freeze,
51
+ FSTYPE_TOPS20 => 'TOPS-20'.freeze,
52
+ FSTYPE_NTFS => 'NTFS'.freeze,
53
+ FSTYPE_QDOS => 'SMS/QDOS'.freeze,
54
+ FSTYPE_ACORN => 'Acorn RISC OS'.freeze,
55
+ FSTYPE_VFAT => 'Win32 VFAT'.freeze,
56
+ FSTYPE_MVS => 'MVS'.freeze,
57
+ FSTYPE_BEOS => 'BeOS'.freeze,
58
+ FSTYPE_TANDEM => 'Tandem NSK'.freeze,
59
+ FSTYPE_THEOS => 'Theos'.freeze,
60
+ FSTYPE_MAC_OSX => 'Mac OS/X (Darwin)'.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'
114
+ }.freeze
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
@@ -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,43 @@
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!; end
28
+ end
29
+
30
+ class NullDecrypter < Decrypter
31
+ include NullEncryption
32
+
33
+ def decrypt(data)
34
+ data
35
+ end
36
+
37
+ def reset!(_header); end
38
+ end
39
+ end
40
+
41
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
42
+ # rubyzip is free software; you can redistribute it and/or
43
+ # 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(num)
28
+ @key0 = ~Zlib.crc32(num, ~@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(num)
67
+ t = decrypt_byte
68
+ update_keys(num.chr)
69
+ t ^ num
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(num)
90
+ num ^= decrypt_byte
91
+ update_keys(num.chr)
92
+ num
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.
@@ -0,0 +1,31 @@
1
+ module Zip
2
+ class Decompressor #:nodoc:all
3
+ CHUNK_SIZE = 32_768
4
+
5
+ def self.decompressor_classes
6
+ @decompressor_classes ||= {}
7
+ end
8
+
9
+ def self.register(compression_method, decompressor_class)
10
+ decompressor_classes[compression_method] = decompressor_class
11
+ end
12
+
13
+ def self.find_by_compression_method(compression_method)
14
+ decompressor_classes[compression_method]
15
+ end
16
+
17
+ attr_reader :input_stream
18
+ attr_reader :decompressed_size
19
+
20
+ def initialize(input_stream, decompressed_size = nil)
21
+ super()
22
+
23
+ @input_stream = input_stream
24
+ @decompressed_size = decompressed_size
25
+ end
26
+ end
27
+ end
28
+
29
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
30
+ # rubyzip is free software; you can redistribute it and/or
31
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,34 @@
1
+ module Zip
2
+ class Deflater < Compressor #:nodoc:all
3
+ def initialize(output_stream, level = Zip.default_compression, encrypter = NullEncrypter.new)
4
+ super()
5
+ @output_stream = output_stream
6
+ @zlib_deflater = ::Zlib::Deflate.new(level, -::Zlib::MAX_WBITS)
7
+ @size = 0
8
+ @crc = ::Zlib.crc32
9
+ @encrypter = encrypter
10
+ end
11
+
12
+ def <<(data)
13
+ val = data.to_s
14
+ @crc = Zlib.crc32(val, @crc)
15
+ @size += val.bytesize
16
+ buffer = @zlib_deflater.deflate(data)
17
+ if buffer.empty?
18
+ @output_stream
19
+ else
20
+ @output_stream << @encrypter.encrypt(buffer)
21
+ end
22
+ end
23
+
24
+ def finish
25
+ @output_stream << @encrypter.encrypt(@zlib_deflater.finish) until @zlib_deflater.finished?
26
+ end
27
+
28
+ attr_reader :size, :crc
29
+ end
30
+ end
31
+
32
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
33
+ # rubyzip is free software; you can redistribute it and/or
34
+ # modify it under the terms of the ruby license.
@@ -0,0 +1,53 @@
1
+ module Zip
2
+ class DOSTime < Time #:nodoc:all
3
+ # MS-DOS File Date and Time format as used in Interrupt 21H Function 57H:
4
+
5
+ # Register CX, the Time:
6
+ # Bits 0-4 2 second increments (0-29)
7
+ # Bits 5-10 minutes (0-59)
8
+ # bits 11-15 hours (0-24)
9
+
10
+ # Register DX, the Date:
11
+ # Bits 0-4 day (1-31)
12
+ # bits 5-8 month (1-12)
13
+ # bits 9-15 year (four digit year minus 1980)
14
+
15
+ def to_binary_dos_time
16
+ (sec / 2) +
17
+ (min << 5) +
18
+ (hour << 11)
19
+ end
20
+
21
+ def to_binary_dos_date
22
+ day +
23
+ (month << 5) +
24
+ ((year - 1980) << 9)
25
+ end
26
+
27
+ # Dos time is only stored with two seconds accuracy
28
+ def dos_equals(other)
29
+ to_i / 2 == other.to_i / 2
30
+ end
31
+
32
+ # Create a DOSTime instance from a vanilla Time instance.
33
+ def self.from_time(time)
34
+ local(time.year, time.month, time.day, time.hour, time.min, time.sec)
35
+ end
36
+
37
+ def self.parse_binary_dos_format(bin_dos_date, bin_dos_time)
38
+ second = 2 * (0b11111 & bin_dos_time)
39
+ minute = (0b11111100000 & bin_dos_time) >> 5
40
+ hour = (0b1111100000000000 & bin_dos_time) >> 11
41
+ day = (0b11111 & bin_dos_date)
42
+ month = (0b111100000 & bin_dos_date) >> 5
43
+ year = ((0b1111111000000000 & bin_dos_date) >> 9) + 1980
44
+ begin
45
+ local(year, month, day, hour, minute, second)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ # Copyright (C) 2002, 2003 Thomas Sondergaard
52
+ # rubyzip is free software; you can redistribute it and/or
53
+ # modify it under the terms of the ruby license.