ruby-ole 1.2.8.2 → 1.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +4 -0
- data/lib/ole/ranges_io.rb +78 -49
- data/lib/ole/storage/base.rb +11 -10
- data/test/test_ranges_io.rb +1 -8
- data/test/test_storage.rb +11 -45
- metadata +18 -18
data/ChangeLog
CHANGED
data/lib/ole/ranges_io.rb
CHANGED
@@ -57,23 +57,14 @@ class RangesIO
|
|
57
57
|
@params = {:close_parent => false}.merge params
|
58
58
|
@mode = IO::Mode.new mode
|
59
59
|
@io = io
|
60
|
-
# convert ranges to arrays. check for negative ranges?
|
61
|
-
ranges ||= [0, io.size]
|
62
|
-
@ranges = ranges.map { |r| Range === r ? [r.begin, r.end - r.begin] : r }
|
63
|
-
# calculate size
|
64
|
-
@size = @ranges.inject(0) { |total, (pos, len)| total + len }
|
65
60
|
# initial position in the file
|
66
61
|
@pos = 0
|
67
|
-
|
62
|
+
self.ranges = ranges || [[0, io.size]]
|
68
63
|
# handle some mode flags
|
69
64
|
truncate 0 if @mode.truncate?
|
70
65
|
seek size if @mode.append?
|
71
66
|
end
|
72
|
-
|
73
|
-
#IOError: closed stream
|
74
|
-
# get this for reading, writing, everything...
|
75
|
-
#IOError: not opened for writing
|
76
|
-
|
67
|
+
|
77
68
|
# add block form. TODO add test for this
|
78
69
|
def self.open(*args, &block)
|
79
70
|
ranges_io = new(*args)
|
@@ -86,6 +77,36 @@ class RangesIO
|
|
86
77
|
end
|
87
78
|
end
|
88
79
|
|
80
|
+
def ranges= ranges
|
81
|
+
# convert ranges to arrays. check for negative ranges?
|
82
|
+
ranges = ranges.map { |r| Range === r ? [r.begin, r.end - r.begin] : r }
|
83
|
+
# combine ranges
|
84
|
+
if @params[:combine] == false
|
85
|
+
# might be useful for debugging...
|
86
|
+
@ranges = ranges
|
87
|
+
else
|
88
|
+
@ranges = []
|
89
|
+
next_pos = nil
|
90
|
+
ranges.each do |pos, len|
|
91
|
+
if next_pos == pos
|
92
|
+
@ranges.last[1] += len
|
93
|
+
next_pos += len
|
94
|
+
else
|
95
|
+
@ranges << [pos, len]
|
96
|
+
next_pos = pos + len
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
# calculate cumulative offsets from range sizes
|
101
|
+
@size = 0
|
102
|
+
@offsets = []
|
103
|
+
@ranges.each do |pos, len|
|
104
|
+
@offsets << @size
|
105
|
+
@size += len
|
106
|
+
end
|
107
|
+
self.pos = @pos
|
108
|
+
end
|
109
|
+
|
89
110
|
def pos= pos, whence=IO::SEEK_SET
|
90
111
|
case whence
|
91
112
|
when IO::SEEK_SET
|
@@ -95,30 +116,36 @@ class RangesIO
|
|
95
116
|
pos = @size + pos
|
96
117
|
else raise Errno::EINVAL
|
97
118
|
end
|
98
|
-
raise Errno::EINVAL unless (0
|
119
|
+
raise Errno::EINVAL unless (0..@size) === pos
|
99
120
|
@pos = pos
|
121
|
+
|
122
|
+
# do a binary search throuh @offsets to find the active range.
|
123
|
+
a, c, b = 0, 0, @offsets.length
|
124
|
+
while a < b
|
125
|
+
c = (a + b) / 2
|
126
|
+
pivot = @offsets[c]
|
127
|
+
if pos == pivot
|
128
|
+
@active = c
|
129
|
+
return
|
130
|
+
elsif pos < pivot
|
131
|
+
b = c
|
132
|
+
else
|
133
|
+
a = c + 1
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
@active = a - 1
|
100
138
|
end
|
101
139
|
|
102
140
|
alias seek :pos=
|
103
141
|
alias tell :pos
|
104
142
|
|
105
|
-
def
|
106
|
-
|
143
|
+
def rewind
|
144
|
+
seek 0
|
107
145
|
end
|
108
146
|
|
109
|
-
|
110
|
-
|
111
|
-
def offset_and_size pos
|
112
|
-
total = 0
|
113
|
-
ranges.each_with_index do |(offset, size), i|
|
114
|
-
if pos <= total + size
|
115
|
-
diff = pos - total
|
116
|
-
return [offset + diff, size - diff], i
|
117
|
-
end
|
118
|
-
total += size
|
119
|
-
end
|
120
|
-
# should be impossible for any valid pos, (0...size) === pos
|
121
|
-
raise ArgumentError, "no range for pos #{pos.inspect}"
|
147
|
+
def close
|
148
|
+
@io.close if @params[:close_parent]
|
122
149
|
end
|
123
150
|
|
124
151
|
def eof?
|
@@ -130,24 +157,26 @@ class RangesIO
|
|
130
157
|
data = ''
|
131
158
|
return data if eof?
|
132
159
|
limit ||= size
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
160
|
+
pos, len = @ranges[@active]
|
161
|
+
diff = @pos - @offsets[@active]
|
162
|
+
pos += diff
|
163
|
+
len -= diff
|
164
|
+
loop do
|
138
165
|
@io.seek pos
|
139
166
|
if limit < len
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
break
|
167
|
+
s = @io.read(limit).to_s
|
168
|
+
@pos += s.length
|
169
|
+
data << s
|
170
|
+
break
|
144
171
|
end
|
145
|
-
|
146
|
-
|
147
|
-
@pos += s.length if s
|
172
|
+
s = @io.read(len).to_s
|
173
|
+
@pos += s.length
|
148
174
|
data << s
|
149
175
|
break if s.length != len
|
150
176
|
limit -= len
|
177
|
+
break if @active == @ranges.length - 1
|
178
|
+
@active += 1
|
179
|
+
pos, len = @ranges[@active]
|
151
180
|
end
|
152
181
|
data
|
153
182
|
end
|
@@ -164,8 +193,6 @@ class RangesIO
|
|
164
193
|
end
|
165
194
|
|
166
195
|
def write data
|
167
|
-
# short cut. needed because truncate 0 may return no ranges, instead of empty range,
|
168
|
-
# thus offset_and_size fails.
|
169
196
|
return 0 if data.empty?
|
170
197
|
data_pos = 0
|
171
198
|
# if we don't have room, we can use the truncate hook to make more space.
|
@@ -176,8 +203,11 @@ class RangesIO
|
|
176
203
|
raise IOError, "unable to grow #{inspect} to write #{data.length} bytes"
|
177
204
|
end
|
178
205
|
end
|
179
|
-
|
180
|
-
|
206
|
+
pos, len = @ranges[@active]
|
207
|
+
diff = @pos - @offsets[@active]
|
208
|
+
pos += diff
|
209
|
+
len -= diff
|
210
|
+
loop do
|
181
211
|
@io.seek pos
|
182
212
|
if data_pos + len > data.length
|
183
213
|
chunk = data[data_pos..-1]
|
@@ -189,6 +219,9 @@ class RangesIO
|
|
189
219
|
@io.write data[data_pos, len]
|
190
220
|
@pos += len
|
191
221
|
data_pos += len
|
222
|
+
break if @active == @ranges.length - 1
|
223
|
+
@active += 1
|
224
|
+
pos, len = @ranges[@active]
|
192
225
|
end
|
193
226
|
data_pos
|
194
227
|
end
|
@@ -202,17 +235,13 @@ class RangesIO
|
|
202
235
|
def gets
|
203
236
|
s = read 1024
|
204
237
|
i = s.index "\n"
|
205
|
-
|
238
|
+
self.pos -= s.length - (i+1)
|
206
239
|
s[0..i]
|
207
240
|
end
|
208
241
|
alias readline :gets
|
209
242
|
|
210
243
|
def inspect
|
211
|
-
|
212
|
-
pos, len = (@ranges[offset_and_size(@pos).last] rescue [nil, nil])
|
213
|
-
range_str = pos ? "#{pos}..#{pos+len}" : 'nil'
|
214
|
-
"#<#{self.class} io=#{io.inspect}, size=#@size, pos=#@pos, "\
|
215
|
-
"range=#{range_str}>"
|
244
|
+
"#<#{self.class} io=#{io.inspect}, size=#{@size}, pos=#{@pos}>"
|
216
245
|
end
|
217
246
|
end
|
218
247
|
|
data/lib/ole/storage/base.rb
CHANGED
@@ -21,7 +21,7 @@ module Ole # :nodoc:
|
|
21
21
|
class FormatError < StandardError # :nodoc:
|
22
22
|
end
|
23
23
|
|
24
|
-
VERSION = '1.2.
|
24
|
+
VERSION = '1.2.9'
|
25
25
|
|
26
26
|
# options used at creation time
|
27
27
|
attr_reader :params
|
@@ -61,7 +61,10 @@ module Ole # :nodoc:
|
|
61
61
|
else
|
62
62
|
@io.flush
|
63
63
|
# this is for the benefit of ruby-1.9
|
64
|
-
|
64
|
+
# generates warnings on jruby though... :/
|
65
|
+
if RUBY_PLATFORM != 'java' and @io.respond_to?(:syswrite)
|
66
|
+
@io.syswrite('')
|
67
|
+
end
|
65
68
|
true
|
66
69
|
end
|
67
70
|
rescue IOError
|
@@ -602,8 +605,8 @@ module Ole # :nodoc:
|
|
602
605
|
# note that old_blocks is != @ranges.length necessarily. i'm planning to write a
|
603
606
|
# merge_ranges function that merges sequential ranges into one as an optimization.
|
604
607
|
@bat.resize_chain @blocks, size
|
605
|
-
@
|
606
|
-
|
608
|
+
@pos = size if @pos > size
|
609
|
+
self.ranges = @bat.ranges(@blocks, size)
|
607
610
|
self.first_block = @blocks.empty? ? AllocationTable::EOC : @blocks.first
|
608
611
|
|
609
612
|
# don't know if this is required, but we explicitly request our @io to grow if necessary
|
@@ -612,8 +615,6 @@ module Ole # :nodoc:
|
|
612
615
|
# maybe its ok to just seek out there later??
|
613
616
|
max = @ranges.map { |pos, len| pos + len }.max || 0
|
614
617
|
@io.truncate max if max > @io.size
|
615
|
-
|
616
|
-
@size = size
|
617
618
|
end
|
618
619
|
end
|
619
620
|
|
@@ -633,8 +634,8 @@ module Ole # :nodoc:
|
|
633
634
|
# bat migration needed! we need to backup some data. the amount of data
|
634
635
|
# should be <= @ole.header.threshold, so we can just hold it all in one buffer.
|
635
636
|
# backup this
|
636
|
-
pos = @pos
|
637
|
-
|
637
|
+
pos = [@pos, size].min
|
638
|
+
self.pos = 0
|
638
639
|
keep = read [@size, size].min
|
639
640
|
# this does a normal truncate to 0, removing our presence from the old bat, and
|
640
641
|
# rewrite the dirent's first_block
|
@@ -645,9 +646,9 @@ module Ole # :nodoc:
|
|
645
646
|
# important to do this now, before the write. as the below write will always
|
646
647
|
# migrate us back to sbat! this will now allocate us +size+ in the new bat.
|
647
648
|
super
|
648
|
-
|
649
|
+
self.pos = 0
|
649
650
|
write keep
|
650
|
-
|
651
|
+
self.pos = pos
|
651
652
|
else
|
652
653
|
super
|
653
654
|
end
|
data/test/test_ranges_io.rb
CHANGED
@@ -31,20 +31,13 @@ class TestRangesIO < Test::Unit::TestCase
|
|
31
31
|
|
32
32
|
def test_basics
|
33
33
|
assert_equal 160, @io.size
|
34
|
-
assert_match %r{size=160
|
34
|
+
assert_match %r{size=160}, @io.inspect
|
35
35
|
end
|
36
36
|
|
37
37
|
def test_truncate
|
38
38
|
assert_raises(NotImplementedError) { @io.size += 10 }
|
39
39
|
end
|
40
40
|
|
41
|
-
def test_offset_and_size
|
42
|
-
assert_equal [[100, 100], 0], @io.offset_and_size(0)
|
43
|
-
assert_equal [[150, 50], 0], @io.offset_and_size(50)
|
44
|
-
assert_equal [[5, 5], 1], @io.offset_and_size(105)
|
45
|
-
assert_raises(ArgumentError) { @io.offset_and_size 1000 }
|
46
|
-
end
|
47
|
-
|
48
41
|
def test_seek
|
49
42
|
@io.pos = 10
|
50
43
|
@io.seek(-100, IO::SEEK_END)
|
data/test/test_storage.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
#! /usr/bin/ruby
|
2
2
|
|
3
3
|
$: << File.dirname(__FILE__) + '/../lib'
|
4
|
+
#require 'rubygems'
|
4
5
|
|
5
6
|
require 'test/unit'
|
6
7
|
require 'ole/storage'
|
7
8
|
require 'digest/sha1'
|
8
9
|
require 'stringio'
|
9
10
|
require 'tempfile'
|
10
|
-
require 'zlib'
|
11
|
-
require 'base64'
|
12
11
|
|
13
12
|
#
|
14
13
|
# = TODO
|
@@ -108,49 +107,18 @@ class TestStorageRead < Test::Unit::TestCase
|
|
108
107
|
def test_read
|
109
108
|
# the regular String#hash was different on the mac, so asserting
|
110
109
|
# against full strings. switch this to sha1 instead of this fugly blob
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
eJztVs9rE0EU/mZ32m5smyZtUlKQunhIezAV6knwYGoRxRLQBG89zCabdiE7
|
118
|
-
K9kJpt7Es1DwLxCsP+jJqycv/S/8I9SrmPgmuy0pK1ilNZd8MPt233zz7dud
|
119
|
-
H+99OXBR+pziILgYgglkqaUvIYFs0pWEBSyzIfsHLKeA3Fl0Y6wTX4d2K7bH
|
120
|
-
uEvP6i90zhuf6P21fxpp0C9nOMOvGuMcUQ1811ZuqOjSVWuzszm8eb52cFR+
|
121
|
-
K/k7yd9L/kHyV6OO8gJBezwT7/UVaj/xY9QRjXHhMDoM5rapZ39o/ntRZ2+0
|
122
|
-
sY3xv0C5xkhT1rXo7gHmBr5VWg7f+gbZqU23KTotSqaT5L+Ba2waDmjR1AsQ
|
123
|
-
qZnf6BVRvv29/5rsUtkJhXpWqiohG6LdCOu7ba+pRFud5veuMBisiKl7rmh4
|
124
|
-
ckfn8jnkv2KxC4tNYpujfhk2NjKaZyNVo0PadoLGni4sMshDM3XlcD3D2DzL
|
125
|
-
gW95oaJcmj3Rv6r174gnyguk1p9HvqtHpdmE/pTHDIUBb50VMHFfNlwS5Fig
|
126
|
-
/ihKrcQH+wPoExCflMZJjWRSxZFf3Cd+zfPd0K64T+1HgS8kZshroLrnO0EL
|
127
|
-
00VNKbc90cKqpi9UPN/phBHXrgQ37a2EwpIelI6JVSFD4kQSGxQVs14WgCMK
|
128
|
-
ZXcQ7WHtYxPWw5JupyuJqLLgeLHPEt5jz4r5CxXWcbY=
|
129
|
-
|
130
|
-
eJzt0z1oU2EcRvE3rR+tWtGtOBQ3hS4tODgWKnQRlM5dHAoZCuIHaLcsBaGT
|
131
|
-
hIBksQmlQ1wCTgF3Q+Z0cHN1lZBQQhL/N60fUEEKh5bK+cHleXlJw+2hHY5S
|
132
|
-
yqXjsruvW++/HzzK3/jwdirN3/n4ZSHu2vspXY+9Gc/ro88txN107P3YK7EP
|
133
|
-
Yq/GPo6diV2LvRabj52KfRl7IbYQeyn2Xezl2N3Yi7H12MnYT7ETsc3Yley+
|
134
|
-
ndIoZN9xN55n8eyM32F2/M6F9vHfYyTa3lm/wH/Ipjyb8mzKsynPpjyb8mzK
|
135
|
-
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
136
|
-
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
137
|
-
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
138
|
-
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
139
|
-
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
140
|
-
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzK
|
141
|
-
synPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPpjyb8mzKsynPprx/NO33
|
142
|
-
+7VaLQ6VSqVUKpXL5cFg0Gq1Go1GtVptNpvFYrFer8dNp9M5lRc+B078dzoc
|
143
|
-
Dnu93uGh2+3G+deNDvm/z7Mpz6Y8m/JsyrMpz6Y8m/JsyrMpz6a8vYmU0rdB
|
144
|
-
SnOx2XkxnqX02/j8ZnXzb+fCrcr09r3Puexnc0efz84z8SznnzzfWH9x++HT
|
145
|
-
V+s/7//8zEnOPwDhN6kw
|
146
|
-
end
|
147
|
-
expect = data.split(/\n\s*\n/).map { |chunk| Zlib::Inflate.inflate Base64.decode64(chunk) }
|
110
|
+
sha1sums = %w[
|
111
|
+
d3d1cde9eb43ed4b77d197af879f5ca8b8837577
|
112
|
+
65b75cbdd1f94ade632baeeb0848dec2a342c844
|
113
|
+
cfc230ec7515892cfdb85e4a173e0ce364094970
|
114
|
+
ffd859d94647a11b693f06f092d1a2bccc59d50d
|
115
|
+
]
|
148
116
|
|
149
117
|
# test the ole storage type
|
150
118
|
type = 'Microsoft Word 6.0-Dokument'
|
151
119
|
assert_equal type, (@ole.root/"\001CompObj").read[32..-1][/([^\x00]+)/m, 1]
|
152
120
|
# i was actually not loading data correctly before, so carefully check everything here
|
153
|
-
assert_equal
|
121
|
+
assert_equal sha1sums, @ole.root.children.map { |child| Digest::SHA1.hexdigest child.read }
|
154
122
|
end
|
155
123
|
|
156
124
|
def test_dirent
|
@@ -169,9 +137,7 @@ class TestStorageRead < Test::Unit::TestCase
|
|
169
137
|
|
170
138
|
dirent.open('r') { |f| assert_equal 2, f.first_block }
|
171
139
|
dirent.open('w') { |f| }
|
172
|
-
|
173
|
-
dirent.open('a') { |f| }
|
174
|
-
end
|
140
|
+
dirent.open('a') { |f| }
|
175
141
|
end
|
176
142
|
|
177
143
|
def test_delete
|
@@ -206,8 +172,8 @@ class TestStorageWrite < Test::Unit::TestCase
|
|
206
172
|
assert_equal '9974e354def8471225f548f82b8d81c701221af7', sha1(io.string)
|
207
173
|
Ole::Storage.open(io, :update_timestamps => false) { }
|
208
174
|
# hash changed. used to be efa8cfaf833b30b1d1d9381771ddaafdfc95305c
|
209
|
-
# thats because i
|
210
|
-
# available blocks.
|
175
|
+
# thats because i now truncate the io, and am probably removing some trailing
|
176
|
+
# allocated available blocks.
|
211
177
|
assert_equal 'a39e3c4041b8a893c753d50793af8d21ca8f0a86', sha1(io.string)
|
212
178
|
# add a repack test here
|
213
179
|
Ole::Storage.open io, :update_timestamps => false, &:repack
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ole
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Lowe
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-07-14 00:00:00 +10:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -28,29 +28,29 @@ files:
|
|
28
28
|
- ChangeLog
|
29
29
|
- data/propids.yaml
|
30
30
|
- bin/oletool
|
31
|
+
- lib/ole/types.rb
|
32
|
+
- lib/ole/storage.rb
|
31
33
|
- lib/ole/support.rb
|
32
34
|
- lib/ole/base.rb
|
33
|
-
- lib/ole/storage.rb
|
34
|
-
- lib/ole/file_system.rb
|
35
35
|
- lib/ole/ranges_io.rb
|
36
|
+
- lib/ole/file_system.rb
|
37
|
+
- lib/ole/types/property_set.rb
|
38
|
+
- lib/ole/types/base.rb
|
39
|
+
- lib/ole/storage/meta_data.rb
|
36
40
|
- lib/ole/storage/base.rb
|
37
41
|
- lib/ole/storage/file_system.rb
|
38
|
-
-
|
39
|
-
-
|
40
|
-
- lib/ole/types/base.rb
|
41
|
-
- lib/ole/types/property_set.rb
|
42
|
-
- test/test_types.rb
|
42
|
+
- test/test_ranges_io.rb
|
43
|
+
- test/test_storage.rb
|
43
44
|
- test/test_filesystem.rb
|
44
45
|
- test/test_support.rb
|
45
|
-
- test/
|
46
|
+
- test/test_mbat.rb
|
47
|
+
- test/test_types.rb
|
46
48
|
- test/test_meta_data.rb
|
47
|
-
- test/test_ranges_io.rb
|
48
49
|
- test/test_property_set.rb
|
49
|
-
- test/test_mbat.rb
|
50
|
-
- test/test.doc
|
51
50
|
- test/test_word_6.doc
|
52
51
|
- test/test_word_97.doc
|
53
52
|
- test/test_word_95.doc
|
53
|
+
- test/test.doc
|
54
54
|
- test/oleWithDirs.ole
|
55
55
|
- test/test_SummaryInformation
|
56
56
|
has_rdoc: true
|
@@ -80,16 +80,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
80
|
requirements: []
|
81
81
|
|
82
82
|
rubyforge_project: ruby-ole
|
83
|
-
rubygems_version: 1.
|
83
|
+
rubygems_version: 1.3.1
|
84
84
|
signing_key:
|
85
85
|
specification_version: 2
|
86
86
|
summary: Ruby OLE library.
|
87
87
|
test_files:
|
88
|
-
- test/
|
88
|
+
- test/test_ranges_io.rb
|
89
|
+
- test/test_storage.rb
|
89
90
|
- test/test_filesystem.rb
|
90
91
|
- test/test_support.rb
|
91
|
-
- test/
|
92
|
+
- test/test_mbat.rb
|
93
|
+
- test/test_types.rb
|
92
94
|
- test/test_meta_data.rb
|
93
|
-
- test/test_ranges_io.rb
|
94
95
|
- test/test_property_set.rb
|
95
|
-
- test/test_mbat.rb
|