ruby-msg 1.2.17
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/FIXES +34 -0
- data/README +121 -0
- data/Rakefile +66 -0
- data/bin/msgtool +63 -0
- data/bin/oletool +35 -0
- data/data/mapitags.yaml +4168 -0
- data/data/named_map.yaml +114 -0
- data/data/types.yaml +15 -0
- data/lib/blah.rb +106 -0
- data/lib/mime-new.rb +210 -0
- data/lib/mime.rb +165 -0
- data/lib/msg/properties.rb +515 -0
- data/lib/msg/rtf.rb +236 -0
- data/lib/msg.rb +505 -0
- data/lib/ole/base.rb +5 -0
- data/lib/ole/file_system.rb +181 -0
- data/lib/ole/io_helpers.rb +184 -0
- data/lib/ole/storage.rb +927 -0
- data/lib/ole/types.rb +36 -0
- data/lib/orderedhash.rb +218 -0
- data/lib/rtf.rb +118 -0
- data/lib/support.rb +51 -0
- data/test/test_mime.rb +22 -0
- data/test/test_storage.rb +139 -0
- data/test/test_word_6.doc +0 -0
- data/test/test_word_95.doc +0 -0
- data/test/test_word_97.doc +0 -0
- metadata +73 -0
data/lib/ole/types.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'iconv'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
require 'ole/base'
|
5
|
+
|
6
|
+
module Ole # :nodoc:
|
7
|
+
# FIXME
|
8
|
+
module Types
|
9
|
+
FROM_UTF16 = Iconv.new 'utf-8', 'utf-16le'
|
10
|
+
TO_UTF16 = Iconv.new 'utf-16le', 'utf-8'
|
11
|
+
EPOCH = DateTime.parse '1601-01-01'
|
12
|
+
# Create a +DateTime+ object from a struct +FILETIME+
|
13
|
+
# (http://msdn2.microsoft.com/en-us/library/ms724284.aspx).
|
14
|
+
#
|
15
|
+
# Converts +str+ to two 32 bit time values, comprising the high and low 32 bits of
|
16
|
+
# the 100's of nanoseconds since 1st january 1601 (Epoch).
|
17
|
+
def self.load_time str
|
18
|
+
low, high = str.unpack 'L2'
|
19
|
+
# we ignore these, without even warning about it
|
20
|
+
return nil if low == 0 and high == 0
|
21
|
+
time = EPOCH + (high * (1 << 32) + low) * 1e-7 / 86400 rescue return
|
22
|
+
# extra sanity check...
|
23
|
+
unless (1800...2100) === time.year
|
24
|
+
Log.warn "ignoring unlikely time value #{time.to_s}"
|
25
|
+
return nil
|
26
|
+
end
|
27
|
+
time
|
28
|
+
end
|
29
|
+
|
30
|
+
# Convert a binary guid into a plain string (will move to proper class later).
|
31
|
+
def self.load_guid str
|
32
|
+
"{%08x-%04x-%04x-%02x%02x-#{'%02x' * 6}}" % str.unpack('L S S CC C6')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/lib/orderedhash.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
# = OrderedHash
|
2
|
+
#
|
3
|
+
# == Version
|
4
|
+
# 1.2006.07.13 (change of the first number means Big Change)
|
5
|
+
#
|
6
|
+
# == Description
|
7
|
+
# Hash which preserves order of added items (like PHP array).
|
8
|
+
#
|
9
|
+
# == Usage
|
10
|
+
#
|
11
|
+
# (see examples directory under the ruby gems root directory)
|
12
|
+
#
|
13
|
+
# require 'rubygems'
|
14
|
+
# require 'ordered_hash'
|
15
|
+
#
|
16
|
+
# hsh = OrderedHash.new
|
17
|
+
# hsh['z'] = 1
|
18
|
+
# hsh['a'] = 2
|
19
|
+
# hsh['c'] = 3
|
20
|
+
# p hsh.keys # ['z','a','c']
|
21
|
+
#
|
22
|
+
# == Source
|
23
|
+
# http://simplypowerful.1984.cz/goodlibs/1.2006.07.13
|
24
|
+
#
|
25
|
+
# == Author
|
26
|
+
# jan molic (/mig/at_sign/1984/dot/cz/)
|
27
|
+
#
|
28
|
+
# == Thanks to
|
29
|
+
# Andrew Johnson for his suggestions and fixes of Hash[], merge, to_a, inspect and shift
|
30
|
+
# Desmond Dsouza for == fixes
|
31
|
+
#
|
32
|
+
# == Licence
|
33
|
+
# You can redistribute it and/or modify it under the same terms of Ruby's license;
|
34
|
+
# either the dual license version in 2003, or any later version.
|
35
|
+
#
|
36
|
+
|
37
|
+
class OrderedHash < Hash
|
38
|
+
|
39
|
+
attr_accessor :order
|
40
|
+
|
41
|
+
class << self
|
42
|
+
|
43
|
+
def [] *args
|
44
|
+
hsh = OrderedHash.new
|
45
|
+
if Hash === args[0]
|
46
|
+
hsh.replace args[0]
|
47
|
+
elsif (args.size % 2) != 0
|
48
|
+
raise ArgumentError, "odd number of elements for Hash"
|
49
|
+
else
|
50
|
+
hsh[args.shift] = args.shift while args.size > 0
|
51
|
+
end
|
52
|
+
hsh
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize(*a, &b)
|
58
|
+
super
|
59
|
+
@order = []
|
60
|
+
end
|
61
|
+
|
62
|
+
def store_only a,b
|
63
|
+
store a,b
|
64
|
+
end
|
65
|
+
|
66
|
+
alias orig_store store
|
67
|
+
|
68
|
+
def store a,b
|
69
|
+
@order.push a unless has_key? a
|
70
|
+
super a,b
|
71
|
+
end
|
72
|
+
|
73
|
+
alias []= store
|
74
|
+
|
75
|
+
def == hsh2
|
76
|
+
return hsh2==self if !hsh2.is_a?(OrderedHash)
|
77
|
+
return false if @order != hsh2.order
|
78
|
+
super hsh2
|
79
|
+
end
|
80
|
+
|
81
|
+
def clear
|
82
|
+
@order = []
|
83
|
+
super
|
84
|
+
end
|
85
|
+
|
86
|
+
def delete key
|
87
|
+
@order.delete key
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
91
|
+
def each_key
|
92
|
+
@order.each { |k| yield k }
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
def each_value
|
97
|
+
@order.each { |k| yield self[k] }
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
def each
|
102
|
+
@order.each { |k| yield k,self[k] }
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
alias each_pair each
|
107
|
+
|
108
|
+
def delete_if
|
109
|
+
@order.clone.each { |k|
|
110
|
+
delete k if yield
|
111
|
+
}
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
def values
|
116
|
+
ary = []
|
117
|
+
@order.each { |k| ary.push self[k] }
|
118
|
+
ary
|
119
|
+
end
|
120
|
+
|
121
|
+
def keys
|
122
|
+
@order
|
123
|
+
end
|
124
|
+
|
125
|
+
def invert
|
126
|
+
hsh2 = Hash.new
|
127
|
+
@order.each { |k| hsh2[self[k]] = k }
|
128
|
+
hsh2
|
129
|
+
end
|
130
|
+
|
131
|
+
def reject &block
|
132
|
+
self.dup.delete_if( &block )
|
133
|
+
end
|
134
|
+
|
135
|
+
def reject! &block
|
136
|
+
hsh2 = reject( &block )
|
137
|
+
self == hsh2 ? nil : hsh2
|
138
|
+
end
|
139
|
+
|
140
|
+
def replace hsh2
|
141
|
+
@order = hsh2.keys
|
142
|
+
super hsh2
|
143
|
+
end
|
144
|
+
|
145
|
+
def shift
|
146
|
+
key = @order.first
|
147
|
+
key ? [key,delete(key)] : super
|
148
|
+
end
|
149
|
+
|
150
|
+
def unshift k,v
|
151
|
+
unless self.include? k
|
152
|
+
@order.unshift k
|
153
|
+
orig_store(k,v)
|
154
|
+
true
|
155
|
+
else
|
156
|
+
false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def push k,v
|
161
|
+
unless self.include? k
|
162
|
+
@order.push k
|
163
|
+
orig_store(k,v)
|
164
|
+
true
|
165
|
+
else
|
166
|
+
false
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def pop
|
171
|
+
key = @order.last
|
172
|
+
key ? [key,delete(key)] : nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def first
|
176
|
+
self[@order.first]
|
177
|
+
end
|
178
|
+
|
179
|
+
def last
|
180
|
+
self[@order.last]
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_a
|
184
|
+
ary = []
|
185
|
+
each { |k,v| ary << [k,v] }
|
186
|
+
ary
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_s
|
190
|
+
self.to_a.to_s
|
191
|
+
end
|
192
|
+
|
193
|
+
def inspect
|
194
|
+
ary = []
|
195
|
+
each {|k,v| ary << k.inspect + "=>" + v.inspect}
|
196
|
+
'{' + ary.join(", ") + '}'
|
197
|
+
end
|
198
|
+
|
199
|
+
def update hsh2
|
200
|
+
hsh2.each { |k,v| self[k] = v }
|
201
|
+
self
|
202
|
+
end
|
203
|
+
|
204
|
+
alias :merge! update
|
205
|
+
|
206
|
+
def merge hsh2
|
207
|
+
self.dup update(hsh2)
|
208
|
+
end
|
209
|
+
|
210
|
+
def select
|
211
|
+
ary = []
|
212
|
+
each { |k,v| ary << [k,v] if yield k,v }
|
213
|
+
ary
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
#=end
|
data/lib/rtf.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
#! /usr/bin/ruby -w
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
# this file is pretty crap, its just to ensure there is always something readable if
|
6
|
+
# there is an rtf only body, with no html encapsulation.
|
7
|
+
|
8
|
+
module RTF
|
9
|
+
class Tokenizer
|
10
|
+
def self.process io
|
11
|
+
while true do
|
12
|
+
case c = io.getc
|
13
|
+
when ?{; yield :open_group
|
14
|
+
when ?}; yield :close_group
|
15
|
+
when ?\\
|
16
|
+
case c = io.getc
|
17
|
+
when ?{, ?}, ?\\; yield :text, c.chr
|
18
|
+
when ?'; yield :text, [io.read(2)].pack('H*')
|
19
|
+
when ?a..?z, ?A..?Z
|
20
|
+
# read control word
|
21
|
+
str = c.chr
|
22
|
+
str << c while c = io.read(1) and c =~ /[a-zA-Z]/
|
23
|
+
neg = 1
|
24
|
+
neg = -1 and c = io.read(1) if c == '-'
|
25
|
+
num = if c =~ /[0-9]/
|
26
|
+
num = c
|
27
|
+
num << c while c = io.read(1) and c =~ /[0-9]/
|
28
|
+
num.to_i * neg
|
29
|
+
end
|
30
|
+
raise "invalid rtf stream" if neg == -1 and !num # ???? \blahblah- some text
|
31
|
+
io.seek(-1, IO::SEEK_CUR) if c != ' '
|
32
|
+
yield :control_word, str, num
|
33
|
+
when nil
|
34
|
+
raise "invalid rtf stream" # \EOF
|
35
|
+
else
|
36
|
+
# other kind of control symbol
|
37
|
+
yield :control_symbol, c.chr
|
38
|
+
end
|
39
|
+
when nil
|
40
|
+
return
|
41
|
+
when ?\r, ?\n
|
42
|
+
# ignore
|
43
|
+
else yield :text, c.chr
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Converter
|
50
|
+
# crappy
|
51
|
+
def self.rtf2text str, format=:text
|
52
|
+
group = 0
|
53
|
+
text = ''
|
54
|
+
text << "<html>\n<body>" if format == :html
|
55
|
+
group_type = []
|
56
|
+
group_tags = []
|
57
|
+
RTF::Tokenizer.process(StringIO.new(str)) do |a, b, c|
|
58
|
+
add_text = ''
|
59
|
+
case a
|
60
|
+
when :open_group; group += 1; group_type[group] = nil; group_tags[group] = []
|
61
|
+
when :close_group; group_tags[group].reverse.each { |t| text << "</#{t}>" }; group -= 1;
|
62
|
+
when :control_word; # ignore
|
63
|
+
group_type[group] ||= b
|
64
|
+
# maybe change this to use utf8 where possible
|
65
|
+
add_text = if b == 'par' || b == 'line' || b == 'page'; "\n"
|
66
|
+
elsif b == 'tab' || b == 'cell'; "\t"
|
67
|
+
elsif b == 'endash' || b == 'emdash'; "-"
|
68
|
+
elsif b == 'emspace' || b == 'enspace' || b == 'qmspace'; " "
|
69
|
+
elsif b == 'ldblquote'; '"'
|
70
|
+
else ''
|
71
|
+
end
|
72
|
+
if b == 'b' || b == 'i' and format == :html
|
73
|
+
close = c == 0 ? '/' : ''
|
74
|
+
text << "<#{close}#{b}>"
|
75
|
+
if c == 0
|
76
|
+
group_tags[group].delete b
|
77
|
+
else
|
78
|
+
group_tags[group] << b
|
79
|
+
end
|
80
|
+
end
|
81
|
+
# lot of other ones belong in here.\
|
82
|
+
=begin
|
83
|
+
\bullet Bullet character.
|
84
|
+
\lquote Left single quotation mark.
|
85
|
+
\rquote Right single quotation mark.
|
86
|
+
\ldblquote Left double quotation mark.
|
87
|
+
\rdblquote
|
88
|
+
=end
|
89
|
+
when :control_symbol; # ignore
|
90
|
+
group_type[group] ||= b
|
91
|
+
add_text = ' ' if b == '~' # non-breakable space
|
92
|
+
add_text = '-' if b == '_' # non-breakable hypen
|
93
|
+
when :text
|
94
|
+
add_text = b if group <= 1 or group_type[group] == 'rtlch' && !group_type[0...group].include?('*')
|
95
|
+
end
|
96
|
+
if format == :html
|
97
|
+
text << add_text.gsub(/([<>&"'])/) do
|
98
|
+
ent = { '<' => 'lt', '>' => 'gt', '&' => 'amp', '"' => 'quot', "'" => 'apos' }[$1]
|
99
|
+
"&#{ent};"
|
100
|
+
end
|
101
|
+
text << '<br>' if add_text == "\n"
|
102
|
+
else
|
103
|
+
text << add_text
|
104
|
+
end
|
105
|
+
end
|
106
|
+
text << "</body>\n</html>\n" if format == :html
|
107
|
+
text
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
if $0 == __FILE__
|
113
|
+
#str = File.read('test.rtf')
|
114
|
+
str = YAML.load(open('rtfs.yaml'))[2]
|
115
|
+
#puts str
|
116
|
+
puts text
|
117
|
+
end
|
118
|
+
|
data/lib/support.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# A file with general support functions used by most files in the project.
|
4
|
+
#
|
5
|
+
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
class File # :nodoc:
|
9
|
+
# for consistency with StringIO and others. makes more sense than forcing
|
10
|
+
# them to provide a #stat
|
11
|
+
def size
|
12
|
+
stat.size
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Symbol # :nodoc:
|
17
|
+
def to_proc
|
18
|
+
proc { |a| a.send self }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Enumerable # :nodoc:
|
23
|
+
# 1.9 backport
|
24
|
+
def group_by
|
25
|
+
hash = Hash.new { |hash, key| hash[key] = [] }
|
26
|
+
each { |item| hash[yield(item)] << item }
|
27
|
+
hash
|
28
|
+
end
|
29
|
+
|
30
|
+
def sum initial=0
|
31
|
+
inject(initial) { |a, b| a + b }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Logger # :nodoc:
|
36
|
+
# A helper method for creating <tt>Logger</tt>s which produce call stack
|
37
|
+
# in their output
|
38
|
+
def self.new_with_callstack logdev=STDERR
|
39
|
+
log = Logger.new logdev
|
40
|
+
log.level = WARN
|
41
|
+
log.formatter = proc do |severity, time, progname, msg|
|
42
|
+
# find where we were called from, in our code
|
43
|
+
callstack = caller.dup
|
44
|
+
callstack.shift while callstack.first =~ /\/logger\.rb:\d+:in/
|
45
|
+
from = callstack.first.sub(/:in `(.*?)'/, ":\\1")
|
46
|
+
"[%s %s]\n%-7s%s\n" % [time.strftime('%H:%M:%S'), from, severity, msg.to_s]
|
47
|
+
end
|
48
|
+
log
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
data/test/test_mime.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#! /usr/bin/ruby -w
|
2
|
+
|
3
|
+
TEST_DIR = File.dirname __FILE__
|
4
|
+
$: << "#{TEST_DIR}/../lib"
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'mime'
|
8
|
+
|
9
|
+
class TestMime < Test::Unit::TestCase
|
10
|
+
# test out the way it partitions a message into parts
|
11
|
+
def test_parsing_no_multipart
|
12
|
+
mime = Mime.new "Header1: Value1\r\nHeader2: Value2\r\n\r\nBody text."
|
13
|
+
assert_equal ['Value1'], mime.headers['Header1']
|
14
|
+
assert_equal 'Body text.', mime.body
|
15
|
+
assert_equal false, mime.multipart?
|
16
|
+
assert_equal nil, mime.parts
|
17
|
+
# we get round trip conversion. this is mostly fluke, as orderedhash hasn't been
|
18
|
+
# added yet
|
19
|
+
assert_equal "Header1: Value1\r\nHeader2: Value2\r\n\r\nBody text.", mime.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,139 @@
|
|
1
|
+
#! /usr/bin/ruby -w
|
2
|
+
|
3
|
+
TEST_DIR = File.dirname __FILE__
|
4
|
+
$: << "#{TEST_DIR}/../lib"
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'ole/storage'
|
8
|
+
require 'digest/sha1'
|
9
|
+
require 'stringio'
|
10
|
+
|
11
|
+
#
|
12
|
+
# = TODO
|
13
|
+
#
|
14
|
+
# These tests could be a lot more complete.
|
15
|
+
#
|
16
|
+
|
17
|
+
class TestRangesIO < Test::Unit::TestCase
|
18
|
+
def setup
|
19
|
+
# why not :) ?
|
20
|
+
# repeats too
|
21
|
+
ranges = [100..200, 0..10, 100..150]
|
22
|
+
@io = RangesIO.new open("#{TEST_DIR}/test_storage.rb"), ranges, :close_parent => true
|
23
|
+
end
|
24
|
+
|
25
|
+
def teardown
|
26
|
+
@io.close
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_basic
|
30
|
+
assert_equal 160, @io.size
|
31
|
+
# this will map to the start of the file:
|
32
|
+
@io.pos = 100
|
33
|
+
assert_equal '#! /usr/bi', @io.read(10)
|
34
|
+
end
|
35
|
+
|
36
|
+
# should test range_and_offset specifically
|
37
|
+
|
38
|
+
def test_reading
|
39
|
+
# test selection of initial range, offset within that range
|
40
|
+
pos = 100
|
41
|
+
@io.seek pos
|
42
|
+
# test advancing of pos properly, by...
|
43
|
+
chunked = (0...10).map { @io.read 10 }.join
|
44
|
+
# given the file is 160 long:
|
45
|
+
assert_equal 60, chunked.length
|
46
|
+
@io.seek pos
|
47
|
+
# comparing with a flat read
|
48
|
+
assert_equal chunked, @io.read(60)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# should test resizeable and migrateable IO.
|
53
|
+
|
54
|
+
class TestStorageRead < Test::Unit::TestCase
|
55
|
+
def setup
|
56
|
+
@ole = Ole::Storage.open "#{TEST_DIR}/test_word_6.doc", 'rb'
|
57
|
+
end
|
58
|
+
|
59
|
+
def teardown
|
60
|
+
@ole.close
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_header
|
64
|
+
# should have further header tests, testing the validation etc.
|
65
|
+
assert_equal 17, @ole.header.to_a.length
|
66
|
+
assert_equal 117, @ole.header.dirent_start
|
67
|
+
assert_equal 1, @ole.header.num_bat
|
68
|
+
assert_equal 1, @ole.header.num_sbat
|
69
|
+
assert_equal 0, @ole.header.num_mbat
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_fat
|
73
|
+
# the fat block has all the numbers from 5..118 bar 117
|
74
|
+
bbat_table = [112] + ((5..118).to_a - [112, 117])
|
75
|
+
assert_equal bbat_table, @ole.bbat.table.reject { |i| i >= (1 << 32) - 3 }, 'bbat'
|
76
|
+
sbat_table = (1..43).to_a - [2, 3]
|
77
|
+
assert_equal sbat_table, @ole.sbat.table.reject { |i| i >= (1 << 32) - 3 }, 'sbat'
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_directories
|
81
|
+
assert_equal 5, @ole.dirents.length, 'have all directories'
|
82
|
+
# a more complicated one would be good for this
|
83
|
+
assert_equal 4, @ole.root.children.length, 'properly nested directories'
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_utf16_conversion
|
87
|
+
assert_equal 'Root Entry', @ole.root.name
|
88
|
+
assert_equal 'WordDocument', @ole.root.children[2].name
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_data
|
92
|
+
# test the ole storage type
|
93
|
+
type = 'Microsoft Word 6.0-Dokument'
|
94
|
+
assert_equal type, @ole.root["\001CompObj"].read[/^.{32}([^\x00]+)/m, 1]
|
95
|
+
# i was actually not loading data correctly before, so carefully check everything here
|
96
|
+
hashes = [-482597081, 285782478, 134862598, -863988921]
|
97
|
+
assert_equal hashes, @ole.root.children.map { |child| child.read.hash }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class TestStorageWrite < Test::Unit::TestCase
|
102
|
+
def sha1 str
|
103
|
+
Digest::SHA1.hexdigest str
|
104
|
+
end
|
105
|
+
|
106
|
+
# FIXME
|
107
|
+
# don't really want to lock down the actual internal api's yet. this will just
|
108
|
+
# ensure for the time being that #flush continues to work properly. need a host
|
109
|
+
# of checks involving writes that resize their file bigger/smaller, that resize
|
110
|
+
# the bats to more blocks, that resizes the sb_blocks, that has migration etc.
|
111
|
+
def test_write_hash
|
112
|
+
io = StringIO.open File.read("#{TEST_DIR}/test_word_6.doc")
|
113
|
+
assert_equal '9974e354def8471225f548f82b8d81c701221af7', sha1(io.string)
|
114
|
+
Ole::Storage.open(io) { }
|
115
|
+
assert_equal 'efa8cfaf833b30b1d1d9381771ddaafdfc95305c', sha1(io.string)
|
116
|
+
# add a repack test here
|
117
|
+
Ole::Storage.open io, &:repack
|
118
|
+
assert_equal 'c8bb9ccacf0aaad33677e1b2a661ee6e66a48b5a', sha1(io.string)
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_plain_repack
|
122
|
+
io = StringIO.open File.read("#{TEST_DIR}/test_word_6.doc")
|
123
|
+
assert_equal '9974e354def8471225f548f82b8d81c701221af7', sha1(io.string)
|
124
|
+
Ole::Storage.open io, &:repack
|
125
|
+
# note equivalence to the above flush, repack, flush
|
126
|
+
assert_equal 'c8bb9ccacf0aaad33677e1b2a661ee6e66a48b5a', sha1(io.string)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_create_from_scratch_hash
|
130
|
+
io = StringIO.new
|
131
|
+
Ole::Storage.new(io) { }
|
132
|
+
assert_equal '6bb9d6c1cdf1656375e30991948d70c5fff63d57', sha1(io.string)
|
133
|
+
# more repack test, note invariance
|
134
|
+
Ole::Storage.open io, &:repack
|
135
|
+
assert_equal '6bb9d6c1cdf1656375e30991948d70c5fff63d57', sha1(io.string)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
Binary file
|
Binary file
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: ruby-msg
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.2.17
|
7
|
+
date: 2007-05-13 00:00:00 +10:00
|
8
|
+
summary: Ruby Msg library.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: aquasync@gmail.com
|
12
|
+
homepage: http://code.google.com/p/ruby-msg
|
13
|
+
rubyforge_project:
|
14
|
+
description: A library for reading Outlook msg files, and for converting them to RFC2822 emails.
|
15
|
+
autorequire: msg
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Charles Lowe
|
31
|
+
files:
|
32
|
+
- data/named_map.yaml
|
33
|
+
- data/types.yaml
|
34
|
+
- data/mapitags.yaml
|
35
|
+
- Rakefile
|
36
|
+
- README
|
37
|
+
- FIXES
|
38
|
+
- bin/msgtool
|
39
|
+
- bin/oletool
|
40
|
+
- lib/orderedhash.rb
|
41
|
+
- lib/blah.rb
|
42
|
+
- lib/mime-new.rb
|
43
|
+
- lib/rtf.rb
|
44
|
+
- lib/support.rb
|
45
|
+
- lib/mime.rb
|
46
|
+
- lib/msg.rb
|
47
|
+
- lib/ole/types.rb
|
48
|
+
- lib/ole/file_system.rb
|
49
|
+
- lib/ole/storage.rb
|
50
|
+
- lib/ole/io_helpers.rb
|
51
|
+
- lib/ole/base.rb
|
52
|
+
- lib/msg/rtf.rb
|
53
|
+
- lib/msg/properties.rb
|
54
|
+
- test/test_mime.rb
|
55
|
+
- test/test_storage.rb
|
56
|
+
- test/test_word_6.doc
|
57
|
+
- test/test_word_95.doc
|
58
|
+
- test/test_word_97.doc
|
59
|
+
test_files: []
|
60
|
+
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
extra_rdoc_files: []
|
64
|
+
|
65
|
+
executables:
|
66
|
+
- msgtool
|
67
|
+
- oletool
|
68
|
+
extensions: []
|
69
|
+
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
dependencies: []
|
73
|
+
|