@@ -33,7 +33,8 @@ class Prototype < String; end
33
33
#
34
34
# This module containts the constants of the types specified in the D-Bus
35
35
# protocol.
36
- module Type
36
+ #
37
+ class Type
37
38
# Mapping from type number to name and alignment.
38
39
TYPE_MAPPING = {
39
40
0 => [ "INVALID" , nil ] ,
@@ -64,91 +65,117 @@ module Type
64
65
class SignatureException < Exception
65
66
end
66
67
67
- # = D-Bus type conversion class
68
- #
69
- # Helper class for representing a D-Bus type.
70
- class Type
71
- # Returns the signature type number.
72
- attr_reader :sigtype
73
- # Return contained member types.
74
- attr_reader :members
75
-
76
- # Create a new type instance for type number _sigtype_.
77
- def initialize ( sigtype )
78
- if !TYPE_MAPPING . keys . member? ( sigtype )
79
- raise SignatureException , "Unknown key in signature: #{ sigtype . chr } "
80
- end
68
+ # Formerly this was a Module and there was a DBus::Type::Type class
69
+ # but the class got too prominent to keep its double double name.
70
+ # This is for backward compatibility.
71
+ Type = self # rubocop:disable Naming/ConstantName
81
72
82
- @sigtype = sigtype
83
- @members = [ ]
84
- end
73
+ # Returns the signature type number.
74
+ attr_reader :sigtype
75
+ # Return contained member types.
76
+ attr_reader :members
85
77
86
- # Return the required alignment for the type.
87
- def alignment
88
- TYPE_MAPPING [ @sigtype ] . last
78
+ # Use {DBus.type} instead, because this allows constructing
79
+ # incomplete or invalid types, for backward compatibility.
80
+ #
81
+ # @param abstract [Boolean] allow abstract types "r" and "e"
82
+ # (Enabled for internal usage by {Parser}.)
83
+ def initialize ( sigtype , abstract : false )
84
+ if !TYPE_MAPPING . keys . member? ( sigtype )
85
+ case sigtype
86
+ when ")"
87
+ raise SignatureException , "STRUCT unexpectedly closed: )"
88
+ when "}"
89
+ raise SignatureException , "DICT_ENTRY unexpectedly closed: }"
90
+ else
91
+ raise SignatureException , "Unknown type code #{ sigtype . inspect } "
92
+ end
89
93
end
90
94
91
- # Return a string representation of the type according to the
92
- # D-Bus specification.
93
- def to_s
94
- case @sigtype
95
+ unless abstract
96
+ case sigtype
95
97
when STRUCT
96
- "(#{ @members . collect ( &:to_s ) . join } )"
97
- when ARRAY
98
- "a#{ child } "
98
+ raise SignatureException , "Abstract STRUCT, use \" (...)\" instead of \" #{ STRUCT } \" "
99
99
when DICT_ENTRY
100
- "{#{ @members . collect ( &:to_s ) . join } }"
101
- else
102
- if !TYPE_MAPPING . keys . member? ( @sigtype )
103
- raise NotImplementedError
104
- end
105
-
106
- @sigtype . chr
100
+ raise SignatureException , "Abstract DICT_ENTRY, use \" {..}\" instead of \" #{ DICT_ENTRY } \" "
107
101
end
108
102
end
109
103
110
- # Add a new member type _item_.
111
- def <<( item )
112
- if ![ STRUCT , ARRAY , DICT_ENTRY ] . member? ( @sigtype )
113
- raise SignatureException
114
- end
115
- raise SignatureException if @sigtype == ARRAY && !@members . empty?
116
-
117
- if @sigtype == DICT_ENTRY
118
- case @members . size
119
- when 2
120
- raise SignatureException , "Dict entries have exactly two members"
121
- when 0
122
- if [ STRUCT , ARRAY , DICT_ENTRY ] . member? ( item . sigtype )
123
- raise SignatureException , "Dict entry keys must be basic types"
124
- end
125
- end
104
+ @sigtype = sigtype
105
+ @members = [ ]
106
+ end
107
+
108
+ # Return the required alignment for the type.
109
+ def alignment
110
+ TYPE_MAPPING [ @sigtype ] . last
111
+ end
112
+
113
+ # Return a string representation of the type according to the
114
+ # D-Bus specification.
115
+ def to_s
116
+ case @sigtype
117
+ when STRUCT
118
+ "(#{ @members . collect ( &:to_s ) . join } )"
119
+ when ARRAY
120
+ "a#{ child } "
121
+ when DICT_ENTRY
122
+ "{#{ @members . collect ( &:to_s ) . join } }"
123
+ else
124
+ if !TYPE_MAPPING . keys . member? ( @sigtype )
125
+ raise NotImplementedError
126
126
end
127
- @members << item
127
+
128
+ @sigtype . chr
128
129
end
130
+ end
129
131
130
- # Return the first contained member type.
131
- def child
132
- @members [ 0 ]
132
+ # Add a new member type _item_.
133
+ def <<( item )
134
+ if ![ STRUCT , ARRAY , DICT_ENTRY ] . member? ( @sigtype )
135
+ raise SignatureException
133
136
end
137
+ raise SignatureException if @sigtype == ARRAY && !@members . empty?
134
138
135
- def inspect
136
- s = TYPE_MAPPING [ @sigtype ] . first
137
- if [ STRUCT , ARRAY ] . member? ( @sigtype )
138
- s += ": #{ @members . inspect } "
139
+ if @sigtype == DICT_ENTRY
140
+ case @members . size
141
+ when 2
142
+ raise SignatureException , "DICT_ENTRY must have 2 subtypes, found 3 or more in #{ @signature } "
143
+ when 0
144
+ if [ STRUCT , ARRAY , DICT_ENTRY , VARIANT ] . member? ( item . sigtype )
145
+ raise SignatureException , "DICT_ENTRY key must be basic (non-container)"
146
+ end
139
147
end
140
- s
141
148
end
149
+ @members << item
150
+ end
151
+
152
+ # Return the first contained member type.
153
+ def child
154
+ @members [ 0 ]
155
+ end
156
+
157
+ def inspect
158
+ s = TYPE_MAPPING [ @sigtype ] . first
159
+ if [ STRUCT , ARRAY ] . member? ( @sigtype )
160
+ s += ": #{ @members . inspect } "
161
+ end
162
+ s
142
163
end
143
164
144
165
# = D-Bus type parser class
145
166
#
146
167
# Helper class to parse a type signature in the protocol.
168
+ # @api private
147
169
class Parser
148
170
# Create a new parser for the given _signature_.
149
171
# @param signature [Signature]
150
172
def initialize ( signature )
151
173
@signature = signature
174
+ if signature . size > 255
175
+ msg = "Potential signature is longer than 255 characters (#{ @signature . size } ): #{ @signature } "
176
+ raise SignatureException , msg
177
+ end
178
+
152
179
@idx = 0
153
180
end
154
181
@@ -160,35 +187,52 @@ def nextchar
160
187
end
161
188
162
189
# Parse one character _char_ of the signature.
163
- def parse_one ( char )
190
+ # @param for_array [Boolean] are we parsing an immediate child of an ARRAY
191
+ def parse_one ( char , for_array : false )
164
192
res = nil
165
193
case char
166
194
when "a"
167
195
res = Type . new ( ARRAY )
168
196
char = nextchar
169
- raise SignatureException , "Parse error in #{ @signature } " if char . nil?
197
+ raise SignatureException , "Empty ARRAY in #{ @signature } " if char . nil?
170
198
171
- child = parse_one ( char )
199
+ child = parse_one ( char , for_array : true )
172
200
res << child
173
201
when "("
174
- res = Type . new ( STRUCT )
202
+ res = Type . new ( STRUCT , abstract : true )
175
203
while ( char = nextchar ) && char != ")"
176
204
res << parse_one ( char )
177
205
end
178
- raise SignatureException , "Parse error in #{ @signature } " if char . nil?
206
+ raise SignatureException , "STRUCT not closed in #{ @signature } " if char . nil?
207
+ raise SignatureException , "Empty STRUCT in #{ @signature } " if res . members . empty?
179
208
when "{"
180
- res = Type . new ( DICT_ENTRY )
181
- while ( char = nextchar ) && char != "}"
209
+ raise SignatureException , "DICT_ENTRY not an immediate child of an ARRAY" unless for_array
210
+
211
+ res = Type . new ( DICT_ENTRY , abstract : true )
212
+
213
+ # key type, value type
214
+ 2 . times do |i |
215
+ char = nextchar
216
+ raise SignatureException , "DICT_ENTRY not closed in #{ @signature } " if char . nil?
217
+
218
+ raise SignatureException , "DICT_ENTRY must have 2 subtypes, found #{ i } in #{ @signature } " if char == "}"
219
+
182
220
res << parse_one ( char )
183
221
end
184
- raise SignatureException , "Parse error in #{ @signature } " if char . nil?
222
+
223
+ # closing "}"
224
+ char = nextchar
225
+ raise SignatureException , "DICT_ENTRY not closed in #{ @signature } " if char . nil?
226
+
227
+ raise SignatureException , "DICT_ENTRY must have 2 subtypes, found 3 or more in #{ @signature } " if char != "}"
185
228
else
186
229
res = Type . new ( char )
187
230
end
188
231
res
189
232
end
190
233
191
234
# Parse the entire signature, return a DBus::Type object.
235
+ # @return [Array<Type>]
192
236
def parse
193
237
@idx = 0
194
238
ret = [ ]
@@ -197,17 +241,43 @@ def parse
197
241
end
198
242
ret
199
243
end
244
+
245
+ # Parse one {SingleCompleteType}
246
+ # @return [Type]
247
+ def parse1
248
+ c = nextchar
249
+ raise SignatureException , "Empty signature, expecting a Single Complete Type" if c . nil?
250
+
251
+ t = parse_one ( c )
252
+ raise SignatureException , "Has more than a Single Complete Type: #{ @signature } " unless nextchar . nil?
253
+
254
+ t
255
+ end
200
256
end
201
257
end
202
258
203
259
# shortcuts
204
260
205
- # Parse a String to a DBus::Type::Type
261
+ # Parse a String to a valid {DBus::Type}.
262
+ # This is prefered to {Type#initialize} which allows
263
+ # incomplete or invalid types.
264
+ # @param string_type [SingleCompleteType]
265
+ # @return [DBus::Type]
266
+ # @raise SignatureException
206
267
def type ( string_type )
207
- Type ::Parser . new ( string_type ) . parse [ 0 ]
268
+ Type ::Parser . new ( string_type ) . parse1
208
269
end
209
270
module_function :type
210
271
272
+ # Parse a String to zero or more {DBus::Type}s.
273
+ # @param string_type [Signature]
274
+ # @return [Array<DBus::Type>]
275
+ # @raise SignatureException
276
+ def types ( string_type )
277
+ Type ::Parser . new ( string_type ) . parse
278
+ end
279
+ module_function :types
280
+
211
281
# Make an explicit [Type, value] pair
212
282
def variant ( string_type , value )
213
283
[ type ( string_type ) , value ]
0 commit comments