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, @endianness = buffer.dup, 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 68 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 52 def unmarshall(signature, len = nil) if len != nil if @buffy.bytesize < @idx + len raise IncompleteBufferException end end sigtree = Type::Parser.new(signature).parse ret = Array.new 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 126 def do_parse(signature) packet = nil case signature.sigtype when Type::BYTE packet = get(1).unpack("C")[0] when Type::UINT16 align(2) packet = get(2).unpack(@uint16)[0] when Type::INT16 align(4) packet = get(4).unpack(@uint16)[0] if (packet & 0x8000) != 0 packet -= 0x10000 end when Type::UINT32, Type::UNIX_FD align(4) packet = get(4).unpack(@uint32)[0] when Type::INT32 align(4) packet = get(4).unpack(@uint32)[0] if (packet & 0x80000000) != 0 packet -= 0x100000000 end when Type::UINT64 align(8) packet_l = get(4).unpack(@uint32)[0] packet_h = get(4).unpack(@uint32)[0] if @endianness == LIL_END packet = packet_l + packet_h * 2**32 else packet = packet_l * 2**32 + packet_h end when Type::INT64 align(8) packet_l = get(4).unpack(@uint32)[0] packet_h = get(4).unpack(@uint32)[0] if @endianness == LIL_END packet = packet_l + packet_h * 2**32 else packet = packet_l * 2**32 + packet_h end if (packet & 0x8000000000000000) != 0 packet -= 0x10000000000000000 end when Type::DOUBLE align(8) packet = get(8).unpack(@double)[0] when Type::BOOLEAN align(4) v = get(4).unpack(@uint32)[0] raise InvalidPacketException if not [0, 1].member?(v) packet = (v == 1) when Type::ARRAY align(4) # checks please array_sz = get(4).unpack(@uint32)[0] raise InvalidPacketException if array_sz > 67108864 align(signature.child.alignment) raise IncompleteBufferException if @idx + array_sz > @buffy.bytesize packet = Array.new start_idx = @idx while @idx - start_idx < array_sz packet << do_parse(signature.child) end if signature.child.sigtype == Type::DICT_ENTRY then packet = packet.inject(Hash.new) do |hash, pair| hash[pair[0]] = pair[1] hash end end when Type::STRUCT align(8) packet = Array.new signature.members.each do |elem| packet << do_parse(elem) end when Type::VARIANT string = get_signature # error checking please sig = Type::Parser.new(string).parse[0] align(sig.alignment) packet = do_parse(sig) when Type::OBJECT_PATH packet = get_string when Type::STRING packet = get_string packet.force_encoding('UTF-8') when Type::SIGNATURE packet = get_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 86 def get(nbytes) raise IncompleteBufferException if @idx + nbytes > @buffy.bytesize ret = @buffy.slice(@idx, nbytes) @idx += nbytes ret end
Get the signature length and signature itself from the buffer. Return the signature.
# File lib/dbus/marshall.rb, line 111 def get_signature str_sz = get(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
Get the string length and string itself from the buffer. Return the string.
# File lib/dbus/marshall.rb, line 95 def get_string align(4) str_sz = get(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