ruby-ole 1.2.3 → 1.2.4
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/ChangeLog +5 -0
- data/Rakefile +1 -1
- data/data/propids.yaml +56 -0
- data/lib/ole/file_system.rb +5 -1
- data/lib/ole/property_set.rb +85 -9
- data/lib/ole/storage.rb +14 -11
- data/lib/ole/types.rb +18 -7
- data/test/test.doc +0 -0
- data/test/test_filesystem.rb +4 -6
- data/test/test_mbat.rb +2 -0
- data/test/test_property_set.rb +13 -3
- data/test/test_storage.rb +45 -4
- data/test/test_support.rb +1 -1
- metadata +4 -2
data/ChangeLog
CHANGED
data/Rakefile
CHANGED
@@ -53,7 +53,7 @@ spec = Gem::Specification.new do |s|
|
|
53
53
|
s.rubyforge_project = %q{ruby-ole}
|
54
54
|
|
55
55
|
s.executables = ['oletool']
|
56
|
-
s.files = ['Rakefile', 'ChangeLog']
|
56
|
+
s.files = ['Rakefile', 'ChangeLog', 'data/propids.yaml']
|
57
57
|
s.files += FileList['lib/**/*.rb']
|
58
58
|
s.files += FileList['test/test_*.rb', 'test/*.doc']
|
59
59
|
s.files += FileList['test/oleWithDirs.ole', 'test/test_SummaryInformation']
|
data/data/propids.yaml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
"{f29f85e0-4ff9-1068-ab91-08002b27b3d9}":
|
2
|
+
- FMTID_SummaryInformation
|
3
|
+
- 2: doc_title
|
4
|
+
3: doc_subject
|
5
|
+
4: doc_author
|
6
|
+
5: doc_keywords
|
7
|
+
6: doc_comments
|
8
|
+
7: doc_template
|
9
|
+
8: doc_last_author
|
10
|
+
9: doc_rev_number
|
11
|
+
10: doc_edit_time
|
12
|
+
11: doc_last_printed
|
13
|
+
12: doc_created_time
|
14
|
+
13: doc_last_saved_time
|
15
|
+
14: doc_page_count
|
16
|
+
15: doc_word_count
|
17
|
+
16: doc_char_count
|
18
|
+
18: doc_app_name
|
19
|
+
19: security
|
20
|
+
|
21
|
+
"{d5cdd502-2e9c-101b-9397-08002b2cf9ae}":
|
22
|
+
- FMTID_DocSummaryInfo
|
23
|
+
- 2: doc_category
|
24
|
+
3: doc_presentation_target
|
25
|
+
4: doc_byte_count
|
26
|
+
5: doc_line_count
|
27
|
+
6: doc_para_count
|
28
|
+
7: doc_slide_count
|
29
|
+
8: doc_note_count
|
30
|
+
9: doc_hidden_count
|
31
|
+
10: mmclips
|
32
|
+
11: scale_crop
|
33
|
+
12: heading_pairs
|
34
|
+
13: doc_part_titles
|
35
|
+
14: doc_manager
|
36
|
+
15: doc_company
|
37
|
+
16: links_up_to_date
|
38
|
+
|
39
|
+
"{d5cdd505-2e9c-101b-9397-08002b2cf9ae}":
|
40
|
+
- FMTID_UserDefinedProperties
|
41
|
+
- {}
|
42
|
+
|
43
|
+
# just dumped these all here. if i can confirm any of these
|
44
|
+
# better, i can update this file so they're recognized.
|
45
|
+
#0b63e343-9ccc-11d0-bcdb-00805fccce04
|
46
|
+
#0b63e350-9ccc-11d0-bcdb-00805fccce04 NetLibrary propset?
|
47
|
+
#31f400a0-fd07-11cf-b9bd-00aa003db18e ScriptInfo propset?
|
48
|
+
#49691c90-7e17-101a-a91c-08002b2ecda9 Query propset?
|
49
|
+
#560c36c0-503a-11cf-baa1-00004c752a9a
|
50
|
+
#70eb7a10-55d9-11cf-b75b-00aa0051fe20 HTMLInfo propset
|
51
|
+
#85ac0960-1819-11d1-896f-00805f053bab message propset?
|
52
|
+
#aa568eec-e0e5-11cf-8fda-00aa00a14f93 NNTP SummaryInformation propset?
|
53
|
+
#b725f130-47ef-101a-a5f1-02608c9eebac Storage propset
|
54
|
+
#c82bf596-b831-11d0-b733-00aa00a1ebd2 NetLibraryInfo propset
|
55
|
+
#c82bf597-b831-11d0-b733-00aa00a1ebd2 LinkInformation propset?
|
56
|
+
#d1b5d3f0-c0b3-11cf-9a92-00a0c908dbf1 LinkInformation propset?
|
data/lib/ole/file_system.rb
CHANGED
@@ -132,7 +132,11 @@ module Ole # :nodoc:
|
|
132
132
|
# just for the .. and . handling
|
133
133
|
# Hmmm, FIXME: won't work on windows i think. on windows it will prepend
|
134
134
|
# the current drive i believe. may just need to strip the first 2 chars.
|
135
|
-
|
135
|
+
if RUBY_PLATFORM =~ /win/o
|
136
|
+
File.expand_path(path)[2..-1]
|
137
|
+
else
|
138
|
+
File.expand_path path
|
139
|
+
end
|
136
140
|
end
|
137
141
|
|
138
142
|
# +orig_path+ is just so that we can use the requested path
|
data/lib/ole/property_set.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ole/types'
|
2
|
+
require 'yaml'
|
2
3
|
|
3
4
|
module Ole
|
4
5
|
module Types
|
@@ -13,30 +14,41 @@ module Ole
|
|
13
14
|
#
|
14
15
|
class PropertySet
|
15
16
|
HEADER_SIZE = 28
|
16
|
-
|
17
|
+
HEADER_PACK = "vvVa#{Clsid::SIZE}V"
|
17
18
|
OS_MAP = {
|
18
19
|
0 => :win16,
|
19
20
|
1 => :mac,
|
20
|
-
2 => :win32
|
21
|
+
2 => :win32,
|
22
|
+
0x20001 => :ooffice, # open office on linux...
|
21
23
|
}
|
22
24
|
|
23
25
|
# define a smattering of the property set guids.
|
24
|
-
FMTID_SummaryInformation = Clsid.parse '{f29f85e0-4ff9-1068-ab91-08002b27b3d9}'
|
25
|
-
FMTID_DocSummaryInformation = Clsid.parse '{d5cdd502-2e9c-101b-9397-08002b2cf9ae}'
|
26
|
-
FMTID_UserDefinedProperties = Clsid.parse '{d5cdd505-2e9c-101b-9397-08002b2cf9ae}'
|
26
|
+
#FMTID_SummaryInformation = Clsid.parse '{f29f85e0-4ff9-1068-ab91-08002b27b3d9}'
|
27
|
+
#FMTID_DocSummaryInformation = Clsid.parse '{d5cdd502-2e9c-101b-9397-08002b2cf9ae}'
|
28
|
+
#FMTID_UserDefinedProperties = Clsid.parse '{d5cdd505-2e9c-101b-9397-08002b2cf9ae}'
|
29
|
+
|
30
|
+
DATA = YAML.load_file(File.dirname(__FILE__) + '/../../data/propids.yaml').
|
31
|
+
inject({}) { |hash, (key, value)| hash.update Clsid.parse(key) => value }
|
32
|
+
|
33
|
+
module Constants
|
34
|
+
DATA.each { |guid, (name, map)| const_set name, guid }
|
35
|
+
end
|
36
|
+
|
37
|
+
include Constants
|
27
38
|
|
28
39
|
class Section < Struct.new(:guid, :offset)
|
29
40
|
include Variant::Constants
|
30
41
|
include Enumerable
|
31
42
|
|
32
43
|
SIZE = Clsid::SIZE + 4
|
33
|
-
|
44
|
+
PACK = "a#{Clsid::SIZE}v"
|
34
45
|
|
35
46
|
attr_reader :length
|
36
47
|
def initialize str, property_set
|
37
48
|
@property_set = property_set
|
38
|
-
super(*str.unpack(
|
49
|
+
super(*str.unpack(PACK))
|
39
50
|
self.guid = Clsid.load guid
|
51
|
+
@map = DATA[guid] ? DATA[guid][1] : nil
|
40
52
|
load_header
|
41
53
|
end
|
42
54
|
|
@@ -66,9 +78,30 @@ module Ole
|
|
66
78
|
self
|
67
79
|
end
|
68
80
|
|
81
|
+
def [] key
|
82
|
+
unless Integer === key
|
83
|
+
return unless @map and key = @map.invert[key]
|
84
|
+
end
|
85
|
+
return unless result = properties.assoc(key)
|
86
|
+
result.last
|
87
|
+
end
|
88
|
+
|
89
|
+
def method_missing name, *args
|
90
|
+
if args.empty? and @map and @map.values.include? name.to_s
|
91
|
+
self[name.to_s]
|
92
|
+
else
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
69
97
|
def properties
|
70
|
-
to_enum.to_a
|
98
|
+
@properties ||= to_enum.to_a
|
71
99
|
end
|
100
|
+
|
101
|
+
#def to_h
|
102
|
+
# properties.inject({}) do |hash, (key, type, value)|
|
103
|
+
# hash.update
|
104
|
+
#end
|
72
105
|
end
|
73
106
|
|
74
107
|
attr_reader :io, :signature, :unknown, :os, :guid, :sections
|
@@ -81,7 +114,7 @@ module Ole
|
|
81
114
|
end
|
82
115
|
|
83
116
|
def load_header str
|
84
|
-
@signature, @unknown, @os_id, @guid, @num_sections = str.unpack
|
117
|
+
@signature, @unknown, @os_id, @guid, @num_sections = str.unpack HEADER_PACK
|
85
118
|
# should i check that unknown == 0? it usually is. so is the guid actually
|
86
119
|
@guid = Clsid.load @guid
|
87
120
|
@os = OS_MAP[@os_id] || Log.warn("unknown operating system id #{@os_id}")
|
@@ -92,5 +125,48 @@ module Ole
|
|
92
125
|
end
|
93
126
|
end
|
94
127
|
end
|
128
|
+
|
129
|
+
class Storage
|
130
|
+
# i'm thinking - search for a property set in +filenames+ containing a
|
131
|
+
# section with guid +guid+. then yield it. can read/write to it in the
|
132
|
+
# block.
|
133
|
+
# propsets themselves can have guids, but they are often all null.
|
134
|
+
def with_property_set guid, filenames=nil
|
135
|
+
end
|
136
|
+
|
137
|
+
class PropertySetSectionProxy
|
138
|
+
attr_reader :obj, :section_num
|
139
|
+
def initialize obj, section_num
|
140
|
+
@obj, @section_num = obj, section_num
|
141
|
+
end
|
142
|
+
|
143
|
+
def method_missing name, *args, &block
|
144
|
+
obj.open do |io|
|
145
|
+
section = Types::PropertySet.new(io).sections[section_num]
|
146
|
+
section.send name, *args, &block
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# this will be changed to use with_property_set
|
152
|
+
def summary_information
|
153
|
+
dirent = root["\005SummaryInformation"]
|
154
|
+
dirent.open do |io|
|
155
|
+
propset = Types::PropertySet.new(io)
|
156
|
+
sections = propset.sections
|
157
|
+
# this will maybe get wrapped up as
|
158
|
+
# section = propset[guid]
|
159
|
+
# maybe taking it one step further, i'd hide the section thing,
|
160
|
+
# and let you use composite keys, like
|
161
|
+
# propset[4, guid] eg in MAPI, and just propset.doc_author.
|
162
|
+
section = sections.find do |section|
|
163
|
+
section.guid == Types::PropertySet::FMTID_SummaryInformation
|
164
|
+
end
|
165
|
+
return PropertySetSectionProxy.new(dirent, sections.index(section))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
alias summary_info :summary_information
|
170
|
+
end
|
95
171
|
end
|
96
172
|
|
data/lib/ole/storage.rb
CHANGED
@@ -67,7 +67,7 @@ module Ole # :nodoc:
|
|
67
67
|
class FormatError < StandardError # :nodoc:
|
68
68
|
end
|
69
69
|
|
70
|
-
VERSION = '1.2.
|
70
|
+
VERSION = '1.2.4'
|
71
71
|
|
72
72
|
# options used at creation time
|
73
73
|
attr_reader :params
|
@@ -151,7 +151,7 @@ module Ole # :nodoc:
|
|
151
151
|
# create an empty bbat.
|
152
152
|
@bbat = AllocationTable::Big.new self
|
153
153
|
mbat_blocks = (0...@header.num_mbat).map { |i| i + @header.mbat_start }
|
154
|
-
bbat_chain = (header_block[Header::SIZE..-1] + @bbat.read(mbat_blocks)).unpack '
|
154
|
+
bbat_chain = (header_block[Header::SIZE..-1] + @bbat.read(mbat_blocks)).unpack 'V*'
|
155
155
|
# am i using num_bat in the right way?
|
156
156
|
@bbat.load @bbat.read(bbat_chain[0, @header.num_bat])
|
157
157
|
|
@@ -308,12 +308,12 @@ module Ole # :nodoc:
|
|
308
308
|
q = @bbat.block_size / 4
|
309
309
|
mbat_data += [AllocationTable::AVAIL] *((mbat_data.length / q.to_f).ceil * q - mbat_data.length)
|
310
310
|
ranges = @bbat.ranges((0...num_mbat_blocks).map { |i| @header.mbat_start + i })
|
311
|
-
RangesIO.open(@io, :ranges => ranges) { |io| io.write mbat_data.pack('
|
311
|
+
RangesIO.open(@io, :ranges => ranges) { |io| io.write mbat_data.pack('V*') }
|
312
312
|
end
|
313
313
|
|
314
314
|
# now seek back and write the header out
|
315
315
|
@io.seek 0
|
316
|
-
@io.write @header.to_s + bbat_chain[0, 109].pack('
|
316
|
+
@io.write @header.to_s + bbat_chain[0, 109].pack('V*')
|
317
317
|
@io.flush
|
318
318
|
end
|
319
319
|
|
@@ -333,10 +333,13 @@ module Ole # :nodoc:
|
|
333
333
|
end
|
334
334
|
|
335
335
|
# could be useful with mis-behaving ole documents. or to just clean them up.
|
336
|
-
# FIXME: heard Tempfile is not binary on windows. check
|
337
336
|
def repack temp=:file
|
338
337
|
case temp
|
339
|
-
when :file
|
338
|
+
when :file
|
339
|
+
Tempfile.open 'ole-repack' do |io|
|
340
|
+
io.binmode
|
341
|
+
repack_using_io io
|
342
|
+
end
|
340
343
|
when :mem; StringIO.open(&method(:repack_using_io))
|
341
344
|
else raise ArgumentError, "unknown temp backing #{temp.inspect}"
|
342
345
|
end
|
@@ -372,7 +375,7 @@ module Ole # :nodoc:
|
|
372
375
|
:reserved, :csectdir, :num_bat, :dirent_start, :transacting_signature, :threshold,
|
373
376
|
:sbat_start, :num_sbat, :mbat_start, :num_mbat
|
374
377
|
)
|
375
|
-
PACK = 'a8 a16
|
378
|
+
PACK = 'a8 a16 v2 a2 v2 a6 V3 a4 V5'
|
376
379
|
SIZE = 0x4c
|
377
380
|
# i have seen it pointed out that the first 4 bytes of hex,
|
378
381
|
# 0xd0cf11e0, is supposed to spell out docfile. hmmm :)
|
@@ -462,7 +465,7 @@ module Ole # :nodoc:
|
|
462
465
|
end
|
463
466
|
|
464
467
|
def load data
|
465
|
-
replace data.unpack('
|
468
|
+
replace data.unpack('V*')
|
466
469
|
end
|
467
470
|
|
468
471
|
def truncate
|
@@ -486,7 +489,7 @@ module Ole # :nodoc:
|
|
486
489
|
# do you really use AVAIL? they probably extend past end of file, and may shortly
|
487
490
|
# be used for the bat. not really good.
|
488
491
|
table += [AVAIL] * (num - (table.length % num)) if (table.length % num) != 0
|
489
|
-
table.pack '
|
492
|
+
table.pack 'V*'
|
490
493
|
end
|
491
494
|
|
492
495
|
# rewrote this to be non-recursive as it broke on a large attachment
|
@@ -716,7 +719,7 @@ module Ole # :nodoc:
|
|
716
719
|
)
|
717
720
|
include RecursivelyEnumerable
|
718
721
|
|
719
|
-
PACK = 'a64
|
722
|
+
PACK = 'a64 v C C V3 a16 V a8 a8 V2 a4'
|
720
723
|
SIZE = 128
|
721
724
|
TYPE_MAP = {
|
722
725
|
# this is temporary
|
@@ -754,7 +757,7 @@ module Ole # :nodoc:
|
|
754
757
|
super(*values)
|
755
758
|
|
756
759
|
# extra parsing from the actual struct values
|
757
|
-
@name = params[:name] || Types::Variant.load(Types::VT_LPWSTR, name_utf16[0...name_len]
|
760
|
+
@name = params[:name] || Types::Variant.load(Types::VT_LPWSTR, name_utf16[0...name_len])
|
758
761
|
@type = if params[:type]
|
759
762
|
unless TYPE_MAP.values.include?(params[:type])
|
760
763
|
raise ArgumentError, "unknown type #{params[:type].inspect}"
|
data/lib/ole/types.rb
CHANGED
@@ -22,7 +22,17 @@ module Ole # :nodoc:
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
class Lpstr <
|
25
|
+
class Lpstr < String
|
26
|
+
def self.load str
|
27
|
+
# not sure if its always there, but there is often a trailing
|
28
|
+
# null byte.
|
29
|
+
new str.chomp(0.chr)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.dump str
|
33
|
+
# do i need to append the null byte?
|
34
|
+
str.to_s
|
35
|
+
end
|
26
36
|
end
|
27
37
|
|
28
38
|
# for VT_LPWSTR
|
@@ -31,10 +41,11 @@ module Ole # :nodoc:
|
|
31
41
|
TO_UTF16 = Iconv.new 'utf-16le', 'utf-8'
|
32
42
|
|
33
43
|
def self.load str
|
34
|
-
new FROM_UTF16.iconv(str)
|
44
|
+
new FROM_UTF16.iconv(str).chomp(0.chr)
|
35
45
|
end
|
36
46
|
|
37
47
|
def self.dump str
|
48
|
+
# need to append nulls?
|
38
49
|
TO_UTF16.iconv str
|
39
50
|
end
|
40
51
|
end
|
@@ -50,7 +61,7 @@ module Ole # :nodoc:
|
|
50
61
|
# Converts +str+ to two 32 bit time values, comprising the high and low 32 bits of
|
51
62
|
# the 100's of nanoseconds since 1st january 1601 (Epoch).
|
52
63
|
def self.load str
|
53
|
-
low, high = str.to_s.unpack '
|
64
|
+
low, high = str.to_s.unpack 'V2'
|
54
65
|
# we ignore these, without even warning about it
|
55
66
|
return nil if low == 0 and high == 0
|
56
67
|
# switched to rational, and fixed the off by 1 second error i sometimes got.
|
@@ -74,7 +85,7 @@ module Ole # :nodoc:
|
|
74
85
|
# don't bother to use const_get here
|
75
86
|
bignum = (time - EPOCH) * 86400 * 1e7.to_i
|
76
87
|
high, low = bignum.divmod 1 << 32
|
77
|
-
[low, high].pack '
|
88
|
+
[low, high].pack 'V2'
|
78
89
|
end
|
79
90
|
end
|
80
91
|
|
@@ -85,7 +96,7 @@ module Ole # :nodoc:
|
|
85
96
|
# helper method for creating a Guid from that readable form (#format).
|
86
97
|
class Clsid < String
|
87
98
|
SIZE = 16
|
88
|
-
|
99
|
+
PACK = 'V v v CC C6'
|
89
100
|
|
90
101
|
def self.load str
|
91
102
|
new str.to_s
|
@@ -103,14 +114,14 @@ module Ole # :nodoc:
|
|
103
114
|
# this is pretty ugly
|
104
115
|
vals[3] = ('%04x' % vals[3]).scan(/../).map(&:hex)
|
105
116
|
vals[4] = ('%012x' % vals[4]).scan(/../).map(&:hex)
|
106
|
-
guid = new vals.flatten.pack(
|
117
|
+
guid = new vals.flatten.pack(PACK)
|
107
118
|
return guid unless guid.delete('{}') == str.downcase.delete('{}')
|
108
119
|
end
|
109
120
|
raise ArgumentError, 'invalid guid - %p' % str
|
110
121
|
end
|
111
122
|
|
112
123
|
def format
|
113
|
-
"%08x-%04x-%04x-%02x%02x-#{'%02x' * 6}" % unpack(
|
124
|
+
"%08x-%04x-%04x-%02x%02x-#{'%02x' * 6}" % unpack(PACK)
|
114
125
|
end
|
115
126
|
|
116
127
|
def inspect
|
data/test/test.doc
ADDED
Binary file
|
data/test/test_filesystem.rb
CHANGED
@@ -49,7 +49,7 @@ end
|
|
49
49
|
|
50
50
|
class OleFsNonmutatingTest < Test::Unit::TestCase
|
51
51
|
def setup
|
52
|
-
@ole = Ole::Storage.open TEST_DIR + '/oleWithDirs.ole'
|
52
|
+
@ole = Ole::Storage.open TEST_DIR + '/oleWithDirs.ole', 'rb'
|
53
53
|
end
|
54
54
|
|
55
55
|
def teardown
|
@@ -502,7 +502,7 @@ end
|
|
502
502
|
class OleFsFileStatTest < Test::Unit::TestCase
|
503
503
|
|
504
504
|
def setup
|
505
|
-
@ole = Ole::Storage.open TEST_DIR + '/oleWithDirs.ole'
|
505
|
+
@ole = Ole::Storage.open TEST_DIR + '/oleWithDirs.ole', 'rb'
|
506
506
|
end
|
507
507
|
|
508
508
|
def teardown
|
@@ -569,7 +569,7 @@ class OleFsFileMutatingTest < Test::Unit::TestCase
|
|
569
569
|
def setup
|
570
570
|
# we use an in memory copy of the file instead of the original
|
571
571
|
# file based.
|
572
|
-
@io = StringIO.new
|
572
|
+
@io = StringIO.new open(TEST_DIR + '/oleWithDirs.ole', 'rb', &:read)
|
573
573
|
end
|
574
574
|
|
575
575
|
def teardown
|
@@ -660,12 +660,10 @@ class OleFsFileMutatingTest < Test::Unit::TestCase
|
|
660
660
|
end
|
661
661
|
|
662
662
|
class ZipFsDirectoryTest < Test::Unit::TestCase
|
663
|
-
TEST_ZIP = "zipWithDirs_copy.zip"
|
664
|
-
|
665
663
|
def setup
|
666
664
|
# we use an in memory copy of the file instead of the original
|
667
665
|
# file based.
|
668
|
-
@io = StringIO.new
|
666
|
+
@io = StringIO.new open(TEST_DIR + '/oleWithDirs.ole', 'rb', &:read)
|
669
667
|
end
|
670
668
|
|
671
669
|
def teardown
|
data/test/test_mbat.rb
CHANGED
@@ -10,6 +10,8 @@ require 'tempfile'
|
|
10
10
|
class TestWriteMbat < Test::Unit::TestCase
|
11
11
|
def test_write_mbat
|
12
12
|
Tempfile.open 'myolefile' do |temp|
|
13
|
+
temp.binmode
|
14
|
+
|
13
15
|
# this used to raise an error at flush time, due to failure to write the mbat
|
14
16
|
Ole::Storage.open temp do |ole|
|
15
17
|
# create a 10mb file
|
data/test/test_property_set.rb
CHANGED
@@ -3,13 +3,14 @@
|
|
3
3
|
$: << File.dirname(__FILE__) + '/../lib'
|
4
4
|
|
5
5
|
require 'test/unit'
|
6
|
+
require 'ole/storage'
|
6
7
|
require 'ole/property_set'
|
7
8
|
|
8
9
|
class TestTypes < Test::Unit::TestCase
|
9
10
|
include Ole::Types
|
10
11
|
|
11
12
|
def setup
|
12
|
-
@io = open File.dirname(__FILE__) + '/test_SummaryInformation'
|
13
|
+
@io = open File.dirname(__FILE__) + '/test_SummaryInformation', 'rb'
|
13
14
|
end
|
14
15
|
|
15
16
|
def teardown
|
@@ -18,13 +19,22 @@ class TestTypes < Test::Unit::TestCase
|
|
18
19
|
|
19
20
|
def test_property_set
|
20
21
|
propset = PropertySet.new @io
|
22
|
+
assert_equal :mac, propset.os
|
21
23
|
assert_equal 1, propset.sections.length
|
22
24
|
section = propset.sections.first
|
23
25
|
assert_equal 14, section.length
|
24
26
|
assert_equal 'f29f85e0-4ff9-1068-ab91-08002b27b3d9', section.guid.format
|
25
27
|
assert_equal PropertySet::FMTID_SummaryInformation, section.guid
|
26
|
-
|
27
|
-
|
28
|
+
assert_equal 'Charles Lowe', section.properties.assoc(4).last
|
29
|
+
# new named support
|
30
|
+
assert_equal 'Charles Lowe', section.doc_author
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_ole_storage_integration
|
34
|
+
Ole::Storage.open File.dirname(__FILE__) + '/test.doc', 'rb' do |ole|
|
35
|
+
assert_equal 'Charles Lowe', ole.summary_info.doc_author
|
36
|
+
assert_equal 'Title', ole.summary_info.doc_title
|
37
|
+
end
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
data/test/test_storage.rb
CHANGED
@@ -7,6 +7,8 @@ require 'ole/storage'
|
|
7
7
|
require 'digest/sha1'
|
8
8
|
require 'stringio'
|
9
9
|
require 'tempfile'
|
10
|
+
require 'zlib'
|
11
|
+
require 'base64'
|
10
12
|
|
11
13
|
#
|
12
14
|
# = TODO
|
@@ -60,12 +62,51 @@ class TestStorageRead < Test::Unit::TestCase
|
|
60
62
|
end
|
61
63
|
|
62
64
|
def test_read
|
65
|
+
# this data should probably be put elsewhere. not asserting
|
66
|
+
# using hashes anymore, cause they were different on the mac.
|
67
|
+
data = <<-end
|
68
|
+
eJxjZGBgYkADAABKAAQ=
|
69
|
+
|
70
|
+
eJxjZPj3n5mLgeE/EDBwMjGAwAEwyeAmAyR8M5OL8ovz00oUwvOLUhTM9Ax0
|
71
|
+
XfKzS3NT80oYuEDywSBxl/xkBgEgD8TWA3LA8npmYGMAKWQZqA==
|
72
|
+
|
73
|
+
eJztVs9rE0EU/mZ32m5smyZtUlKQunhIezAV6knwYGoRxRLQBG89zCabdiE7
|
74
|
+
K9kJpt7Es1DwLxCsP+jJqycv/S/8I9SrmPgmuy0pK1ilNZd8MPt233zz7dud
|
75
|
+
H+99OXBR+pziILgYgglkqaUvIYFs0pWEBSyzIfsHLKeA3Fl0Y6wTX4d2K7bH
|
76
|
+
uEvP6i90zhuf6P21fxpp0C9nOMOvGuMcUQ1811ZuqOjSVWuzszm8eb52cFR+
|
77
|
+
K/k7yd9L/kHyV6OO8gJBezwT7/UVaj/xY9QRjXHhMDoM5rapZ39o/ntRZ2+0
|
78
|
+
sY3xv0C5xkhT1rXo7gHmBr5VWg7f+gbZqU23KTotSqaT5L+Ba2waDmjR1AsQ
|
79
|
+
qZnf6BVRvv29/5rsUtkJhXpWqiohG6LdCOu7ba+pRFud5veuMBisiKl7rmh4
|
80
|
+
ckfn8jnkv2KxC4tNYpujfhk2NjKaZyNVo0PadoLGni4sMshDM3XlcD3D2DzL
|
81
|
+
gW95oaJcmj3Rv6r174gnyguk1p9HvqtHpdmE/pTHDIUBb50VMHFfNlwS5Fig
|
82
|
+
/ihKrcQH+wPoExCflMZJjWRSxZFf3Cd+zfPd0K64T+1HgS8kZshroLrnO0EL
|
83
|
+
00VNKbc90cKqpi9UPN/phBHXrgQ37a2EwpIelI6JVSFD4kQSGxQVs14WgCMK
|
84
|
+
ZXcQ7WHtYxPWw5JupyuJqLLgeLHPEt5jz4r5CxXWcbY=
|
85
|
+
|
86
|
+
eJzt0z1oU2EcRvE3rR+tWtGtOBQ3hS4tODgWKnQRlM5dHAoZCuIHaLcsBaGT
|
87
|
+
hIBksQmlQ1wCTgF3Q+Z0cHN1lZBQQhL/N60fUEEKh5bK+cHleXlJw+2hHY5S
|
88
|
+
yqXjsruvW++/HzzK3/jwdirN3/n4ZSHu2vspXY+9Gc/ro88txN107P3YK7EP
|
89
|
+
Yq/GPo6diV2LvRabj52KfRl7IbYQeyn2Xezl2N3Yi7H12MnYT7ETsc3Yley+
|
90
|
+
ndIoZN9xN55n8eyM32F2/M6F9vHfYyTa3lm/wH/Ipjyb8mzKsynPpjyb8mzK
|
91
|
+
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
92
|
+
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
93
|
+
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
94
|
+
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
95
|
+
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
96
|
+
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
97
|
+
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPprx/NO33
|
98
|
+
+7VaLQ6VSqVUKpXL5cFg0Gq1Go1GtVptNpvFYrFer8dNp9M5lRc+B078dzoc
|
99
|
+
Dnu93uGh2+3G+deNDvm/z7Mpz6Y8m/JsyrMpz6Y8m/JsyrMpz6a8vYmU0rdB
|
100
|
+
SnOx2XkxnqX02/j8ZnXzb+fCrcr09r3Puexnc0efz84z8SznnzzfWH9x++HT
|
101
|
+
V+s/7//8zEnOPwDhN6kw
|
102
|
+
end
|
103
|
+
expect = data.split(/\n\s*\n/).map { |chunk| Zlib::Inflate.inflate Base64.decode64(chunk) }
|
104
|
+
|
63
105
|
# test the ole storage type
|
64
106
|
type = 'Microsoft Word 6.0-Dokument'
|
65
107
|
assert_equal type, (@ole.root/"\001CompObj").read[/^.{32}([^\x00]+)/m, 1]
|
66
108
|
# i was actually not loading data correctly before, so carefully check everything here
|
67
|
-
|
68
|
-
assert_equal hashes, @ole.root.children.map { |child| child.read.hash }
|
109
|
+
assert_equal expect, @ole.root.children.map { |child| child.read }
|
69
110
|
end
|
70
111
|
end
|
71
112
|
|
@@ -86,7 +127,7 @@ class TestStorageWrite < Test::Unit::TestCase
|
|
86
127
|
# of checks involving writes that resize their file bigger/smaller, that resize
|
87
128
|
# the bats to more blocks, that resizes the sb_blocks, that has migration etc.
|
88
129
|
def test_write_hash
|
89
|
-
io = StringIO.open
|
130
|
+
io = StringIO.open open("#{TEST_DIR}/test_word_6.doc", 'rb', &:read)
|
90
131
|
assert_equal '9974e354def8471225f548f82b8d81c701221af7', sha1(io.string)
|
91
132
|
Ole::Storage.open(io, :update_timestamps => false) { }
|
92
133
|
# hash changed. used to be efa8cfaf833b30b1d1d9381771ddaafdfc95305c
|
@@ -99,7 +140,7 @@ class TestStorageWrite < Test::Unit::TestCase
|
|
99
140
|
end
|
100
141
|
|
101
142
|
def test_plain_repack
|
102
|
-
io = StringIO.open
|
143
|
+
io = StringIO.open open("#{TEST_DIR}/test_word_6.doc", 'rb', &:read)
|
103
144
|
assert_equal '9974e354def8471225f548f82b8d81c701221af7', sha1(io.string)
|
104
145
|
Ole::Storage.open io, :update_timestamps => false, &:repack
|
105
146
|
# note equivalence to the above flush, repack, flush
|
data/test/test_support.rb
CHANGED
@@ -11,7 +11,7 @@ class TestSupport < Test::Unit::TestCase
|
|
11
11
|
def test_file
|
12
12
|
assert_equal 4096, open("#{TEST_DIR}/oleWithDirs.ole") { |f| f.size }
|
13
13
|
# point is to have same interface as:
|
14
|
-
assert_equal 4096, StringIO.open(
|
14
|
+
assert_equal 4096, StringIO.open(open("#{TEST_DIR}/oleWithDirs.ole", 'rb', &:read)).size
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_enumerable
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-ole
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.2.
|
7
|
-
date:
|
6
|
+
version: 1.2.4
|
7
|
+
date: 2008-01-10 00:00:00 +11:00
|
8
8
|
summary: Ruby OLE library.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -31,6 +31,7 @@ authors:
|
|
31
31
|
files:
|
32
32
|
- Rakefile
|
33
33
|
- ChangeLog
|
34
|
+
- data/propids.yaml
|
34
35
|
- bin/oletool
|
35
36
|
- lib/ole/ranges_io.rb
|
36
37
|
- lib/ole/property_set.rb
|
@@ -48,6 +49,7 @@ files:
|
|
48
49
|
- test/test_filesystem.rb
|
49
50
|
- test/test_word_6.doc
|
50
51
|
- test/test_word_95.doc
|
52
|
+
- test/test.doc
|
51
53
|
- test/test_word_97.doc
|
52
54
|
- test/oleWithDirs.ole
|
53
55
|
- test/test_SummaryInformation
|