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