# class DBus::PacketUnmarshaller

# D-Bus packet unmarshaller class¶ ↑

`Class` that handles the conversion (unmarshalling) of payload data to Array.

### Attributes

idx[R]

Index pointer that points to the byte in the data that is currently being processed.

Used to kown what part of the buffer has been consumed by unmarshalling. FIXME: Maybe should be accessed with a “consumed_size” method.

### Public Class Methods

new(buffer, endianness) click to toggle source

Create a new unmarshaller for the given data buffer and endianness.

       # File lib/dbus/marshall.rb
    34 def initialize(buffer, endianness)
    35   @buffy = buffer.dup
    36   @endianness = endianness
    37   if @endianness == BIG_END
    38     @uint32 = "N"
    39     @uint16 = "n"
    40     @double = "G"
    41   elsif @endianness == LIL_END
    42     @uint32 = "V"
    43     @uint16 = "v"
    44     @double = "E"
    45   else
    46     raise InvalidPacketException, "Incorrect endianness #{@endianness}"
    47   end
    48   @idx = 0
    49 end

### Public Instance Methods

align(a) click to toggle source

Align the pointer index on a byte index of a, where a must be 1, 2, 4 or 8.

       # File lib/dbus/marshall.rb
    69 def align(a)
    70   case a
    71   when 1
    72     nil
    73   when 2, 4, 8
    74     bits = a - 1
    75     @idx = @idx + bits & ~bits
    76     raise IncompleteBufferException if @idx > @buffy.bytesize
    77   else
    78     raise "Unsupported alignment #{a}"
    79   end
    80 end

unmarshall(signature, len = nil) click to toggle source

Unmarshall the buffer for a given signature and length len. Return an array of unmarshalled objects

       # File lib/dbus/marshall.rb
    53 def unmarshall(signature, len = nil)
    54   if !len.nil?
    55     if @buffy.bytesize < @idx + len
    56       raise IncompleteBufferException
    57     end
    58   end
    59   sigtree = Type::Parser.new(signature).parse
    60   ret = []
    61   sigtree.each do |elem|
    62     ret << do_parse(elem)
    63   end
    64   ret
    65 end

### Private Instance Methods

do_parse(signature) click to toggle source

Based on the signature type, retrieve a packet from the buffer and return it.

        # File lib/dbus/marshall.rb
    128 def do_parse(signature)
    129   packet = nil
    130   case signature.sigtype
    131   when Type::BYTE
    132     packet = read(1).unpack("C")[0]
    133   when Type::UINT16
    134     align(2)
    135     packet = read(2).unpack(@uint16)[0]
    136   when Type::INT16
    137     align(2)
    138     packet = read(2).unpack(@uint16)[0]
    139     if (packet & 0x8000) != 0
    140       packet -= 0x10000
    141     end
    142   when Type::UINT32, Type::UNIX_FD
    143     align(4)
    144     packet = read(4).unpack(@uint32)[0]
    145   when Type::INT32
    146     align(4)
    147     packet = read(4).unpack(@uint32)[0]
    148     if (packet & 0x80000000) != 0
    149       packet -= 0x100000000
    150     end
    151   when Type::UINT64
    152     align(8)
    153     packet_l = read(4).unpack(@uint32)[0]
    154     packet_h = read(4).unpack(@uint32)[0]
    155     packet = if @endianness == LIL_END
    156                packet_l + packet_h * 2**32
    157              else
    158                packet_l * 2**32 + packet_h
    159              end
    160   when Type::INT64
    161     align(8)
    162     packet_l = read(4).unpack(@uint32)[0]
    163     packet_h = read(4).unpack(@uint32)[0]
    164     packet = if @endianness == LIL_END
    165                packet_l + packet_h * 2**32
    166              else
    167                packet_l * 2**32 + packet_h
    168              end
    169     if (packet & 0x8000000000000000) != 0
    170       packet -= 0x10000000000000000
    171     end
    172   when Type::DOUBLE
    173     align(8)
    174     packet = read(8).unpack(@double)[0]
    175   when Type::BOOLEAN
    176     align(4)
    177     v = read(4).unpack(@uint32)[0]
    178     raise InvalidPacketException if ![0, 1].member?(v)
    179     packet = (v == 1)
    180   when Type::ARRAY
    181     align(4)
    182     # checks please
    183     array_sz = read(4).unpack(@uint32)[0]
    184     raise InvalidPacketException if array_sz > 67_108_864
    185
    186     align(signature.child.alignment)
    187     raise IncompleteBufferException if @idx + array_sz > @buffy.bytesize
    188
    189     packet = []
    190     start_idx = @idx
    191     while @idx - start_idx < array_sz
    192       packet << do_parse(signature.child)
    193     end
    194
    195     if signature.child.sigtype == Type::DICT_ENTRY
    196       packet = Hash[packet]
    197     end
    198   when Type::STRUCT
    199     align(8)
    200     packet = []
    201     signature.members.each do |elem|
    202       packet << do_parse(elem)
    203     end
    204   when Type::VARIANT
    205     string = read_signature
    206     # error checking please
    207     sig = Type::Parser.new(string).parse[0]
    208     align(sig.alignment)
    209     packet = do_parse(sig)
    210   when Type::OBJECT_PATH
    211     packet = read_string
    212   when Type::STRING
    213     packet = read_string
    214     packet.force_encoding("UTF-8")
    215   when Type::SIGNATURE
    216     packet = read_signature
    217   when Type::DICT_ENTRY
    218     align(8)
    219     key = do_parse(signature.members[0])
    220     value = do_parse(signature.members[1])
    221     packet = [key, value]
    222   else
    223     raise NotImplementedError,
    224           "sigtype: #{signature.sigtype} (#{signature.sigtype.chr})"
    225   end
    226   packet
    227 end

read(nbytes) click to toggle source

Retrieve the next nbytes number of bytes from the buffer.

       # File lib/dbus/marshall.rb
    88 def read(nbytes)
    89   raise IncompleteBufferException if @idx + nbytes > @buffy.bytesize
    90   ret = @buffy.slice(@idx, nbytes)
    91   @idx += nbytes
    92   ret
    93 end

read_signature() click to toggle source

Read the signature length and signature itself from the buffer. Return the signature.

        # File lib/dbus/marshall.rb
    113 def read_signature
    114   str_sz = read(1).unpack("C")[0]
    115   ret = @buffy.slice(@idx, str_sz)
    116   raise IncompleteBufferException if @idx + str_sz + 1 >= @buffy.bytesize
    117   @idx += str_sz
    118   if @buffy[@idx].ord != 0
    119     raise InvalidPacketException, "Type is not nul-terminated"
    120   end
    121   @idx += 1
    122   # no exception, see check above
    123   ret
    124 end

read_string() click to toggle source

Read the string length and string itself from the buffer. Return the string.

        # File lib/dbus/marshall.rb
     97 def read_string
     98   align(4)
     99   str_sz = read(4).unpack(@uint32)[0]
    100   ret = @buffy.slice(@idx, str_sz)
    101   raise IncompleteBufferException if @idx + str_sz + 1 > @buffy.bytesize
    102   @idx += str_sz
    103   if @buffy[@idx].ord != 0
    104     raise InvalidPacketException, "String is not nul-terminated"
    105   end
    106   @idx += 1
    107   # no exception, see check above
    108   ret
    109 end