ruby-ole 1.2.6 → 1.2.7

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.
@@ -99,6 +99,8 @@ module RecursivelyEnumerable
99
99
  end
100
100
  end
101
101
 
102
+ # don't think this is actually a proper breadth first recursion. only first
103
+ # level is breadth first.
102
104
  def each_recursive_breadth_first(&block)
103
105
  children = []
104
106
  each_child do |child|
@@ -131,41 +133,35 @@ module RecursivelyEnumerable
131
133
  # streams a "tree" form of the recursively enumerable structure to +io+, or
132
134
  # return a string form instead if +io+ is not specified.
133
135
  #
134
- # mostly a debugging aid. can specify a different +method+ to call if desired,
135
- # though it should return a single line string.
136
- def to_tree io=nil, method=:inspect
137
- unless io
138
- to_tree io = StringIO.new
139
- return io.string
140
- end
141
- io << "- #{send method}\n"
142
- to_tree_helper io, method, ' '
143
- end
144
-
145
- def to_tree_helper io, method, prefix
146
- # i need to know when i get to the last child. use delay to know
147
- child = nil
148
- each_child do |next_child|
149
- if child
150
- io << "#{prefix}|- #{child.send method}\n"
151
- if child.respond_to? :to_tree_helper
152
- child.to_tree_helper io, method, prefix + '| '
136
+ # mostly a debugging aid. can specify a different block which will be called
137
+ # to provide the string form for each node.
138
+ def to_tree io='', &inspect
139
+ inspect ||= :inspect.to_proc
140
+ io << "- #{inspect[self]}\n"
141
+ recurse = proc do |node, prefix|
142
+ child = nil
143
+ node.each_child do |next_child|
144
+ if child
145
+ io << "#{prefix}|- #{inspect[child]}\n"
146
+ recurse.call child, prefix + '| '
153
147
  end
148
+ child = next_child
149
+ end if node.respond_to?(:each_child)
150
+ if child
151
+ io << "#{prefix}\\- #{inspect[child]}\n"
152
+ recurse.call child, prefix + ' '
154
153
  end
155
- child = next_child
156
- end
157
- return unless child
158
- # child is the last child
159
- io << "#{prefix}\\- #{child.send method}\n"
160
- if child.respond_to? :to_tree_helper
161
- child.to_tree_helper io, method, prefix + ' '
162
154
  end
155
+ recurse.call self, ' '
156
+ io
163
157
  end
164
- protected :to_tree_helper
165
158
  end
166
159
 
167
160
  # can include File::Constants
168
161
  class IO
162
+ # this is for jruby
163
+ include File::Constants unless defined?(RDONLY)
164
+
169
165
  # nabbed from rubinius, and modified
170
166
  def self.parse_mode mode
171
167
  ret = 0
