ruby-dbus 0.15.0 → 0.18.0.beta1
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 +5 -5
- data/NEWS.md +41 -1
- data/README.md +3 -5
- data/Rakefile +18 -8
- data/VERSION +1 -1
- data/doc/Reference.md +93 -3
- data/examples/doc/_extract_examples +7 -0
- data/examples/gdbus/gdbus +31 -24
- data/examples/no-introspect/nm-test.rb +2 -0
- data/examples/no-introspect/tracker-test.rb +3 -1
- data/examples/rhythmbox/playpause.rb +2 -1
- data/examples/service/call_service.rb +2 -1
- data/examples/service/service_newapi.rb +1 -1
- data/examples/simple/call_introspect.rb +1 -0
- data/examples/simple/get_id.rb +2 -1
- data/examples/simple/properties.rb +2 -0
- data/examples/utils/listnames.rb +1 -0
- data/examples/utils/notify.rb +1 -0
- data/lib/dbus/api_options.rb +9 -0
- data/lib/dbus/auth.rb +20 -15
- data/lib/dbus/bus.rb +129 -74
- data/lib/dbus/bus_name.rb +31 -0
- data/lib/dbus/core_ext/class/attribute.rb +1 -1
- data/lib/dbus/error.rb +4 -2
- data/lib/dbus/introspect.rb +90 -34
- data/lib/dbus/logger.rb +3 -1
- data/lib/dbus/marshall.rb +119 -87
- data/lib/dbus/matchrule.rb +16 -16
- data/lib/dbus/message.rb +40 -27
- data/lib/dbus/message_queue.rb +26 -18
- data/lib/dbus/object.rb +401 -0
- data/lib/dbus/object_path.rb +28 -0
- data/lib/dbus/proxy_object.rb +23 -2
- data/lib/dbus/proxy_object_factory.rb +11 -7
- data/lib/dbus/proxy_object_interface.rb +26 -21
- data/lib/dbus/type.rb +59 -34
- data/lib/dbus/xml.rb +28 -17
- data/lib/dbus.rb +10 -8
- data/ruby-dbus.gemspec +8 -4
- data/spec/async_spec.rb +2 -0
- data/spec/binding_spec.rb +2 -0
- data/spec/bus_and_xml_backend_spec.rb +2 -0
- data/spec/bus_driver_spec.rb +2 -0
- data/spec/bus_name_spec.rb +27 -0
- data/spec/bus_spec.rb +2 -0
- data/spec/byte_array_spec.rb +2 -0
- data/spec/client_robustness_spec.rb +27 -0
- data/spec/err_msg_spec.rb +2 -0
- data/spec/introspect_xml_parser_spec.rb +2 -0
- data/spec/introspection_spec.rb +2 -0
- data/spec/main_loop_spec.rb +3 -1
- data/spec/node_spec.rb +23 -0
- data/spec/object_path_spec.rb +25 -0
- data/spec/property_spec.rb +64 -5
- data/spec/proxy_object_spec.rb +2 -0
- data/spec/server_robustness_spec.rb +2 -0
- data/spec/server_spec.rb +2 -0
- data/spec/service_newapi.rb +39 -70
- data/spec/session_bus_spec.rb +3 -1
- data/spec/session_bus_spec_manual.rb +2 -0
- data/spec/signal_spec.rb +5 -3
- data/spec/spec_helper.rb +23 -9
- data/spec/thread_safety_spec.rb +2 -0
- data/spec/tools/dbus-limited-session.conf +4 -0
- data/spec/type_spec.rb +2 -0
- data/spec/value_spec.rb +16 -1
- data/spec/variant_spec.rb +4 -2
- metadata +32 -12
- data/lib/dbus/export.rb +0 -131
data/lib/dbus/introspect.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# dbus/introspection.rb - module containing a low-level D-Bus introspection implementation
|
2
4
|
#
|
3
5
|
# This file is part of the ruby-dbus project
|
@@ -10,13 +12,9 @@
|
|
10
12
|
|
11
13
|
module DBus
|
12
14
|
# Regular expressions that should match all method names.
|
13
|
-
METHOD_SIGNAL_RE = /^[A-Za-z][A-Za-z0-9_]
|
15
|
+
METHOD_SIGNAL_RE = /^[A-Za-z][A-Za-z0-9_]*$/.freeze
|
14
16
|
# Regular expressions that should match all interface names.
|
15
|
-
INTERFACE_ELEMENT_RE = /^[A-Za-z][A-Za-z0-9_]
|
16
|
-
|
17
|
-
# Exception raised when an unknown signal is used.
|
18
|
-
class UnknownSignal < Exception
|
19
|
-
end
|
17
|
+
INTERFACE_ELEMENT_RE = /^[A-Za-z][A-Za-z0-9_]*$/.freeze
|
20
18
|
|
21
19
|
# Exception raised when an invalid class definition is encountered.
|
22
20
|
class InvalidClassDefinition < Exception
|
@@ -30,19 +28,23 @@ module DBus
|
|
30
28
|
# It also is the local definition of interface exported by the program.
|
31
29
|
# At the client side, see ProxyObjectInterface
|
32
30
|
class Interface
|
33
|
-
# The name of the interface.
|
31
|
+
# @return [String] The name of the interface.
|
34
32
|
attr_reader :name
|
35
|
-
# The methods that are part of the interface.
|
33
|
+
# @return [Hash{Symbol => DBus::Method}] The methods that are part of the interface.
|
36
34
|
attr_reader :methods
|
37
|
-
# The signals that are part of the interface.
|
35
|
+
# @return [Hash{Symbol => Signal}] The signals that are part of the interface.
|
38
36
|
attr_reader :signals
|
39
37
|
|
38
|
+
# @return [Hash{Symbol => Property}]
|
39
|
+
attr_reader :properties
|
40
|
+
|
40
41
|
# Creates a new interface with a given _name_.
|
41
42
|
def initialize(name)
|
42
43
|
validate_name(name)
|
43
44
|
@name = name
|
44
45
|
@methods = {}
|
45
46
|
@signals = {}
|
47
|
+
@properties = {}
|
46
48
|
end
|
47
49
|
|
48
50
|
# Validates a service _name_.
|
@@ -51,33 +53,45 @@ module DBus
|
|
51
53
|
raise InvalidIntrospectionData if name =~ /^\./ || name =~ /\.$/
|
52
54
|
raise InvalidIntrospectionData if name =~ /\.\./
|
53
55
|
raise InvalidIntrospectionData if name !~ /\./
|
56
|
+
|
54
57
|
name.split(".").each do |element|
|
55
58
|
raise InvalidIntrospectionData if element !~ INTERFACE_ELEMENT_RE
|
56
59
|
end
|
57
60
|
end
|
58
61
|
|
59
|
-
#
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
62
|
+
# Add _ifc_el_ as a known {Method}, {Signal} or {Property}
|
63
|
+
# @param ifc_el [InterfaceElement]
|
64
|
+
def define(ifc_el)
|
65
|
+
name = ifc_el.name.to_sym
|
66
|
+
category = case ifc_el
|
67
|
+
when Method
|
68
|
+
@methods
|
69
|
+
when Signal
|
70
|
+
@signals
|
71
|
+
when Property
|
72
|
+
@properties
|
73
|
+
end
|
74
|
+
category[name] = ifc_el
|
66
75
|
end
|
76
|
+
alias declare define
|
67
77
|
alias << define
|
68
78
|
|
69
79
|
# Defines a method with name _id_ and a given _prototype_ in the
|
70
80
|
# interface.
|
81
|
+
# Better name: declare_method
|
71
82
|
def define_method(id, prototype)
|
72
83
|
m = Method.new(id)
|
73
84
|
m.from_prototype(prototype)
|
74
85
|
define(m)
|
75
86
|
end
|
76
|
-
|
87
|
+
alias declare_method define_method
|
88
|
+
end
|
77
89
|
|
78
90
|
# = A formal parameter has a name and a type
|
79
91
|
class FormalParameter
|
92
|
+
# @return [#to_s]
|
80
93
|
attr_reader :name
|
94
|
+
# @return [SingleCompleteType]
|
81
95
|
attr_reader :type
|
82
96
|
|
83
97
|
def initialize(name, type)
|
@@ -99,14 +113,16 @@ module DBus
|
|
99
113
|
# This is a generic class for entities that are part of the interface
|
100
114
|
# such as methods and signals.
|
101
115
|
class InterfaceElement
|
102
|
-
# The name of the interface element
|
116
|
+
# @return [Symbol] The name of the interface element
|
103
117
|
attr_reader :name
|
104
|
-
|
118
|
+
|
119
|
+
# @return [Array<FormalParameter>] The parameters of the interface element
|
105
120
|
attr_reader :params
|
106
121
|
|
107
122
|
# Validates element _name_.
|
108
123
|
def validate_name(name)
|
109
124
|
return if (name =~ METHOD_SIGNAL_RE) && (name.bytesize <= 255)
|
125
|
+
|
110
126
|
raise InvalidMethodName, name
|
111
127
|
end
|
112
128
|
|
@@ -127,13 +143,13 @@ module DBus
|
|
127
143
|
def add_param(name_signature_pair)
|
128
144
|
add_fparam(*name_signature_pair)
|
129
145
|
end
|
130
|
-
end
|
146
|
+
end
|
131
147
|
|
132
148
|
# = D-Bus interface method class
|
133
149
|
#
|
134
150
|
# This is a class representing methods that are part of an interface.
|
135
151
|
class Method < InterfaceElement
|
136
|
-
# The list of return values for the method
|
152
|
+
# @return [Array<FormalParameter>] The list of return values for the method
|
137
153
|
attr_reader :rets
|
138
154
|
|
139
155
|
# Creates a new method interface element with the given _name_.
|
@@ -143,15 +159,19 @@ module DBus
|
|
143
159
|
end
|
144
160
|
|
145
161
|
# Add a return value _name_ and _signature_.
|
162
|
+
# @param name [#to_s]
|
163
|
+
# @param signature [SingleCompleteType]
|
146
164
|
def add_return(name, signature)
|
147
165
|
@rets << FormalParameter.new(name, signature)
|
148
166
|
end
|
149
167
|
|
150
168
|
# Add parameter types by parsing the given _prototype_.
|
169
|
+
# @param prototype [Prototype]
|
151
170
|
def from_prototype(prototype)
|
152
171
|
prototype.split(/, */).each do |arg|
|
153
172
|
arg = arg.split(" ")
|
154
173
|
raise InvalidClassDefinition if arg.size != 2
|
174
|
+
|
155
175
|
dir, arg = arg
|
156
176
|
if arg =~ /:/
|
157
177
|
arg = arg.split(":")
|
@@ -171,19 +191,19 @@ module DBus
|
|
171
191
|
|
172
192
|
# Return an XML string representation of the method interface elment.
|
173
193
|
def to_xml
|
174
|
-
xml =
|
194
|
+
xml = " <method name=\"#{@name}\">\n"
|
175
195
|
@params.each do |param|
|
176
|
-
name = param.name ?
|
177
|
-
xml +=
|
196
|
+
name = param.name ? "name=\"#{param.name}\" " : ""
|
197
|
+
xml += " <arg #{name}direction=\"in\" type=\"#{param.type}\"/>\n"
|
178
198
|
end
|
179
199
|
@rets.each do |param|
|
180
|
-
name = param.name ?
|
181
|
-
xml +=
|
200
|
+
name = param.name ? "name=\"#{param.name}\" " : ""
|
201
|
+
xml += " <arg #{name}direction=\"out\" type=\"#{param.type}\"/>\n"
|
182
202
|
end
|
183
|
-
xml +=
|
203
|
+
xml += " </method>\n"
|
184
204
|
xml
|
185
205
|
end
|
186
|
-
end
|
206
|
+
end
|
187
207
|
|
188
208
|
# = D-Bus interface signal class
|
189
209
|
#
|
@@ -205,13 +225,49 @@ module DBus
|
|
205
225
|
|
206
226
|
# Return an XML string representation of the signal interface elment.
|
207
227
|
def to_xml
|
208
|
-
xml =
|
228
|
+
xml = " <signal name=\"#{@name}\">\n"
|
209
229
|
@params.each do |param|
|
210
|
-
name = param.name ?
|
211
|
-
xml +=
|
230
|
+
name = param.name ? "name=\"#{param.name}\" " : ""
|
231
|
+
xml += " <arg #{name}type=\"#{param.type}\"/>\n"
|
212
232
|
end
|
213
|
-
xml +=
|
233
|
+
xml += " </signal>\n"
|
214
234
|
xml
|
215
235
|
end
|
216
|
-
end
|
217
|
-
|
236
|
+
end
|
237
|
+
|
238
|
+
# An (exported) property
|
239
|
+
# https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
|
240
|
+
class Property
|
241
|
+
# @return [String] The name of the property, for example FooBar.
|
242
|
+
attr_reader :name
|
243
|
+
attr_reader :type
|
244
|
+
# @return [Symbol] :read :write or :readwrite
|
245
|
+
attr_reader :access
|
246
|
+
|
247
|
+
# @return [Symbol] What to call at Ruby side.
|
248
|
+
# (Always without the trailing `=`)
|
249
|
+
attr_reader :ruby_name
|
250
|
+
|
251
|
+
def initialize(name, type, access, ruby_name:)
|
252
|
+
@name = name
|
253
|
+
@type = type
|
254
|
+
@access = access
|
255
|
+
@ruby_name = ruby_name
|
256
|
+
end
|
257
|
+
|
258
|
+
# @return [Boolean]
|
259
|
+
def readable?
|
260
|
+
access == :read || access == :readwrite
|
261
|
+
end
|
262
|
+
|
263
|
+
# @return [Boolean]
|
264
|
+
def writable?
|
265
|
+
access == :write || access == :readwrite
|
266
|
+
end
|
267
|
+
|
268
|
+
# Return introspection XML string representation of the property.
|
269
|
+
def to_xml
|
270
|
+
" <property type=\"#{@type}\" name=\"#{@name}\" access=\"#{@access}\"/>\n"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
data/lib/dbus/logger.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# dbus/logger.rb - debug logging
|
2
4
|
#
|
3
5
|
# This file is part of the ruby-dbus project
|
@@ -16,7 +18,7 @@ module DBus
|
|
16
18
|
# with DEBUG if $DEBUG is set, otherwise INFO.
|
17
19
|
def logger
|
18
20
|
unless defined? @logger
|
19
|
-
@logger = Logger.new(
|
21
|
+
@logger = Logger.new($stderr)
|
20
22
|
@logger.level = $DEBUG ? Logger::DEBUG : Logger::INFO
|
21
23
|
end
|
22
24
|
@logger
|
data/lib/dbus/marshall.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# dbus.rb - Module containing the low-level D-Bus implementation
|
2
4
|
#
|
3
5
|
# This file is part of the ruby-dbus project
|
@@ -34,11 +36,12 @@ module DBus
|
|
34
36
|
def initialize(buffer, endianness)
|
35
37
|
@buffy = buffer.dup
|
36
38
|
@endianness = endianness
|
37
|
-
|
39
|
+
case @endianness
|
40
|
+
when BIG_END
|
38
41
|
@uint32 = "N"
|
39
42
|
@uint16 = "n"
|
40
43
|
@double = "G"
|
41
|
-
|
44
|
+
when LIL_END
|
42
45
|
@uint32 = "V"
|
43
46
|
@uint16 = "v"
|
44
47
|
@double = "E"
|
@@ -50,12 +53,14 @@ module DBus
|
|
50
53
|
|
51
54
|
# Unmarshall the buffer for a given _signature_ and length _len_.
|
52
55
|
# Return an array of unmarshalled objects
|
56
|
+
# @param signature [Signature]
|
57
|
+
# @param len [Integer,nil] if given, and there is not enough data
|
58
|
+
# in the buffer, raise {IncompleteBufferException}
|
59
|
+
# @return [Array<::Object>]
|
60
|
+
# @raise IncompleteBufferException
|
53
61
|
def unmarshall(signature, len = nil)
|
54
|
-
if
|
55
|
-
|
56
|
-
raise IncompleteBufferException
|
57
|
-
end
|
58
|
-
end
|
62
|
+
raise IncompleteBufferException if len && @buffy.bytesize < @idx + len
|
63
|
+
|
59
64
|
sigtree = Type::Parser.new(signature).parse
|
60
65
|
ret = []
|
61
66
|
sigtree.each do |elem|
|
@@ -64,18 +69,18 @@ module DBus
|
|
64
69
|
ret
|
65
70
|
end
|
66
71
|
|
67
|
-
# Align the pointer index on a byte index of
|
72
|
+
# Align the pointer index on a byte index of _alignment_, which
|
68
73
|
# must be 1, 2, 4 or 8.
|
69
|
-
def align(
|
70
|
-
case
|
74
|
+
def align(alignment)
|
75
|
+
case alignment
|
71
76
|
when 1
|
72
77
|
nil
|
73
78
|
when 2, 4, 8
|
74
|
-
bits =
|
79
|
+
bits = alignment - 1
|
75
80
|
@idx = @idx + bits & ~bits
|
76
81
|
raise IncompleteBufferException if @idx > @buffy.bytesize
|
77
82
|
else
|
78
|
-
raise "Unsupported alignment #{
|
83
|
+
raise ArgumentError, "Unsupported alignment #{alignment}"
|
79
84
|
end
|
80
85
|
end
|
81
86
|
|
@@ -87,6 +92,7 @@ module DBus
|
|
87
92
|
# Retrieve the next _nbytes_ number of bytes from the buffer.
|
88
93
|
def read(nbytes)
|
89
94
|
raise IncompleteBufferException if @idx + nbytes > @buffy.bytesize
|
95
|
+
|
90
96
|
ret = @buffy.slice(@idx, nbytes)
|
91
97
|
@idx += nbytes
|
92
98
|
ret
|
@@ -96,13 +102,15 @@ module DBus
|
|
96
102
|
# Return the string.
|
97
103
|
def read_string
|
98
104
|
align(4)
|
99
|
-
str_sz = read(4).
|
105
|
+
str_sz = read(4).unpack1(@uint32)
|
100
106
|
ret = @buffy.slice(@idx, str_sz)
|
101
107
|
raise IncompleteBufferException if @idx + str_sz + 1 > @buffy.bytesize
|
108
|
+
|
102
109
|
@idx += str_sz
|
103
110
|
if @buffy[@idx].ord != 0
|
104
111
|
raise InvalidPacketException, "String is not nul-terminated"
|
105
112
|
end
|
113
|
+
|
106
114
|
@idx += 1
|
107
115
|
# no exception, see check above
|
108
116
|
ret
|
@@ -111,13 +119,15 @@ module DBus
|
|
111
119
|
# Read the signature length and signature itself from the buffer.
|
112
120
|
# Return the signature.
|
113
121
|
def read_signature
|
114
|
-
str_sz = read(1).
|
122
|
+
str_sz = read(1).unpack1("C")
|
115
123
|
ret = @buffy.slice(@idx, str_sz)
|
116
124
|
raise IncompleteBufferException if @idx + str_sz + 1 >= @buffy.bytesize
|
125
|
+
|
117
126
|
@idx += str_sz
|
118
127
|
if @buffy[@idx].ord != 0
|
119
128
|
raise InvalidPacketException, "Type is not nul-terminated"
|
120
129
|
end
|
130
|
+
|
121
131
|
@idx += 1
|
122
132
|
# no exception, see check above
|
123
133
|
ret
|
@@ -129,29 +139,29 @@ module DBus
|
|
129
139
|
packet = nil
|
130
140
|
case signature.sigtype
|
131
141
|
when Type::BYTE
|
132
|
-
packet = read(1).
|
142
|
+
packet = read(1).unpack1("C")
|
133
143
|
when Type::UINT16
|
134
144
|
align(2)
|
135
|
-
packet = read(2).
|
145
|
+
packet = read(2).unpack1(@uint16)
|
136
146
|
when Type::INT16
|
137
147
|
align(2)
|
138
|
-
packet = read(2).
|
148
|
+
packet = read(2).unpack1(@uint16)
|
139
149
|
if (packet & 0x8000) != 0
|
140
150
|
packet -= 0x10000
|
141
151
|
end
|
142
152
|
when Type::UINT32, Type::UNIX_FD
|
143
153
|
align(4)
|
144
|
-
packet = read(4).
|
154
|
+
packet = read(4).unpack1(@uint32)
|
145
155
|
when Type::INT32
|
146
156
|
align(4)
|
147
|
-
packet = read(4).
|
157
|
+
packet = read(4).unpack1(@uint32)
|
148
158
|
if (packet & 0x80000000) != 0
|
149
159
|
packet -= 0x100000000
|
150
160
|
end
|
151
161
|
when Type::UINT64
|
152
162
|
align(8)
|
153
|
-
packet_l = read(4).
|
154
|
-
packet_h = read(4).
|
163
|
+
packet_l = read(4).unpack1(@uint32)
|
164
|
+
packet_h = read(4).unpack1(@uint32)
|
155
165
|
packet = if @endianness == LIL_END
|
156
166
|
packet_l + packet_h * 2**32
|
157
167
|
else
|
@@ -159,8 +169,8 @@ module DBus
|
|
159
169
|
end
|
160
170
|
when Type::INT64
|
161
171
|
align(8)
|
162
|
-
packet_l = read(4).
|
163
|
-
packet_h = read(4).
|
172
|
+
packet_l = read(4).unpack1(@uint32)
|
173
|
+
packet_h = read(4).unpack1(@uint32)
|
164
174
|
packet = if @endianness == LIL_END
|
165
175
|
packet_l + packet_h * 2**32
|
166
176
|
else
|
@@ -171,16 +181,17 @@ module DBus
|
|
171
181
|
end
|
172
182
|
when Type::DOUBLE
|
173
183
|
align(8)
|
174
|
-
packet = read(8).
|
184
|
+
packet = read(8).unpack1(@double)
|
175
185
|
when Type::BOOLEAN
|
176
186
|
align(4)
|
177
|
-
v = read(4).
|
187
|
+
v = read(4).unpack1(@uint32)
|
178
188
|
raise InvalidPacketException if ![0, 1].member?(v)
|
189
|
+
|
179
190
|
packet = (v == 1)
|
180
191
|
when Type::ARRAY
|
181
192
|
align(4)
|
182
193
|
# checks please
|
183
|
-
array_sz = read(4).
|
194
|
+
array_sz = read(4).unpack1(@uint32)
|
184
195
|
raise InvalidPacketException if array_sz > 67_108_864
|
185
196
|
|
186
197
|
align(signature.child.alignment)
|
@@ -201,6 +212,7 @@ module DBus
|
|
201
212
|
signature.members.each do |elem|
|
202
213
|
packet << do_parse(elem)
|
203
214
|
end
|
215
|
+
packet.freeze
|
204
216
|
when Type::VARIANT
|
205
217
|
string = read_signature
|
206
218
|
# error checking please
|
@@ -224,8 +236,8 @@ module DBus
|
|
224
236
|
"sigtype: #{signature.sigtype} (#{signature.sigtype.chr})"
|
225
237
|
end
|
226
238
|
packet
|
227
|
-
end
|
228
|
-
end
|
239
|
+
end
|
240
|
+
end
|
229
241
|
|
230
242
|
# D-Bus packet marshaller class
|
231
243
|
#
|
@@ -243,20 +255,21 @@ module DBus
|
|
243
255
|
@offset = offset # for correct alignment of nested marshallers
|
244
256
|
end
|
245
257
|
|
246
|
-
# Round
|
247
|
-
def num_align(
|
248
|
-
case
|
258
|
+
# Round _num_ up to the specified power of two, _alignment_
|
259
|
+
def num_align(num, alignment)
|
260
|
+
case alignment
|
249
261
|
when 1, 2, 4, 8
|
250
|
-
bits =
|
251
|
-
|
262
|
+
bits = alignment - 1
|
263
|
+
num + bits & ~bits
|
252
264
|
else
|
253
|
-
raise "Unsupported alignment"
|
265
|
+
raise ArgumentError, "Unsupported alignment #{alignment}"
|
254
266
|
end
|
255
267
|
end
|
256
268
|
|
257
|
-
# Align the buffer with NULL (\0) bytes on a byte length of
|
258
|
-
def align(
|
259
|
-
|
269
|
+
# Align the buffer with NULL (\0) bytes on a byte length of _alignment_.
|
270
|
+
def align(alignment)
|
271
|
+
pad_count = num_align(@offset + @packet.bytesize, alignment) - @offset
|
272
|
+
@packet = @packet.ljust(pad_count, 0.chr)
|
260
273
|
end
|
261
274
|
|
262
275
|
# Append the the string _str_ itself to the packet.
|
@@ -267,7 +280,7 @@ module DBus
|
|
267
280
|
|
268
281
|
# Append the the signature _signature_ itself to the packet.
|
269
282
|
def append_signature(str)
|
270
|
-
@packet += str.bytesize.chr
|
283
|
+
@packet += "#{str.bytesize.chr}#{str}\u0000"
|
271
284
|
end
|
272
285
|
|
273
286
|
# Append the array type _type_ to the packet and allow for appending
|
@@ -282,6 +295,7 @@ module DBus
|
|
282
295
|
yield
|
283
296
|
sz = @packet.bytesize - contentidx
|
284
297
|
raise InvalidPacketException if sz > 67_108_864
|
298
|
+
|
285
299
|
@packet[sizeidx...sizeidx + 4] = [sz].pack("L")
|
286
300
|
end
|
287
301
|
|
@@ -337,57 +351,24 @@ module DBus
|
|
337
351
|
when Type::SIGNATURE
|
338
352
|
append_signature(val)
|
339
353
|
when Type::VARIANT
|
340
|
-
|
341
|
-
if val.is_a?(Array) && val.size == 2
|
342
|
-
if val[0].is_a?(DBus::Type::Type)
|
343
|
-
vartype, vardata = val
|
344
|
-
elsif val[0].is_a?(String)
|
345
|
-
begin
|
346
|
-
parsed = Type::Parser.new(val[0]).parse
|
347
|
-
vartype = parsed[0] if parsed.size == 1
|
348
|
-
vardata = val[1]
|
349
|
-
rescue Type::SignatureException
|
350
|
-
# no assignment
|
351
|
-
end
|
352
|
-
end
|
353
|
-
end
|
354
|
-
if vartype.nil?
|
355
|
-
vartype, vardata = PacketMarshaller.make_variant(val)
|
356
|
-
vartype = Type::Parser.new(vartype).parse[0]
|
357
|
-
end
|
358
|
-
|
359
|
-
append_signature(vartype.to_s)
|
360
|
-
align(vartype.alignment)
|
361
|
-
sub = PacketMarshaller.new(@offset + @packet.bytesize)
|
362
|
-
sub.append(vartype, vardata)
|
363
|
-
@packet += sub.packet
|
354
|
+
append_variant(val)
|
364
355
|
when Type::ARRAY
|
365
|
-
|
366
|
-
raise TypeException, "Expected an Array but got a Hash" if type.child.sigtype != Type::DICT_ENTRY
|
367
|
-
# Damn ruby rocks here
|
368
|
-
val = val.to_a
|
369
|
-
end
|
370
|
-
# If string is recieved and ay is expected, explode the string
|
371
|
-
if val.is_a?(String) && type.child.sigtype == Type::BYTE
|
372
|
-
val = val.bytes
|
373
|
-
end
|
374
|
-
if !val.is_a?(Enumerable)
|
375
|
-
raise TypeException, "Expected an Enumerable of #{type.child.inspect} but got a #{val.class}"
|
376
|
-
end
|
377
|
-
array(type.child) do
|
378
|
-
val.each do |elem|
|
379
|
-
append(type.child, elem)
|
380
|
-
end
|
381
|
-
end
|
356
|
+
append_array(type.child, val)
|
382
357
|
when Type::STRUCT, Type::DICT_ENTRY
|
383
|
-
|
384
|
-
|
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
|
362
|
+
|
385
363
|
if type.sigtype == Type::DICT_ENTRY && val.size != 2
|
386
|
-
raise TypeException, "
|
364
|
+
raise TypeException, "DICT_ENTRY expects a pair"
|
387
365
|
end
|
366
|
+
|
388
367
|
if type.members.size != val.size
|
389
|
-
|
368
|
+
type_name = Type::TYPE_MAPPING[type.sigtype].first
|
369
|
+
raise TypeException, "#{type_name} has #{val.size} elements but type info for #{type.members.size}"
|
390
370
|
end
|
371
|
+
|
391
372
|
struct do
|
392
373
|
type.members.zip(val).each do |t, v|
|
393
374
|
append(t, v)
|
@@ -397,7 +378,58 @@ module DBus
|
|
397
378
|
raise NotImplementedError,
|
398
379
|
"sigtype: #{type.sigtype} (#{type.sigtype.chr})"
|
399
380
|
end
|
400
|
-
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def append_variant(val)
|
384
|
+
vartype = nil
|
385
|
+
if val.is_a?(Array) && val.size == 2
|
386
|
+
case val[0]
|
387
|
+
when DBus::Type::Type
|
388
|
+
vartype, vardata = val
|
389
|
+
when String
|
390
|
+
begin
|
391
|
+
parsed = Type::Parser.new(val[0]).parse
|
392
|
+
vartype = parsed[0] if parsed.size == 1
|
393
|
+
vardata = val[1]
|
394
|
+
rescue Type::SignatureException
|
395
|
+
# no assignment
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
if vartype.nil?
|
400
|
+
vartype, vardata = PacketMarshaller.make_variant(val)
|
401
|
+
vartype = Type::Parser.new(vartype).parse[0]
|
402
|
+
end
|
403
|
+
|
404
|
+
append_signature(vartype.to_s)
|
405
|
+
align(vartype.alignment)
|
406
|
+
sub = PacketMarshaller.new(@offset + @packet.bytesize)
|
407
|
+
sub.append(vartype, vardata)
|
408
|
+
@packet += sub.packet
|
409
|
+
end
|
410
|
+
|
411
|
+
# @param child_type [DBus::Type::Type]
|
412
|
+
def append_array(child_type, val)
|
413
|
+
if val.is_a?(Hash)
|
414
|
+
raise TypeException, "Expected an Array but got a Hash" if child_type.sigtype != Type::DICT_ENTRY
|
415
|
+
|
416
|
+
# Damn ruby rocks here
|
417
|
+
val = val.to_a
|
418
|
+
end
|
419
|
+
# If string is recieved and ay is expected, explode the string
|
420
|
+
if val.is_a?(String) && child_type.sigtype == Type::BYTE
|
421
|
+
val = val.bytes
|
422
|
+
end
|
423
|
+
if !val.is_a?(Enumerable)
|
424
|
+
raise TypeException, "Expected an Enumerable of #{child_type.inspect} but got a #{val.class}"
|
425
|
+
end
|
426
|
+
|
427
|
+
array(child_type) do
|
428
|
+
val.each do |elem|
|
429
|
+
append(child_type, elem)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
401
433
|
|
402
434
|
# Make a [signature, value] pair for a variant
|
403
435
|
def self.make_variant(value)
|
@@ -422,12 +454,12 @@ module DBus
|
|
422
454
|
["s", value.to_str]
|
423
455
|
elsif value.respond_to? :to_int
|
424
456
|
i = value.to_int
|
425
|
-
if -2_147_483_648
|
457
|
+
if (-2_147_483_648...2_147_483_648).cover?(i)
|
426
458
|
["i", i]
|
427
459
|
else
|
428
460
|
["x", i]
|
429
461
|
end
|
430
462
|
end
|
431
463
|
end
|
432
|
-
end
|
433
|
-
end
|
464
|
+
end
|
465
|
+
end
|