rubyzip 0.9.1 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
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.