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