ruby-dbus 0.18.0.beta1 → 0.18.0.beta4
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.
- checksums.yaml +4 -4
- data/NEWS.md +33 -0
- data/VERSION +1 -1
- data/doc/Reference.md +1 -1
- data/examples/service/complex-property.rb +21 -0
- data/lib/dbus/data.rb +744 -0
- data/lib/dbus/introspect.rb +1 -0
- data/lib/dbus/marshall.rb +172 -259
- data/lib/dbus/message.rb +4 -10
- data/lib/dbus/object.rb +11 -11
- data/lib/dbus/object_path.rb +2 -1
- data/lib/dbus/raw_message.rb +91 -0
- data/lib/dbus/type.rb +147 -70
- data/lib/dbus.rb +6 -0
- data/spec/data/marshall.yaml +1667 -0
- data/spec/data_spec.rb +353 -0
- data/spec/object_path_spec.rb +1 -0
- data/spec/packet_marshaller_spec.rb +41 -0
- data/spec/packet_unmarshaller_spec.rb +262 -0
- data/spec/property_spec.rb +80 -2
- data/spec/service_newapi.rb +19 -1
- data/spec/spec_helper.rb +14 -0
- data/spec/type_spec.rb +67 -6
- data/spec/zzz_quit_spec.rb +16 -0
- metadata +10 -2
data/lib/dbus/introspect.rb
CHANGED
data/lib/dbus/marshall.rb
CHANGED
@@ -12,6 +12,8 @@
|
|
12
12
|
|
13
13
|
require "socket"
|
14
14
|
|
15
|
+
require_relative "../dbus/type"
|
16
|
+
|
15
17
|
# = D-Bus main module
|
16
18
|
#
|
17
19
|
# Module containing all the D-Bus modules and classes.
|
@@ -23,217 +25,130 @@ module DBus
|
|
23
25
|
# = D-Bus packet unmarshaller class
|
24
26
|
#
|
25
27
|
# Class that handles the conversion (unmarshalling) of payload data
|
26
|
-
# to
|
28
|
+
# to #{::Object}s (in **plain** mode) or to {Data::Base} (in **exact** mode)
|
29
|
+
#
|
30
|
+
# Spelling note: this codebase always uses a double L
|
31
|
+
# in the "marshall" word and its inflections.
|
27
32
|
class PacketUnmarshaller
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
# Used to kown what part of the buffer has been consumed by unmarshalling.
|
32
|
-
# FIXME: Maybe should be accessed with a "consumed_size" method.
|
33
|
-
attr_reader :idx
|
34
|
-
|
35
|
-
# Create a new unmarshaller for the given data _buffer_ and _endianness_.
|
33
|
+
# Create a new unmarshaller for the given data *buffer*.
|
34
|
+
# @param buffer [String]
|
35
|
+
# @param endianness [:little,:big]
|
36
36
|
def initialize(buffer, endianness)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@uint32 = "N"
|
42
|
-
@uint16 = "n"
|
43
|
-
@double = "G"
|
44
|
-
when LIL_END
|
45
|
-
@uint32 = "V"
|
46
|
-
@uint16 = "v"
|
47
|
-
@double = "E"
|
48
|
-
else
|
49
|
-
raise InvalidPacketException, "Incorrect endianness #{@endianness}"
|
50
|
-
end
|
51
|
-
@idx = 0
|
37
|
+
# TODO: this dup can be avoided if we can prove
|
38
|
+
# that an IncompleteBufferException leaves the original *buffer* intact
|
39
|
+
buffer = buffer.dup
|
40
|
+
@raw_msg = RawMessage.new(buffer, endianness)
|
52
41
|
end
|
53
42
|
|
54
43
|
# Unmarshall the buffer for a given _signature_ and length _len_.
|
55
|
-
# Return an array of unmarshalled objects
|
44
|
+
# Return an array of unmarshalled objects.
|
56
45
|
# @param signature [Signature]
|
57
46
|
# @param len [Integer,nil] if given, and there is not enough data
|
58
47
|
# in the buffer, raise {IncompleteBufferException}
|
59
|
-
# @
|
48
|
+
# @param mode [:plain,:exact]
|
49
|
+
# @return [Array<::Object,DBus::Data::Base>]
|
50
|
+
# Objects in `:plain` mode, {DBus::Data::Base} in `:exact` mode
|
51
|
+
# The array size corresponds to the number of types in *signature*.
|
60
52
|
# @raise IncompleteBufferException
|
61
|
-
|
62
|
-
|
53
|
+
# @raise InvalidPacketException
|
54
|
+
def unmarshall(signature, len = nil, mode: :plain)
|
55
|
+
@raw_msg.want!(len) if len
|
63
56
|
|
64
57
|
sigtree = Type::Parser.new(signature).parse
|
65
58
|
ret = []
|
66
59
|
sigtree.each do |elem|
|
67
|
-
ret << do_parse(elem)
|
60
|
+
ret << do_parse(elem, mode: mode)
|
68
61
|
end
|
69
62
|
ret
|
70
63
|
end
|
71
64
|
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
case alignment
|
76
|
-
when 1
|
77
|
-
nil
|
78
|
-
when 2, 4, 8
|
79
|
-
bits = alignment - 1
|
80
|
-
@idx = @idx + bits & ~bits
|
81
|
-
raise IncompleteBufferException if @idx > @buffy.bytesize
|
82
|
-
else
|
83
|
-
raise ArgumentError, "Unsupported alignment #{alignment}"
|
84
|
-
end
|
65
|
+
# after the headers, the body starts 8-aligned
|
66
|
+
def align_body
|
67
|
+
@raw_msg.align(8)
|
85
68
|
end
|
86
69
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
70
|
+
# @return [Integer]
|
71
|
+
def consumed_size
|
72
|
+
@raw_msg.pos
|
73
|
+
end
|
91
74
|
|
92
|
-
|
93
|
-
def read(nbytes)
|
94
|
-
raise IncompleteBufferException if @idx + nbytes > @buffy.bytesize
|
75
|
+
private
|
95
76
|
|
96
|
-
|
97
|
-
|
98
|
-
|
77
|
+
# @param data_class [Class] a subclass of Data::Base (specific?)
|
78
|
+
# @return [::Integer,::Float]
|
79
|
+
def aligned_read_value(data_class)
|
80
|
+
@raw_msg.align(data_class.alignment)
|
81
|
+
bytes = @raw_msg.read(data_class.alignment)
|
82
|
+
bytes.unpack1(data_class.format[@raw_msg.endianness])
|
99
83
|
end
|
100
84
|
|
101
|
-
#
|
102
|
-
#
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
85
|
+
# Based on the _signature_ type, retrieve a packet from the buffer
|
86
|
+
# and return it.
|
87
|
+
# @param signature [Type]
|
88
|
+
# @param mode [:plain,:exact]
|
89
|
+
# @return [Data::Base]
|
90
|
+
def do_parse(signature, mode: :plain)
|
91
|
+
# FIXME: better naming for packet vs value
|
92
|
+
packet = nil
|
93
|
+
data_class = Data::BY_TYPE_CODE[signature.sigtype]
|
108
94
|
|
109
|
-
|
110
|
-
|
111
|
-
|
95
|
+
if data_class.nil?
|
96
|
+
raise NotImplementedError,
|
97
|
+
"sigtype: #{signature.sigtype} (#{signature.sigtype.chr})"
|
112
98
|
end
|
113
99
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
100
|
+
if data_class.fixed?
|
101
|
+
value = aligned_read_value(data_class)
|
102
|
+
packet = data_class.from_raw(value, mode: mode)
|
103
|
+
elsif data_class.basic?
|
104
|
+
size = aligned_read_value(data_class.size_class)
|
105
|
+
# @raw_msg.align(data_class.alignment)
|
106
|
+
# ^ is not necessary because we've just read a suitably-aligned *size*
|
107
|
+
value = @raw_msg.read(size)
|
108
|
+
nul = @raw_msg.read(1)
|
109
|
+
if nul != "\u0000"
|
110
|
+
raise InvalidPacketException, "#{data_class} is not NUL-terminated"
|
111
|
+
end
|
118
112
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
113
|
+
packet = data_class.from_raw(value, mode: mode)
|
114
|
+
else
|
115
|
+
@raw_msg.align(data_class.alignment)
|
116
|
+
case signature.sigtype
|
117
|
+
when Type::STRUCT, Type::DICT_ENTRY
|
118
|
+
values = signature.members.map do |child_sig|
|
119
|
+
do_parse(child_sig, mode: mode)
|
120
|
+
end
|
121
|
+
packet = data_class.from_items(values, mode: mode, member_types: signature.members)
|
125
122
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
123
|
+
when Type::VARIANT
|
124
|
+
data_sig = do_parse(Data::Signature.type, mode: :exact) # -> Data::Signature
|
125
|
+
types = Type::Parser.new(data_sig.value).parse # -> Array<Type>
|
126
|
+
unless types.size == 1
|
127
|
+
raise InvalidPacketException, "VARIANT must contain 1 value, #{types.size} found"
|
128
|
+
end
|
130
129
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
end
|
130
|
+
type = types.first
|
131
|
+
value = do_parse(type, mode: mode)
|
132
|
+
packet = data_class.from_items(value, mode: mode, member_type: type)
|
135
133
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
when Type::BYTE
|
142
|
-
packet = read(1).unpack1("C")
|
143
|
-
when Type::UINT16
|
144
|
-
align(2)
|
145
|
-
packet = read(2).unpack1(@uint16)
|
146
|
-
when Type::INT16
|
147
|
-
align(2)
|
148
|
-
packet = read(2).unpack1(@uint16)
|
149
|
-
if (packet & 0x8000) != 0
|
150
|
-
packet -= 0x10000
|
151
|
-
end
|
152
|
-
when Type::UINT32, Type::UNIX_FD
|
153
|
-
align(4)
|
154
|
-
packet = read(4).unpack1(@uint32)
|
155
|
-
when Type::INT32
|
156
|
-
align(4)
|
157
|
-
packet = read(4).unpack1(@uint32)
|
158
|
-
if (packet & 0x80000000) != 0
|
159
|
-
packet -= 0x100000000
|
160
|
-
end
|
161
|
-
when Type::UINT64
|
162
|
-
align(8)
|
163
|
-
packet_l = read(4).unpack1(@uint32)
|
164
|
-
packet_h = read(4).unpack1(@uint32)
|
165
|
-
packet = if @endianness == LIL_END
|
166
|
-
packet_l + packet_h * 2**32
|
167
|
-
else
|
168
|
-
packet_l * 2**32 + packet_h
|
169
|
-
end
|
170
|
-
when Type::INT64
|
171
|
-
align(8)
|
172
|
-
packet_l = read(4).unpack1(@uint32)
|
173
|
-
packet_h = read(4).unpack1(@uint32)
|
174
|
-
packet = if @endianness == LIL_END
|
175
|
-
packet_l + packet_h * 2**32
|
176
|
-
else
|
177
|
-
packet_l * 2**32 + packet_h
|
178
|
-
end
|
179
|
-
if (packet & 0x8000000000000000) != 0
|
180
|
-
packet -= 0x10000000000000000
|
181
|
-
end
|
182
|
-
when Type::DOUBLE
|
183
|
-
align(8)
|
184
|
-
packet = read(8).unpack1(@double)
|
185
|
-
when Type::BOOLEAN
|
186
|
-
align(4)
|
187
|
-
v = read(4).unpack1(@uint32)
|
188
|
-
raise InvalidPacketException if ![0, 1].member?(v)
|
189
|
-
|
190
|
-
packet = (v == 1)
|
191
|
-
when Type::ARRAY
|
192
|
-
align(4)
|
193
|
-
# checks please
|
194
|
-
array_sz = read(4).unpack1(@uint32)
|
195
|
-
raise InvalidPacketException if array_sz > 67_108_864
|
196
|
-
|
197
|
-
align(signature.child.alignment)
|
198
|
-
raise IncompleteBufferException if @idx + array_sz > @buffy.bytesize
|
199
|
-
|
200
|
-
packet = []
|
201
|
-
start_idx = @idx
|
202
|
-
while @idx - start_idx < array_sz
|
203
|
-
packet << do_parse(signature.child)
|
204
|
-
end
|
134
|
+
when Type::ARRAY
|
135
|
+
array_bytes = aligned_read_value(Data::UInt32)
|
136
|
+
if array_bytes > 67_108_864
|
137
|
+
raise InvalidPacketException, "ARRAY body longer than 64MiB"
|
138
|
+
end
|
205
139
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
140
|
+
# needed here because of empty arrays
|
141
|
+
@raw_msg.align(signature.child.alignment)
|
142
|
+
|
143
|
+
items = []
|
144
|
+
end_pos = @raw_msg.pos + array_bytes
|
145
|
+
while @raw_msg.pos < end_pos
|
146
|
+
item = do_parse(signature.child, mode: mode)
|
147
|
+
items << item
|
148
|
+
end
|
149
|
+
is_hash = signature.child.sigtype == Type::DICT_ENTRY
|
150
|
+
packet = data_class.from_items(items, mode: mode, member_type: signature.child, hash: is_hash)
|
214
151
|
end
|
215
|
-
packet.freeze
|
216
|
-
when Type::VARIANT
|
217
|
-
string = read_signature
|
218
|
-
# error checking please
|
219
|
-
sig = Type::Parser.new(string).parse[0]
|
220
|
-
align(sig.alignment)
|
221
|
-
packet = do_parse(sig)
|
222
|
-
when Type::OBJECT_PATH
|
223
|
-
packet = read_string
|
224
|
-
when Type::STRING
|
225
|
-
packet = read_string
|
226
|
-
packet.force_encoding("UTF-8")
|
227
|
-
when Type::SIGNATURE
|
228
|
-
packet = read_signature
|
229
|
-
when Type::DICT_ENTRY
|
230
|
-
align(8)
|
231
|
-
key = do_parse(signature.members[0])
|
232
|
-
value = do_parse(signature.members[1])
|
233
|
-
packet = [key, value]
|
234
|
-
else
|
235
|
-
raise NotImplementedError,
|
236
|
-
"sigtype: #{signature.sigtype} (#{signature.sigtype.chr})"
|
237
152
|
end
|
238
153
|
packet
|
239
154
|
end
|
@@ -246,11 +161,16 @@ module DBus
|
|
246
161
|
class PacketMarshaller
|
247
162
|
# The current or result packet.
|
248
163
|
# FIXME: allow access only when marshalling is finished
|
164
|
+
# @return [String]
|
249
165
|
attr_reader :packet
|
250
166
|
|
167
|
+
# @return [:little,:big]
|
168
|
+
attr_reader :endianness
|
169
|
+
|
251
170
|
# Create a new marshaller, setting the current packet to the
|
252
171
|
# empty packet.
|
253
|
-
def initialize(offset = 0)
|
172
|
+
def initialize(offset = 0, endianness: HOST_ENDIANNESS)
|
173
|
+
@endianness = endianness
|
254
174
|
@packet = ""
|
255
175
|
@offset = offset # for correct alignment of nested marshallers
|
256
176
|
end
|
@@ -272,17 +192,6 @@ module DBus
|
|
272
192
|
@packet = @packet.ljust(pad_count, 0.chr)
|
273
193
|
end
|
274
194
|
|
275
|
-
# Append the the string _str_ itself to the packet.
|
276
|
-
def append_string(str)
|
277
|
-
align(4)
|
278
|
-
@packet += [str.bytesize].pack("L") + [str].pack("Z*")
|
279
|
-
end
|
280
|
-
|
281
|
-
# Append the the signature _signature_ itself to the packet.
|
282
|
-
def append_signature(str)
|
283
|
-
@packet += "#{str.bytesize.chr}#{str}\u0000"
|
284
|
-
end
|
285
|
-
|
286
195
|
# Append the array type _type_ to the packet and allow for appending
|
287
196
|
# the child elements.
|
288
197
|
def array(type)
|
@@ -296,7 +205,8 @@ module DBus
|
|
296
205
|
sz = @packet.bytesize - contentidx
|
297
206
|
raise InvalidPacketException if sz > 67_108_864
|
298
207
|
|
299
|
-
|
208
|
+
sz_data = Data::UInt32.new(sz)
|
209
|
+
@packet[sizeidx...sizeidx + 4] = sz_data.marshall(endianness)
|
300
210
|
end
|
301
211
|
|
302
212
|
# Align and allow for appending struct fields.
|
@@ -308,84 +218,79 @@ module DBus
|
|
308
218
|
# Append a value _val_ to the packet based on its _type_.
|
309
219
|
#
|
310
220
|
# Host native endianness is used, declared in Message#marshall
|
221
|
+
#
|
222
|
+
# @param type [SingleCompleteType] (or Integer or {Type})
|
223
|
+
# @param val [::Object]
|
311
224
|
def append(type, val)
|
312
225
|
raise TypeException, "Cannot send nil" if val.nil?
|
313
226
|
|
314
227
|
type = type.chr if type.is_a?(Integer)
|
315
228
|
type = Type::Parser.new(type).parse[0] if type.is_a?(String)
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
when Type::UINT64
|
323
|
-
align(8)
|
324
|
-
@packet += [val].pack("Q")
|
325
|
-
when Type::INT64
|
326
|
-
align(8)
|
327
|
-
@packet += [val].pack("q")
|
328
|
-
when Type::INT32
|
329
|
-
align(4)
|
330
|
-
@packet += [val].pack("l")
|
331
|
-
when Type::UINT16
|
332
|
-
align(2)
|
333
|
-
@packet += [val].pack("S")
|
334
|
-
when Type::INT16
|
335
|
-
align(2)
|
336
|
-
@packet += [val].pack("s")
|
337
|
-
when Type::DOUBLE
|
338
|
-
align(8)
|
339
|
-
@packet += [val].pack("d")
|
340
|
-
when Type::BOOLEAN
|
341
|
-
align(4)
|
342
|
-
@packet += if val
|
343
|
-
[1].pack("L")
|
344
|
-
else
|
345
|
-
[0].pack("L")
|
346
|
-
end
|
347
|
-
when Type::OBJECT_PATH
|
348
|
-
append_string(val)
|
349
|
-
when Type::STRING
|
350
|
-
append_string(val)
|
351
|
-
when Type::SIGNATURE
|
352
|
-
append_signature(val)
|
353
|
-
when Type::VARIANT
|
354
|
-
append_variant(val)
|
355
|
-
when Type::ARRAY
|
356
|
-
append_array(type.child, val)
|
357
|
-
when Type::STRUCT, Type::DICT_ENTRY
|
358
|
-
unless val.is_a?(Array) || val.is_a?(Struct)
|
359
|
-
type_name = Type::TYPE_MAPPING[type.sigtype].first
|
360
|
-
raise TypeException, "#{type_name} expects an Array or Struct"
|
361
|
-
end
|
229
|
+
# type is [Type] now
|
230
|
+
data_class = Data::BY_TYPE_CODE[type.sigtype]
|
231
|
+
if data_class.nil?
|
232
|
+
raise NotImplementedError,
|
233
|
+
"sigtype: #{type.sigtype} (#{type.sigtype.chr})"
|
234
|
+
end
|
362
235
|
|
363
|
-
|
364
|
-
|
365
|
-
|
236
|
+
if data_class.fixed?
|
237
|
+
align(data_class.alignment)
|
238
|
+
data = data_class.new(val)
|
239
|
+
@packet += data.marshall(endianness)
|
240
|
+
elsif data_class.basic?
|
241
|
+
val = val.value if val.is_a?(Data::Basic)
|
242
|
+
align(data_class.size_class.alignment)
|
243
|
+
size_data = data_class.size_class.new(val.bytesize)
|
244
|
+
@packet += size_data.marshall(endianness)
|
245
|
+
# Z* makes a binary string, as opposed to interpolation
|
246
|
+
@packet += [val].pack("Z*")
|
247
|
+
else
|
248
|
+
case type.sigtype
|
249
|
+
|
250
|
+
when Type::VARIANT
|
251
|
+
append_variant(val)
|
252
|
+
when Type::ARRAY
|
253
|
+
val = val.value if val.is_a?(Data::Array)
|
254
|
+
append_array(type.child, val)
|
255
|
+
when Type::STRUCT, Type::DICT_ENTRY
|
256
|
+
val = val.value if val.is_a?(Data::Struct) || val.is_a?(Data::DictEntry)
|
257
|
+
unless val.is_a?(Array) || val.is_a?(Struct)
|
258
|
+
type_name = Type::TYPE_MAPPING[type.sigtype].first
|
259
|
+
raise TypeException, "#{type_name} expects an Array or Struct, seen #{val.class}"
|
260
|
+
end
|
366
261
|
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
262
|
+
if type.sigtype == Type::DICT_ENTRY && val.size != 2
|
263
|
+
raise TypeException, "DICT_ENTRY expects a pair"
|
264
|
+
end
|
265
|
+
|
266
|
+
if type.members.size != val.size
|
267
|
+
type_name = Type::TYPE_MAPPING[type.sigtype].first
|
268
|
+
raise TypeException, "#{type_name} has #{val.size} elements but type info for #{type.members.size}"
|
269
|
+
end
|
371
270
|
|
372
|
-
|
373
|
-
|
374
|
-
|
271
|
+
struct do
|
272
|
+
type.members.zip(val).each do |t, v|
|
273
|
+
append(t, v)
|
274
|
+
end
|
375
275
|
end
|
276
|
+
else
|
277
|
+
raise NotImplementedError,
|
278
|
+
"sigtype: #{type.sigtype} (#{type.sigtype.chr})"
|
376
279
|
end
|
377
|
-
else
|
378
|
-
raise NotImplementedError,
|
379
|
-
"sigtype: #{type.sigtype} (#{type.sigtype.chr})"
|
380
280
|
end
|
381
281
|
end
|
382
282
|
|
383
283
|
def append_variant(val)
|
384
284
|
vartype = nil
|
385
|
-
if val.is_a?(
|
285
|
+
if val.is_a?(DBus::Data::Base)
|
286
|
+
vartype = val.type # FIXME: box or unbox another variant?
|
287
|
+
vardata = val.value
|
288
|
+
elsif val.is_a?(Array) && val.size == 2
|
386
289
|
case val[0]
|
387
|
-
when
|
290
|
+
when Type
|
388
291
|
vartype, vardata = val
|
292
|
+
# Ambiguous but easy to use, because Type
|
293
|
+
# cannot construct "as" "a{sv}" easily
|
389
294
|
when String
|
390
295
|
begin
|
391
296
|
parsed = Type::Parser.new(val[0]).parse
|
@@ -401,14 +306,14 @@ module DBus
|
|
401
306
|
vartype = Type::Parser.new(vartype).parse[0]
|
402
307
|
end
|
403
308
|
|
404
|
-
|
309
|
+
append(Data::Signature.type, vartype.to_s)
|
405
310
|
align(vartype.alignment)
|
406
|
-
sub = PacketMarshaller.new(@offset + @packet.bytesize)
|
311
|
+
sub = PacketMarshaller.new(@offset + @packet.bytesize, endianness: endianness)
|
407
312
|
sub.append(vartype, vardata)
|
408
313
|
@packet += sub.packet
|
409
314
|
end
|
410
315
|
|
411
|
-
# @param child_type [
|
316
|
+
# @param child_type [Type]
|
412
317
|
def append_array(child_type, val)
|
413
318
|
if val.is_a?(Hash)
|
414
319
|
raise TypeException, "Expected an Array but got a Hash" if child_type.sigtype != Type::DICT_ENTRY
|
@@ -449,15 +354,23 @@ module DBus
|
|
449
354
|
elsif value.is_a? Hash
|
450
355
|
h = {}
|
451
356
|
value.each_key { |k| h[k] = make_variant(value[k]) }
|
452
|
-
|
357
|
+
key_type = if value.empty?
|
358
|
+
"s"
|
359
|
+
else
|
360
|
+
t, = make_variant(value.first.first)
|
361
|
+
t
|
362
|
+
end
|
363
|
+
["a{#{key_type}v}", h]
|
453
364
|
elsif value.respond_to? :to_str
|
454
365
|
["s", value.to_str]
|
455
366
|
elsif value.respond_to? :to_int
|
456
367
|
i = value.to_int
|
457
|
-
if
|
368
|
+
if Data::Int32.range.cover?(i)
|
458
369
|
["i", i]
|
459
|
-
|
370
|
+
elsif Data::Int64.range.cover?(i)
|
460
371
|
["x", i]
|
372
|
+
else
|
373
|
+
["t", i]
|
461
374
|
end
|
462
375
|
end
|
463
376
|
end
|
data/lib/dbus/message.rb
CHANGED
@@ -172,7 +172,7 @@ module DBus
|
|
172
172
|
@body_length = params.packet.bytesize
|
173
173
|
|
174
174
|
marshaller = PacketMarshaller.new
|
175
|
-
marshaller.append(Type::BYTE, HOST_END)
|
175
|
+
marshaller.append(Type::BYTE, HOST_END.ord)
|
176
176
|
marshaller.append(Type::BYTE, @message_type)
|
177
177
|
marshaller.append(Type::BYTE, @flags)
|
178
178
|
marshaller.append(Type::BYTE, @protocol)
|
@@ -204,13 +204,7 @@ module DBus
|
|
204
204
|
# the detected message (self) and
|
205
205
|
# the index pointer of the buffer where the message data ended.
|
206
206
|
def unmarshall_buffer(buf)
|
207
|
-
|
208
|
-
endianness = if buf[0] == "l"
|
209
|
-
LIL_END
|
210
|
-
else
|
211
|
-
BIG_END
|
212
|
-
end
|
213
|
-
pu = PacketUnmarshaller.new(buf, endianness)
|
207
|
+
pu = PacketUnmarshaller.new(buf, RawMessage.endianness(buf[0]))
|
214
208
|
mdata = pu.unmarshall(MESSAGE_SIGNATURE)
|
215
209
|
_, @message_type, @flags, @protocol, @body_length, @serial,
|
216
210
|
headers = mdata
|
@@ -235,11 +229,11 @@ module DBus
|
|
235
229
|
@signature = struct[1]
|
236
230
|
end
|
237
231
|
end
|
238
|
-
pu.
|
232
|
+
pu.align_body
|
239
233
|
if @body_length.positive? && @signature
|
240
234
|
@params = pu.unmarshall(@signature, @body_length)
|
241
235
|
end
|
242
|
-
[self, pu.
|
236
|
+
[self, pu.consumed_size]
|
243
237
|
end
|
244
238
|
|
245
239
|
# Make a new exception from ex, mark it as being caused by this message
|
data/lib/dbus/object.rb
CHANGED
@@ -61,15 +61,7 @@ module DBus
|
|
61
61
|
retdata = [*retdata]
|
62
62
|
|
63
63
|
reply = Message.method_return(msg)
|
64
|
-
|
65
|
-
# Use the specific property type instead of the generic variant
|
66
|
-
# returned by Get.
|
67
|
-
# TODO: GetAll and Set still missing
|
68
|
-
property = dbus_lookup_property(msg.params[0], msg.params[1])
|
69
|
-
rsigs = [property.type]
|
70
|
-
else
|
71
|
-
rsigs = meth.rets.map(&:type)
|
72
|
-
end
|
64
|
+
rsigs = meth.rets.map(&:type)
|
73
65
|
rsigs.zip(retdata).each do |rsig, rdata|
|
74
66
|
reply.add_param(rsig, rdata)
|
75
67
|
end
|
@@ -345,7 +337,9 @@ module DBus
|
|
345
337
|
if property.readable?
|
346
338
|
ruby_name = property.ruby_name
|
347
339
|
value = public_send(ruby_name)
|
348
|
-
|
340
|
+
# may raise, DBus.error or https://ruby-doc.com/core-3.1.0/TypeError.html
|
341
|
+
typed_value = Data.make_typed(property.type, value)
|
342
|
+
[typed_value]
|
349
343
|
else
|
350
344
|
raise DBus.error("org.freedesktop.DBus.Error.PropertyWriteOnly"),
|
351
345
|
"Property '#{interface_name}.#{property_name}' (on object '#{@path}') is not readable"
|
@@ -357,6 +351,9 @@ module DBus
|
|
357
351
|
|
358
352
|
if property.writable?
|
359
353
|
ruby_name_eq = "#{property.ruby_name}="
|
354
|
+
# TODO: declare dbus_method :Set to take :exact argument
|
355
|
+
# and type check it here before passing its :plain value
|
356
|
+
# to the implementation
|
360
357
|
public_send(ruby_name_eq, value)
|
361
358
|
else
|
362
359
|
raise DBus.error("org.freedesktop.DBus.Error.PropertyReadOnly"),
|
@@ -385,7 +382,10 @@ module DBus
|
|
385
382
|
# > array.
|
386
383
|
# so we will silently omit properties that fail to read.
|
387
384
|
# Get'ting them individually will send DBus.Error
|
388
|
-
|
385
|
+
value = public_send(ruby_name)
|
386
|
+
# may raise, DBus.error or https://ruby-doc.com/core-3.1.0/TypeError.html
|
387
|
+
typed_value = Data.make_typed(property.type, value)
|
388
|
+
p_hash[p_name.to_s] = typed_value
|
389
389
|
rescue StandardError
|
390
390
|
DBus.logger.debug "Property '#{interface_name}.#{p_name}' (on object '#{@path}')" \
|
391
391
|
" has raised during GetAll, omitting it"
|
data/lib/dbus/object_path.rb
CHANGED
@@ -9,7 +9,8 @@
|
|
9
9
|
# See the file "COPYING" for the exact licensing terms.
|
10
10
|
|
11
11
|
module DBus
|
12
|
-
# A {::String} that validates at initialization time
|
12
|
+
# A {::String} that validates at initialization time.
|
13
|
+
# See also {DBus::Data::ObjectPath}
|
13
14
|
# @see https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-object-path
|
14
15
|
class ObjectPath < String
|
15
16
|
# @raise Error if not a valid object path
|