1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
# dbus/type.rb - module containing low-level D-Bus data type information
#
# This file is part of the ruby-dbus project
# Copyright (C) 2007 Arnaud Cornet and Paul van Tilburg
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License, version 2.1 as published by the Free Software Foundation.
# See the file "COPYING" for the exact licensing terms.
module DBus
# = D-Bus type module
#
# This module containts the constants of the types specified in the D-Bus
# protocol.
module Type
# Mapping from type number to name and alignment.
TypeMapping = {
0 => ["INVALID", nil],
"y" => ["BYTE", 1],
"b" => ["BOOLEAN", 4],
"n" => ["INT16", 2],
"q" => ["UINT16", 2],
"i" => ["INT32", 4],
"u" => ["UINT32", 4],
"x" => ["INT64", 8],
"t" => ["UINT64", 8],
"d" => ["DOUBLE", 8],
"r" => ["STRUCT", 8],
"a" => ["ARRAY", 4],
"v" => ["VARIANT", 1],
"o" => ["OBJECT_PATH", 4],
"s" => ["STRING", 4],
"g" => ["SIGNATURE", 1],
"e" => ["DICT_ENTRY", 8],
"h" => ["UNIX_FD", 4]
}.freeze
# Defines the set of constants
TypeMapping.each_pair do |key, value|
Type.const_set(value.first, key)
end
# Exception raised when an unknown/incorrect type is encountered.
class SignatureException < Exception
end
# = D-Bus type conversion class
#
# Helper class for representing a D-Bus type.
class Type
# Returns the signature type number.
attr_reader :sigtype
# Return contained member types.
attr_reader :members
# Create a new type instance for type number _sigtype_.
def initialize(sigtype)
if !TypeMapping.keys.member?(sigtype)
raise SignatureException, "Unknown key in signature: #{sigtype.chr}"
end
@sigtype = sigtype
@members = []
end
# Return the required alignment for the type.
def alignment
TypeMapping[@sigtype].last
end
# Return a string representation of the type according to the
# D-Bus specification.
def to_s
case @sigtype
when STRUCT
"(" + @members.collect(&:to_s).join + ")"
when ARRAY
"a" + child.to_s
when DICT_ENTRY
"{" + @members.collect(&:to_s).join + "}"
else
if !TypeMapping.keys.member?(@sigtype)
raise NotImplementedError
end
@sigtype.chr
end
end
# Add a new member type _a_.
def <<(a)
if ![STRUCT, ARRAY, DICT_ENTRY].member?(@sigtype)
raise SignatureException
end
raise SignatureException if @sigtype == ARRAY && !@members.empty?
if @sigtype == DICT_ENTRY
if @members.size == 2
raise SignatureException, "Dict entries have exactly two members"
end
if @members.empty?
if [STRUCT, ARRAY, DICT_ENTRY].member?(a.sigtype)
raise SignatureException, "Dict entry keys must be basic types"
end
end
end
@members << a
end
# Return the first contained member type.
def child
@members[0]
end
def inspect
s = TypeMapping[@sigtype].first
if [STRUCT, ARRAY].member?(@sigtype)
s += ": " + @members.inspect
end
s
end
end # class Type
# = D-Bus type parser class
#
# Helper class to parse a type signature in the protocol.
class Parser
# Create a new parser for the given _signature_.
def initialize(signature)
@signature = signature
@idx = 0
end
# Returns the next character from the signature.
def nextchar
c = @signature[@idx]
@idx += 1
c
end
# Parse one character _c_ of the signature.
def parse_one(c)
res = nil
case c
when "a"
res = Type.new(ARRAY)
c = nextchar
raise SignatureException, "Parse error in #{@signature}" if c.nil?
child = parse_one(c)
res << child
when "("
res = Type.new(STRUCT)
while (c = nextchar) && c != ")"
res << parse_one(c)
end
raise SignatureException, "Parse error in #{@signature}" if c.nil?
when "{"
res = Type.new(DICT_ENTRY)
while (c = nextchar) && c != "}"
res << parse_one(c)
end
raise SignatureException, "Parse error in #{@signature}" if c.nil?
else
res = Type.new(c)
end
res
end
# Parse the entire signature, return a DBus::Type object.
def parse
@idx = 0
ret = []
while (c = nextchar)
ret << parse_one(c)
end
ret
end
end # class Parser
end # module Type
# shortcuts
# Parse a String to a DBus::Type::Type
def type(string_type)
Type::Parser.new(string_type).parse[0]
end
module_function :type
# Make an explicit [Type, value] pair
def variant(string_type, value)
[type(string_type), value]
end
module_function :variant
end # module DBus
|