rubyzip 0.5.12 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubyzip might be problematic. Click here for more details.
- data/ChangeLog +151 -17
- data/NEWS +13 -0
- data/README +2 -0
- data/Rakefile +2 -3
- data/TODO +2 -3
- data/lib/download_quizzes.rb +119 -0
- data/lib/quiz1/t/solutions/Bill Guindon/solitaire.rb +205 -0
- data/lib/quiz1/t/solutions/Carlos/solitaire.rb +111 -0
- data/lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb +111 -0
- data/lib/quiz1/t/solutions/Florian Gross/solitaire.rb +301 -0
- data/lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb +268 -0
- data/lib/quiz1/t/solutions/James Edward Gray II/solitaire.rb +132 -0
- data/lib/quiz1/t/solutions/Jamis Buck/bin/main.rb +13 -0
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb +230 -0
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cli.rb +24 -0
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_deck.rb +30 -0
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_key-stream.rb +19 -0
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_keying-algorithms.rb +31 -0
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_solitaire-cipher.rb +66 -0
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_unkeyed-algorithm.rb +17 -0
- data/lib/quiz1/t/solutions/Jamis Buck/test/tests.rb +2 -0
- data/lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb +204 -0
- data/lib/quiz1/t/solutions/Jim Menard/test.rb +47 -0
- data/lib/quiz1/t/solutions/Moses Hohman/cipher.rb +97 -0
- data/lib/quiz1/t/solutions/Moses Hohman/deck.rb +140 -0
- data/lib/quiz1/t/solutions/Moses Hohman/solitaire.rb +14 -0
- data/lib/quiz1/t/solutions/Moses Hohman/test_cipher.rb +68 -0
- data/lib/quiz1/t/solutions/Moses Hohman/test_deck.rb +146 -0
- data/lib/quiz1/t/solutions/Moses Hohman/test_util.rb +38 -0
- data/lib/quiz1/t/solutions/Moses Hohman/testsuite.rb +5 -0
- data/lib/quiz1/t/solutions/Moses Hohman/util.rb +27 -0
- data/lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb +151 -0
- data/lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb +198 -0
- data/lib/zip/ioextras.rb +17 -15
- data/lib/zip/zip.rb +394 -112
- data/lib/zip/zipfilesystem.rb +2 -2
- data/test/gentestfiles.rb +3 -1
- data/test/zipfilesystemtest.rb +2 -2
- data/test/ziptest.rb +34 -29
- metadata +35 -12
- data/samples/zipdialogui.rb +0 -80
- data/test/data/file2.txt.other +0 -0
- data/test/zlibtest.rb +0 -26
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'test/unit'
|
3
|
+
require 'util'
|
4
|
+
|
5
|
+
class TestArray < Test::Unit::TestCase
|
6
|
+
def test_peel_all_arrays_same_length
|
7
|
+
tuples = []
|
8
|
+
a1 = [1,3,5]
|
9
|
+
a2 = [2,4,6]
|
10
|
+
a3 = [1,4,9]
|
11
|
+
[a1, a2, a3].peel { |x,y,z| tuples << [x,y,z] }
|
12
|
+
assert_equal([[1,2,1],[3,4,4],[5,6,9]], tuples)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_peel_one_array_shorter
|
16
|
+
tuples = []
|
17
|
+
a1 = [1,3,5]
|
18
|
+
a2 = [2,4]
|
19
|
+
a3 = [1,4,9]
|
20
|
+
[a1, a2, a3].peel { |x,y,z| tuples << [x,y,z] }
|
21
|
+
assert_equal([[1,2,1],[3,4,4]], tuples)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_collect_peel
|
25
|
+
a1 = [1,3,5]
|
26
|
+
a2 = [2,4,6]
|
27
|
+
assert_equal([3,7,11], [a1, a2].collect_peel { |a,b| a+b })
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class TestFixnum < Test::Unit::TestCase
|
32
|
+
def test_offset_mod
|
33
|
+
assert_equal(1, 27.offset_mod(26), "27 wrong")
|
34
|
+
assert_equal(26, 26.offset_mod(26), "26 wrong")
|
35
|
+
assert_equal(26, 0.offset_mod(26), "0 wrong")
|
36
|
+
assert_equal(25, -1.offset_mod(26), "-1 wrong")
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class Array
|
4
|
+
# "Peels" off a tuple of the elements at each successive index across multiple arrays.
|
5
|
+
# Assumes self is an array of these multiple arrays. Stops when any of the arrays is
|
6
|
+
# exhausted. I stole this from a ruby mailing list somewhere. I also considered calling this each_tuple
|
7
|
+
def peel(&p)
|
8
|
+
collect { |a|
|
9
|
+
a.length
|
10
|
+
}.min.times { |i|
|
11
|
+
yield collect { |a| a[i] }
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
# syntactic sugar for Cipher
|
16
|
+
def collect_peel(&p)
|
17
|
+
collected = []
|
18
|
+
peel { |a,b| collected << p.call(a,b) }
|
19
|
+
collected
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Fixnum
|
24
|
+
def offset_mod(base)
|
25
|
+
((self-1)%base)+1
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
def succ?(*a)
|
2
|
+
begin
|
3
|
+
(0..(a.size-2)).each {|i| return false if a[i].succ != a[i+1]}
|
4
|
+
return true
|
5
|
+
rescue
|
6
|
+
return false
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Deck
|
11
|
+
def initialize
|
12
|
+
@deck = (1..52).to_a + [:A, :B]
|
13
|
+
end
|
14
|
+
|
15
|
+
def move_a
|
16
|
+
move_down(@deck.index(:A))
|
17
|
+
end
|
18
|
+
|
19
|
+
def move_b
|
20
|
+
move_down(move_down(@deck.index(:B)))
|
21
|
+
end
|
22
|
+
|
23
|
+
def move_down(index)
|
24
|
+
if index < 53
|
25
|
+
new = index + 1
|
26
|
+
@deck[new], @deck[index] = @deck[index], @deck[new]
|
27
|
+
else
|
28
|
+
@deck = @deck[0,1] + @deck[-1,1] + @deck[1..-2]
|
29
|
+
new = 1
|
30
|
+
end
|
31
|
+
return new
|
32
|
+
end
|
33
|
+
|
34
|
+
def triple_cut
|
35
|
+
jokers = [@deck.index(:A), @deck.index(:B)]
|
36
|
+
top, bottom = jokers.min, jokers.max
|
37
|
+
@deck = @deck[(bottom+1)..-1] + @deck[top..bottom] + @deck[0...top]
|
38
|
+
end
|
39
|
+
|
40
|
+
def number_value(x)
|
41
|
+
return 53 if x == :A or x == :B
|
42
|
+
return x
|
43
|
+
end
|
44
|
+
|
45
|
+
def count_cut
|
46
|
+
count = number_value( @deck[-1] )
|
47
|
+
@deck = @deck[count..-2] + @deck[0,count] + @deck[-1,1]
|
48
|
+
end
|
49
|
+
|
50
|
+
def output
|
51
|
+
return @deck[ number_value(@deck[0]) ]
|
52
|
+
end
|
53
|
+
|
54
|
+
def update
|
55
|
+
move_a
|
56
|
+
move_b
|
57
|
+
triple_cut
|
58
|
+
count_cut
|
59
|
+
end
|
60
|
+
|
61
|
+
def get
|
62
|
+
while true
|
63
|
+
update
|
64
|
+
c = output
|
65
|
+
if c != :A and c != :B
|
66
|
+
letter = ( ((c-1) % 26) + 65 ).chr
|
67
|
+
return letter
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
a = []
|
74
|
+
@deck.each_index {|i|
|
75
|
+
if succ?(a[-1], @deck[i], @deck[i+1])
|
76
|
+
a << "..."
|
77
|
+
elsif a[-1] == "..." and succ?(@deck[i-1], @deck[i], @deck[i+1])
|
78
|
+
# nop
|
79
|
+
else
|
80
|
+
a << @deck[i]
|
81
|
+
end
|
82
|
+
}
|
83
|
+
return a.join(" ")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class Encrypter
|
88
|
+
def initialize(keystream)
|
89
|
+
@keystream = keystream
|
90
|
+
end
|
91
|
+
|
92
|
+
def sanitize(s)
|
93
|
+
s = s.upcase
|
94
|
+
s = s.gsub(/[^A-Z]/, "")
|
95
|
+
s = s + "X" * ((5 - s.size % 5) % 5)
|
96
|
+
out = ""
|
97
|
+
(s.size / 5).times {|i| out << s[i*5,5] << " "}
|
98
|
+
return out
|
99
|
+
end
|
100
|
+
|
101
|
+
def mod(c)
|
102
|
+
return c - 26 if c > 26
|
103
|
+
return c + 26 if c < 1
|
104
|
+
return c
|
105
|
+
end
|
106
|
+
|
107
|
+
def process(s, &combiner)
|
108
|
+
s = sanitize(s)
|
109
|
+
out = ""
|
110
|
+
s.each_byte { |c|
|
111
|
+
if c >= ?A and c <= ?Z
|
112
|
+
key = @keystream.get
|
113
|
+
res = combiner.call(c, key[0])
|
114
|
+
out << res.chr
|
115
|
+
else
|
116
|
+
out << c.chr
|
117
|
+
end
|
118
|
+
}
|
119
|
+
return out
|
120
|
+
end
|
121
|
+
|
122
|
+
def encrypt(s)
|
123
|
+
return process(s) {|c, key| 64 + mod(c + key - 128)}
|
124
|
+
end
|
125
|
+
|
126
|
+
def decrypt(s)
|
127
|
+
return process(s) {|c, key| 64 + mod(c -key)}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def test
|
133
|
+
d = Deck.new()
|
134
|
+
d.update
|
135
|
+
puts d
|
136
|
+
|
137
|
+
e = Encrypter.new( Deck.new() )
|
138
|
+
cipher = e.encrypt('Code in Ruby, live longer!')
|
139
|
+
puts cipher
|
140
|
+
|
141
|
+
e = Encrypter.new( Deck.new() )
|
142
|
+
puts e.decrypt(cipher)
|
143
|
+
|
144
|
+
e = Encrypter.new( Deck.new() )
|
145
|
+
puts e.decrypt("CLEPK HHNIY CFPWH FDFEH")
|
146
|
+
|
147
|
+
e = Encrypter.new( Deck.new() )
|
148
|
+
puts e.decrypt("ABVAW LWZSY OORYK DUPVH")
|
149
|
+
end
|
150
|
+
|
151
|
+
test()
|
@@ -0,0 +1,198 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
# Handles the deck
|
7
|
+
class Deck
|
8
|
+
|
9
|
+
# Initializes the deck with the default values
|
10
|
+
def initialize
|
11
|
+
@deck = (1..52).to_a << 'A' << 'B'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Operation "move a" (step 2)
|
15
|
+
def move_A
|
16
|
+
move_down( @deck.index( 'A' ) )
|
17
|
+
end
|
18
|
+
|
19
|
+
# Operation "move b" (step 3)
|
20
|
+
def move_B
|
21
|
+
2.times { move_down( @deck.index( 'B' ) ) }
|
22
|
+
end
|
23
|
+
|
24
|
+
# Operation "triple cut" (step 4)
|
25
|
+
def triple_cut
|
26
|
+
a = @deck.index( 'A' )
|
27
|
+
b = @deck.index( 'B' )
|
28
|
+
a, b = b, a if a > b
|
29
|
+
@deck.replace( [@deck[(b + 1)..-1], @deck[a..b], @deck[0...a]].flatten )
|
30
|
+
end
|
31
|
+
|
32
|
+
# Operation "count cut" (step 5)
|
33
|
+
def count_cut
|
34
|
+
temp = @deck[0..(@deck[-1] - 1)]
|
35
|
+
@deck[0..(@deck[-1] - 1)] = []
|
36
|
+
@deck[-1..-1] = [temp, @deck[-1]].flatten
|
37
|
+
end
|
38
|
+
|
39
|
+
# Operation "output the found letter" (step 6)
|
40
|
+
def output_letter
|
41
|
+
a = @deck.first
|
42
|
+
a = 53 if a.instance_of? String
|
43
|
+
output = @deck[a]
|
44
|
+
if output.instance_of? String
|
45
|
+
nil
|
46
|
+
else
|
47
|
+
output -= 26 if output > 26
|
48
|
+
(output + 64).chr
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Shuffle the deck using the initialization number +init+ and the method +method+.
|
53
|
+
# Currently there are only two methods: <tt>:fisher_yates</tt> and <tt>naive</tt>.
|
54
|
+
def shuffle( init, method = :fisher_yates )
|
55
|
+
srand( init )
|
56
|
+
self.send( method.id2name + "_shuffle", @deck )
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# From pleac.sf.net
|
62
|
+
def fisher_yates_shuffle( a )
|
63
|
+
(a.size-1).downto(0) { |i|
|
64
|
+
j = rand(i+1)
|
65
|
+
a[i], a[j] = a[j], a[i] if i != j
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
# From pleac.sf.net
|
70
|
+
def naive_shuffle( a )
|
71
|
+
for i in 0...a.size
|
72
|
+
j = rand(a.size)
|
73
|
+
a[i], a[j] = a[j], a[i]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Moves the index one place down while treating the used array as circular list.
|
78
|
+
def move_down( index )
|
79
|
+
if index == @deck.length - 1
|
80
|
+
@deck[1..1] = @deck[index], @deck[1]
|
81
|
+
@deck.pop
|
82
|
+
else
|
83
|
+
@deck[index], @deck[index + 1] = @deck[index + 1], @deck[index]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
# Implements the Solitaire Cipher algorithm
|
91
|
+
class SolitaireCipher
|
92
|
+
|
93
|
+
# Initialize the deck
|
94
|
+
def initialize( init = -1, method = :fisher_yates )
|
95
|
+
@deck = Deck.new
|
96
|
+
@deck.shuffle( init, method ) unless init == -1
|
97
|
+
end
|
98
|
+
|
99
|
+
# Decodes the given +msg+ using the internal deck
|
100
|
+
def decode( msg )
|
101
|
+
msgNumbers = to_numbers( msg )
|
102
|
+
cipherNumbers = to_numbers( generate_keystream( msg.length ) )
|
103
|
+
|
104
|
+
resultNumbers = []
|
105
|
+
msgNumbers.each_with_index do |item, index|
|
106
|
+
item += 26 if item <= cipherNumbers[index]
|
107
|
+
temp = item - cipherNumbers[index]
|
108
|
+
resultNumbers << temp
|
109
|
+
end
|
110
|
+
|
111
|
+
return to_chars( resultNumbers )
|
112
|
+
end
|
113
|
+
|
114
|
+
# Encodes the given +msg+ using the internal deck
|
115
|
+
def encode( msg )
|
116
|
+
msg = msg.gsub(/[^A-Za-z]/, '').upcase
|
117
|
+
msg += "X"*(5 - (msg.length % 5)) unless msg.length % 5 == 0
|
118
|
+
|
119
|
+
msgNumbers = to_numbers( msg )
|
120
|
+
cipherNumbers = to_numbers( generate_keystream( msg.length ) )
|
121
|
+
|
122
|
+
resultNumbers = []
|
123
|
+
msgNumbers.each_with_index do |item, index|
|
124
|
+
temp = item + cipherNumbers[index]
|
125
|
+
temp = temp - 26 if temp > 26
|
126
|
+
resultNumbers << temp
|
127
|
+
end
|
128
|
+
|
129
|
+
return to_chars( resultNumbers )
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
# Converts the string of uppercase letters into numbers (A=1, B=2, ...)
|
135
|
+
def to_numbers( chars )
|
136
|
+
chars.unpack("C*").collect {|x| x - 64}
|
137
|
+
end
|
138
|
+
|
139
|
+
# Converts the array of numbers to a string (1=A, 2=B, ...)
|
140
|
+
def to_chars( numbers )
|
141
|
+
numbers.collect {|x| x + 64}.pack("C*")
|
142
|
+
end
|
143
|
+
|
144
|
+
# Generates a keystream for the given +length+.
|
145
|
+
def generate_keystream( length )
|
146
|
+
deck = @deck.dup
|
147
|
+
result = []
|
148
|
+
while result.length != length
|
149
|
+
deck.move_A
|
150
|
+
deck.move_B
|
151
|
+
deck.triple_cut
|
152
|
+
deck.count_cut
|
153
|
+
letter = deck.output_letter
|
154
|
+
result << letter unless letter.nil?
|
155
|
+
end
|
156
|
+
result.join
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
options = OpenStruct.new
|
163
|
+
options.key = -1
|
164
|
+
options.shuffle = :fisher_yates
|
165
|
+
options.call_method = :decode
|
166
|
+
|
167
|
+
opts = OptionParser.new do |opts|
|
168
|
+
opts.banner = "Usage: #{File.basename($0, '.*')} [options] message"
|
169
|
+
opts.separator ""
|
170
|
+
opts.separator "Options:"
|
171
|
+
opts.on( "-d", "--decode", "Decode the message" ) do
|
172
|
+
options.call_method = :decode
|
173
|
+
end
|
174
|
+
opts.on( "-e", "--encode", "Encode the message" ) do
|
175
|
+
options.call_method = :encode
|
176
|
+
end
|
177
|
+
opts.on( "-k", "--key KEY", Integer, "Key for shuffling the deck" ) do |key|
|
178
|
+
options.key = key
|
179
|
+
end
|
180
|
+
opts.on( "-m", "--method METHOD", [:fisher_yates, :naive],
|
181
|
+
"Select the shuffling method (fisher_yates, naive" ) do |method|
|
182
|
+
options.shuffle = method
|
183
|
+
end
|
184
|
+
opts.on( "-h", "--help", "Show help" ) do
|
185
|
+
puts opts
|
186
|
+
exit
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
if ARGV.length == 0
|
192
|
+
puts opts
|
193
|
+
exit
|
194
|
+
end
|
195
|
+
|
196
|
+
message = opts.permute!( ARGV )[0]
|
197
|
+
cipher = SolitaireCipher.new( options.key, options.shuffle )
|
198
|
+
puts cipher.send( options.call_method, message )
|
data/lib/zip/ioextras.rb
CHANGED
@@ -33,26 +33,28 @@ module IOExtras #:nodoc:
|
|
33
33
|
attr_accessor :lineno
|
34
34
|
|
35
35
|
def read(numberOfBytes = nil, buf = nil)
|
36
|
-
|
36
|
+
tbuf = nil
|
37
37
|
|
38
|
-
if
|
38
|
+
if @outputBuffer.length > 0
|
39
39
|
if numberOfBytes <= @outputBuffer.length
|
40
|
-
|
40
|
+
tbuf = @outputBuffer.slice!(0, numberOfBytes)
|
41
41
|
else
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
42
|
+
numberOfBytes -= @outputBuffer.length if (numberOfBytes)
|
43
|
+
rbuf = sysread(numberOfBytes, buf)
|
44
|
+
tbuf = @outputBuffer
|
45
|
+
tbuf << rbuf if (rbuf)
|
46
|
+
@outputBuffer = ""
|
48
47
|
end
|
49
48
|
else
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
tbuf = sysread(numberOfBytes, buf)
|
50
|
+
end
|
51
|
+
|
52
|
+
return nil unless (tbuf)
|
53
|
+
|
54
|
+
if buf
|
55
|
+
buf.replace(tbuf)
|
56
|
+
else
|
57
|
+
buf = tbuf
|
56
58
|
end
|
57
59
|
|
58
60
|
buf
|