rubyzip 0.9.1 → 2.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +354 -0
- data/Rakefile +15 -104
- data/TODO +0 -1
- data/lib/zip/central_directory.rb +212 -0
- data/lib/zip/compressor.rb +9 -0
- data/lib/zip/constants.rb +115 -0
- data/lib/zip/crypto/decrypted_io.rb +40 -0
- data/lib/zip/crypto/encryption.rb +11 -0
- data/lib/zip/crypto/null_encryption.rb +43 -0
- data/lib/zip/crypto/traditional_encryption.rb +99 -0
- data/lib/zip/decompressor.rb +31 -0
- data/lib/zip/deflater.rb +34 -0
- data/lib/zip/dos_time.rb +53 -0
- data/lib/zip/entry.rb +719 -0
- data/lib/zip/entry_set.rb +88 -0
- data/lib/zip/errors.rb +19 -0
- data/lib/zip/extra_field/generic.rb +44 -0
- data/lib/zip/extra_field/ntfs.rb +94 -0
- data/lib/zip/extra_field/old_unix.rb +46 -0
- data/lib/zip/extra_field/universal_time.rb +77 -0
- data/lib/zip/extra_field/unix.rb +39 -0
- data/lib/zip/extra_field/zip64.rb +70 -0
- data/lib/zip/extra_field/zip64_placeholder.rb +15 -0
- data/lib/zip/extra_field.rb +103 -0
- data/lib/zip/file.rb +468 -0
- data/lib/zip/filesystem.rb +643 -0
- data/lib/zip/inflater.rb +54 -0
- data/lib/zip/input_stream.rb +180 -0
- data/lib/zip/ioextras/abstract_input_stream.rb +122 -0
- data/lib/zip/ioextras/abstract_output_stream.rb +43 -0
- data/lib/zip/ioextras.rb +21 -140
- data/lib/zip/null_compressor.rb +15 -0
- data/lib/zip/null_decompressor.rb +19 -0
- data/lib/zip/null_input_stream.rb +10 -0
- data/lib/zip/output_stream.rb +198 -0
- data/lib/zip/pass_thru_compressor.rb +23 -0
- data/lib/zip/pass_thru_decompressor.rb +31 -0
- data/lib/zip/streamable_directory.rb +15 -0
- data/lib/zip/streamable_stream.rb +52 -0
- data/lib/zip/version.rb +3 -0
- data/lib/zip.rb +72 -0
- data/samples/example.rb +44 -32
- data/samples/example_filesystem.rb +16 -19
- data/samples/example_recursive.rb +54 -0
- data/samples/gtk_ruby_zip.rb +84 -0
- data/samples/qtzip.rb +25 -34
- data/samples/write_simple.rb +10 -13
- data/samples/zipfind.rb +38 -45
- metadata +182 -91
- data/ChangeLog +0 -1504
- data/NEWS +0 -144
- data/README +0 -72
- data/install.rb +0 -22
- data/lib/download_quizzes.rb +0 -119
- data/lib/quiz1/t/solutions/Bill Guindon/solitaire.rb +0 -205
- data/lib/quiz1/t/solutions/Carlos/solitaire.rb +0 -111
- data/lib/quiz1/t/solutions/Dennis Ranke/solitaire.rb +0 -111
- data/lib/quiz1/t/solutions/Florian Gross/solitaire.rb +0 -301
- data/lib/quiz1/t/solutions/Glen M. Lewis/solitaire.rb +0 -268
- data/lib/quiz1/t/solutions/James Edward Gray II/solitaire.rb +0 -132
- data/lib/quiz1/t/solutions/Jamis Buck/bin/main.rb +0 -13
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cipher.rb +0 -230
- data/lib/quiz1/t/solutions/Jamis Buck/lib/cli.rb +0 -24
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_deck.rb +0 -30
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_key-stream.rb +0 -19
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_keying-algorithms.rb +0 -31
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_solitaire-cipher.rb +0 -66
- data/lib/quiz1/t/solutions/Jamis Buck/test/tc_unkeyed-algorithm.rb +0 -17
- data/lib/quiz1/t/solutions/Jamis Buck/test/tests.rb +0 -2
- data/lib/quiz1/t/solutions/Jim Menard/solitaire_cypher.rb +0 -204
- data/lib/quiz1/t/solutions/Jim Menard/test.rb +0 -47
- data/lib/quiz1/t/solutions/Moses Hohman/cipher.rb +0 -97
- data/lib/quiz1/t/solutions/Moses Hohman/deck.rb +0 -140
- data/lib/quiz1/t/solutions/Moses Hohman/solitaire.rb +0 -14
- data/lib/quiz1/t/solutions/Moses Hohman/test_cipher.rb +0 -68
- data/lib/quiz1/t/solutions/Moses Hohman/test_deck.rb +0 -146
- data/lib/quiz1/t/solutions/Moses Hohman/test_util.rb +0 -38
- data/lib/quiz1/t/solutions/Moses Hohman/testsuite.rb +0 -5
- data/lib/quiz1/t/solutions/Moses Hohman/util.rb +0 -27
- data/lib/quiz1/t/solutions/Niklas Frykholm/solitaire.rb +0 -151
- data/lib/quiz1/t/solutions/Thomas Leitner/solitaire.rb +0 -198
- data/lib/zip/stdrubyext.rb +0 -111
- data/lib/zip/tempfile_bugfixed.rb +0 -195
- data/lib/zip/zip.rb +0 -1847
- data/lib/zip/zipfilesystem.rb +0 -609
- data/lib/zip/ziprequire.rb +0 -90
- data/samples/gtkRubyzip.rb +0 -86
- data/test/alltests.rb +0 -9
- data/test/data/file1.txt +0 -46
- data/test/data/file1.txt.deflatedData +0 -0
- data/test/data/file2.txt +0 -1504
- data/test/data/notzippedruby.rb +0 -7
- data/test/data/rubycode.zip +0 -0
- data/test/data/rubycode2.zip +0 -0
- data/test/data/testDirectory.bin +0 -0
- data/test/data/zipWithDirs.zip +0 -0
- data/test/gentestfiles.rb +0 -157
- data/test/ioextrastest.rb +0 -208
- data/test/stdrubyexttest.rb +0 -52
- data/test/zipfilesystemtest.rb +0 -831
- data/test/ziprequiretest.rb +0 -43
- data/test/ziptest.rb +0 -1599
@@ -1,111 +0,0 @@
|
|
1
|
-
class Deck
|
2
|
-
def initialize
|
3
|
-
@deck = Array.new(54) {|i| i}
|
4
|
-
end
|
5
|
-
|
6
|
-
def create_keystream(count)
|
7
|
-
stream = []
|
8
|
-
count.times do
|
9
|
-
letter = next_letter
|
10
|
-
redo unless letter
|
11
|
-
stream << letter
|
12
|
-
end
|
13
|
-
return stream
|
14
|
-
end
|
15
|
-
|
16
|
-
def next_letter
|
17
|
-
##
|
18
|
-
# move the jokers
|
19
|
-
##
|
20
|
-
|
21
|
-
2.times do |j|
|
22
|
-
# find the joker
|
23
|
-
index = @deck.index(52 + j)
|
24
|
-
|
25
|
-
# remove it from the deck
|
26
|
-
@deck.delete_at(index)
|
27
|
-
|
28
|
-
# calculate new index
|
29
|
-
index = ((index + j) % 53) + 1
|
30
|
-
|
31
|
-
# insert the joker at that index
|
32
|
-
@deck[index, 0] = 52 + j
|
33
|
-
end
|
34
|
-
|
35
|
-
##
|
36
|
-
# do the tripple cut
|
37
|
-
##
|
38
|
-
|
39
|
-
# first find both jokers
|
40
|
-
a = @deck.index(52)
|
41
|
-
b = @deck.index(53)
|
42
|
-
|
43
|
-
# sort the two indeces
|
44
|
-
low, hi = [a, b].sort
|
45
|
-
|
46
|
-
# get the lower and upper parts of the deck
|
47
|
-
upper = @deck.slice!((hi + 1)..-1)
|
48
|
-
lower = @deck.slice!(0, low)
|
49
|
-
|
50
|
-
# swap them
|
51
|
-
@deck = upper + @deck + lower
|
52
|
-
|
53
|
-
##
|
54
|
-
# do the count cut
|
55
|
-
##
|
56
|
-
|
57
|
-
# find out the number of cards to cut
|
58
|
-
count = value_at(53)
|
59
|
-
|
60
|
-
# remove them from the top of the deck
|
61
|
-
cards = @deck.slice!(0, count)
|
62
|
-
|
63
|
-
# reinsert them just above the lowest card
|
64
|
-
@deck[-1, 0] = cards
|
65
|
-
|
66
|
-
return letter_at(value_at(0))
|
67
|
-
end
|
68
|
-
|
69
|
-
def value_at(index)
|
70
|
-
id = @deck[index]
|
71
|
-
(id > 51) ? 53 : id + 1
|
72
|
-
end
|
73
|
-
|
74
|
-
def letter_at(index)
|
75
|
-
id = @deck[index]
|
76
|
-
(id > 51) ? nil : (id % 26) + 1
|
77
|
-
end
|
78
|
-
|
79
|
-
def to_s
|
80
|
-
@deck.map {|v| (v > 51) ? (v + 13).chr : (v + 1).to_s}.join(' ')
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def encode(data, keystream)
|
85
|
-
result = []
|
86
|
-
data.size.times {|i| result << ((data[i] + keystream[i]) % 26)}
|
87
|
-
return result
|
88
|
-
end
|
89
|
-
|
90
|
-
def decode(data, keystream)
|
91
|
-
encode(data, keystream.map {|v| 26 - v})
|
92
|
-
end
|
93
|
-
|
94
|
-
def data_to_string(data)
|
95
|
-
data = data.map {|v| (v + 65).chr}.join
|
96
|
-
(0...(data.size / 5)).map {|i| data[i * 5, 5]}.join(' ')
|
97
|
-
end
|
98
|
-
|
99
|
-
if ARGV.size != 1
|
100
|
-
puts "Usage: solitaire.rb MESSAGE"
|
101
|
-
exit
|
102
|
-
end
|
103
|
-
|
104
|
-
data = ARGV[0].upcase.split(//).select {|c| c =~ /[A-Z]/}.map {|c| c[0] - 65}
|
105
|
-
data += [?X - 65] * (4 - (data.size + 4) % 5)
|
106
|
-
|
107
|
-
deck = Deck.new
|
108
|
-
keystream = deck.create_keystream(data.size)
|
109
|
-
|
110
|
-
puts 'encoded:', data_to_string(encode(data, keystream))
|
111
|
-
puts 'decoded:', data_to_string(decode(data, keystream))
|
@@ -1,301 +0,0 @@
|
|
1
|
-
class Array
|
2
|
-
# Moves the item from a specified index to
|
3
|
-
# just before the item with the specified index.
|
4
|
-
def move(from_index, to_index)
|
5
|
-
from_index += self.size if from_index < 0
|
6
|
-
to_index += self.size if to_index < 0
|
7
|
-
|
8
|
-
item = self.slice!(from_index)
|
9
|
-
self.insert(to_index, item)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
module Solitaire
|
14
|
-
extend self
|
15
|
-
|
16
|
-
Letters = ('A' .. 'Z').to_a
|
17
|
-
|
18
|
-
class Card < Struct.new(:face, :type)
|
19
|
-
Faces = [:ace, :two, :three, :four, :five, :six, :seven,
|
20
|
-
:eight, :nine, :ten, :jack, :queen, :king]
|
21
|
-
Types = [:clubs, :diamonds, :hearts, :spades, :special]
|
22
|
-
SpecialFaces = [:joker_a, :joker_b]
|
23
|
-
|
24
|
-
def self.deck
|
25
|
-
Types.map do |type|
|
26
|
-
if type == :special
|
27
|
-
SpecialFaces.map do |face|
|
28
|
-
new(face, type)
|
29
|
-
end
|
30
|
-
else
|
31
|
-
Faces.map do |face|
|
32
|
-
new(face, type)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end.flatten
|
36
|
-
end
|
37
|
-
|
38
|
-
def special?; type == :special; end
|
39
|
-
|
40
|
-
def value
|
41
|
-
if special? then 53
|
42
|
-
else
|
43
|
-
Faces.index(face) + 1 + 13 * Types.index(type)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def letter
|
48
|
-
Letters[(value - 1) % 26]
|
49
|
-
end
|
50
|
-
|
51
|
-
def name
|
52
|
-
if face == :joker_a then "JokerA"
|
53
|
-
elsif face == :joker_b then "JokerB"
|
54
|
-
else
|
55
|
-
face_str = face.to_s.capitalize.gsub(/_(\w)/) { $1.upcase }
|
56
|
-
type_str = type.to_s.capitalize
|
57
|
-
face_str + " of " + type_str
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def compact_inspect
|
62
|
-
if face == :joker_a then "A"
|
63
|
-
elsif face == :joker_b then "B"
|
64
|
-
else value end
|
65
|
-
end
|
66
|
-
|
67
|
-
def inspect
|
68
|
-
"#<#{self.class} #{name} (#{letter}/#{value})>"
|
69
|
-
end
|
70
|
-
alias :to_s :inspect
|
71
|
-
|
72
|
-
deck.each do |card|
|
73
|
-
const_set(card.name.sub(" of ", "Of"), card)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
class KeyStream
|
78
|
-
def initialize(key_method = nil)
|
79
|
-
case key_method
|
80
|
-
when true then
|
81
|
-
@deck = Card.deck.sort_by { rand }
|
82
|
-
when String then
|
83
|
-
@deck = Card.deck
|
84
|
-
generate_letter(key_method)
|
85
|
-
else
|
86
|
-
@deck = Card.deck
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def generate_letter(seed_phrase = nil)
|
91
|
-
if seed_phrase
|
92
|
-
seed_phrase = Solitaire.clean(seed_phrase)
|
93
|
-
seed_phrase = nil if seed_phrase.empty?
|
94
|
-
end
|
95
|
-
|
96
|
-
result = nil
|
97
|
-
|
98
|
-
until result
|
99
|
-
deck_size = @deck.size
|
100
|
-
|
101
|
-
# Move JokerA down one card
|
102
|
-
old_a_pos = @deck.index(Card::JokerA)
|
103
|
-
new_a_pos = case old_a_pos
|
104
|
-
when deck_size - 1 then 1
|
105
|
-
else old_a_pos + 1
|
106
|
-
end
|
107
|
-
@deck.move(old_a_pos, new_a_pos)
|
108
|
-
|
109
|
-
# Move JokerB down two cards
|
110
|
-
old_b_pos = @deck.index(Card::JokerB)
|
111
|
-
new_b_pos = case old_b_pos
|
112
|
-
when deck_size - 1 then 2
|
113
|
-
when deck_size - 2 then 1
|
114
|
-
else old_b_pos + 2
|
115
|
-
end
|
116
|
-
@deck.move(old_b_pos, new_b_pos)
|
117
|
-
|
118
|
-
# Perform triple cut
|
119
|
-
top_pos, bot_pos = [@deck.index(Card::JokerA), @deck.index(Card::JokerB)].sort
|
120
|
-
@deck.replace(
|
121
|
-
@deck[(bot_pos + 1) .. -1] +
|
122
|
-
@deck[top_pos .. bot_pos] +
|
123
|
-
@deck[0 ... top_pos])
|
124
|
-
|
125
|
-
# Perform count cut
|
126
|
-
top = @deck.slice!(0 ... @deck.last.value)
|
127
|
-
@deck.insert(-2, *top)
|
128
|
-
|
129
|
-
if seed_phrase
|
130
|
-
key = seed_phrase.slice!(0, 1)
|
131
|
-
top = @deck.slice!(0 ... Solitaire.letter_to_number(key))
|
132
|
-
@deck.insert(-2, *top)
|
133
|
-
result = true if seed_phrase.empty?
|
134
|
-
else
|
135
|
-
# Fetch result
|
136
|
-
card = @deck[@deck.first.value]
|
137
|
-
result = card.letter unless card.special?
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
return result
|
142
|
-
end
|
143
|
-
alias :shift :generate_letter
|
144
|
-
end
|
145
|
-
|
146
|
-
def letter_to_number(letter)
|
147
|
-
Letters.index(letter) + 1
|
148
|
-
end
|
149
|
-
|
150
|
-
def number_to_letter(number)
|
151
|
-
Letters[number - 1]
|
152
|
-
end
|
153
|
-
|
154
|
-
def clean(text)
|
155
|
-
text.upcase.delete("^A-Z")
|
156
|
-
end
|
157
|
-
|
158
|
-
def pretty(text)
|
159
|
-
clean(text).scan(/.{1,5}/).join(" ")
|
160
|
-
end
|
161
|
-
|
162
|
-
def encrypt(raw_text, keystream = nil, pretty = true)
|
163
|
-
keystream ||= KeyStream.new
|
164
|
-
text = clean(raw_text)
|
165
|
-
text += "X" * ((text.size / 5.0).ceil * 5 - text.size)
|
166
|
-
|
167
|
-
result = ""
|
168
|
-
0.upto(text.size - 1) do |index|
|
169
|
-
source_num = letter_to_number(text[index, 1])
|
170
|
-
key_num = letter_to_number(keystream.shift)
|
171
|
-
result << number_to_letter((source_num + key_num) % 26)
|
172
|
-
end
|
173
|
-
|
174
|
-
result = pretty(result) if pretty
|
175
|
-
return result
|
176
|
-
end
|
177
|
-
|
178
|
-
def decrypt(raw_text, keystream = nil, pretty = true)
|
179
|
-
keystream ||= KeyStream.new
|
180
|
-
text = clean(raw_text)
|
181
|
-
|
182
|
-
result = ""
|
183
|
-
0.upto(text.size - 1) do |index|
|
184
|
-
source_num = letter_to_number(text[index, 1])
|
185
|
-
key_num = letter_to_number(keystream.shift)
|
186
|
-
result << number_to_letter((source_num - key_num) % 26)
|
187
|
-
end
|
188
|
-
|
189
|
-
result = pretty(result) if pretty
|
190
|
-
return result
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
if __FILE__ == $0
|
195
|
-
require 'optparse'
|
196
|
-
|
197
|
-
options = {
|
198
|
-
:mode => nil,
|
199
|
-
:keystream => nil,
|
200
|
-
:keylength => 80,
|
201
|
-
:text => nil
|
202
|
-
}
|
203
|
-
|
204
|
-
ARGV.options do |opts|
|
205
|
-
script_name = File.basename($0)
|
206
|
-
opts.banner = "Usage: ruby #{script_name} [options]"
|
207
|
-
|
208
|
-
opts.separator ""
|
209
|
-
|
210
|
-
opts.on("-d", "--decrypt",
|
211
|
-
"Decrypt an encrypted message.",
|
212
|
-
"This is the default if the message looks encrypted.") do
|
213
|
-
options[:mode] = :decrypt
|
214
|
-
end
|
215
|
-
opts.on("-e", "--encrypt",
|
216
|
-
"Encrypt an unencrypted message.") do
|
217
|
-
options[:mode] = :encrypt
|
218
|
-
end
|
219
|
-
opts.on("-m", "--message message",
|
220
|
-
"Specify the message.",
|
221
|
-
"Default: Read from terminal.") do |text|
|
222
|
-
options[:text] = text
|
223
|
-
end
|
224
|
-
opts.on("-k", "--key=key",
|
225
|
-
"Specify the key that will be used for shuffling the deck.",
|
226
|
-
"Default: Use an unshuffled deck.") do |key|
|
227
|
-
options[:keystream] = Solitaire::KeyStream.new(key)
|
228
|
-
end
|
229
|
-
opts.on("-R", "--random-key length", Integer,
|
230
|
-
"Use a randomly generated key for shuffling the deck.",
|
231
|
-
"The key length can be specified. It defaults to 80.",
|
232
|
-
"The key will be printed to the first line of STDOUT.") do |width|
|
233
|
-
options[:keylength] = width if width
|
234
|
-
options[:keystream] = :random
|
235
|
-
end
|
236
|
-
opts.on("-W", "--word-key file",
|
237
|
-
"Use a randomly generated key phrase.",
|
238
|
-
"It will consist of random words in the specified file.",
|
239
|
-
"The key length can be specified via the -R option.",
|
240
|
-
"The key phrase and the key will be printed to STDOUT.") do |word_file|
|
241
|
-
options[:keystream] = :random_words
|
242
|
-
options[:word_file] = word_file
|
243
|
-
end
|
244
|
-
|
245
|
-
opts.separator ""
|
246
|
-
|
247
|
-
opts.on("-h", "--help",
|
248
|
-
"Show this help message.") do
|
249
|
-
puts opts; exit
|
250
|
-
end
|
251
|
-
|
252
|
-
opts.parse!
|
253
|
-
end
|
254
|
-
|
255
|
-
input = options[:text] || STDIN.read
|
256
|
-
|
257
|
-
options[:mode] = :decrypt if /\A(?:[A-Z]{5}\s*)+\Z/.match(input)
|
258
|
-
|
259
|
-
case options[:keystream]
|
260
|
-
when :random then
|
261
|
-
key = Array.new(options[:keylength]) { Solitaire::Letters[rand(26)] }.join
|
262
|
-
|
263
|
-
puts "Key: " + Solitaire.pretty(key)
|
264
|
-
options[:keystream] = Solitaire::KeyStream.new(key)
|
265
|
-
when :random_words then
|
266
|
-
begin
|
267
|
-
words = File.read(options[:word_file]).scan(/\w+/)
|
268
|
-
rescue
|
269
|
-
STDERR.puts "Word file doesn't exist or can't be read."
|
270
|
-
exit -1
|
271
|
-
end
|
272
|
-
|
273
|
-
words_size = words.size
|
274
|
-
|
275
|
-
min_words = options[:keylength] / 6
|
276
|
-
if words_size < min_words
|
277
|
-
STDERR.puts "Word file must contain at least #{min_words} words," +
|
278
|
-
" but it contains only #{words_size} words!"
|
279
|
-
exit -2
|
280
|
-
end
|
281
|
-
|
282
|
-
key = []
|
283
|
-
until key.join("").length >= options[:keylength]
|
284
|
-
key << words[rand(words_size)]
|
285
|
-
end
|
286
|
-
key = key.join(" ")
|
287
|
-
|
288
|
-
puts "Keyphrase: " + key
|
289
|
-
puts "Key: " + Solitaire.pretty(key)
|
290
|
-
options[:keystream] = Solitaire::KeyStream.new(key)
|
291
|
-
end
|
292
|
-
|
293
|
-
if options[:mode] == :decrypt
|
294
|
-
puts Solitaire.decrypt(input, options[:keystream])
|
295
|
-
else
|
296
|
-
unless options[:keystream]
|
297
|
-
STDERR.puts "WARNING: Using an unshuffled deck for encrypting!"
|
298
|
-
end
|
299
|
-
puts Solitaire.encrypt(input, options[:keystream])
|
300
|
-
end
|
301
|
-
end
|
@@ -1,268 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# Solitaire Cipher
|
3
|
-
# Ruby-lang quiz #1
|
4
|
-
# Solution by Glenn M. Lewis - 9/27/04
|
5
|
-
|
6
|
-
$debug = nil
|
7
|
-
|
8
|
-
class Card
|
9
|
-
attr_reader :value, :face_value, :suit
|
10
|
-
|
11
|
-
def initialize(face_value, suit)
|
12
|
-
@face_value = face_value
|
13
|
-
@suit = suit
|
14
|
-
if suit then
|
15
|
-
@value = calc_value(face_value, suit)
|
16
|
-
return
|
17
|
-
end
|
18
|
-
case face_value
|
19
|
-
when "AJoker"
|
20
|
-
@value = 53
|
21
|
-
when "BJoker"
|
22
|
-
@value = 53
|
23
|
-
else
|
24
|
-
puts "ERROR: Unknown joker: #{joker}, should be 'AJoker' or 'BJoker'"
|
25
|
-
exit
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def calc_value(face_value, suit)
|
30
|
-
val = 0
|
31
|
-
case suit
|
32
|
-
when "S" then val += 39
|
33
|
-
when "H" then val += 26
|
34
|
-
when "D" then val += 13
|
35
|
-
when "C"
|
36
|
-
else
|
37
|
-
puts "ERROR: Unknown suit: #{suit}, should be C,D,H,S"
|
38
|
-
end
|
39
|
-
case face_value
|
40
|
-
when 2..10 then val += face_value
|
41
|
-
when "A" then val += 1
|
42
|
-
when "J" then val += 11
|
43
|
-
when "Q" then val += 12
|
44
|
-
when "K" then val += 13
|
45
|
-
else
|
46
|
-
puts "ERROR: Unknown card face value: #{face_value}, should be A,2-10,J,Q,K"
|
47
|
-
end
|
48
|
-
return val
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
class Deck < Array
|
53
|
-
def initialize
|
54
|
-
["C", "D", "H", "S"].each do |suit|
|
55
|
-
["A", 2, 3, 4, 5, 6, 7, 8, 9, 10, "J", "Q", "K"].each do |face_value|
|
56
|
-
self.push(Card.new(face_value, suit))
|
57
|
-
end
|
58
|
-
end
|
59
|
-
self.push(Card.new("AJoker", nil))
|
60
|
-
self.push(Card.new("BJoker", nil))
|
61
|
-
@deck_size = self.size
|
62
|
-
end
|
63
|
-
|
64
|
-
def dump
|
65
|
-
self.each do |c|
|
66
|
-
if (c.value == 53)
|
67
|
-
print c.face_value
|
68
|
-
else
|
69
|
-
print c.value
|
70
|
-
end
|
71
|
-
print " "
|
72
|
-
end
|
73
|
-
print "\n\n"
|
74
|
-
if (@deck_size != self.size) then
|
75
|
-
puts "ERROR! Deck size changed to #{self.size}"
|
76
|
-
exit
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def find_joker(j)
|
81
|
-
self.each_index do |i|
|
82
|
-
if (self[i].face_value == j)
|
83
|
-
return i
|
84
|
-
end
|
85
|
-
end
|
86
|
-
puts "ERROR: Could not find joker '#{j}' in deck."
|
87
|
-
end
|
88
|
-
|
89
|
-
def move_card_down(pos, num)
|
90
|
-
print "before move_card_down(#{pos}, #{num}): " if $debug
|
91
|
-
self.dump if $debug
|
92
|
-
dest = pos + num
|
93
|
-
dest -= (self.size-1) if (dest >= self.size)
|
94
|
-
card = self.delete_at(pos)
|
95
|
-
temp = self.dup
|
96
|
-
self.clear
|
97
|
-
temp.slice(0, dest).each {|x| self.push(x) }
|
98
|
-
self << card
|
99
|
-
temp.slice(dest..(-1)).each {|x| self.push(x) }
|
100
|
-
print "after move_card_down(#{pos}, #{num}): " if $debug
|
101
|
-
self.dump if $debug
|
102
|
-
end
|
103
|
-
|
104
|
-
def triple_cut_split(a, b)
|
105
|
-
a,b=b,a if (a > b)
|
106
|
-
print "before triple_cut_split(#{a}, #{b}): " if $debug
|
107
|
-
self.dump if $debug
|
108
|
-
temp = self.dup
|
109
|
-
self.clear
|
110
|
-
temp.slice((b+1)..-1).each {|x| self.push(x) }
|
111
|
-
temp.slice(a..b).each {|x| self.push(x) }
|
112
|
-
temp.slice(0..(a-1)).each {|x| self.push(x) }
|
113
|
-
print "after triple_cut_split(#{a}, #{b}): " if $debug
|
114
|
-
self.dump if $debug
|
115
|
-
end
|
116
|
-
|
117
|
-
def count_cut
|
118
|
-
print "before count_cut: " if $debug
|
119
|
-
self.dump if $debug
|
120
|
-
temp = self.dup
|
121
|
-
self.clear
|
122
|
-
num = temp[-1].value
|
123
|
-
temp.slice(num..-2).each {|x| self.push(x) }
|
124
|
-
temp.slice(0..(num-1)).each {|x| self.push(x) }
|
125
|
-
self.push(temp[-1])
|
126
|
-
print "after count_cut: " if $debug
|
127
|
-
self.dump if $debug
|
128
|
-
end
|
129
|
-
|
130
|
-
def output_letter
|
131
|
-
num = self[0].value
|
132
|
-
card = self[num]
|
133
|
-
return nil if (card.value == 53)
|
134
|
-
num = (card.value > 26 ? card.value-26 : card.value)
|
135
|
-
char = (num-1 + "A"[0]).chr
|
136
|
-
puts "card.value=#{card.value}, char=#{char}" if $debug
|
137
|
-
return char
|
138
|
-
end
|
139
|
-
|
140
|
-
def keystream_message(msg)
|
141
|
-
# result = "DWJXHYRFDGTMSHPUURXJ"
|
142
|
-
result = ""
|
143
|
-
while (result.length < msg.length) do
|
144
|
-
# Step 2 - Move the A Joker down one card
|
145
|
-
pos = find_joker("AJoker")
|
146
|
-
move_card_down(pos, 1)
|
147
|
-
# Step 3 - Move the B Joker down two cards
|
148
|
-
pos = find_joker("BJoker")
|
149
|
-
move_card_down(pos, 2)
|
150
|
-
# Step 4 - Triple cut split around two jokers
|
151
|
-
apos = find_joker("AJoker")
|
152
|
-
bpos = find_joker("BJoker")
|
153
|
-
triple_cut_split(apos, bpos)
|
154
|
-
# Step 5 - Count cut
|
155
|
-
count_cut
|
156
|
-
# Step 6 - Output letter - might be nil
|
157
|
-
letter = output_letter
|
158
|
-
result << letter if letter
|
159
|
-
end
|
160
|
-
return result
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
message = ARGV[0].dup
|
165
|
-
|
166
|
-
encrypted = true
|
167
|
-
encrypted = false if (message =~ /[a-z]/)
|
168
|
-
words = message.split(/\s+/)
|
169
|
-
words.each do |word|
|
170
|
-
encrypted = false if (word.length != 5)
|
171
|
-
encrypted = false if (word =~ /[^A-Z]/)
|
172
|
-
end
|
173
|
-
|
174
|
-
def message2nums(msg)
|
175
|
-
result = []
|
176
|
-
msg.each_byte do |c|
|
177
|
-
result.push(c+1-"A"[0])
|
178
|
-
end
|
179
|
-
return result
|
180
|
-
end
|
181
|
-
|
182
|
-
def nums2message(nums)
|
183
|
-
result = ""
|
184
|
-
nums.each do |val|
|
185
|
-
result << (val-1+"A"[0]).chr
|
186
|
-
end
|
187
|
-
return result
|
188
|
-
end
|
189
|
-
|
190
|
-
deck = Deck.new
|
191
|
-
|
192
|
-
if encrypted then
|
193
|
-
puts "Encrypted message: '#{message}'"
|
194
|
-
message.gsub!(/[^A-Z]/, '')
|
195
|
-
|
196
|
-
# Step 1
|
197
|
-
keystream_message = deck.keystream_message(message)
|
198
|
-
# puts "keystream_message = #{keystream_message}"
|
199
|
-
|
200
|
-
# Step 2
|
201
|
-
num_message = message2nums(message)
|
202
|
-
# puts "num_message = "
|
203
|
-
# p num_message
|
204
|
-
|
205
|
-
# Step 3
|
206
|
-
num_keystream = message2nums(keystream_message)
|
207
|
-
# puts "num_keystream = "
|
208
|
-
# p num_keystream
|
209
|
-
|
210
|
-
# Step 4
|
211
|
-
num_result = []
|
212
|
-
num_message.each_index do |index|
|
213
|
-
num_result[index] = num_message[index] - num_keystream[index]
|
214
|
-
num_result[index] += 26 if (num_result[index] < 1)
|
215
|
-
end
|
216
|
-
|
217
|
-
# Step 6
|
218
|
-
result = nums2message(num_result)
|
219
|
-
print "Unencrypted message: "
|
220
|
-
count = 0
|
221
|
-
result.each_byte do |c|
|
222
|
-
print c.chr
|
223
|
-
count += 1
|
224
|
-
print " " if ((count % 5) == 0)
|
225
|
-
end
|
226
|
-
print "\n"
|
227
|
-
|
228
|
-
else
|
229
|
-
puts "Unencrypted message: '#{message}'"
|
230
|
-
|
231
|
-
# Step 1
|
232
|
-
message.upcase!
|
233
|
-
message.gsub!(/[^A-Z]/, '')
|
234
|
-
message << "X" * ((message.length % 5)==0 ? 0 : (5-(message.length % 5)))
|
235
|
-
# puts "message: #{message}"
|
236
|
-
|
237
|
-
# Step 2
|
238
|
-
keystream_message = deck.keystream_message(message)
|
239
|
-
# puts "keystream_message = #{keystream_message}"
|
240
|
-
|
241
|
-
# Step 3
|
242
|
-
num_message = message2nums(message)
|
243
|
-
# puts "num_message = "
|
244
|
-
# p num_message
|
245
|
-
|
246
|
-
# Step 4
|
247
|
-
num_keystream = message2nums(keystream_message)
|
248
|
-
# puts "num_keystream = "
|
249
|
-
# p num_keystream
|
250
|
-
|
251
|
-
# Step 5
|
252
|
-
num_result = []
|
253
|
-
num_message.each_index do |index|
|
254
|
-
num_result[index] = num_message[index] + num_keystream[index]
|
255
|
-
num_result[index] -= 26 if (num_result[index] > 26)
|
256
|
-
end
|
257
|
-
|
258
|
-
# Step 6
|
259
|
-
result = nums2message(num_result)
|
260
|
-
print "Encrypted message: "
|
261
|
-
count = 0
|
262
|
-
result.each_byte do |c|
|
263
|
-
print c.chr
|
264
|
-
count += 1
|
265
|
-
print " " if ((count % 5) == 0)
|
266
|
-
end
|
267
|
-
print "\n"
|
268
|
-
end
|