@@ -1,243 +1,2 @@
1
- require 'iconv'
2
- require 'date'
3
-
4
- require 'ole/base'
5
-
6
- module Ole # :nodoc:
7
- #
8
- # The Types module contains all the serialization and deserialization code for standard ole
9
- # types.
10
- #
11
- # It also defines all the variant type constants, and symbolic names.
12
- #
13
- module Types
14
- # for anything that we don't have serialization code for
15
- class Data < String
16
- def self.load str
17
- new str
18
- end
19
-
20
- def self.dump str
21
- str.to_s
22
- end
23
- end
24
-
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
36
- end
37
-
38
- # for VT_LPWSTR
39
- class Lpwstr < String
40
- FROM_UTF16 = Iconv.new 'utf-8', 'utf-16le'
41
- TO_UTF16 = Iconv.new 'utf-16le', 'utf-8'
42
-
43
- def self.load str
44
- new FROM_UTF16.iconv(str).chomp(0.chr)
45
- end
46
-
47
- def self.dump str
48
- # need to append nulls?
49
- TO_UTF16.iconv str
50
- end
51
- end
52
-
53
- # for VT_FILETIME
54
- class FileTime < DateTime
55
- SIZE = 8
56
- EPOCH = new 1601, 1, 1
57
-
58
- # Create a +DateTime+ object from a struct +FILETIME+
59
- # (http://msdn2.microsoft.com/en-us/library/ms724284.aspx).
60
- #
61
- # Converts +str+ to two 32 bit time values, comprising the high and low 32 bits of
62
- # the 100's of nanoseconds since 1st january 1601 (Epoch).
63
- def self.load str
64
- low, high = str.to_s.unpack 'V2'
65
- # we ignore these, without even warning about it
66
- return nil if low == 0 and high == 0
67
- # switched to rational, and fixed the off by 1 second error i sometimes got.
68
- # time = EPOCH + (high * (1 << 32) + low) / 1e7 / 86400 rescue return
69
- # use const_get to ensure we can return anything which subclasses this (VT_DATE?)
70
- const_get('EPOCH') + Rational(high * (1 << 32) + low, 1e7.to_i * 86400) rescue return
71
- # extra sanity check...
72
- #unless (1800...2100) === time.year
73
- # Log.warn "ignoring unlikely time value #{time.to_s}"
74
- # return nil
75
- #end
76
- #time
77
- end
78
-
79
- # +time+ should be able to be either a Time, Date, or DateTime.
80
- def self.dump time
81
- # i think i'll convert whatever i get to be a datetime, because of
82
- # the covered range.
83
- return 0.chr * SIZE unless time
84
- time = time.send(:to_datetime) if Time === time
85
- # don't bother to use const_get here
86
- bignum = (time - EPOCH) * 86400 * 1e7.to_i
87
- high, low = bignum.divmod 1 << 32
88
- [low, high].pack 'V2'
89
- end
90
- end
91
-
92
- # for VT_CLSID
93
- # Unlike most of the other conversions, the Guid's are serialized/deserialized by actually
94
- # doing nothing! (eg, _load & _dump are null ops)
95
- # Rather, its just a string with a different inspect string, and it includes a
96
- # helper method for creating a Guid from that readable form (#format).
97
- class Clsid < String
98
- SIZE = 16
99
- PACK = 'V v v CC C6'
100
-
101
- def self.load str
102
- new str.to_s
103
- end
104
-
105
- def self.dump guid
106
- return 0.chr * SIZE unless guid
107
- # allow use of plain strings in place of guids.
108
- guid['-'] ? parse(guid) : guid
109
- end
110
-
111
- def self.parse str
112
- vals = str.scan(/[a-f\d]+/i).map(&:hex)
113
- if vals.length == 5
114
- # this is pretty ugly
115
- vals[3] = ('%04x' % vals[3]).scan(/../).map(&:hex)
116
- vals[4] = ('%012x' % vals[4]).scan(/../).map(&:hex)
117
- guid = new vals.flatten.pack(PACK)
118
- return guid unless guid.delete('{}') == str.downcase.delete('{}')
119
- end
120
- raise ArgumentError, 'invalid guid - %p' % str
121
- end
122
-
123
- def format
124
- "%08x-%04x-%04x-%02x%02x-#{'%02x' * 6}" % unpack(PACK)
125
- end
126
-
127
- def inspect
128
- "#<#{self.class}:{#{format}}>"
129
- end
130
- end
131
-
132
- #
133
- # The OLE variant types, extracted from
134
- # http://www.marin.clara.net/COM/variant_type_definitions.htm.
135
- #
136
- # A subset is also in WIN32OLE::VARIANT, but its not cross platform (obviously).
137
- #
138
- # Use like:
139
- #
140
- # p Ole::Types::Variant::NAMES[0x001f] => 'VT_LPWSTR'
141
- # p Ole::Types::VT_DATE # => 7
142
- #
143
- # The serialization / deserialization functions should be fixed to make it easier
144
- # to work with. like
145
- #
146
- # Ole::Types.from_str(VT_DATE, data) # and
147
- # Ole::Types.to_str(VT_DATE, data)
148
- #
149
- # Or similar, rather than having to do VT_* <=> ad hoc class name etc as it is
150
- # currently.
151
- #
152
- module Variant
153
- NAMES = {
154
- 0x0000 => 'VT_EMPTY',
155
- 0x0001 => 'VT_NULL',
156
- 0x0002 => 'VT_I2',
157
- 0x0003 => 'VT_I4',
158
- 0x0004 => 'VT_R4',
159
- 0x0005 => 'VT_R8',
160
- 0x0006 => 'VT_CY',
161
- 0x0007 => 'VT_DATE',
162
- 0x0008 => 'VT_BSTR',
163
- 0x0009 => 'VT_DISPATCH',
164
- 0x000a => 'VT_ERROR',
165
- 0x000b => 'VT_BOOL',
166
- 0x000c => 'VT_VARIANT',
167
- 0x000d => 'VT_UNKNOWN',
168
- 0x000e => 'VT_DECIMAL',
169
- 0x0010 => 'VT_I1',
170
- 0x0011 => 'VT_UI1',
171
- 0x0012 => 'VT_UI2',
172
- 0x0013 => 'VT_UI4',
173
- 0x0014 => 'VT_I8',
174
- 0x0015 => 'VT_UI8',
175
- 0x0016 => 'VT_INT',
176
- 0x0017 => 'VT_UINT',
177
- 0x0018 => 'VT_VOID',
178
- 0x0019 => 'VT_HRESULT',
179
- 0x001a => 'VT_PTR',
180
- 0x001b => 'VT_SAFEARRAY',
181
- 0x001c => 'VT_CARRAY',
182
- 0x001d => 'VT_USERDEFINED',
183
- 0x001e => 'VT_LPSTR',
184
- 0x001f => 'VT_LPWSTR',
185
- 0x0040 => 'VT_FILETIME',
186
- 0x0041 => 'VT_BLOB',
187
- 0x0042 => 'VT_STREAM',
188
- 0x0043 => 'VT_STORAGE',
189
- 0x0044 => 'VT_STREAMED_OBJECT',
190
- 0x0045 => 'VT_STORED_OBJECT',
191
- 0x0046 => 'VT_BLOB_OBJECT',
192
- 0x0047 => 'VT_CF',
193
- 0x0048 => 'VT_CLSID',
194
- 0x0fff => 'VT_ILLEGALMASKED',
195
- 0x0fff => 'VT_TYPEMASK',
196
- 0x1000 => 'VT_VECTOR',
197
- 0x2000 => 'VT_ARRAY',
198
- 0x4000 => 'VT_BYREF',
199
- 0x8000 => 'VT_RESERVED',
200
- 0xffff => 'VT_ILLEGAL'
201
- }
202
-
203
- CLASS_MAP = {
204
- # haven't seen one of these. wonder if its same as FILETIME?
205
- #'VT_DATE' => ?,
206
- 'VT_LPSTR' => Lpstr,
207
- 'VT_LPWSTR' => Lpwstr,
208
- 'VT_FILETIME' => FileTime,
209
- 'VT_CLSID' => Clsid
210
- }
211
-
212
- module Constants
213
- NAMES.each { |num, name| const_set name, num }
214
- end
215
-
216
- def self.load type, str
217
- type = NAMES[type] or raise ArgumentError, 'unknown ole type - 0x%04x' % type
218
- (CLASS_MAP[type] || Data).load str
219
- end
220
-
221
- def self.dump type, variant
222
- type = NAMES[type] or raise ArgumentError, 'unknown ole type - 0x%04x' % type
223
- (CLASS_MAP[type] || Data).dump variant
224
- end
225
- end
226
-
227
- include Variant::Constants
228
-
229
- # deprecated aliases, kept mostly for the benefit of ruby-msg, until
230
- # i release a new version.
231
- def self.load_guid str
232
- Variant.load VT_CLSID, str
233
- end
234
-
235
- def self.load_time str
236
- Variant.load VT_FILETIME, str
237
- end
238
-
239
- FROM_UTF16 = Lpwstr::FROM_UTF16
240
- TO_UTF16 = Lpwstr::TO_UTF16
241
- end
242
- end
243
-
1
+ require 'ole/types/base'
2
+ require 'ole/types/property_set'
@@ -0,0 +1,247 @@
1
+ require 'iconv'
2
+ require 'date'
3
+
4
+ require 'ole/base'
5
+
6
+ module Ole # :nodoc:
7
+ #
8
+ # The Types module contains all the serialization and deserialization code for standard ole
9
+ # types.
10
+ #
11
+ # It also defines all the variant type constants, and symbolic names.
12
+ #
13
+ module Types
14
+ # for anything that we don't have serialization code for
15
+ class Data < String
16
+ def self.load str
17
+ new str
18
+ end
19
+
20
+ def self.dump str
21
+ str.to_s
22
+ end
23
+ end
24
+
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
36
+ end
37
+
38
+ # for VT_LPWSTR
39
+ class Lpwstr < String
40
+ FROM_UTF16 = Iconv.new 'utf-8', 'utf-16le'
41
+ TO_UTF16 = Iconv.new 'utf-16le', 'utf-8'
42
+
43
+ def self.load str
44
+ new FROM_UTF16.iconv(str).chomp(0.chr)
45
+ end
46
+
47
+ def self.dump str
48
+ # need to append nulls?
49
+ TO_UTF16.iconv str
50
+ end
51
+ end
52
+
53
+ # for VT_FILETIME
54
+ class FileTime < DateTime
55
+ SIZE = 8
56
+ EPOCH = new 1601, 1, 1
57
+
58
+ # Create a +DateTime+ object from a struct +FILETIME+
59
+ # (http://msdn2.microsoft.com/en-us/library/ms724284.aspx).
60
+ #
61
+ # Converts +str+ to two 32 bit time values, comprising the high and low 32 bits of
62
+ # the 100's of nanoseconds since 1st january 1601 (Epoch).
63
+ def self.load str
64
+ low, high = str.to_s.unpack 'V2'
65
+ # we ignore these, without even warning about it
66
+ return nil if low == 0 and high == 0
67
+ # switched to rational, and fixed the off by 1 second error i sometimes got.
68
+ # time = EPOCH + (high * (1 << 32) + low) / 1e7 / 86400 rescue return
69
+ # use const_get to ensure we can return anything which subclasses this (VT_DATE?)
70
+ const_get('EPOCH') + Rational(high * (1 << 32) + low, 1e7.to_i * 86400) rescue return
71
+ # extra sanity check...
72
+ #unless (1800...2100) === time.year
73
+ # Log.warn "ignoring unlikely time value #{time.to_s}"
74
+ # return nil
75
+ #end
76
+ #time
77
+ end
78
+
79
+ # +time+ should be able to be either a Time, Date, or DateTime.
80
+ def self.dump time
81
+ # i think i'll convert whatever i get to be a datetime, because of
82
+ # the covered range.
83
+ return 0.chr * SIZE unless time
84
+ time = time.send(:to_datetime) if Time === time
85
+ # don't bother to use const_get here
86
+ bignum = (time - EPOCH) * 86400 * 1e7.to_i
87
+ high, low = bignum.divmod 1 << 32
88
+ [low, high].pack 'V2'
89
+ end
90
+
91
+ def inspect
92
+ "#<#{self.class} #{to_s}>"
93
+ end
94
+ end
95
+
96
+ # for VT_CLSID
97
+ # Unlike most of the other conversions, the Guid's are serialized/deserialized by actually
98
+ # doing nothing! (eg, _load & _dump are null ops)
99
+ # Rather, its just a string with a different inspect string, and it includes a
100
+ # helper method for creating a Guid from that readable form (#format).
101
+ class Clsid < String
102
+ SIZE = 16
103
+ PACK = 'V v v CC C6'
104
+
105
+ def self.load str
106
+ new str.to_s
107
+ end
108
+
109
+ def self.dump guid
110
+ return 0.chr * SIZE unless guid
111
+ # allow use of plain strings in place of guids.
112
+ guid['-'] ? parse(guid) : guid
113
+ end
114
+
115
+ def self.parse str
116
+ vals = str.scan(/[a-f\d]+/i).map(&:hex)
117
+ if vals.length == 5
118
+ # this is pretty ugly
119
+ vals[3] = ('%04x' % vals[3]).scan(/../).map(&:hex)
120
+ vals[4] = ('%012x' % vals[4]).scan(/../).map(&:hex)
121
+ guid = new vals.flatten.pack(PACK)
122
+ return guid if guid.format.delete('{}') == str.downcase.delete('{}')
123
+ end
124
+ raise ArgumentError, 'invalid guid - %p' % str
125
+ end
126
+
127
+ def format
128
+ "%08x-%04x-%04x-%02x%02x-#{'%02x' * 6}" % unpack(PACK)
129
+ end
130
+
131
+ def inspect
132
+ "#<#{self.class}:{#{format}}>"
133
+ end
134
+ end
135
+
136
+ #
137
+ # The OLE variant types, extracted from
138
+ # http://www.marin.clara.net/COM/variant_type_definitions.htm.
139
+ #
140
+ # A subset is also in WIN32OLE::VARIANT, but its not cross platform (obviously).
141
+ #
142
+ # Use like:
143
+ #
144
+ # p Ole::Types::Variant::NAMES[0x001f] => 'VT_LPWSTR'
145
+ # p Ole::Types::VT_DATE # => 7
146
+ #
147
+ # The serialization / deserialization functions should be fixed to make it easier
148
+ # to work with. like
149
+ #
150
+ # Ole::Types.from_str(VT_DATE, data) # and
151
+ # Ole::Types.to_str(VT_DATE, data)
152
+ #
153
+ # Or similar, rather than having to do VT_* <=> ad hoc class name etc as it is
154
+ # currently.
155
+ #
156
+ module Variant
157
+ NAMES = {
158
+ 0x0000 => 'VT_EMPTY',
159
+ 0x0001 => 'VT_NULL',
160
+ 0x0002 => 'VT_I2',
161
+ 0x0003 => 'VT_I4',
162
+ 0x0004 => 'VT_R4',
163
+ 0x0005 => 'VT_R8',
164
+ 0x0006 => 'VT_CY',
165
+ 0x0007 => 'VT_DATE',
166
+ 0x0008 => 'VT_BSTR',
167
+ 0x0009 => 'VT_DISPATCH',
168
+ 0x000a => 'VT_ERROR',
169
+ 0x000b => 'VT_BOOL',
170
+ 0x000c => 'VT_VARIANT',
171
+ 0x000d => 'VT_UNKNOWN',
172
+ 0x000e => 'VT_DECIMAL',
173
+ 0x0010 => 'VT_I1',
174
+ 0x0011 => 'VT_UI1',
175
+ 0x0012 => 'VT_UI2',
176
+ 0x0013 => 'VT_UI4',
177
+ 0x0014 => 'VT_I8',
178
+ 0x0015 => 'VT_UI8',
179
+ 0x0016 => 'VT_INT',
180
+ 0x0017 => 'VT_UINT',
181
+ 0x0018 => 'VT_VOID',
182
+ 0x0019 => 'VT_HRESULT',
183
+ 0x001a => 'VT_PTR',
184
+ 0x001b => 'VT_SAFEARRAY',
185
+ 0x001c => 'VT_CARRAY',
186
+ 0x001d => 'VT_USERDEFINED',
187
+ 0x001e => 'VT_LPSTR',
188
+ 0x001f => 'VT_LPWSTR',
189
+ 0x0040 => 'VT_FILETIME',
190
+ 0x0041 => 'VT_BLOB',
191
+ 0x0042 => 'VT_STREAM',
192
+ 0x0043 => 'VT_STORAGE',
193
+ 0x0044 => 'VT_STREAMED_OBJECT',
194
+ 0x0045 => 'VT_STORED_OBJECT',
195
+ 0x0046 => 'VT_BLOB_OBJECT',
196
+ 0x0047 => 'VT_CF',
197
+ 0x0048 => 'VT_CLSID',
198
+ 0x0fff => 'VT_ILLEGALMASKED',
199
+ 0x0fff => 'VT_TYPEMASK',
200
+ 0x1000 => 'VT_VECTOR',
201
+ 0x2000 => 'VT_ARRAY',
202
+ 0x4000 => 'VT_BYREF',
203
+ 0x8000 => 'VT_RESERVED',
204
+ 0xffff => 'VT_ILLEGAL'
205
+ }
206
+
207
+ CLASS_MAP = {
208
+ # haven't seen one of these. wonder if its same as FILETIME?
209
+ #'VT_DATE' => ?,
210
+ 'VT_LPSTR' => Lpstr,
211
+ 'VT_LPWSTR' => Lpwstr,
212
+ 'VT_FILETIME' => FileTime,
213
+ 'VT_CLSID' => Clsid
214
+ }
215
+
216
+ module Constants
217
+ NAMES.each { |num, name| const_set name, num }
218
+ end
219
+
220
+ def self.load type, str
221
+ type = NAMES[type] or raise ArgumentError, 'unknown ole type - 0x%04x' % type
222
+ (CLASS_MAP[type] || Data).load str
223
+ end
224
+
225
+ def self.dump type, variant
226
+ type = NAMES[type] or raise ArgumentError, 'unknown ole type - 0x%04x' % type
227
+ (CLASS_MAP[type] || Data).dump variant
228
+ end
229
+ end
230
+
231
+ include Variant::Constants
232
+
233
+ # deprecated aliases, kept mostly for the benefit of ruby-msg, until
234
+ # i release a new version.
235
+ def self.load_guid str
236
+ Variant.load VT_CLSID, str
237
+ end
238
+
239
+ def self.load_time str
240
+ Variant.load VT_FILETIME, str
241
+ end
242
+
243
+ FROM_UTF16 = Lpwstr::FROM_UTF16
244
+ TO_UTF16 = Lpwstr::TO_UTF16
245
+ end
246
+ end
247
+