class DBus::PacketUnmarshaller
D-Bus packet unmarshaller class¶ ↑
Class that handles the conversion (unmarshalling) of payload data to Array.
Attributes
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
Create a new unmarshaller for the given data buffer and endianness.
# File lib/dbus/marshall.rb, line 34 def initialize(buffer, endianness) @buffy = buffer.dup @endianness = endianness if @endianness == BIG_END @uint32 = "N" @uint16 = "n" @double = "G" elsif @endianness == LIL_END @uint32 = "V" @uint16 = "v" @double = "E" else raise InvalidPacketException, "Incorrect endianness #{@endianness}" end @idx = 0 end
Public Instance Methods
Align the pointer index on a byte index of a, where a must be 1, 2, 4 or 8.
# File lib/dbus/marshall.rb, line 69 def align(a) case a when 1 when 2, 4, 8 bits = a - 1 @idx = @idx + bits & ~bits raise IncompleteBufferException if @idx > @buffy.bytesize else raise "Unsupported alignment #{a}" end end
Unmarshall the buffer for a given signature and length len. Return an array of unmarshalled objects
# File lib/dbus/marshall.rb, line 53 def unmarshall(signature, len = nil) if !len.nil? if @buffy.bytesize < @idx + len raise IncompleteBufferException end end sigtree = Type::Parser.new(signature).parse ret = [] sigtree.each do |elem| ret << do_parse(elem) end ret end
Private Instance Methods
Based on the signature type, retrieve a packet from the buffer and return it.
# File lib/dbus/marshall.rb, line 127 def do_parse(signature) packet = nil case signature.sigtype when Type::BYTE packet = read(1).unpack("C")[0] when Type::UINT16 align(2) packet = read(2).unpack(@uint16)[0] when Type::INT16 align(4) packet = read(4).unpack(@uint16)[0] if (packet & 0x8000) != 0 packet -= 0x10000 end when Type::UINT32, Type::UNIX_FD align(4) packet = read(4).unpack(@uint32)[0] when Type::INT32 align(4) packet = read(4).unpack(@uint32)[0] if (packet & 0x80000000) != 0 packet -= 0x100000000 end when Type::UINT64 align(8) packet_l = read(4).unpack(@uint32)[0] packet_h = read(4).unpack(@uint32)[0] packet = if @endianness == LIL_END packet_l + packet_h * 2**32 else packet_l * 2**32 + packet_h end when Type::INT64 align(8) packet_l = read(4).unpack(@uint32)[0] packet_h = read(4).unpack(@uint32)[0] packet = if @endianness == LIL_END packet_l + packet_h * 2**32 else packet_l * 2**32 + packet_h end if (packet & 0x8000000000000000) != 0 packet -= 0x10000000000000000 end when Type::DOUBLE align(8) packet = read(8).unpack(@double)[0] when Type::BOOLEAN align(4) v = read(4).unpack(@uint32)[0] raise InvalidPacketException if ![0, 1].member?(v) packet = (v == 1) when Type::ARRAY align(4) # checks please array_sz = read(4).unpack(@uint32)[0] raise InvalidPacketException if array_sz > 67_108_864 align(signature.child.alignment) raise IncompleteBufferException if @idx + array_sz > @buffy.bytesize packet = [] start_idx = @idx while @idx - start_idx < array_sz packet << do_parse(signature.child) end if signature.child.sigtype == Type::DICT_ENTRY packet = Hash[packet] end when Type::STRUCT align(8) packet = [] signature.members.each do |elem| packet << do_parse(elem) end when Type::VARIANT string = read_signature # error checking please sig = Type::Parser.new(string).parse[0] align(sig.alignment) packet = do_parse(sig) when Type::OBJECT_PATH packet = read_string when Type::STRING packet = read_string packet.force_encoding("UTF-8") when Type::SIGNATURE packet = read_signature when Type::DICT_ENTRY align(8) key = do_parse(signature.members[0]) value = do_parse(signature.members[1]) packet = [key, value] else raise NotImplementedError, "sigtype: #{signature.sigtype} (#{signature.sigtype.chr})" end packet end
Retrieve the next nbytes number of bytes from the buffer.
# File lib/dbus/marshall.rb, line 87 def read(nbytes) raise IncompleteBufferException if @idx + nbytes > @buffy.bytesize ret = @buffy.slice(@idx, nbytes) @idx += nbytes ret end
Read the signature length and signature itself from the buffer. Return the signature.
# File lib/dbus/marshall.rb, line 112 def read_signature str_sz = read(1).unpack("C")[0] ret = @buffy.slice(@idx, str_sz) raise IncompleteBufferException if @idx + str_sz + 1 >= @buffy.bytesize @idx += str_sz if @buffy[@idx].ord != 0 raise InvalidPacketException, "Type is not nul-terminated" end @idx += 1 # no exception, see check above ret end
Read the string length and string itself from the buffer. Return the string.
# File lib/dbus/marshall.rb, line 96 def read_string align(4) str_sz = read(4).unpack(@uint32)[0] ret = @buffy.slice(@idx, str_sz) raise IncompleteBufferException if @idx + str_sz + 1 > @buffy.bytesize @idx += str_sz if @buffy[@idx].ord != 0 raise InvalidPacketException, "String is not nul-terminated" end @idx += 1 # no exception, see check above ret end