ruby-ole 1.2.7 → 1.2.8
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/README +89 -6
- data/bin/oletool +0 -0
- data/lib/ole/ranges_io.rb +3 -2
- data/lib/ole/storage/base.rb +30 -64
- data/lib/ole/storage/file_system.rb +3 -24
- data/lib/ole/storage/meta_data.rb +25 -19
- data/lib/ole/support.rb +1 -1
- data/test/test_filesystem.rb +0 -0
- data/test/test_mbat.rb +0 -0
- data/test/test_meta_data.rb +1 -1
- data/test/test_property_set.rb +0 -0
- data/test/test_ranges_io.rb +0 -0
- data/test/test_storage.rb +2 -1
- data/test/test_support.rb +0 -0
- data/test/test_types.rb +0 -0
- metadata +18 -18
data/ChangeLog
CHANGED
data/README
CHANGED
@@ -1,22 +1,104 @@
|
|
1
1
|
= Introduction
|
2
2
|
|
3
|
-
|
3
|
+
The ruby-ole library provides a variety of functions primarily for
|
4
|
+
working with OLE2 structured storage files, such as those produced by
|
5
|
+
Microsoft Office - eg *.doc, *.msg etc.
|
6
|
+
|
7
|
+
= Example Usage
|
8
|
+
|
9
|
+
Here are some examples of how to use the library functionality,
|
10
|
+
categorised roughly by purpose.
|
11
|
+
|
12
|
+
1. Reading and writing files within an OLE container
|
13
|
+
|
14
|
+
The recommended way to manipulate the contents is via the
|
15
|
+
"file_system" API, whereby you use Ole::Storage instance methods
|
16
|
+
similar to the regular File and Dir class methods.
|
17
|
+
|
18
|
+
ole = Ole::Storage.open('oleWithDirs.ole', 'rb+')
|
19
|
+
p ole.dir.entries('.') # => [".", "..", "dir1", "dir2", "file1"]
|
20
|
+
p ole.file.read('file1')[0, 25] # => "this is the entry 'file1'"
|
21
|
+
ole.dir.mkdir('newdir')
|
22
|
+
|
23
|
+
2. Accessing OLE meta data
|
24
|
+
|
25
|
+
Some convenience functions are provided for (currently read only)
|
26
|
+
access to OLE property sets and other sources of meta data.
|
27
|
+
|
28
|
+
ole = Ole::Storage.open('test_word_95.doc')
|
29
|
+
p ole.meta_data.file_format # => "MSWordDoc"
|
30
|
+
p ole.meta_data.mime_type # => "application/msword"
|
31
|
+
p ole.meta_data.doc_author.split.first # => "Charles"
|
32
|
+
|
33
|
+
3. Raw access to underlying OLE internals
|
34
|
+
|
35
|
+
This is probably of little interest to most developers using the
|
36
|
+
library, but for some use cases you may need to drop down to the
|
37
|
+
lower level API on which the "file_system" API is constructed,
|
38
|
+
which exposes more of the format details.
|
39
|
+
|
40
|
+
<tt>Ole::Storage</tt> files can have multiple files with the same name,
|
41
|
+
or with a slash in the name, and other things that are probably
|
42
|
+
strictly invalid. This API is the only way to access those files.
|
43
|
+
|
44
|
+
You can access the header object directly:
|
45
|
+
|
46
|
+
p ole.header.num_sbat # => 1
|
47
|
+
p ole.header.magic.unpack('H*') # => ["d0cf11e0a1b11ae1"]
|
48
|
+
|
49
|
+
You can directly access the array of all Dirent objects,
|
50
|
+
including the root:
|
51
|
+
|
52
|
+
p ole.dirents.length # => 5
|
53
|
+
puts ole.root.to_tree
|
54
|
+
# =>
|
55
|
+
- #<Dirent:"Root Entry">
|
56
|
+
|- #<Dirent:"\001Ole" size=20 data="\001\000\000\002\000...">
|
57
|
+
|- #<Dirent:"\001CompObj" size=98 data="\001\000\376\377\003...">
|
58
|
+
|- #<Dirent:"WordDocument" size=2574 data="\334\245e\000-...">
|
59
|
+
\- #<Dirent:"\005SummaryInformation" size=54788 data="\376\377\000\000\001...">
|
60
|
+
|
61
|
+
You can access (through RangesIO methods, or by using the
|
62
|
+
relevant Dirent and AllocationTable methods) information like where within
|
63
|
+
the container a stream is located (these are offset/length pairs):
|
64
|
+
|
65
|
+
p ole.root["\001CompObj"].open { |io| io.ranges } # => [[0, 64], [64, 34]]
|
66
|
+
|
67
|
+
See the documentation for each class for more details.
|
68
|
+
|
69
|
+
= Thanks
|
70
|
+
|
71
|
+
* The code contained in this project was initially based on chicago's libole
|
72
|
+
(source available at http://prdownloads.sf.net/chicago/ole.tgz).
|
73
|
+
|
74
|
+
* It was later augmented with some corrections by inspecting pole, and (purely
|
75
|
+
for header definitions) gsf.
|
76
|
+
|
77
|
+
* The property set parsing code came from the apache java project POIFS.
|
78
|
+
|
79
|
+
* The excellent idea for using a pseudo file system style interface by providing
|
80
|
+
#file and #dir methods which mimic File and Dir, was borrowed (along with almost
|
81
|
+
unchanged tests!) from Thomas Sondergaard's rubyzip.
|
4
82
|
|
5
83
|
= TODO
|
6
84
|
|
7
|
-
== 1.2.
|
85
|
+
== 1.2.9
|
8
86
|
|
9
|
-
*
|
87
|
+
* add buffering to rangesio so that performance for small reads and writes
|
88
|
+
isn't so awful. maybe try and remove the bottlenecks of unbuffered first
|
89
|
+
with more profiling, then implement the buffering on top of that.
|
10
90
|
* fix mode strings - like truncate when using 'w+', supporting append
|
11
91
|
'a+' modes etc. done?
|
12
92
|
* make ranges io obey readable vs writeable modes.
|
13
93
|
* more RangesIO completion. ie, doesn't support #<< at the moment.
|
14
|
-
* ability to zero out padding and unused blocks
|
15
|
-
* case insensitive mode for ole/file_system?
|
16
94
|
|
17
95
|
== 1.3.1
|
18
96
|
|
19
|
-
* fix
|
97
|
+
* fix property sets a bit more. see TODO in Ole::Storage::MetaData
|
98
|
+
* ability to zero out padding and unused blocks
|
99
|
+
* case insensitive mode for ole/file_system?
|
100
|
+
* better tests for mbat support.
|
101
|
+
* further doc cleanup
|
20
102
|
|
21
103
|
== Longer term
|
22
104
|
|
@@ -25,3 +107,4 @@ For now, see the docs for the Ole::Storage class.
|
|
25
107
|
ole implementations (maybe perl's, and poifs) just to check its in the
|
26
108
|
ballpark, with no remaining silly bottlenecks.
|
27
109
|
* supposedly vba does something weird to ole files. test that.
|
110
|
+
|
data/bin/oletool
CHANGED
File without changes
|
data/lib/ole/ranges_io.rb
CHANGED
@@ -217,8 +217,9 @@ end
|
|
217
217
|
# this subclass of ranges io explicitly ignores the truncate part of 'w' modes.
|
218
218
|
# only really needed for the allocation table writes etc. maybe just use explicit modes
|
219
219
|
# for those
|
220
|
-
# better yet write a test that breaks before I fix it.
|
221
|
-
|
220
|
+
# better yet write a test that breaks before I fix it. added nodoc for the
|
221
|
+
# time being.
|
222
|
+
class RangesIONonResizeable < RangesIO # :nodoc:
|
222
223
|
def initialize io, mode='r', params={}
|
223
224
|
mode, params = 'r', mode if Hash === mode
|
224
225
|
flags = IO::Mode.new(mode).flags & ~IO::TRUNC
|
data/lib/ole/storage/base.rb
CHANGED
@@ -5,54 +5,8 @@ require 'ole/types'
|
|
5
5
|
require 'ole/ranges_io'
|
6
6
|
|
7
7
|
module Ole # :nodoc:
|
8
|
-
#
|
9
|
-
# = Introduction
|
10
8
|
#
|
11
|
-
#
|
12
|
-
# access to OLE2 structured storage files, such as those produced by
|
13
|
-
# Microsoft Office, eg *.doc, *.msg etc.
|
14
|
-
#
|
15
|
-
# = Usage
|
16
|
-
#
|
17
|
-
# Usage should be fairly straight forward:
|
18
|
-
#
|
19
|
-
# # get the parent ole storage object
|
20
|
-
# ole = Ole::Storage.open 'myfile.msg', 'r+'
|
21
|
-
# # => #<Ole::Storage io=#<File:myfile.msg> root=#<Dirent:"Root Entry">>
|
22
|
-
# # read some data
|
23
|
-
# ole.root[1].read 4
|
24
|
-
# # => "\001\000\376\377"
|
25
|
-
# # get the top level root object and output a tree structure for
|
26
|
-
# # debugging
|
27
|
-
# puts ole.root.to_tree
|
28
|
-
# # =>
|
29
|
-
# - #<Dirent:"Root Entry" size=3840 time="2006-11-03T00:52:53Z">
|
30
|
-
# |- #<Dirent:"__nameid_version1.0" size=0 time="2006-11-03T00:52:53Z">
|
31
|
-
# | |- #<Dirent:"__substg1.0_00020102" size=16 data="CCAGAAAAAADAAA...">
|
32
|
-
# ...
|
33
|
-
# |- #<Dirent:"__substg1.0_8002001E" size=4 data="MTEuMA==">
|
34
|
-
# |- #<Dirent:"__properties_version1.0" size=800 data="AAAAAAAAAAABAA...">
|
35
|
-
# \- #<Dirent:"__recip_version1.0_#00000000" size=0 time="2006-11-03T00:52:53Z">
|
36
|
-
# |- #<Dirent:"__substg1.0_0FF60102" size=4 data="AAAAAA==">
|
37
|
-
# ...
|
38
|
-
# # write some data, and finish up (note that open is 'r+', so this overwrites
|
39
|
-
# # but doesn't truncate)
|
40
|
-
# ole.root["\001CompObj"].open { |f| f.write "blah blah" }
|
41
|
-
# ole.close
|
42
|
-
#
|
43
|
-
# = Thanks
|
44
|
-
#
|
45
|
-
# * The code contained in this project was initially based on chicago's libole
|
46
|
-
# (source available at http://prdownloads.sf.net/chicago/ole.tgz).
|
47
|
-
#
|
48
|
-
# * It was later augmented with some corrections by inspecting pole, and (purely
|
49
|
-
# for header definitions) gsf.
|
50
|
-
#
|
51
|
-
# * The property set parsing code came from the apache java project POIFS.
|
52
|
-
#
|
53
|
-
# * The excellent idea for using a pseudo file system style interface by providing
|
54
|
-
# #file and #dir methods which mimic File and Dir, was borrowed (along with almost
|
55
|
-
# unchanged tests!) from Thomas Sondergaard's rubyzip.
|
9
|
+
# This class is the primary way the user interacts with an OLE storage file.
|
56
10
|
#
|
57
11
|
# = TODO
|
58
12
|
#
|
@@ -67,7 +21,7 @@ module Ole # :nodoc:
|
|
67
21
|
class FormatError < StandardError # :nodoc:
|
68
22
|
end
|
69
23
|
|
70
|
-
VERSION = '1.2.
|
24
|
+
VERSION = '1.2.8'
|
71
25
|
|
72
26
|
# options used at creation time
|
73
27
|
attr_reader :params
|
@@ -81,8 +35,8 @@ module Ole # :nodoc:
|
|
81
35
|
# Low level internals, you probably shouldn't need to mess with these
|
82
36
|
attr_reader :header, :bbat, :sbat, :sb_file
|
83
37
|
|
84
|
-
#
|
85
|
-
# +
|
38
|
+
# +arg+ should be either a filename, or an +IO+ object, and needs to be seekable.
|
39
|
+
# +mode+ is optional, and should be a regular mode string.
|
86
40
|
def initialize arg, mode=nil, params={}
|
87
41
|
params, mode = mode, nil if Hash === mode
|
88
42
|
params = {:update_timestamps => true}.merge(params)
|
@@ -118,6 +72,8 @@ module Ole # :nodoc:
|
|
118
72
|
@io.size > 0 ? load : clear
|
119
73
|
end
|
120
74
|
|
75
|
+
# somewhat similar to File.open, the open class method allows a block form where
|
76
|
+
# the Ole::Storage object is automatically closed on completion of the block.
|
121
77
|
def self.open arg, mode=nil, params={}
|
122
78
|
ole = new arg, mode, params
|
123
79
|
if block_given?
|
@@ -150,8 +106,13 @@ module Ole # :nodoc:
|
|
150
106
|
|
151
107
|
# create an empty bbat.
|
152
108
|
@bbat = AllocationTable::Big.new self
|
153
|
-
|
154
|
-
|
109
|
+
bbat_chain = header_block[Header::SIZE..-1].unpack 'V*'
|
110
|
+
mbat_block = @header.mbat_start
|
111
|
+
@header.num_mbat.times do
|
112
|
+
blocks = @bbat.read([mbat_block]).unpack 'V*'
|
113
|
+
mbat_block = blocks.pop
|
114
|
+
bbat_chain += blocks
|
115
|
+
end
|
155
116
|
# am i using num_bat in the right way?
|
156
117
|
@bbat.load @bbat.read(bbat_chain[0, @header.num_bat])
|
157
118
|
|
@@ -268,7 +229,7 @@ module Ole # :nodoc:
|
|
268
229
|
# mbat must remain contiguous.
|
269
230
|
bbat_data_len = ((@bbat.length + num_mbat_blocks) * 4 / @bbat.block_size.to_f).ceil * @bbat.block_size
|
270
231
|
# now storing the excess mbat blocks also increases the size of the bbat:
|
271
|
-
new_num_mbat_blocks = ([bbat_data_len / @bbat.block_size - 109, 0].max * 4 / @bbat.block_size.to_f).ceil
|
232
|
+
new_num_mbat_blocks = ([bbat_data_len / @bbat.block_size - 109, 0].max * 4 / (@bbat.block_size.to_f - 4)).ceil
|
272
233
|
if new_num_mbat_blocks != num_mbat_blocks
|
273
234
|
# need more space for the mbat.
|
274
235
|
num_mbat_blocks = new_num_mbat_blocks
|
@@ -284,13 +245,16 @@ module Ole # :nodoc:
|
|
284
245
|
# now extract the info we want:
|
285
246
|
ranges = io.ranges
|
286
247
|
bbat_chain = @bbat.chain io.first_block
|
287
|
-
# the extra mbat data is a set of contiguous blocks at the end
|
288
248
|
io.close
|
289
249
|
bbat_chain.each { |b| @bbat[b] = AllocationTable::BAT }
|
290
250
|
# tack on the mbat stuff
|
291
|
-
@header.mbat_start = @bbat.length # need to record this here before tacking on the mbat
|
292
251
|
@header.num_bat = bbat_chain.length
|
293
|
-
num_mbat_blocks.
|
252
|
+
mbat_blocks = (0...num_mbat_blocks).map do
|
253
|
+
block = @bbat.free_block
|
254
|
+
@bbat[block] = AllocationTable::META_BAT
|
255
|
+
block
|
256
|
+
end
|
257
|
+
@header.mbat_start = mbat_blocks.first || AllocationTable::EOC
|
294
258
|
|
295
259
|
# now finally write the bbat, using a not resizable io.
|
296
260
|
# the mode here will be 'r', which allows write atm.
|
@@ -299,15 +263,17 @@ module Ole # :nodoc:
|
|
299
263
|
# this is the mbat. pad it out.
|
300
264
|
bbat_chain += [AllocationTable::AVAIL] * [109 - bbat_chain.length, 0].max
|
301
265
|
@header.num_mbat = num_mbat_blocks
|
302
|
-
if num_mbat_blocks
|
303
|
-
@header.mbat_start = AllocationTable::EOC
|
304
|
-
else
|
266
|
+
if num_mbat_blocks != 0
|
305
267
|
# write out the mbat blocks now. first of all, where are they going to be?
|
306
268
|
mbat_data = bbat_chain[109..-1]
|
307
|
-
|
308
|
-
mbat_data
|
309
|
-
|
310
|
-
|
269
|
+
# expand the mbat_data to include the linked list forward pointers.
|
270
|
+
mbat_data = mbat_data.to_enum(:each_slice, @bbat.block_size / 4 - 1).to_a.
|
271
|
+
zip(mbat_blocks[1..-1] + [nil]).map { |a, b| b ? a + [b] : a }
|
272
|
+
# pad out the last one.
|
273
|
+
mbat_data.last.push(*([AllocationTable::AVAIL] * (@bbat.block_size / 4 - mbat_data.last.length)))
|
274
|
+
RangesIO.open @io, :ranges => @bbat.ranges(mbat_blocks) do |f|
|
275
|
+
f.write mbat_data.flatten.pack('V*')
|
276
|
+
end
|
311
277
|
end
|
312
278
|
|
313
279
|
# now seek back and write the header out
|
@@ -561,7 +527,7 @@ module Ole # :nodoc:
|
|
561
527
|
length - 1
|
562
528
|
end
|
563
529
|
|
564
|
-
# must return first_block
|
530
|
+
# must return first_block. modifies +blocks+ in place
|
565
531
|
def resize_chain blocks, size
|
566
532
|
new_num_blocks = (size / block_size.to_f).ceil
|
567
533
|
old_num_blocks = blocks.length
|
@@ -3,32 +3,11 @@
|
|
3
3
|
#
|
4
4
|
# This file intends to provide file system-like api support, a la <tt>zip/zipfilesystem</tt>.
|
5
5
|
#
|
6
|
-
# Ideally, this will be the recommended interface, allowing Ole::Storage, Dir, and
|
7
|
-
# Zip::ZipFile to be used exchangably. It should be possible to write recursive copy using
|
8
|
-
# the plain api, such that you can copy dirs/files agnostically between any of ole docs, dirs,
|
9
|
-
# and zip files.
|
10
|
-
#
|
11
|
-
# = Usage
|
12
|
-
#
|
13
|
-
# Currently you can do something like the following:
|
14
|
-
#
|
15
|
-
# Ole::Storage.open 'test.doc' do |ole|
|
16
|
-
# ole.dir.entries '/' # => [".", "..", "\001Ole", "1Table", "\001CompObj", ...]
|
17
|
-
# ole.file.read "\001CompObj" # => "\001\000\376\377\003\n\000\000\377\377..."
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# = Notes
|
21
|
-
#
|
22
|
-
# <tt>Ole::Storage</tt> files can have multiple files with the same name,
|
23
|
-
# or with / in the name, and other things that are probably invalid anyway.
|
24
|
-
# This API is unable to access those files, but of course the core, low-
|
25
|
-
# level API can.
|
26
|
-
#
|
27
|
-
# need to implement some more IO functions on RangesIO, like #puts, #print
|
28
|
-
# etc, like AbstractOutputStream from zipfile.
|
29
|
-
#
|
30
6
|
# = TODO
|
31
7
|
#
|
8
|
+
# - need to implement some more IO functions on RangesIO, like #puts, #print
|
9
|
+
# etc, like AbstractOutputStream from zipfile.
|
10
|
+
#
|
32
11
|
# - check Dir.mkdir, and File.open, and File.rename, to add in filename
|
33
12
|
# length checks (max 32 / 31 or something).
|
34
13
|
# do the automatic truncation, and add in any necessary warnings.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'ole/types/property_set'
|
2
2
|
|
3
|
-
module Ole
|
3
|
+
module Ole
|
4
4
|
class Storage
|
5
5
|
#
|
6
6
|
# The MetaData class is designed to be high level interface to all the
|
@@ -35,33 +35,37 @@ module Ole
|
|
35
35
|
FORMAT_MAP = {
|
36
36
|
'MSWordDoc' => :doc
|
37
37
|
}
|
38
|
-
|
38
|
+
|
39
39
|
CLSID_EXCEL97 = Types::Clsid.parse "{00020820-0000-0000-c000-000000000046}"
|
40
40
|
CLSID_EXCEL95 = Types::Clsid.parse "{00020810-0000-0000-c000-000000000046}"
|
41
41
|
CLSID_WORD97 = Types::Clsid.parse "{00020906-0000-0000-c000-000000000046}"
|
42
42
|
CLSID_WORD95 = Types::Clsid.parse "{00020900-0000-0000-c000-000000000046}"
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
|
44
|
+
CLSID_MAP = {
|
45
|
+
CLSID_EXCEL97 => :xls,
|
46
|
+
CLSID_EXCEL95 => :xls,
|
47
|
+
CLSID_WORD97 => :doc,
|
48
|
+
CLSID_WORD95 => :doc
|
49
|
+
}
|
50
50
|
|
51
51
|
MIME_TYPES = {
|
52
52
|
:xls => 'application/vnd.ms-excel',
|
53
53
|
:doc => 'application/msword',
|
54
54
|
:ppt => 'application/vnd.ms-powerpoint',
|
55
|
-
|
55
|
+
# not registered at IANA, but seems most common usage
|
56
|
+
:msg => 'application/vnd.ms-outlook',
|
57
|
+
# this is my default fallback option. also not registered at IANA.
|
58
|
+
# file(1)'s default is application/msword, which is useless...
|
59
|
+
nil => 'application/x-ole-storage'
|
56
60
|
}
|
57
|
-
|
61
|
+
|
58
62
|
def initialize ole
|
59
63
|
@ole = ole
|
60
64
|
end
|
61
65
|
|
62
66
|
# i'm thinking of making file_format and mime_type available through
|
63
67
|
# #[], #each, and #to_h also, as calculated meta data (not assignable)
|
64
|
-
|
68
|
+
|
65
69
|
def comp_obj
|
66
70
|
return {} unless dirent = @ole.root["\001CompObj"]
|
67
71
|
data = dirent.read
|
@@ -70,7 +74,7 @@ module Ole
|
|
70
74
|
# byte_order: 0xffe
|
71
75
|
# windows_version: 0x00000a03 (win31 apparently)
|
72
76
|
# marker: 0xffffffff
|
73
|
-
compobj_version, byte_order, windows_version, marker, clsid =
|
77
|
+
compobj_version, byte_order, windows_version, marker, clsid =
|
74
78
|
data.unpack("vvVVa#{Types::Clsid::SIZE}")
|
75
79
|
strings = []
|
76
80
|
i = 28
|
@@ -84,7 +88,7 @@ module Ole
|
|
84
88
|
{:username => strings[0], :file_format => strings[1], :unknown => strings[2..-1]}
|
85
89
|
end
|
86
90
|
private :comp_obj
|
87
|
-
|
91
|
+
|
88
92
|
def file_format
|
89
93
|
comp_obj[:file_format]
|
90
94
|
end
|
@@ -93,7 +97,7 @@ module Ole
|
|
93
97
|
# based on the CompObj stream contents
|
94
98
|
type = FORMAT_MAP[file_format]
|
95
99
|
return MIME_TYPES[type] if type
|
96
|
-
|
100
|
+
|
97
101
|
# based on the root clsid
|
98
102
|
type = CLSID_MAP[Types::Clsid.load(@ole.root.clsid)]
|
99
103
|
return MIME_TYPES[type] if type
|
@@ -103,19 +107,21 @@ module Ole
|
|
103
107
|
return MIME_TYPES[:msg] if has_file['__nameid_version1.0'] or has_file['__properties_version1.0']
|
104
108
|
return MIME_TYPES[:doc] if has_file['worddocument'] or has_file['document']
|
105
109
|
return MIME_TYPES[:xls] if has_file['workbook'] or has_file['book']
|
110
|
+
|
111
|
+
MIME_TYPES[nil]
|
106
112
|
end
|
107
|
-
|
113
|
+
|
108
114
|
def [] key
|
109
115
|
pair = Types::PropertySet::PROPERTY_MAP[key.to_s] or return nil
|
110
116
|
file = FILE_MAP[pair.first] or return nil
|
111
117
|
dirent = @ole.root[file] or return nil
|
112
118
|
dirent.open { |io| return Types::PropertySet.new(io)[key] }
|
113
119
|
end
|
114
|
-
|
120
|
+
|
115
121
|
def []= key, value
|
116
122
|
raise NotImplementedError, 'meta data writes not implemented'
|
117
123
|
end
|
118
|
-
|
124
|
+
|
119
125
|
def each(&block)
|
120
126
|
FILE_MAP.values.each do |file|
|
121
127
|
dirent = @ole.root[file] or next
|
@@ -126,7 +132,7 @@ module Ole
|
|
126
132
|
def to_h
|
127
133
|
inject({}) { |hash, (name, value)| hash.update name.to_sym => value }
|
128
134
|
end
|
129
|
-
|
135
|
+
|
130
136
|
def method_missing name, *args, &block
|
131
137
|
return super unless args.empty?
|
132
138
|
pair = Types::PropertySet::PROPERTY_MAP[name.to_s] or return super
|
data/lib/ole/support.rb
CHANGED
@@ -89,7 +89,7 @@ end
|
|
89
89
|
# breadth first iteration holds its own copy of the children around.
|
90
90
|
#
|
91
91
|
# Main methods are #recursive, and #to_tree
|
92
|
-
module RecursivelyEnumerable
|
92
|
+
module RecursivelyEnumerable # :nodoc:
|
93
93
|
def each_recursive_depth_first(&block)
|
94
94
|
each_child do |child|
|
95
95
|
yield child
|
data/test/test_filesystem.rb
CHANGED
File without changes
|
data/test/test_mbat.rb
CHANGED
File without changes
|
data/test/test_meta_data.rb
CHANGED
@@ -32,7 +32,7 @@ class TestMetaData < Test::Unit::TestCase
|
|
32
32
|
|
33
33
|
ole.root.clsid = 0.chr * Ole::Types::Clsid::SIZE
|
34
34
|
assert_equal nil, ole.meta_data.file_format
|
35
|
-
assert_equal
|
35
|
+
assert_equal 'application/x-ole-storage', ole.meta_data.mime_type
|
36
36
|
|
37
37
|
ole.file.open('Book', 'w') { |f| }
|
38
38
|
assert_equal 'application/vnd.ms-excel', ole.meta_data.mime_type
|
data/test/test_property_set.rb
CHANGED
File without changes
|
data/test/test_ranges_io.rb
CHANGED
File without changes
|
data/test/test_storage.rb
CHANGED
@@ -173,7 +173,8 @@ class TestStorageRead < Test::Unit::TestCase
|
|
173
173
|
|
174
174
|
def test_dirent
|
175
175
|
dirent = @ole.root.children.first
|
176
|
-
assert_equal
|
176
|
+
assert_equal "\001Ole", dirent.name
|
177
|
+
assert_equal 20, dirent.size
|
177
178
|
assert_equal '#<Dirent:"Root Entry">', @ole.root.inspect
|
178
179
|
|
179
180
|
# exercise Dirent#[]. note that if you use a number, you get the Struct
|
data/test/test_support.rb
CHANGED
File without changes
|
data/test/test_types.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
5
|
-
platform:
|
4
|
+
version: 1.2.8
|
5
|
+
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Lowe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-08
|
12
|
+
date: 2008-10-08 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -27,29 +27,29 @@ files:
|
|
27
27
|
- ChangeLog
|
28
28
|
- data/propids.yaml
|
29
29
|
- bin/oletool
|
30
|
+
- lib/ole/support.rb
|
30
31
|
- lib/ole/base.rb
|
32
|
+
- lib/ole/storage.rb
|
31
33
|
- lib/ole/file_system.rb
|
32
34
|
- lib/ole/ranges_io.rb
|
33
35
|
- lib/ole/storage/base.rb
|
34
36
|
- lib/ole/storage/file_system.rb
|
35
37
|
- lib/ole/storage/meta_data.rb
|
36
|
-
- lib/ole/
|
37
|
-
- lib/ole/support.rb
|
38
|
+
- lib/ole/types.rb
|
38
39
|
- lib/ole/types/base.rb
|
39
40
|
- lib/ole/types/property_set.rb
|
40
|
-
-
|
41
|
+
- test/test_types.rb
|
41
42
|
- test/test_filesystem.rb
|
42
|
-
- test/
|
43
|
+
- test/test_support.rb
|
44
|
+
- test/test_storage.rb
|
43
45
|
- test/test_meta_data.rb
|
44
|
-
- test/test_property_set.rb
|
45
46
|
- test/test_ranges_io.rb
|
46
|
-
- test/
|
47
|
-
- test/
|
48
|
-
- test/test_types.rb
|
47
|
+
- test/test_property_set.rb
|
48
|
+
- test/test_mbat.rb
|
49
49
|
- test/test.doc
|
50
50
|
- test/test_word_6.doc
|
51
|
-
- test/test_word_95.doc
|
52
51
|
- test/test_word_97.doc
|
52
|
+
- test/test_word_95.doc
|
53
53
|
- test/oleWithDirs.ole
|
54
54
|
- test/test_SummaryInformation
|
55
55
|
has_rdoc: true
|
@@ -79,16 +79,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements: []
|
80
80
|
|
81
81
|
rubyforge_project: ruby-ole
|
82
|
-
rubygems_version:
|
82
|
+
rubygems_version: 1.2.0
|
83
83
|
signing_key:
|
84
84
|
specification_version: 2
|
85
85
|
summary: Ruby OLE library.
|
86
86
|
test_files:
|
87
|
+
- test/test_types.rb
|
87
88
|
- test/test_filesystem.rb
|
88
|
-
- test/
|
89
|
+
- test/test_support.rb
|
90
|
+
- test/test_storage.rb
|
89
91
|
- test/test_meta_data.rb
|
90
|
-
- test/test_property_set.rb
|
91
92
|
- test/test_ranges_io.rb
|
92
|
-
- test/
|
93
|
-
- test/
|
94
|
-
- test/test_types.rb
|
93
|
+
- test/test_property_set.rb
|
94
|
+
- test/test_mbat.rb
|