ruby-ole 1.2.8.2 → 1.2.9

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 CHANGED
@@ -1,3 +1,7 @@
1
+ == 1.2.9 / 2009-07-14
2
+
3
+ - Lots of performance enhancements for RangesIO.
4
+
1
5
  == 1.2.8.2 / 2009-01-01
2
6
 
3
7
  - Update code to support ruby 1.9.1
@@ -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...@size) === pos
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 close
106
- @io.close if @params[:close_parent]
143
+ def rewind
144
+ seek 0
107
145
  end
108
146
 
109
- # returns the [+offset+, +size+], pair inorder to read/write at +pos+
110
- # (like a partial range), and its index.
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
- partial_range, i = offset_and_size @pos
134
- # this may be conceptually nice (create sub-range starting where we are), but
135
- # for a large range array its pretty wasteful. even the previous way was. but
136
- # i'm not trying to optimize this atm. it may even go to c later if necessary.
137
- ([partial_range] + ranges[i+1..-1]).each do |pos, len|
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
- # convoluted, to handle read errors. s may be nil
141
- s = @io.read limit
142
- @pos += s.length if s
143
- break data << s
167
+ s = @io.read(limit).to_s
168
+ @pos += s.length
169
+ data << s
170
+ break
144
171
  end
145
- # convoluted, to handle ranges beyond the size of the file
146
- s = @io.read len
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
- partial_range, i = offset_and_size @pos
180
- ([partial_range] + ranges[i+1..-1]).each do |pos, len|
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
- @pos -= s.length - (i+1)
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
- # the rescue is for empty files
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
 
@@ -21,7 +21,7 @@ module Ole # :nodoc:
21
21
  class FormatError < StandardError # :nodoc:
22
22
  end
23
23
 
24
- VERSION = '1.2.8.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
- @io.syswrite('') if @io.respond_to?(:syswrite)
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
- @ranges = @bat.ranges @blocks, size
606
- @pos = @size if @pos > size
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
- @pos = 0
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
- @pos = 0
649
+ self.pos = 0
649
650
  write keep
650
- @pos = pos
651
+ self.pos = pos
651
652
  else
652
653
  super
653
654
  end
@@ -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,.*range=100\.\.200}, @io.inspect
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)
@@ -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
- data = <<-end
112
- eJxjZGBgYkADAABKAAQ=
113
-
114
- eJxjZPj3n5mLgeE/EDBwMjGAwAEwyeAmAyR8M5OL8ovz00oUwvOLUhTM9Ax0
115
- XfKzS3NT80oYuEDywSBxl/xkBgEgD8TWA3LA8npmYGMAKWQZqA==
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 expect, @ole.root.children.map { |child| child.read }
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
- assert_raises Errno::EINVAL do
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 know truncate the io, and am probably removing some trailing allocated
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.8.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-01-01 00:00:00 +11:00
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
- - lib/ole/storage/meta_data.rb
39
- - lib/ole/types.rb
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/test_storage.rb
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.2.0
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/test_types.rb
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/test_storage.rb
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