GDBusMessage: fast-path decoding of fixed arrays
[platform/upstream/glib.git] / gio / gdbusmessage.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20
21 /* Uncomment to debug serializer code */
22 /* #define DEBUG_SERIALIZER */
23
24 #include "config.h"
25
26 #include <string.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30
31 #if MAJOR_IN_MKDEV
32 #include <sys/mkdev.h>
33 #elif MAJOR_IN_SYSMACROS
34 #include <sys/sysmacros.h>
35 #endif
36
37 #include "gdbusutils.h"
38 #include "gdbusmessage.h"
39 #include "gdbuserror.h"
40 #include "gioenumtypes.h"
41 #include "ginputstream.h"
42 #include "gdatainputstream.h"
43 #include "gmemoryinputstream.h"
44 #include "goutputstream.h"
45 #include "gdataoutputstream.h"
46 #include "gmemoryoutputstream.h"
47 #include "gseekable.h"
48 #include "gioerror.h"
49 #include "gdbusprivate.h"
50
51 #ifdef G_OS_UNIX
52 #include "gunixfdlist.h"
53 #endif
54
55 #include "glibintl.h"
56
57 typedef struct _GMemoryBuffer GMemoryBuffer;
58 struct _GMemoryBuffer
59 {
60   gsize len;
61   gsize valid_len;
62   gsize pos;
63   gchar *data;
64   GDataStreamByteOrder byte_order;
65 };
66
67 static gboolean
68 g_memory_buffer_is_byteswapped (GMemoryBuffer *mbuf)
69 {
70 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
71   return mbuf->byte_order == G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
72 #else
73   return mbuf->byte_order == G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
74 #endif
75 }
76
77 static guchar
78 g_memory_buffer_read_byte (GMemoryBuffer  *mbuf)
79 {
80   if (mbuf->pos >= mbuf->valid_len)
81     return 0;
82   return mbuf->data [mbuf->pos++];
83 }
84
85 static gint16
86 g_memory_buffer_read_int16 (GMemoryBuffer  *mbuf)
87 {
88   gint16 v;
89   
90   if (mbuf->pos > mbuf->valid_len - 2)
91     {
92       mbuf->pos = mbuf->valid_len;
93       return 0;
94     }
95
96   memcpy (&v, mbuf->data + mbuf->pos, 2);
97   mbuf->pos += 2;
98
99   if (g_memory_buffer_is_byteswapped (mbuf))
100     v = GUINT16_SWAP_LE_BE (v);
101
102   return v;
103 }
104
105 static guint16
106 g_memory_buffer_read_uint16 (GMemoryBuffer  *mbuf)
107 {
108   guint16 v;
109   
110   if (mbuf->pos > mbuf->valid_len - 2)
111     {
112       mbuf->pos = mbuf->valid_len;
113       return 0;
114     }
115
116   memcpy (&v, mbuf->data + mbuf->pos, 2);
117   mbuf->pos += 2;
118
119   if (g_memory_buffer_is_byteswapped (mbuf))
120     v = GUINT16_SWAP_LE_BE (v);
121
122   return v;
123 }
124
125 static gint32
126 g_memory_buffer_read_int32 (GMemoryBuffer  *mbuf)
127 {
128   gint32 v;
129   
130   if (mbuf->pos > mbuf->valid_len - 4)
131     {
132       mbuf->pos = mbuf->valid_len;
133       return 0;
134     }
135
136   memcpy (&v, mbuf->data + mbuf->pos, 4);
137   mbuf->pos += 4;
138
139   if (g_memory_buffer_is_byteswapped (mbuf))
140     v = GUINT32_SWAP_LE_BE (v);
141
142   return v;
143 }
144
145 static guint32
146 g_memory_buffer_read_uint32 (GMemoryBuffer  *mbuf)
147 {
148   guint32 v;
149   
150   if (mbuf->pos > mbuf->valid_len - 4)
151     {
152       mbuf->pos = mbuf->valid_len;
153       return 0;
154     }
155
156   memcpy (&v, mbuf->data + mbuf->pos, 4);
157   mbuf->pos += 4;
158
159   if (g_memory_buffer_is_byteswapped (mbuf))
160     v = GUINT32_SWAP_LE_BE (v);
161
162   return v;
163 }
164
165 static gint64
166 g_memory_buffer_read_int64 (GMemoryBuffer  *mbuf)
167 {
168   gint64 v;
169   
170   if (mbuf->pos > mbuf->valid_len - 8)
171     {
172       mbuf->pos = mbuf->valid_len;
173       return 0;
174     }
175
176   memcpy (&v, mbuf->data + mbuf->pos, 8);
177   mbuf->pos += 8;
178
179   if (g_memory_buffer_is_byteswapped (mbuf))
180     v = GUINT64_SWAP_LE_BE (v);
181
182   return v;
183 }
184
185 static guint64
186 g_memory_buffer_read_uint64 (GMemoryBuffer  *mbuf)
187 {
188   guint64 v;
189   
190   if (mbuf->pos > mbuf->valid_len - 8)
191     {
192       mbuf->pos = mbuf->valid_len;
193       return 0;
194     }
195
196   memcpy (&v, mbuf->data + mbuf->pos, 8);
197   mbuf->pos += 8;
198
199   if (g_memory_buffer_is_byteswapped (mbuf))
200     v = GUINT64_SWAP_LE_BE (v);
201
202   return v;
203 }
204
205 #define MIN_ARRAY_SIZE  128
206
207 static gint
208 g_nearest_pow (gint num)
209 {
210   gint n = 1;
211
212   while (n < num)
213     n <<= 1;
214
215   return n;
216 }
217
218 static void
219 array_resize (GMemoryBuffer  *mbuf,
220               gsize           size)
221 {
222   gpointer data;
223   gsize len;
224
225   if (mbuf->len == size)
226     return;
227
228   len = mbuf->len;
229   data = g_realloc (mbuf->data, size);
230
231   if (size > len)
232     memset ((guint8 *)data + len, 0, size - len);
233
234   mbuf->data = data;
235   mbuf->len = size;
236
237   if (mbuf->len < mbuf->valid_len)
238     mbuf->valid_len = mbuf->len;
239 }
240
241 static gboolean
242 g_memory_buffer_write (GMemoryBuffer  *mbuf,
243                        const void     *buffer,
244                        gsize           count)
245 {
246   guint8   *dest;
247   gsize new_size;
248
249   if (count == 0)
250     return TRUE;
251
252   /* Check for address space overflow, but only if the buffer is resizable.
253      Otherwise we just do a short write and don't worry. */
254   if (mbuf->pos + count < mbuf->pos)
255     return FALSE;
256
257   if (mbuf->pos + count > mbuf->len)
258     {
259       /* At least enought to fit the write, rounded up
260              for greater than linear growth.
261          TODO: This wastes a lot of memory at large buffer sizes.
262                Figure out a more rational allocation strategy. */
263       new_size = g_nearest_pow (mbuf->pos + count);
264       /* Check for overflow again. We have only checked if
265          pos + count > G_MAXSIZE, but it only catches the case of writing
266          more than 4GiB total on a 32-bit system. There's still the problem
267          of g_nearest_pow overflowing above 0x7fffffff, so we're
268          effectively limited to 2GiB. */
269       if (new_size < mbuf->len)
270         return FALSE;
271
272       new_size = MAX (new_size, MIN_ARRAY_SIZE);
273       array_resize (mbuf, new_size);
274     }
275
276   dest = (guint8 *)mbuf->data + mbuf->pos;
277   memcpy (dest, buffer, count);
278   mbuf->pos += count;
279
280   if (mbuf->pos > mbuf->valid_len)
281     mbuf->valid_len = mbuf->pos;
282
283   return TRUE;
284 }
285
286 static gboolean
287 g_memory_buffer_put_byte (GMemoryBuffer  *mbuf,
288                           guchar          data)
289 {
290   return g_memory_buffer_write (mbuf, &data, 1);
291 }
292
293 static gboolean
294 g_memory_buffer_put_int16 (GMemoryBuffer  *mbuf,
295                            gint16          data)
296 {
297   switch (mbuf->byte_order)
298     {
299     case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
300       data = GINT16_TO_BE (data);
301       break;
302     case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
303       data = GINT16_TO_LE (data);
304       break;
305     case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
306     default:
307       break;
308     }
309   
310   return g_memory_buffer_write (mbuf, &data, 2);
311 }
312
313 static gboolean
314 g_memory_buffer_put_uint16 (GMemoryBuffer  *mbuf,
315                             guint16         data)
316 {
317   switch (mbuf->byte_order)
318     {
319     case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
320       data = GUINT16_TO_BE (data);
321       break;
322     case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
323       data = GUINT16_TO_LE (data);
324       break;
325     case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
326     default:
327       break;
328     }
329   
330   return g_memory_buffer_write (mbuf, &data, 2);
331 }
332
333 static gboolean
334 g_memory_buffer_put_int32 (GMemoryBuffer  *mbuf,
335                            gint32          data)
336 {
337   switch (mbuf->byte_order)
338     {
339     case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
340       data = GINT32_TO_BE (data);
341       break;
342     case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
343       data = GINT32_TO_LE (data);
344       break;
345     case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
346     default:
347       break;
348     }
349   
350   return g_memory_buffer_write (mbuf, &data, 4);
351 }
352
353 static gboolean
354 g_memory_buffer_put_uint32 (GMemoryBuffer  *mbuf,
355                             guint32         data)
356 {
357   switch (mbuf->byte_order)
358     {
359     case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
360       data = GUINT32_TO_BE (data);
361       break;
362     case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
363       data = GUINT32_TO_LE (data);
364       break;
365     case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
366     default:
367       break;
368     }
369   
370   return g_memory_buffer_write (mbuf, &data, 4);
371 }
372
373 static gboolean
374 g_memory_buffer_put_int64 (GMemoryBuffer  *mbuf,
375                            gint64          data)
376 {
377   switch (mbuf->byte_order)
378     {
379     case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
380       data = GINT64_TO_BE (data);
381       break;
382     case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
383       data = GINT64_TO_LE (data);
384       break;
385     case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
386     default:
387       break;
388     }
389   
390   return g_memory_buffer_write (mbuf, &data, 8);
391 }
392
393 static gboolean
394 g_memory_buffer_put_uint64 (GMemoryBuffer  *mbuf,
395                             guint64         data)
396 {
397   switch (mbuf->byte_order)
398     {
399     case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
400       data = GUINT64_TO_BE (data);
401       break;
402     case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
403       data = GUINT64_TO_LE (data);
404       break;
405     case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
406     default:
407       break;
408     }
409   
410   return g_memory_buffer_write (mbuf, &data, 8);
411 }
412
413 static gboolean
414 g_memory_buffer_put_string (GMemoryBuffer  *mbuf,
415                             const char     *str)
416 {
417   g_return_val_if_fail (str != NULL, FALSE);
418
419   return g_memory_buffer_write (mbuf, str, strlen (str));
420 }
421
422
423 /**
424  * SECTION:gdbusmessage
425  * @short_description: D-Bus Message
426  * @include: gio/gio.h
427  *
428  * A type for representing D-Bus messages that can be sent or received
429  * on a #GDBusConnection.
430  */
431
432 typedef struct _GDBusMessageClass GDBusMessageClass;
433
434 /**
435  * GDBusMessageClass:
436  *
437  * Class structure for #GDBusMessage.
438  *
439  * Since: 2.26
440  */
441 struct _GDBusMessageClass
442 {
443   /*< private >*/
444   GObjectClass parent_class;
445 };
446
447 /**
448  * GDBusMessage:
449  *
450  * The #GDBusMessage structure contains only private data and should
451  * only be accessed using the provided API.
452  *
453  * Since: 2.26
454  */
455 struct _GDBusMessage
456 {
457   /*< private >*/
458   GObject parent_instance;
459
460   GDBusMessageType type;
461   GDBusMessageFlags flags;
462   gboolean locked;
463   GDBusMessageByteOrder byte_order;
464   guchar major_protocol_version;
465   guint32 serial;
466   GHashTable *headers;
467   GVariant *body;
468 #ifdef G_OS_UNIX
469   GUnixFDList *fd_list;
470 #endif
471 };
472
473 enum
474 {
475   PROP_0,
476   PROP_LOCKED
477 };
478
479 G_DEFINE_TYPE (GDBusMessage, g_dbus_message, G_TYPE_OBJECT);
480
481 static void
482 g_dbus_message_finalize (GObject *object)
483 {
484   GDBusMessage *message = G_DBUS_MESSAGE (object);
485
486   if (message->headers != NULL)
487     g_hash_table_unref (message->headers);
488   if (message->body != NULL)
489     g_variant_unref (message->body);
490 #ifdef G_OS_UNIX
491   if (message->fd_list != NULL)
492     g_object_unref (message->fd_list);
493 #endif
494
495   if (G_OBJECT_CLASS (g_dbus_message_parent_class)->finalize != NULL)
496     G_OBJECT_CLASS (g_dbus_message_parent_class)->finalize (object);
497 }
498
499 static void
500 g_dbus_message_get_property (GObject    *object,
501                              guint       prop_id,
502                              GValue     *value,
503                              GParamSpec *pspec)
504 {
505   GDBusMessage *message = G_DBUS_MESSAGE (object);
506
507   switch (prop_id)
508     {
509     case PROP_LOCKED:
510       g_value_set_boolean (value, g_dbus_message_get_locked (message));
511       break;
512
513     default:
514       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
515       break;
516     }
517 }
518
519 static void
520 g_dbus_message_class_init (GDBusMessageClass *klass)
521 {
522   GObjectClass *gobject_class;
523
524   gobject_class = G_OBJECT_CLASS (klass);
525   gobject_class->finalize     = g_dbus_message_finalize;
526   gobject_class->get_property = g_dbus_message_get_property;
527
528   /**
529    * GDBusConnection:locked:
530    *
531    * A boolean specifying whether the message is locked.
532    *
533    * Since: 2.26
534    */
535   g_object_class_install_property (gobject_class,
536                                    PROP_LOCKED,
537                                    g_param_spec_boolean ("locked",
538                                                          P_("Locked"),
539                                                          P_("Whether the message is locked"),
540                                                          FALSE,
541                                                          G_PARAM_READABLE |
542                                                          G_PARAM_STATIC_NAME |
543                                                          G_PARAM_STATIC_BLURB |
544                                                          G_PARAM_STATIC_NICK));
545 }
546
547 static void
548 g_dbus_message_init (GDBusMessage *message)
549 {
550   /* Any D-Bus implementation is supposed to handle both Big and
551    * Little Endian encodings and the Endianness is part of the D-Bus
552    * message - we prefer to use Big Endian (since it's Network Byte
553    * Order and just easier to read for humans) but if the machine is
554    * Little Endian we use that for performance reasons.
555    */
556 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
557   message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
558 #else
559   /* this could also be G_PDP_ENDIAN */
560   message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
561 #endif
562   message->headers = g_hash_table_new_full (g_direct_hash,
563                                             g_direct_equal,
564                                             NULL,
565                                             (GDestroyNotify) g_variant_unref);
566 }
567
568 /**
569  * g_dbus_message_new:
570  *
571  * Creates a new empty #GDBusMessage.
572  *
573  * Returns: A #GDBusMessage. Free with g_object_unref().
574  *
575  * Since: 2.26
576  */
577 GDBusMessage *
578 g_dbus_message_new (void)
579 {
580   return g_object_new (G_TYPE_DBUS_MESSAGE, NULL);
581 }
582
583 /**
584  * g_dbus_message_new_method_call:
585  * @name: (allow-none): A valid D-Bus name or %NULL.
586  * @path: A valid object path.
587  * @interface_: (allow-none): A valid D-Bus interface name or %NULL.
588  * @method: A valid method name.
589  *
590  * Creates a new #GDBusMessage for a method call.
591  *
592  * Returns: A #GDBusMessage. Free with g_object_unref().
593  *
594  * Since: 2.26
595  */
596 GDBusMessage *
597 g_dbus_message_new_method_call (const gchar *name,
598                                 const gchar *path,
599                                 const gchar *interface_,
600                                 const gchar *method)
601 {
602   GDBusMessage *message;
603
604   g_return_val_if_fail (name == NULL || g_dbus_is_name (name), NULL);
605   g_return_val_if_fail (g_variant_is_object_path (path), NULL);
606   g_return_val_if_fail (g_dbus_is_member_name (method), NULL);
607   g_return_val_if_fail (interface_ == NULL || g_dbus_is_interface_name (interface_), NULL);
608
609   message = g_dbus_message_new ();
610   message->type = G_DBUS_MESSAGE_TYPE_METHOD_CALL;
611
612   if (name != NULL)
613     g_dbus_message_set_destination (message, name);
614   g_dbus_message_set_path (message, path);
615   g_dbus_message_set_member (message, method);
616   if (interface_ != NULL)
617     g_dbus_message_set_interface (message, interface_);
618
619   return message;
620 }
621
622 /**
623  * g_dbus_message_new_signal:
624  * @path: A valid object path.
625  * @interface_: A valid D-Bus interface name.
626  * @signal: A valid signal name.
627  *
628  * Creates a new #GDBusMessage for a signal emission.
629  *
630  * Returns: A #GDBusMessage. Free with g_object_unref().
631  *
632  * Since: 2.26
633  */
634 GDBusMessage *
635 g_dbus_message_new_signal (const gchar  *path,
636                            const gchar  *interface_,
637                            const gchar  *signal)
638 {
639   GDBusMessage *message;
640
641   g_return_val_if_fail (g_variant_is_object_path (path), NULL);
642   g_return_val_if_fail (g_dbus_is_member_name (signal), NULL);
643   g_return_val_if_fail (g_dbus_is_interface_name (interface_), NULL);
644
645   message = g_dbus_message_new ();
646   message->type = G_DBUS_MESSAGE_TYPE_SIGNAL;
647   message->flags = G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
648
649   g_dbus_message_set_path (message, path);
650   g_dbus_message_set_member (message, signal);
651   g_dbus_message_set_interface (message, interface_);
652
653   return message;
654 }
655
656
657 /**
658  * g_dbus_message_new_method_reply:
659  * @method_call_message: A message of type %G_DBUS_MESSAGE_TYPE_METHOD_CALL to
660  * create a reply message to.
661  *
662  * Creates a new #GDBusMessage that is a reply to @method_call_message.
663  *
664  * Returns: (transfer full):  #GDBusMessage. Free with g_object_unref().
665  *
666  * Since: 2.26
667  */
668 GDBusMessage *
669 g_dbus_message_new_method_reply (GDBusMessage *method_call_message)
670 {
671   GDBusMessage *message;
672   const gchar *sender;
673
674   g_return_val_if_fail (G_IS_DBUS_MESSAGE (method_call_message), NULL);
675   g_return_val_if_fail (g_dbus_message_get_message_type (method_call_message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL, NULL);
676   g_return_val_if_fail (g_dbus_message_get_serial (method_call_message) != 0, NULL);
677
678   message = g_dbus_message_new ();
679   message->type = G_DBUS_MESSAGE_TYPE_METHOD_RETURN;
680   message->flags = G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
681   /* reply with same endianness */
682   message->byte_order = method_call_message->byte_order;
683
684   g_dbus_message_set_reply_serial (message, g_dbus_message_get_serial (method_call_message));
685   sender = g_dbus_message_get_sender (method_call_message);
686   if (sender != NULL)
687     g_dbus_message_set_destination (message, sender);
688
689   return message;
690 }
691
692 /**
693  * g_dbus_message_new_method_error:
694  * @method_call_message: A message of type %G_DBUS_MESSAGE_TYPE_METHOD_CALL to
695  * create a reply message to.
696  * @error_name: A valid D-Bus error name.
697  * @error_message_format: The D-Bus error message in a printf() format.
698  * @...: Arguments for @error_message_format.
699  *
700  * Creates a new #GDBusMessage that is an error reply to @method_call_message.
701  *
702  * Returns: (transfer full): A #GDBusMessage. Free with g_object_unref().
703  *
704  * Since: 2.26
705  */
706 GDBusMessage *
707 g_dbus_message_new_method_error (GDBusMessage             *method_call_message,
708                                  const gchar              *error_name,
709                                  const gchar              *error_message_format,
710                                  ...)
711 {
712   GDBusMessage *ret;
713   va_list var_args;
714
715   va_start (var_args, error_message_format);
716   ret = g_dbus_message_new_method_error_valist (method_call_message,
717                                                 error_name,
718                                                 error_message_format,
719                                                 var_args);
720   va_end (var_args);
721
722   return ret;
723 }
724
725 /**
726  * g_dbus_message_new_method_error_literal:
727  * @method_call_message: A message of type %G_DBUS_MESSAGE_TYPE_METHOD_CALL to
728  * create a reply message to.
729  * @error_name: A valid D-Bus error name.
730  * @error_message: The D-Bus error message.
731  *
732  * Creates a new #GDBusMessage that is an error reply to @method_call_message.
733  *
734  * Returns: (transfer full): A #GDBusMessage. Free with g_object_unref().
735  *
736  * Since: 2.26
737  */
738 GDBusMessage *
739 g_dbus_message_new_method_error_literal (GDBusMessage  *method_call_message,
740                                          const gchar   *error_name,
741                                          const gchar   *error_message)
742 {
743   GDBusMessage *message;
744   const gchar *sender;
745
746   g_return_val_if_fail (G_IS_DBUS_MESSAGE (method_call_message), NULL);
747   g_return_val_if_fail (g_dbus_message_get_message_type (method_call_message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL, NULL);
748   g_return_val_if_fail (g_dbus_message_get_serial (method_call_message) != 0, NULL);
749   g_return_val_if_fail (g_dbus_is_name (error_name), NULL);
750   g_return_val_if_fail (error_message != NULL, NULL);
751
752   message = g_dbus_message_new ();
753   message->type = G_DBUS_MESSAGE_TYPE_ERROR;
754   message->flags = G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
755   /* reply with same endianness */
756   message->byte_order = method_call_message->byte_order;
757
758   g_dbus_message_set_reply_serial (message, g_dbus_message_get_serial (method_call_message));
759   g_dbus_message_set_error_name (message, error_name);
760   g_dbus_message_set_body (message, g_variant_new ("(s)", error_message));
761
762   sender = g_dbus_message_get_sender (method_call_message);
763   if (sender != NULL)
764     g_dbus_message_set_destination (message, sender);
765
766   return message;
767 }
768
769 /**
770  * g_dbus_message_new_method_error_valist:
771  * @method_call_message: A message of type %G_DBUS_MESSAGE_TYPE_METHOD_CALL to
772  * create a reply message to.
773  * @error_name: A valid D-Bus error name.
774  * @error_message_format: The D-Bus error message in a printf() format.
775  * @var_args: Arguments for @error_message_format.
776  *
777  * Like g_dbus_message_new_method_error() but intended for language bindings.
778  *
779  * Returns: (transfer full): A #GDBusMessage. Free with g_object_unref().
780  *
781  * Since: 2.26
782  */
783 G_GNUC_PRINTF(3, 0)
784 GDBusMessage *
785 g_dbus_message_new_method_error_valist (GDBusMessage             *method_call_message,
786                                         const gchar              *error_name,
787                                         const gchar              *error_message_format,
788                                         va_list                   var_args)
789 {
790   GDBusMessage *ret;
791   gchar *error_message;
792   error_message = g_strdup_vprintf (error_message_format, var_args);
793   ret = g_dbus_message_new_method_error_literal (method_call_message,
794                                                  error_name,
795                                                  error_message);
796   g_free (error_message);
797   return ret;
798 }
799
800 /* ---------------------------------------------------------------------------------------------------- */
801
802 /**
803  * g_dbus_message_get_byte_order:
804  * @message: A #GDBusMessage.
805  *
806  * Gets the byte order of @message.
807  *
808  * Returns: The byte order.
809  */
810 GDBusMessageByteOrder
811 g_dbus_message_get_byte_order (GDBusMessage *message)
812 {
813   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), (GDBusMessageByteOrder) 0);
814   return message->byte_order;
815 }
816
817 /**
818  * g_dbus_message_set_byte_order:
819  * @message: A #GDBusMessage.
820  * @byte_order: The byte order.
821  *
822  * Sets the byte order of @message.
823  */
824 void
825 g_dbus_message_set_byte_order (GDBusMessage          *message,
826                                GDBusMessageByteOrder  byte_order)
827 {
828   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
829
830   if (message->locked)
831     {
832       g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
833       return;
834     }
835
836   message->byte_order = byte_order;
837 }
838
839 /* ---------------------------------------------------------------------------------------------------- */
840
841 /* TODO: need GI annotations to specify that any guchar value goes for the type */
842
843 /**
844  * g_dbus_message_get_message_type:
845  * @message: A #GDBusMessage.
846  *
847  * Gets the type of @message.
848  *
849  * Returns: A 8-bit unsigned integer (typically a value from the #GDBusMessageType enumeration).
850  *
851  * Since: 2.26
852  */
853 GDBusMessageType
854 g_dbus_message_get_message_type (GDBusMessage  *message)
855 {
856   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), G_DBUS_MESSAGE_TYPE_INVALID);
857   return message->type;
858 }
859
860 /**
861  * g_dbus_message_set_message_type:
862  * @message: A #GDBusMessage.
863  * @type: A 8-bit unsigned integer (typically a value from the #GDBusMessageType enumeration).
864  *
865  * Sets @message to be of @type.
866  *
867  * Since: 2.26
868  */
869 void
870 g_dbus_message_set_message_type (GDBusMessage      *message,
871                                  GDBusMessageType   type)
872 {
873   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
874   g_return_if_fail (type >=0 && type < 256);
875
876   if (message->locked)
877     {
878       g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
879       return;
880     }
881
882   message->type = type;
883 }
884
885 /* ---------------------------------------------------------------------------------------------------- */
886
887 /* TODO: need GI annotations to specify that any guchar value goes for flags */
888
889 /**
890  * g_dbus_message_get_flags:
891  * @message: A #GDBusMessage.
892  *
893  * Gets the flags for @message.
894  *
895  * Returns: Flags that are set (typically values from the #GDBusMessageFlags enumeration bitwise ORed together).
896  *
897  * Since: 2.26
898  */
899 GDBusMessageFlags
900 g_dbus_message_get_flags (GDBusMessage  *message)
901 {
902   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), G_DBUS_MESSAGE_FLAGS_NONE);
903   return message->flags;
904 }
905
906 /**
907  * g_dbus_message_set_flags:
908  * @message: A #GDBusMessage.
909  * @flags: Flags for @message that are set (typically values from the #GDBusMessageFlags
910  * enumeration bitwise ORed together).
911  *
912  * Sets the flags to set on @message.
913  *
914  * Since: 2.26
915  */
916 void
917 g_dbus_message_set_flags (GDBusMessage       *message,
918                           GDBusMessageFlags   flags)
919 {
920   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
921   g_return_if_fail (flags >=0 && flags < 256);
922
923   if (message->locked)
924     {
925       g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
926       return;
927     }
928
929   message->flags = flags;
930 }
931
932 /* ---------------------------------------------------------------------------------------------------- */
933
934 /**
935  * g_dbus_message_get_serial:
936  * @message: A #GDBusMessage.
937  *
938  * Gets the serial for @message.
939  *
940  * Returns: A #guint32.
941  *
942  * Since: 2.26
943  */
944 guint32
945 g_dbus_message_get_serial (GDBusMessage *message)
946 {
947   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), 0);
948   return message->serial;
949 }
950
951 /**
952  * g_dbus_message_set_serial:
953  * @message: A #GDBusMessage.
954  * @serial: A #guint32.
955  *
956  * Sets the serial for @message.
957  *
958  * Since: 2.26
959  */
960 void
961 g_dbus_message_set_serial (GDBusMessage  *message,
962                            guint32        serial)
963 {
964   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
965
966   if (message->locked)
967     {
968       g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
969       return;
970     }
971
972   message->serial = serial;
973 }
974
975 /* ---------------------------------------------------------------------------------------------------- */
976
977 /* TODO: need GI annotations to specify that any guchar value goes for header_field */
978
979 /**
980  * g_dbus_message_get_header:
981  * @message: A #GDBusMessage.
982  * @header_field: A 8-bit unsigned integer (typically a value from the #GDBusMessageHeaderField enumeration)
983  *
984  * Gets a header field on @message.
985  *
986  * Returns: A #GVariant with the value if the header was found, %NULL
987  * otherwise. Do not free, it is owned by @message.
988  *
989  * Since: 2.26
990  */
991 GVariant *
992 g_dbus_message_get_header (GDBusMessage             *message,
993                            GDBusMessageHeaderField   header_field)
994 {
995   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
996   g_return_val_if_fail (header_field >=0 && header_field < 256, NULL);
997   return g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
998 }
999
1000 /**
1001  * g_dbus_message_set_header:
1002  * @message: A #GDBusMessage.
1003  * @header_field: A 8-bit unsigned integer (typically a value from the #GDBusMessageHeaderField enumeration)
1004  * @value: (allow-none): A #GVariant to set the header field or %NULL to clear the header field.
1005  *
1006  * Sets a header field on @message.
1007  *
1008  * If @value is floating, @message assumes ownership of @value.
1009  *
1010  * Since: 2.26
1011  */
1012 void
1013 g_dbus_message_set_header (GDBusMessage             *message,
1014                            GDBusMessageHeaderField   header_field,
1015                            GVariant                 *value)
1016 {
1017   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1018   g_return_if_fail (header_field >=0 && header_field < 256);
1019
1020   if (message->locked)
1021     {
1022       g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
1023       return;
1024     }
1025
1026   if (value == NULL)
1027     {
1028       g_hash_table_remove (message->headers, GUINT_TO_POINTER (header_field));
1029     }
1030   else
1031     {
1032       g_hash_table_insert (message->headers, GUINT_TO_POINTER (header_field), g_variant_ref_sink (value));
1033     }
1034 }
1035
1036 /**
1037  * g_dbus_message_get_header_fields:
1038  * @message: A #GDBusMessage.
1039  *
1040  * Gets an array of all header fields on @message that are set.
1041  *
1042  * Returns: (array zero-terminated=1): An array of header fields
1043  * terminated by %G_DBUS_MESSAGE_HEADER_FIELD_INVALID.  Each element
1044  * is a #guchar. Free with g_free().
1045  *
1046  * Since: 2.26
1047  */
1048 guchar *
1049 g_dbus_message_get_header_fields (GDBusMessage  *message)
1050 {
1051   GList *keys;
1052   guchar *ret;
1053   guint num_keys;
1054   GList *l;
1055   guint n;
1056
1057   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1058
1059   keys = g_hash_table_get_keys (message->headers);
1060   num_keys = g_list_length (keys);
1061   ret = g_new (guchar, num_keys + 1);
1062   for (l = keys, n = 0; l != NULL; l = l->next, n++)
1063     ret[n] = GPOINTER_TO_UINT (l->data);
1064   g_assert (n == num_keys);
1065   ret[n] = G_DBUS_MESSAGE_HEADER_FIELD_INVALID;
1066   g_list_free (keys);
1067
1068   return ret;
1069 }
1070
1071 /* ---------------------------------------------------------------------------------------------------- */
1072
1073 /**
1074  * g_dbus_message_get_body:
1075  * @message: A #GDBusMessage.
1076  *
1077  * Gets the body of a message.
1078  *
1079  * Returns: (transfer none): A #GVariant or %NULL if the body is
1080  * empty. Do not free, it is owned by @message.
1081  *
1082  * Since: 2.26
1083  */
1084 GVariant *
1085 g_dbus_message_get_body (GDBusMessage  *message)
1086 {
1087   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1088   return message->body;
1089 }
1090
1091 /**
1092  * g_dbus_message_set_body:
1093  * @message: A #GDBusMessage.
1094  * @body: Either %NULL or a #GVariant that is a tuple.
1095  *
1096  * Sets the body @message. As a side-effect the
1097  * %G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE header field is set to the
1098  * type string of @body (or cleared if @body is %NULL).
1099  *
1100  * If @body is floating, @message assumes ownership of @body.
1101  *
1102  * Since: 2.26
1103  */
1104 void
1105 g_dbus_message_set_body (GDBusMessage  *message,
1106                          GVariant      *body)
1107 {
1108   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1109   g_return_if_fail ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE_TUPLE));
1110
1111   if (message->locked)
1112     {
1113       g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
1114       return;
1115     }
1116
1117   if (message->body != NULL)
1118     g_variant_unref (message->body);
1119   if (body == NULL)
1120     {
1121       message->body = NULL;
1122       g_dbus_message_set_signature (message, NULL);
1123     }
1124   else
1125     {
1126       const gchar *type_string;
1127       gsize type_string_len;
1128       gchar *signature;
1129
1130       message->body = g_variant_ref_sink (body);
1131
1132       type_string = g_variant_get_type_string (body);
1133       type_string_len = strlen (type_string);
1134       g_assert (type_string_len >= 2);
1135       signature = g_strndup (type_string + 1, type_string_len - 2);
1136       g_dbus_message_set_signature (message, signature);
1137       g_free (signature);
1138     }
1139 }
1140
1141 /* ---------------------------------------------------------------------------------------------------- */
1142
1143 #ifdef G_OS_UNIX
1144 /**
1145  * g_dbus_message_get_unix_fd_list:
1146  * @message: A #GDBusMessage.
1147  *
1148  * Gets the UNIX file descriptors associated with @message, if any.
1149  *
1150  * This method is only available on UNIX.
1151  *
1152  * Returns: (transfer none):A #GUnixFDList or %NULL if no file descriptors are
1153  * associated. Do not free, this object is owned by @message.
1154  *
1155  * Since: 2.26
1156  */
1157 GUnixFDList *
1158 g_dbus_message_get_unix_fd_list (GDBusMessage  *message)
1159 {
1160   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1161   return message->fd_list;
1162 }
1163
1164 /**
1165  * g_dbus_message_set_unix_fd_list:
1166  * @message: A #GDBusMessage.
1167  * @fd_list: (allow-none): A #GUnixFDList or %NULL.
1168  *
1169  * Sets the UNIX file descriptors associated with @message. As a
1170  * side-effect the %G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS header
1171  * field is set to the number of fds in @fd_list (or cleared if
1172  * @fd_list is %NULL).
1173  *
1174  * This method is only available on UNIX.
1175  *
1176  * Since: 2.26
1177  */
1178 void
1179 g_dbus_message_set_unix_fd_list (GDBusMessage  *message,
1180                                  GUnixFDList   *fd_list)
1181 {
1182   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1183   g_return_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list));
1184
1185   if (message->locked)
1186     {
1187       g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
1188       return;
1189     }
1190
1191   if (message->fd_list != NULL)
1192     g_object_unref (message->fd_list);
1193   if (fd_list != NULL)
1194     {
1195       message->fd_list = g_object_ref (fd_list);
1196       g_dbus_message_set_num_unix_fds (message, g_unix_fd_list_get_length (fd_list));
1197     }
1198   else
1199     {
1200       message->fd_list = NULL;
1201       g_dbus_message_set_num_unix_fds (message, 0);
1202     }
1203 }
1204 #endif
1205
1206 /* ---------------------------------------------------------------------------------------------------- */
1207
1208 static guint
1209 get_type_fixed_size (const GVariantType *type)
1210 {
1211   /* NB: we do not treat 'b' as fixed-size here because GVariant and
1212    * D-Bus disagree about the size.
1213    */
1214   switch (*g_variant_type_peek_string (type))
1215     {
1216     case 'y':
1217       return 1;
1218     case 'n': case 'q':
1219       return 2;
1220     case 'i': case 'u': case 'h':
1221       return 4;
1222     case 'x': case 't': case 'd':
1223       return 8;
1224     default:
1225       return 0;
1226     }
1227 }
1228
1229 static gboolean
1230 validate_headers (GDBusMessage  *message,
1231                   GError       **error)
1232 {
1233   gboolean ret;
1234
1235   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
1236   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1237
1238   ret = FALSE;
1239
1240   switch (message->type)
1241     {
1242     case G_DBUS_MESSAGE_TYPE_INVALID:
1243       g_set_error_literal (error,
1244                            G_IO_ERROR,
1245                            G_IO_ERROR_INVALID_ARGUMENT,
1246                            _("type is INVALID"));
1247       goto out;
1248       break;
1249
1250     case G_DBUS_MESSAGE_TYPE_METHOD_CALL:
1251       if (g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH) == NULL ||
1252           g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER) == NULL)
1253         {
1254           g_set_error_literal (error,
1255                                G_IO_ERROR,
1256                                G_IO_ERROR_INVALID_ARGUMENT,
1257                                _("METHOD_CALL message: PATH or MEMBER header field is missing"));
1258           goto out;
1259         }
1260       break;
1261
1262     case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
1263       if (g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL) == NULL)
1264         {
1265           g_set_error_literal (error,
1266                                G_IO_ERROR,
1267                                G_IO_ERROR_INVALID_ARGUMENT,
1268                                _("METHOD_RETURN message: REPLY_SERIAL header field is missing"));
1269           goto out;
1270         }
1271       break;
1272
1273     case G_DBUS_MESSAGE_TYPE_ERROR:
1274       if (g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME) == NULL ||
1275           g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL) == NULL)
1276         {
1277           g_set_error_literal (error,
1278                                G_IO_ERROR,
1279                                G_IO_ERROR_INVALID_ARGUMENT,
1280                                _("ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing"));
1281           goto out;
1282         }
1283       break;
1284
1285     case G_DBUS_MESSAGE_TYPE_SIGNAL:
1286       if (g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH) == NULL ||
1287           g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE) == NULL ||
1288           g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER) == NULL)
1289         {
1290           g_set_error_literal (error,
1291                                G_IO_ERROR,
1292                                G_IO_ERROR_INVALID_ARGUMENT,
1293                                _("SIGNAL message: PATH, INTERFACE or MEMBER header field is missing"));
1294           goto out;
1295         }
1296       if (g_strcmp0 (g_dbus_message_get_path (message), "/org/freedesktop/DBus/Local") == 0)
1297         {
1298           g_set_error_literal (error,
1299                                G_IO_ERROR,
1300                                G_IO_ERROR_INVALID_ARGUMENT,
1301                                _("SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local"));
1302           goto out;
1303         }
1304       if (g_strcmp0 (g_dbus_message_get_interface (message), "org.freedesktop.DBus.Local") == 0)
1305         {
1306           g_set_error_literal (error,
1307                                G_IO_ERROR,
1308                                G_IO_ERROR_INVALID_ARGUMENT,
1309                                _("SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local"));
1310           goto out;
1311         }
1312       break;
1313
1314     default:
1315       /* hitherto unknown type - nothing to check */
1316       break;
1317     }
1318
1319   ret = TRUE;
1320
1321  out:
1322   g_assert (ret || (error == NULL || *error != NULL));
1323   return ret;
1324 }
1325
1326 /* ---------------------------------------------------------------------------------------------------- */
1327
1328 static gboolean
1329 ensure_input_padding (GMemoryBuffer  *buf,
1330                       gsize           padding_size)
1331 {
1332   gsize offset;
1333   gsize wanted_offset;
1334
1335   offset = buf->pos;
1336   wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size;
1337   buf->pos = wanted_offset;
1338   return TRUE;
1339 }
1340
1341 static const gchar *
1342 read_string (GMemoryBuffer  *mbuf,
1343              gsize           len,
1344              GError        **error)
1345 {
1346   gchar *str;
1347   const gchar *end_valid;
1348
1349   if (mbuf->pos + len >= mbuf->valid_len || mbuf->pos + len < mbuf->pos)
1350     {
1351       mbuf->pos = mbuf->valid_len;
1352       /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
1353       g_set_error (error,
1354                    G_IO_ERROR,
1355                    G_IO_ERROR_INVALID_ARGUMENT,
1356                    g_dngettext (GETTEXT_PACKAGE,
1357                                 "Wanted to read %lu byte but only got %lu",
1358                                 "Wanted to read %lu bytes but only got %lu",
1359                                 (gulong)len),
1360                                 (gulong)len,
1361                    (gulong)(mbuf->valid_len - mbuf->pos));
1362       return NULL;
1363     }
1364
1365   if (mbuf->data[mbuf->pos + len] != '\0')
1366     {
1367       str = g_strndup (mbuf->data + mbuf->pos, len);
1368       g_set_error (error,
1369                    G_IO_ERROR,
1370                    G_IO_ERROR_INVALID_ARGUMENT,
1371                    _("Expected NUL byte after the string '%s' but found byte %d"),
1372                    str, mbuf->data[mbuf->pos + len]);
1373       g_free (str);
1374       mbuf->pos += len + 1;
1375       return NULL;
1376     }
1377
1378   str = mbuf->data + mbuf->pos;
1379   mbuf->pos += len + 1;
1380
1381   if (!g_utf8_validate (str, -1, &end_valid))
1382     {
1383       gint offset;
1384       gchar *valid_str;
1385       offset = (gint) (end_valid - str);
1386       valid_str = g_strndup (str, offset);
1387       g_set_error (error,
1388                    G_IO_ERROR,
1389                    G_IO_ERROR_INVALID_ARGUMENT,
1390                    _("Expected valid UTF-8 string but found invalid bytes at byte offset %d (length of string is %d). "
1391                      "The valid UTF-8 string up until that point was '%s'"),
1392                    offset,
1393                    (gint) len,
1394                    valid_str);
1395       g_free (valid_str);
1396       return NULL;
1397     }
1398
1399   return str;
1400 }
1401
1402 static gconstpointer
1403 read_bytes (GMemoryBuffer  *mbuf,
1404             gsize           len,
1405             GError        **error)
1406 {
1407   gconstpointer result;
1408
1409   if (mbuf->pos + len > mbuf->valid_len || mbuf->pos + len < mbuf->pos)
1410     {
1411       mbuf->pos = mbuf->valid_len;
1412       /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
1413       g_set_error (error,
1414                    G_IO_ERROR,
1415                    G_IO_ERROR_INVALID_ARGUMENT,
1416                    g_dngettext (GETTEXT_PACKAGE,
1417                                 "Wanted to read %lu byte but only got %lu",
1418                                 "Wanted to read %lu bytes but only got %lu",
1419                                 (gulong)len),
1420                                 (gulong)len,
1421                    (gulong)(mbuf->valid_len - mbuf->pos));
1422       return NULL;
1423     }
1424
1425   result = mbuf->data + mbuf->pos;
1426   mbuf->pos += len;
1427
1428   return result;
1429 }
1430
1431 /* if just_align==TRUE, don't read a value, just align the input stream wrt padding */
1432
1433 /* returns a non-floating GVariant! */
1434 static GVariant *
1435 parse_value_from_blob (GMemoryBuffer       *buf,
1436                        const GVariantType  *type,
1437                        gboolean             just_align,
1438                        guint                indent,
1439                        GError             **error)
1440 {
1441   GVariant *ret;
1442   GError *local_error;
1443   gboolean is_leaf;
1444   const gchar *type_string;
1445
1446   type_string = g_variant_type_peek_string (type);
1447
1448 #ifdef DEBUG_SERIALIZER
1449     {
1450       gchar *s;
1451       s = g_variant_type_dup_string (type);
1452       g_print ("%*s%s type %s from offset 0x%04x",
1453                indent, "",
1454                just_align ? "Aligning" : "Reading",
1455                s,
1456                (gint) g_seekable_tell (G_SEEKABLE (buf)));
1457       g_free (s);
1458     }
1459 #endif /* DEBUG_SERIALIZER */
1460
1461   ret = NULL;
1462
1463   is_leaf = TRUE;
1464   local_error = NULL;
1465   switch (type_string[0])
1466     {
1467     case 'b': /* G_VARIANT_TYPE_BOOLEAN */
1468       ensure_input_padding (buf, 4);
1469       if (!just_align)
1470         {
1471           gboolean v;
1472           v = g_memory_buffer_read_uint32 (buf);
1473           ret = g_variant_new_boolean (v);
1474         }
1475       break;
1476
1477     case 'y': /* G_VARIANT_TYPE_BYTE */
1478       if (!just_align)
1479         {
1480           guchar v;
1481           v = g_memory_buffer_read_byte (buf);
1482           ret = g_variant_new_byte (v);
1483         }
1484       break;
1485
1486     case 'n': /* G_VARIANT_TYPE_INT16 */
1487       ensure_input_padding (buf, 2);
1488       if (!just_align)
1489         {
1490           gint16 v;
1491           v = g_memory_buffer_read_int16 (buf);
1492           ret = g_variant_new_int16 (v);
1493         }
1494       break;
1495
1496     case 'q': /* G_VARIANT_TYPE_UINT16 */
1497       ensure_input_padding (buf, 2);
1498       if (!just_align)
1499         {
1500           guint16 v;
1501           v = g_memory_buffer_read_uint16 (buf);
1502           ret = g_variant_new_uint16 (v);
1503         }
1504       break;
1505
1506     case 'i': /* G_VARIANT_TYPE_INT32 */
1507       ensure_input_padding (buf, 4);
1508       if (!just_align)
1509         {
1510           gint32 v;
1511           v = g_memory_buffer_read_int32 (buf);
1512           ret = g_variant_new_int32 (v);
1513         }
1514       break;
1515
1516     case 'u': /* G_VARIANT_TYPE_UINT32 */
1517       ensure_input_padding (buf, 4);
1518       if (!just_align)
1519         {
1520           guint32 v;
1521           v = g_memory_buffer_read_uint32 (buf);
1522           ret = g_variant_new_uint32 (v);
1523         }
1524       break;
1525
1526     case 'x': /* G_VARIANT_TYPE_INT64 */
1527       ensure_input_padding (buf, 8);
1528       if (!just_align)
1529         {
1530           gint64 v;
1531           v = g_memory_buffer_read_int64 (buf);
1532           ret = g_variant_new_int64 (v);
1533         }
1534       break;
1535
1536     case 't': /* G_VARIANT_TYPE_UINT64 */
1537       ensure_input_padding (buf, 8);
1538       if (!just_align)
1539         {
1540           guint64 v;
1541           v = g_memory_buffer_read_uint64 (buf);
1542           ret = g_variant_new_uint64 (v);
1543         }
1544       break;
1545
1546     case 'd': /* G_VARIANT_TYPE_DOUBLE */
1547       ensure_input_padding (buf, 8);
1548       if (!just_align)
1549         {
1550           union {
1551             guint64 v_uint64;
1552             gdouble v_double;
1553           } u;
1554           G_STATIC_ASSERT (sizeof (gdouble) == sizeof (guint64));
1555           u.v_uint64 = g_memory_buffer_read_uint64 (buf);
1556           ret = g_variant_new_double (u.v_double);
1557         }
1558       break;
1559
1560     case 's': /* G_VARIANT_TYPE_STRING */
1561       ensure_input_padding (buf, 4);
1562       if (!just_align)
1563         {
1564           guint32 len;
1565           const gchar *v;
1566           len = g_memory_buffer_read_uint32 (buf);
1567           v = read_string (buf, (gsize) len, &local_error);
1568           if (v == NULL)
1569             goto fail;
1570           ret = g_variant_new_string (v);
1571         }
1572       break;
1573
1574     case 'o': /* G_VARIANT_TYPE_OBJECT_PATH */
1575       ensure_input_padding (buf, 4);
1576       if (!just_align)
1577         {
1578           guint32 len;
1579           const gchar *v;
1580           len = g_memory_buffer_read_uint32 (buf);
1581           v = read_string (buf, (gsize) len, &local_error);
1582           if (v == NULL)
1583             goto fail;
1584           if (!g_variant_is_object_path (v))
1585             {
1586               g_set_error (&local_error,
1587                            G_IO_ERROR,
1588                            G_IO_ERROR_INVALID_ARGUMENT,
1589                            _("Parsed value '%s' is not a valid D-Bus object path"),
1590                            v);
1591               goto fail;
1592             }
1593           ret = g_variant_new_object_path (v);
1594         }
1595       break;
1596
1597     case 'g': /* G_VARIANT_TYPE_SIGNATURE */
1598       if (!just_align)
1599         {
1600           guchar len;
1601           const gchar *v;
1602           len = g_memory_buffer_read_byte (buf);
1603           v = read_string (buf, (gsize) len, &local_error);
1604           if (v == NULL)
1605             goto fail;
1606           if (!g_variant_is_signature (v))
1607             {
1608               g_set_error (&local_error,
1609                            G_IO_ERROR,
1610                            G_IO_ERROR_INVALID_ARGUMENT,
1611                            _("Parsed value '%s' is not a valid D-Bus signature"),
1612                        v);
1613               goto fail;
1614             }
1615           ret = g_variant_new_signature (v);
1616         }
1617       break;
1618
1619     case 'h': /* G_VARIANT_TYPE_HANDLE */
1620       ensure_input_padding (buf, 4);
1621       if (!just_align)
1622         {
1623           gint32 v;
1624           v = g_memory_buffer_read_int32 (buf);
1625           ret = g_variant_new_handle (v);
1626         }
1627       break;
1628
1629     case 'a': /* G_VARIANT_TYPE_ARRAY */
1630       ensure_input_padding (buf, 4);
1631
1632       /* If we are only aligning for this array type, it is the child type of
1633        * another array, which is empty. So, we do not need to add padding for
1634        * this nonexistent array's elements: we only need to align for this
1635        * array itself (4 bytes). See
1636        * <https://bugzilla.gnome.org/show_bug.cgi?id=673612>.
1637        */
1638       if (!just_align)
1639         {
1640           guint32 array_len;
1641           const GVariantType *element_type;
1642           guint fixed_size;
1643
1644           array_len = g_memory_buffer_read_uint32 (buf);
1645
1646           is_leaf = FALSE;
1647 #ifdef DEBUG_SERIALIZER
1648           g_print (": array spans 0x%04x bytes\n", array_len);
1649 #endif /* DEBUG_SERIALIZER */
1650
1651           if (array_len > (2<<26))
1652             {
1653               /* G_GUINT32_FORMAT doesn't work with gettext, so use u */
1654               g_set_error (&local_error,
1655                            G_IO_ERROR,
1656                            G_IO_ERROR_INVALID_ARGUMENT,
1657                            g_dngettext (GETTEXT_PACKAGE,
1658                                         "Encountered array of length %u byte. Maximum length is 2<<26 bytes (64 MiB).",
1659                                         "Encountered array of length %u bytes. Maximum length is 2<<26 bytes (64 MiB).",
1660                                         array_len),
1661                            array_len);
1662               goto fail;
1663             }
1664
1665           element_type = g_variant_type_element (type);
1666           fixed_size = get_type_fixed_size (element_type);
1667
1668           /* Fast-path the cases like 'ay', etc. */
1669           if (fixed_size != 0)
1670             {
1671               gconstpointer array_data;
1672
1673               if (array_len % fixed_size != 0)
1674                 {
1675                   g_set_error (&local_error,
1676                                G_IO_ERROR,
1677                                G_IO_ERROR_INVALID_ARGUMENT,
1678                                _("Encountered array of type 'a%c', expected to have a length a multiple "
1679                                  "of %u bytes, but found to be %u bytes in length"),
1680                                g_variant_type_peek_string (element_type)[0], fixed_size, array_len);
1681                   goto fail;
1682                 }
1683
1684               ensure_input_padding (buf, fixed_size);
1685               array_data = read_bytes (buf, array_len, &local_error);
1686               if (array_data == NULL)
1687                 goto fail;
1688
1689               ret = g_variant_new_fixed_array (element_type, array_data, array_len / fixed_size, fixed_size);
1690
1691               if (g_memory_buffer_is_byteswapped (buf))
1692                 {
1693                   GVariant *tmp = g_variant_ref_sink (ret);
1694                   ret = g_variant_byteswap (tmp);
1695                   g_variant_unref (tmp);
1696                 }
1697             }
1698           else
1699             {
1700               GVariantBuilder builder;
1701               goffset offset;
1702               goffset target;
1703
1704               g_variant_builder_init (&builder, type);
1705
1706               if (array_len == 0)
1707                 {
1708                   GVariant *item;
1709                   item = parse_value_from_blob (buf,
1710                                                 element_type,
1711                                                 TRUE,
1712                                                 indent + 2,
1713                                                 NULL);
1714                   g_assert (item == NULL);
1715                 }
1716               else
1717                 {
1718                   offset = buf->pos;
1719                   target = offset + array_len;
1720                   while (offset < target)
1721                     {
1722                       GVariant *item;
1723                       item = parse_value_from_blob (buf,
1724                                                     element_type,
1725                                                     FALSE,
1726                                                     indent + 2,
1727                                                     &local_error);
1728                       if (item == NULL)
1729                         {
1730                           g_variant_builder_clear (&builder);
1731                           goto fail;
1732                         }
1733                       g_variant_builder_add_value (&builder, item);
1734                       g_variant_unref (item);
1735                       offset = buf->pos;
1736                     }
1737                 }
1738
1739               ret = g_variant_builder_end (&builder);
1740             }
1741         }
1742       break;
1743
1744     default:
1745       if (g_variant_type_is_dict_entry (type))
1746         {
1747           const GVariantType *key_type;
1748           const GVariantType *value_type;
1749           GVariant *key;
1750           GVariant *value;
1751
1752           ensure_input_padding (buf, 8);
1753
1754           is_leaf = FALSE;
1755 #ifdef DEBUG_SERIALIZER
1756           g_print ("\n");
1757 #endif /* DEBUG_SERIALIZER */
1758
1759           if (!just_align)
1760             {
1761               key_type = g_variant_type_key (type);
1762               key = parse_value_from_blob (buf,
1763                                            key_type,
1764                                            FALSE,
1765                                            indent + 2,
1766                                            &local_error);
1767               if (key == NULL)
1768                 goto fail;
1769               value_type = g_variant_type_value (type);
1770               value = parse_value_from_blob (buf,
1771                                              value_type,
1772                                              FALSE,
1773                                              indent + 2,
1774                                              &local_error);
1775               if (value == NULL)
1776                 {
1777                   g_variant_unref (key);
1778                   goto fail;
1779                 }
1780               ret = g_variant_new_dict_entry (key, value);
1781               g_variant_unref (key);
1782               g_variant_unref (value);
1783             }
1784         }
1785       else if (g_variant_type_is_tuple (type))
1786         {
1787           ensure_input_padding (buf, 8);
1788
1789           is_leaf = FALSE;
1790 #ifdef DEBUG_SERIALIZER
1791           g_print ("\n");
1792 #endif /* DEBUG_SERIALIZER */
1793
1794           if (!just_align)
1795             {
1796               const GVariantType *element_type;
1797               GVariantBuilder builder;
1798
1799               g_variant_builder_init (&builder, type);
1800               element_type = g_variant_type_first (type);
1801               while (element_type != NULL)
1802                 {
1803                   GVariant *item;
1804                   item = parse_value_from_blob (buf,
1805                                                 element_type,
1806                                                 FALSE,
1807                                                 indent + 2,
1808                                                 &local_error);
1809                   if (item == NULL)
1810                     {
1811                       g_variant_builder_clear (&builder);
1812                       goto fail;
1813                     }
1814                   g_variant_builder_add_value (&builder, item);
1815                   g_variant_unref (item);
1816
1817                   element_type = g_variant_type_next (element_type);
1818                 }
1819               ret = g_variant_builder_end (&builder);
1820             }
1821         }
1822       else if (g_variant_type_is_variant (type))
1823         {
1824           is_leaf = FALSE;
1825 #ifdef DEBUG_SERIALIZER
1826           g_print ("\n");
1827 #endif /* DEBUG_SERIALIZER */
1828
1829           if (!just_align)
1830             {
1831               guchar siglen;
1832               const gchar *sig;
1833               GVariantType *variant_type;
1834               GVariant *value;
1835
1836               siglen = g_memory_buffer_read_byte (buf);
1837               sig = read_string (buf, (gsize) siglen, &local_error);
1838               if (sig == NULL)
1839                 goto fail;
1840               if (!g_variant_is_signature (sig))
1841                 {
1842                   g_set_error (&local_error,
1843                                G_IO_ERROR,
1844                                G_IO_ERROR_INVALID_ARGUMENT,
1845                                _("Parsed value '%s' for variant is not a valid D-Bus signature"),
1846                                sig);
1847                   goto fail;
1848                 }
1849               variant_type = g_variant_type_new (sig);
1850               value = parse_value_from_blob (buf,
1851                                              variant_type,
1852                                              FALSE,
1853                                              indent + 2,
1854                                              &local_error);
1855               g_variant_type_free (variant_type);
1856               if (value == NULL)
1857                 goto fail;
1858               ret = g_variant_new_variant (value);
1859               g_variant_unref (value);
1860             }
1861         }
1862       else
1863         {
1864           gchar *s;
1865           s = g_variant_type_dup_string (type);
1866           g_set_error (&local_error,
1867                        G_IO_ERROR,
1868                        G_IO_ERROR_INVALID_ARGUMENT,
1869                        _("Error deserializing GVariant with type string '%s' from the D-Bus wire format"),
1870                        s);
1871           g_free (s);
1872           goto fail;
1873         }
1874       break;
1875     }
1876
1877   g_assert ((just_align && ret == NULL) || (!just_align && ret != NULL));
1878
1879 #ifdef DEBUG_SERIALIZER
1880   if (ret != NULL)
1881     {
1882       if (is_leaf)
1883         {
1884           gchar *s;
1885           if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
1886             {
1887               s = g_strdup_printf ("0x%02x '%c'", g_variant_get_byte (ret), g_variant_get_byte (ret));
1888             }
1889           else
1890             {
1891               s = g_variant_print (ret, FALSE);
1892             }
1893           g_print (": %s\n", s);
1894           g_free (s);
1895         }
1896     }
1897 #else
1898   is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */
1899 #endif /* DEBUG_SERIALIZER */
1900
1901   /* sink the reference, if floating */
1902   if (ret != NULL)
1903     g_variant_take_ref (ret);
1904   return ret;
1905
1906  fail:
1907 #ifdef DEBUG_SERIALIZER
1908   g_print ("\n"
1909            "%*sFAILURE: %s (%s, %d)\n",
1910            indent, "",
1911            local_error->message,
1912            g_quark_to_string (local_error->domain),
1913            local_error->code);
1914 #endif /* DEBUG_SERIALIZER */
1915   g_propagate_error (error, local_error);
1916   return NULL;
1917 }
1918
1919 /* ---------------------------------------------------------------------------------------------------- */
1920
1921 /* message_header must be at least 16 bytes */
1922
1923 /**
1924  * g_dbus_message_bytes_needed:
1925  * @blob: (array length=blob_len) (element-type guint8): A blob represent a binary D-Bus message.
1926  * @blob_len: The length of @blob (must be at least 16).
1927  * @error: Return location for error or %NULL.
1928  *
1929  * Utility function to calculate how many bytes are needed to
1930  * completely deserialize the D-Bus message stored at @blob.
1931  *
1932  * Returns: Number of bytes needed or -1 if @error is set (e.g. if
1933  * @blob contains invalid data or not enough data is available to
1934  * determine the size).
1935  *
1936  * Since: 2.26
1937  */
1938 gssize
1939 g_dbus_message_bytes_needed (guchar  *blob,
1940                              gsize    blob_len,
1941                              GError **error)
1942 {
1943   gssize ret;
1944
1945   ret = -1;
1946
1947   g_return_val_if_fail (blob != NULL, -1);
1948   g_return_val_if_fail (error == NULL || *error == NULL, -1);
1949   g_return_val_if_fail (blob_len >= 16, -1);
1950
1951   if (blob[0] == 'l')
1952     {
1953       /* core header (12 bytes) + ARRAY of STRUCT of (BYTE,VARIANT) */
1954       ret = 12 + 4 + GUINT32_FROM_LE (((guint32 *) blob)[3]);
1955       /* round up so it's a multiple of 8 */
1956       ret = 8 * ((ret + 7)/8);
1957       /* finally add the body size */
1958       ret += GUINT32_FROM_LE (((guint32 *) blob)[1]);
1959     }
1960   else if (blob[0] == 'B')
1961     {
1962       /* core header (12 bytes) + ARRAY of STRUCT of (BYTE,VARIANT) */
1963       ret = 12 + 4 + GUINT32_FROM_BE (((guint32 *) blob)[3]);
1964       /* round up so it's a multiple of 8 */
1965       ret = 8 * ((ret + 7)/8);
1966       /* finally add the body size */
1967       ret += GUINT32_FROM_BE (((guint32 *) blob)[1]);
1968     }
1969   else
1970     {
1971       g_set_error (error,
1972                    G_IO_ERROR,
1973                    G_IO_ERROR_INVALID_ARGUMENT,
1974                    "Unable to determine message blob length - given blob is malformed");
1975     }
1976
1977   if (ret > (2<<27))
1978     {
1979       g_set_error (error,
1980                    G_IO_ERROR,
1981                    G_IO_ERROR_INVALID_ARGUMENT,
1982                    "Blob indicates that message exceeds maximum message length (128MiB)");
1983       ret = -1;
1984     }
1985
1986   return ret;
1987 }
1988
1989 /* ---------------------------------------------------------------------------------------------------- */
1990
1991 /**
1992  * g_dbus_message_new_from_blob:
1993  * @blob: (array length=blob_len) (element-type guint8): A blob represent a binary D-Bus message.
1994  * @blob_len: The length of @blob.
1995  * @capabilities: A #GDBusCapabilityFlags describing what protocol features are supported.
1996  * @error: Return location for error or %NULL.
1997  *
1998  * Creates a new #GDBusMessage from the data stored at @blob. The byte
1999  * order that the message was in can be retrieved using
2000  * g_dbus_message_get_byte_order().
2001  *
2002  * Returns: A new #GDBusMessage or %NULL if @error is set. Free with
2003  * g_object_unref().
2004  *
2005  * Since: 2.26
2006  */
2007 GDBusMessage *
2008 g_dbus_message_new_from_blob (guchar                *blob,
2009                               gsize                  blob_len,
2010                               GDBusCapabilityFlags   capabilities,
2011                               GError               **error)
2012 {
2013   gboolean ret;
2014   GMemoryBuffer mbuf;
2015   GDBusMessage *message;
2016   guchar endianness;
2017   guchar major_protocol_version;
2018   guint32 message_body_len;
2019   GVariant *headers;
2020   GVariant *item;
2021   GVariantIter iter;
2022   GVariant *signature;
2023
2024   /* TODO: check against @capabilities */
2025
2026   ret = FALSE;
2027
2028   g_return_val_if_fail (blob != NULL, NULL);
2029   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2030   g_return_val_if_fail (blob_len >= 12, NULL);
2031
2032   message = g_dbus_message_new ();
2033
2034   memset (&mbuf, 0, sizeof (mbuf));
2035   mbuf.data = (gchar *)blob;
2036   mbuf.len = mbuf.valid_len = blob_len;
2037
2038   endianness = g_memory_buffer_read_byte (&mbuf);
2039   switch (endianness)
2040     {
2041     case 'l':
2042       mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
2043       message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
2044       break;
2045     case 'B':
2046       mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
2047       message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
2048       break;
2049     default:
2050       g_set_error (error,
2051                    G_IO_ERROR,
2052                    G_IO_ERROR_INVALID_ARGUMENT,
2053                    _("Invalid endianness value. Expected 0x6c ('l') or 0x42 ('B') but found value 0x%02x"),
2054                    endianness);
2055       goto out;
2056     }
2057
2058   message->type = g_memory_buffer_read_byte (&mbuf);
2059   message->flags = g_memory_buffer_read_byte (&mbuf);
2060   major_protocol_version = g_memory_buffer_read_byte (&mbuf);
2061   if (major_protocol_version != 1)
2062     {
2063       g_set_error (error,
2064                    G_IO_ERROR,
2065                    G_IO_ERROR_INVALID_ARGUMENT,
2066                    _("Invalid major protocol version. Expected 1 but found %d"),
2067                    major_protocol_version);
2068       goto out;
2069     }
2070   message_body_len = g_memory_buffer_read_uint32 (&mbuf);
2071   message->serial = g_memory_buffer_read_uint32 (&mbuf);
2072
2073 #ifdef DEBUG_SERIALIZER
2074   g_print ("Parsing blob (blob_len = 0x%04x bytes)\n", (gint) blob_len);
2075   {
2076     gchar *s;
2077     s = _g_dbus_hexdump ((const gchar *) blob, blob_len, 2);
2078     g_print ("%s\n", s);
2079     g_free (s);
2080   }
2081 #endif /* DEBUG_SERIALIZER */
2082
2083 #ifdef DEBUG_SERIALIZER
2084   g_print ("Parsing headers (blob_len = 0x%04x bytes)\n", (gint) blob_len);
2085 #endif /* DEBUG_SERIALIZER */
2086   headers = parse_value_from_blob (&mbuf,
2087                                    G_VARIANT_TYPE ("a{yv}"),
2088                                    FALSE,
2089                                    2,
2090                                    error);
2091   if (headers == NULL)
2092     goto out;
2093   g_variant_iter_init (&iter, headers);
2094   while ((item = g_variant_iter_next_value (&iter)) != NULL)
2095     {
2096       guchar header_field;
2097       GVariant *value;
2098       g_variant_get (item,
2099                      "{yv}",
2100                      &header_field,
2101                      &value);
2102       g_dbus_message_set_header (message, header_field, value);
2103       g_variant_unref (value);
2104       g_variant_unref (item);
2105     }
2106   g_variant_unref (headers);
2107
2108   signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE);
2109   if (signature != NULL)
2110     {
2111       const gchar *signature_str;
2112       gsize signature_str_len;
2113
2114       signature_str = g_variant_get_string (signature, &signature_str_len);
2115
2116       /* signature but no body */
2117       if (message_body_len == 0 && signature_str_len > 0)
2118         {
2119           g_set_error (error,
2120                        G_IO_ERROR,
2121                        G_IO_ERROR_INVALID_ARGUMENT,
2122                        _("Signature header with signature '%s' found but message body is empty"),
2123                        signature_str);
2124           goto out;
2125         }
2126       else if (signature_str_len > 0)
2127         {
2128           GVariantType *variant_type;
2129           gchar *tupled_signature_str;
2130
2131           if (!g_variant_is_signature (signature_str))
2132             {
2133               g_set_error (error,
2134                            G_IO_ERROR,
2135                            G_IO_ERROR_INVALID_ARGUMENT,
2136                            _("Parsed value '%s' is not a valid D-Bus signature (for body)"),
2137                            signature_str);
2138               goto out;
2139             }
2140           tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
2141           variant_type = g_variant_type_new (tupled_signature_str);
2142           g_free (tupled_signature_str);
2143 #ifdef DEBUG_SERIALIZER
2144           g_print ("Parsing body (blob_len = 0x%04x bytes)\n", (gint) blob_len);
2145 #endif /* DEBUG_SERIALIZER */
2146           message->body = parse_value_from_blob (&mbuf,
2147                                                  variant_type,
2148                                                  FALSE,
2149                                                  2,
2150                                                  error);
2151           g_variant_type_free (variant_type);
2152           if (message->body == NULL)
2153             goto out;
2154         }
2155     }
2156   else
2157     {
2158       /* no signature, this is only OK if the body is empty */
2159       if (message_body_len != 0)
2160         {
2161           /* G_GUINT32_FORMAT doesn't work with gettext, just use %u */
2162           g_set_error (error,
2163                        G_IO_ERROR,
2164                        G_IO_ERROR_INVALID_ARGUMENT,
2165                        g_dngettext (GETTEXT_PACKAGE,
2166                                     "No signature header in message but the message body is %u byte",
2167                                     "No signature header in message but the message body is %u bytes",
2168                                     message_body_len),
2169                        message_body_len);
2170           goto out;
2171         }
2172     }
2173
2174   if (!validate_headers (message, error))
2175     {
2176       g_prefix_error (error, _("Cannot deserialize message: "));
2177       goto out;
2178     }
2179
2180   ret = TRUE;
2181
2182  out:
2183   if (ret)
2184     {
2185       return message;
2186     }
2187   else
2188     {
2189       if (message != NULL)
2190         g_object_unref (message);
2191       return NULL;
2192     }
2193 }
2194
2195 /* ---------------------------------------------------------------------------------------------------- */
2196
2197 static gsize
2198 ensure_output_padding (GMemoryBuffer  *mbuf,
2199                        gsize           padding_size)
2200 {
2201   gsize offset;
2202   gsize wanted_offset;
2203   gsize padding_needed;
2204   guint n;
2205
2206   offset = mbuf->pos;
2207   wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size;
2208   padding_needed = wanted_offset - offset;
2209
2210   for (n = 0; n < padding_needed; n++)
2211     g_memory_buffer_put_byte (mbuf, '\0');
2212
2213   return padding_needed;
2214 }
2215
2216 /* note that value can be NULL for e.g. empty arrays - type is never NULL */
2217 static gboolean
2218 append_value_to_blob (GVariant            *value,
2219                       const GVariantType  *type,
2220                       GMemoryBuffer       *mbuf,
2221                       gsize               *out_padding_added,
2222                       GError             **error)
2223 {
2224   gsize padding_added;
2225   const gchar *type_string;
2226
2227   type_string = g_variant_type_peek_string (type);
2228
2229   padding_added = 0;
2230
2231   switch (type_string[0])
2232     {
2233     case 'b': /* G_VARIANT_TYPE_BOOLEAN */
2234       padding_added = ensure_output_padding (mbuf, 4);
2235       if (value != NULL)
2236         {
2237           gboolean v = g_variant_get_boolean (value);
2238           g_memory_buffer_put_uint32 (mbuf, v);
2239         }
2240       break;
2241
2242     case 'y': /* G_VARIANT_TYPE_BYTE */
2243       if (value != NULL)
2244         {
2245           guint8 v = g_variant_get_byte (value);
2246           g_memory_buffer_put_byte (mbuf, v);
2247         }
2248       break;
2249
2250     case 'n': /* G_VARIANT_TYPE_INT16 */
2251       padding_added = ensure_output_padding (mbuf, 2);
2252       if (value != NULL)
2253         {
2254           gint16 v = g_variant_get_int16 (value);
2255           g_memory_buffer_put_int16 (mbuf, v);
2256         }
2257       break;
2258
2259     case 'q': /* G_VARIANT_TYPE_UINT16 */
2260       padding_added = ensure_output_padding (mbuf, 2);
2261       if (value != NULL)
2262         {
2263           guint16 v = g_variant_get_uint16 (value);
2264           g_memory_buffer_put_uint16 (mbuf, v);
2265         }
2266       break;
2267
2268     case 'i': /* G_VARIANT_TYPE_INT32 */
2269       padding_added = ensure_output_padding (mbuf, 4);
2270       if (value != NULL)
2271         {
2272           gint32 v = g_variant_get_int32 (value);
2273           g_memory_buffer_put_int32 (mbuf, v);
2274         }
2275       break;
2276
2277     case 'u': /* G_VARIANT_TYPE_UINT32 */
2278       padding_added = ensure_output_padding (mbuf, 4);
2279       if (value != NULL)
2280         {
2281           guint32 v = g_variant_get_uint32 (value);
2282           g_memory_buffer_put_uint32 (mbuf, v);
2283         }
2284       break;
2285
2286     case 'x': /* G_VARIANT_TYPE_INT64 */
2287       padding_added = ensure_output_padding (mbuf, 8);
2288       if (value != NULL)
2289         {
2290           gint64 v = g_variant_get_int64 (value);
2291           g_memory_buffer_put_int64 (mbuf, v);
2292         }
2293       break;
2294
2295     case 't': /* G_VARIANT_TYPE_UINT64 */
2296       padding_added = ensure_output_padding (mbuf, 8);
2297       if (value != NULL)
2298         {
2299           guint64 v = g_variant_get_uint64 (value);
2300           g_memory_buffer_put_uint64 (mbuf, v);
2301         }
2302       break;
2303
2304     case 'd': /* G_VARIANT_TYPE_DOUBLE */
2305       padding_added = ensure_output_padding (mbuf, 8);
2306       if (value != NULL)
2307         {
2308           union {
2309             guint64 v_uint64;
2310             gdouble v_double;
2311           } u;
2312           G_STATIC_ASSERT (sizeof (gdouble) == sizeof (guint64));
2313           u.v_double = g_variant_get_double (value);
2314           g_memory_buffer_put_uint64 (mbuf, u.v_uint64);
2315         }
2316       break;
2317
2318     case 's': /* G_VARIANT_TYPE_STRING */
2319       padding_added = ensure_output_padding (mbuf, 4);
2320       if (value != NULL)
2321         {
2322           gsize len;
2323           const gchar *v;
2324           const gchar *end;
2325           v = g_variant_get_string (value, &len);
2326           g_assert (g_utf8_validate (v, -1, &end) && (end == v + len));
2327           g_memory_buffer_put_uint32 (mbuf, len);
2328           g_memory_buffer_put_string (mbuf, v);
2329           g_memory_buffer_put_byte (mbuf, '\0');
2330         }
2331       break;
2332
2333     case 'o': /* G_VARIANT_TYPE_OBJECT_PATH */
2334       padding_added = ensure_output_padding (mbuf, 4);
2335       if (value != NULL)
2336         {
2337           gsize len;
2338           const gchar *v = g_variant_get_string (value, &len);
2339           g_assert (g_variant_is_object_path (v));
2340           g_memory_buffer_put_uint32 (mbuf, len);
2341           g_memory_buffer_put_string (mbuf, v);
2342           g_memory_buffer_put_byte (mbuf, '\0');
2343         }
2344       break;
2345
2346     case 'g': /* G_VARIANT_TYPE_SIGNATURE */
2347       if (value != NULL)
2348         {
2349           gsize len;
2350           const gchar *v = g_variant_get_string (value, &len);
2351           g_assert (g_variant_is_signature (v));
2352           g_memory_buffer_put_byte (mbuf, len);
2353           g_memory_buffer_put_string (mbuf, v);
2354           g_memory_buffer_put_byte (mbuf, '\0');
2355         }
2356       break;
2357
2358     case 'h': /* G_VARIANT_TYPE_HANDLE */
2359       padding_added = ensure_output_padding (mbuf, 4);
2360       if (value != NULL)
2361         {
2362           gint32 v = g_variant_get_handle (value);
2363           g_memory_buffer_put_int32 (mbuf, v);
2364         }
2365       break;
2366
2367     case 'a': /* G_VARIANT_TYPE_ARRAY */
2368       {
2369         const GVariantType *element_type;
2370         GVariant *item;
2371         GVariantIter iter;
2372         goffset array_len_offset;
2373         goffset array_payload_begin_offset;
2374         goffset cur_offset;
2375         gsize array_len;
2376         guint fixed_size;
2377
2378         padding_added = ensure_output_padding (mbuf, 4);
2379         if (value != NULL)
2380           {
2381             /* array length - will be filled in later */
2382             array_len_offset = mbuf->valid_len;
2383             g_memory_buffer_put_uint32 (mbuf, 0xF00DFACE);
2384
2385             /* From the D-Bus spec:
2386              *
2387              *   "A UINT32 giving the length of the array data in bytes,
2388              *    followed by alignment padding to the alignment boundary of
2389              *    the array element type, followed by each array element. The
2390              *    array length is from the end of the alignment padding to
2391              *    the end of the last element, i.e. it does not include the
2392              *    padding after the length, or any padding after the last
2393              *    element."
2394              *
2395              * Thus, we need to count how much padding the first element
2396              * contributes and subtract that from the array length.
2397              */
2398             array_payload_begin_offset = mbuf->valid_len;
2399
2400             element_type = g_variant_type_element (type);
2401             fixed_size = get_type_fixed_size (element_type);
2402
2403             if (g_variant_n_children (value) == 0)
2404               {
2405                 gsize padding_added_for_item;
2406                 if (!append_value_to_blob (NULL,
2407                                            element_type,
2408                                            mbuf,
2409                                            &padding_added_for_item,
2410                                            error))
2411                   goto fail;
2412                 array_payload_begin_offset += padding_added_for_item;
2413               }
2414             else if (fixed_size != 0)
2415               {
2416                 GVariant *use_value;
2417
2418                 if (g_memory_buffer_is_byteswapped (mbuf))
2419                   use_value = g_variant_byteswap (value);
2420                 else
2421                   use_value = g_variant_ref (value);
2422
2423                 ensure_output_padding (mbuf, fixed_size);
2424                 array_len = g_variant_get_size (use_value);
2425                 g_memory_buffer_write (mbuf, g_variant_get_data (use_value), array_len);
2426                 g_variant_unref (use_value);
2427               }
2428             else
2429               {
2430                 guint n;
2431                 n = 0;
2432                 g_variant_iter_init (&iter, value);
2433                 while ((item = g_variant_iter_next_value (&iter)) != NULL)
2434                   {
2435                     gsize padding_added_for_item;
2436                     if (!append_value_to_blob (item,
2437                                                g_variant_get_type (item),
2438                                                mbuf,
2439                                                &padding_added_for_item,
2440                                                error))
2441                       {
2442                         g_variant_unref (item);
2443                         goto fail;
2444                       }
2445                     g_variant_unref (item);
2446                     if (n == 0)
2447                       {
2448                         array_payload_begin_offset += padding_added_for_item;
2449                       }
2450                     n++;
2451                   }
2452               }
2453
2454             cur_offset = mbuf->valid_len;
2455             array_len = cur_offset - array_payload_begin_offset;
2456             mbuf->pos = array_len_offset;
2457
2458             g_memory_buffer_put_uint32 (mbuf, array_len);
2459             mbuf->pos = cur_offset;
2460           }
2461       }
2462       break;
2463
2464     default:
2465       if (g_variant_type_is_dict_entry (type) || g_variant_type_is_tuple (type))
2466         {
2467           padding_added = ensure_output_padding (mbuf, 8);
2468           if (value != NULL)
2469             {
2470               GVariant *item;
2471               GVariantIter iter;
2472               g_variant_iter_init (&iter, value);
2473               while ((item = g_variant_iter_next_value (&iter)) != NULL)
2474                 {
2475                   if (!append_value_to_blob (item,
2476                                              g_variant_get_type (item),
2477                                              mbuf,
2478                                              NULL,
2479                                              error))
2480                     {
2481                       g_variant_unref (item);
2482                       goto fail;
2483                     }
2484                   g_variant_unref (item);
2485                 }
2486             }
2487         }
2488       else if (g_variant_type_is_variant (type))
2489         {
2490           if (value != NULL)
2491             {
2492               GVariant *child;
2493               const gchar *signature;
2494               child = g_variant_get_child_value (value, 0);
2495               signature = g_variant_get_type_string (child);
2496               g_memory_buffer_put_byte (mbuf, strlen (signature));
2497               g_memory_buffer_put_string (mbuf, signature);
2498               g_memory_buffer_put_byte (mbuf, '\0');
2499               if (!append_value_to_blob (child,
2500                                          g_variant_get_type (child),
2501                                          mbuf,
2502                                          NULL,
2503                                          error))
2504                 {
2505                   g_variant_unref (child);
2506                   goto fail;
2507                 }
2508               g_variant_unref (child);
2509             }
2510         }
2511       else
2512         {
2513           g_set_error (error,
2514                        G_IO_ERROR,
2515                        G_IO_ERROR_INVALID_ARGUMENT,
2516                        _("Error serializing GVariant with type string '%s' to the D-Bus wire format"),
2517                        g_variant_get_type_string (value));
2518           goto fail;
2519         }
2520       break;
2521     }
2522
2523   if (out_padding_added != NULL)
2524     *out_padding_added = padding_added;
2525
2526   return TRUE;
2527
2528  fail:
2529   return FALSE;
2530 }
2531
2532 static gboolean
2533 append_body_to_blob (GVariant       *value,
2534                      GMemoryBuffer  *mbuf,
2535                      GError        **error)
2536 {
2537   GVariant *item;
2538   GVariantIter iter;
2539
2540   if (!g_variant_is_of_type (value, G_VARIANT_TYPE_TUPLE))
2541     {
2542       g_set_error (error,
2543                    G_IO_ERROR,
2544                    G_IO_ERROR_INVALID_ARGUMENT,
2545                    "Expected a tuple for the body of the GDBusMessage.");
2546       goto fail;
2547     }
2548
2549   g_variant_iter_init (&iter, value);
2550   while ((item = g_variant_iter_next_value (&iter)) != NULL)
2551     {
2552       if (!append_value_to_blob (item,
2553                                  g_variant_get_type (item),
2554                                  mbuf,
2555                                  NULL,
2556                                  error))
2557         {
2558           g_variant_unref (item);
2559           goto fail;
2560         }
2561       g_variant_unref (item);
2562     }
2563   return TRUE;
2564
2565  fail:
2566   return FALSE;
2567 }
2568
2569 /* ---------------------------------------------------------------------------------------------------- */
2570
2571 /**
2572  * g_dbus_message_to_blob:
2573  * @message: A #GDBusMessage.
2574  * @out_size: Return location for size of generated blob.
2575  * @capabilities: A #GDBusCapabilityFlags describing what protocol features are supported.
2576  * @error: Return location for error.
2577  *
2578  * Serializes @message to a blob. The byte order returned by
2579  * g_dbus_message_get_byte_order() will be used.
2580  *
2581  * Returns: (array length=out_size) (transfer full): A pointer to a
2582  * valid binary D-Bus message of @out_size bytes generated by @message
2583  * or %NULL if @error is set. Free with g_free().
2584  *
2585  * Since: 2.26
2586  */
2587 guchar *
2588 g_dbus_message_to_blob (GDBusMessage          *message,
2589                         gsize                 *out_size,
2590                         GDBusCapabilityFlags   capabilities,
2591                         GError               **error)
2592 {
2593   GMemoryBuffer mbuf;
2594   guchar *ret;
2595   gsize size;
2596   goffset body_len_offset;
2597   goffset body_start_offset;
2598   gsize body_size;
2599   GVariant *header_fields;
2600   GVariantBuilder builder;
2601   GHashTableIter hash_iter;
2602   gpointer key;
2603   GVariant *header_value;
2604   GVariant *signature;
2605   const gchar *signature_str;
2606   gint num_fds_in_message;
2607   gint num_fds_according_to_header;
2608
2609   /* TODO: check against @capabilities */
2610
2611   ret = NULL;
2612
2613   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
2614   g_return_val_if_fail (out_size != NULL, NULL);
2615   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2616
2617   memset (&mbuf, 0, sizeof (mbuf));
2618   mbuf.len = MIN_ARRAY_SIZE;
2619   mbuf.data = g_malloc (mbuf.len);
2620
2621   mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN;
2622   switch (message->byte_order)
2623     {
2624     case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN:
2625       mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
2626       break;
2627     case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN:
2628       mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
2629       break;
2630     }
2631
2632   /* Core header */
2633   g_memory_buffer_put_byte (&mbuf, (guchar) message->byte_order);
2634   g_memory_buffer_put_byte (&mbuf, message->type);
2635   g_memory_buffer_put_byte (&mbuf, message->flags);
2636   g_memory_buffer_put_byte (&mbuf, 1); /* major protocol version */
2637   body_len_offset = mbuf.valid_len;
2638   /* body length - will be filled in later */
2639   g_memory_buffer_put_uint32 (&mbuf, 0xF00DFACE);
2640   g_memory_buffer_put_uint32 (&mbuf, message->serial);
2641
2642   num_fds_in_message = 0;
2643 #ifdef G_OS_UNIX
2644   if (message->fd_list != NULL)
2645     num_fds_in_message = g_unix_fd_list_get_length (message->fd_list);
2646 #endif
2647   num_fds_according_to_header = g_dbus_message_get_num_unix_fds (message);
2648   if (num_fds_in_message != num_fds_according_to_header)
2649     {
2650       g_set_error (error,
2651                    G_IO_ERROR,
2652                    G_IO_ERROR_INVALID_ARGUMENT,
2653                    _("Message has %d file descriptors but the header field indicates %d file descriptors"),
2654                    num_fds_in_message,
2655                    num_fds_according_to_header);
2656       goto out;
2657     }
2658
2659   if (!validate_headers (message, error))
2660     {
2661       g_prefix_error (error, _("Cannot serialize message: "));
2662       goto out;
2663     }
2664
2665   g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{yv}"));
2666   g_hash_table_iter_init (&hash_iter, message->headers);
2667   while (g_hash_table_iter_next (&hash_iter, &key, (gpointer) &header_value))
2668     {
2669       g_variant_builder_add (&builder,
2670                              "{yv}",
2671                              (guchar) GPOINTER_TO_UINT (key),
2672                              header_value);
2673     }
2674   header_fields = g_variant_builder_end (&builder);
2675
2676   if (!append_value_to_blob (header_fields,
2677                              g_variant_get_type (header_fields),
2678                              &mbuf,
2679                              NULL,
2680                              error))
2681     {
2682       g_variant_unref (header_fields);
2683       goto out;
2684     }
2685   g_variant_unref (header_fields);
2686
2687   /* header size must be a multiple of 8 */
2688   ensure_output_padding (&mbuf, 8);
2689
2690   body_start_offset = mbuf.valid_len;
2691
2692   signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE);
2693   signature_str = NULL;
2694   if (signature != NULL)
2695       signature_str = g_variant_get_string (signature, NULL);
2696   if (message->body != NULL)
2697     {
2698       gchar *tupled_signature_str;
2699       tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
2700       if (signature == NULL)
2701         {
2702           g_set_error (error,
2703                        G_IO_ERROR,
2704                        G_IO_ERROR_INVALID_ARGUMENT,
2705                        _("Message body has signature '%s' but there is no signature header"),
2706                        signature_str);
2707           g_free (tupled_signature_str);
2708           goto out;
2709         }
2710       else if (g_strcmp0 (tupled_signature_str, g_variant_get_type_string (message->body)) != 0)
2711         {
2712           g_set_error (error,
2713                        G_IO_ERROR,
2714                        G_IO_ERROR_INVALID_ARGUMENT,
2715                        _("Message body has type signature '%s' but signature in the header field is '%s'"),
2716                        tupled_signature_str, g_variant_get_type_string (message->body));
2717           g_free (tupled_signature_str);
2718           goto out;
2719         }
2720       g_free (tupled_signature_str);
2721       if (!append_body_to_blob (message->body, &mbuf, error))
2722         goto out;
2723     }
2724   else
2725     {
2726       if (signature != NULL && strlen (signature_str) > 0)
2727         {
2728           g_set_error (error,
2729                        G_IO_ERROR,
2730                        G_IO_ERROR_INVALID_ARGUMENT,
2731                        _("Message body is empty but signature in the header field is '(%s)'"),
2732                        signature_str);
2733           goto out;
2734         }
2735     }
2736
2737   /* OK, we're done writing the message - set the body length */
2738   size = mbuf.valid_len;
2739   body_size = size - body_start_offset;
2740
2741   mbuf.pos = body_len_offset;
2742
2743   g_memory_buffer_put_uint32 (&mbuf, body_size);
2744
2745   *out_size = size;
2746   ret = (guchar *)mbuf.data;
2747
2748  out:
2749   return ret;
2750 }
2751
2752 /* ---------------------------------------------------------------------------------------------------- */
2753
2754 static guint32
2755 get_uint32_header (GDBusMessage            *message,
2756                    GDBusMessageHeaderField  header_field)
2757 {
2758   GVariant *value;
2759   guint32 ret;
2760
2761   ret = 0;
2762   value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
2763   if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32))
2764     ret = g_variant_get_uint32 (value);
2765
2766   return ret;
2767 }
2768
2769 static const gchar *
2770 get_string_header (GDBusMessage            *message,
2771                    GDBusMessageHeaderField  header_field)
2772 {
2773   GVariant *value;
2774   const gchar *ret;
2775
2776   ret = NULL;
2777   value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
2778   if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
2779     ret = g_variant_get_string (value, NULL);
2780
2781   return ret;
2782 }
2783
2784 static const gchar *
2785 get_object_path_header (GDBusMessage            *message,
2786                         GDBusMessageHeaderField  header_field)
2787 {
2788   GVariant *value;
2789   const gchar *ret;
2790
2791   ret = NULL;
2792   value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
2793   if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_OBJECT_PATH))
2794     ret = g_variant_get_string (value, NULL);
2795
2796   return ret;
2797 }
2798
2799 static const gchar *
2800 get_signature_header (GDBusMessage            *message,
2801                       GDBusMessageHeaderField  header_field)
2802 {
2803   GVariant *value;
2804   const gchar *ret;
2805
2806   ret = NULL;
2807   value = g_hash_table_lookup (message->headers, GUINT_TO_POINTER (header_field));
2808   if (value != NULL && g_variant_is_of_type (value, G_VARIANT_TYPE_SIGNATURE))
2809     ret = g_variant_get_string (value, NULL);
2810
2811   return ret;
2812 }
2813
2814 /* ---------------------------------------------------------------------------------------------------- */
2815
2816 static void
2817 set_uint32_header (GDBusMessage             *message,
2818                    GDBusMessageHeaderField   header_field,
2819                    guint32                   value)
2820 {
2821   g_dbus_message_set_header (message,
2822                              header_field,
2823                              g_variant_new_uint32 (value));
2824 }
2825
2826 static void
2827 set_string_header (GDBusMessage             *message,
2828                    GDBusMessageHeaderField   header_field,
2829                    const gchar              *value)
2830 {
2831   g_dbus_message_set_header (message,
2832                              header_field,
2833                              value == NULL ? NULL : g_variant_new_string (value));
2834 }
2835
2836 static void
2837 set_object_path_header (GDBusMessage             *message,
2838                         GDBusMessageHeaderField   header_field,
2839                         const gchar              *value)
2840 {
2841   g_dbus_message_set_header (message,
2842                              header_field,
2843                              value == NULL ? NULL : g_variant_new_object_path (value));
2844 }
2845
2846 static void
2847 set_signature_header (GDBusMessage             *message,
2848                       GDBusMessageHeaderField   header_field,
2849                       const gchar              *value)
2850 {
2851   g_dbus_message_set_header (message,
2852                              header_field,
2853                              value == NULL ? NULL : g_variant_new_signature (value));
2854 }
2855
2856 /* ---------------------------------------------------------------------------------------------------- */
2857
2858 /**
2859  * g_dbus_message_get_reply_serial:
2860  * @message: A #GDBusMessage.
2861  *
2862  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL header field.
2863  *
2864  * Returns: The value.
2865  *
2866  * Since: 2.26
2867  */
2868 guint32
2869 g_dbus_message_get_reply_serial (GDBusMessage  *message)
2870 {
2871   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), 0);
2872   return get_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL);
2873 }
2874
2875 /**
2876  * g_dbus_message_set_reply_serial:
2877  * @message: A #GDBusMessage.
2878  * @value: The value to set.
2879  *
2880  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL header field.
2881  *
2882  * Since: 2.26
2883  */
2884 void
2885 g_dbus_message_set_reply_serial (GDBusMessage  *message,
2886                                  guint32        value)
2887 {
2888   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
2889   set_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, value);
2890 }
2891
2892 /* ---------------------------------------------------------------------------------------------------- */
2893
2894 /**
2895  * g_dbus_message_get_interface:
2896  * @message: A #GDBusMessage.
2897  *
2898  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE header field.
2899  *
2900  * Returns: The value.
2901  *
2902  * Since: 2.26
2903  */
2904 const gchar *
2905 g_dbus_message_get_interface (GDBusMessage  *message)
2906 {
2907   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
2908   return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE);
2909 }
2910
2911 /**
2912  * g_dbus_message_set_interface:
2913  * @message: A #GDBusMessage.
2914  * @value: The value to set.
2915  *
2916  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE header field.
2917  *
2918  * Since: 2.26
2919  */
2920 void
2921 g_dbus_message_set_interface (GDBusMessage  *message,
2922                               const gchar   *value)
2923 {
2924   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
2925   g_return_if_fail (value == NULL || g_dbus_is_interface_name (value));
2926   set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE, value);
2927 }
2928
2929 /* ---------------------------------------------------------------------------------------------------- */
2930
2931 /**
2932  * g_dbus_message_get_member:
2933  * @message: A #GDBusMessage.
2934  *
2935  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_MEMBER header field.
2936  *
2937  * Returns: The value.
2938  *
2939  * Since: 2.26
2940  */
2941 const gchar *
2942 g_dbus_message_get_member (GDBusMessage  *message)
2943 {
2944   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
2945   return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER);
2946 }
2947
2948 /**
2949  * g_dbus_message_set_member:
2950  * @message: A #GDBusMessage.
2951  * @value: The value to set.
2952  *
2953  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_MEMBER header field.
2954  *
2955  * Since: 2.26
2956  */
2957 void
2958 g_dbus_message_set_member (GDBusMessage  *message,
2959                            const gchar   *value)
2960 {
2961   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
2962   g_return_if_fail (value == NULL || g_dbus_is_member_name (value));
2963   set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, value);
2964 }
2965
2966 /* ---------------------------------------------------------------------------------------------------- */
2967
2968 /**
2969  * g_dbus_message_get_path:
2970  * @message: A #GDBusMessage.
2971  *
2972  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_PATH header field.
2973  *
2974  * Returns: The value.
2975  *
2976  * Since: 2.26
2977  */
2978 const gchar *
2979 g_dbus_message_get_path (GDBusMessage  *message)
2980 {
2981   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
2982   return get_object_path_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH);
2983 }
2984
2985 /**
2986  * g_dbus_message_set_path:
2987  * @message: A #GDBusMessage.
2988  * @value: The value to set.
2989  *
2990  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_PATH header field.
2991  *
2992  * Since: 2.26
2993  */
2994 void
2995 g_dbus_message_set_path (GDBusMessage  *message,
2996                          const gchar   *value)
2997 {
2998   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
2999   g_return_if_fail (value == NULL || g_variant_is_object_path (value));
3000   set_object_path_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, value);
3001 }
3002
3003 /* ---------------------------------------------------------------------------------------------------- */
3004
3005 /**
3006  * g_dbus_message_get_sender:
3007  * @message: A #GDBusMessage.
3008  *
3009  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_SENDER header field.
3010  *
3011  * Returns: The value.
3012  *
3013  * Since: 2.26
3014  */
3015 const gchar *
3016 g_dbus_message_get_sender (GDBusMessage *message)
3017 {
3018   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3019   return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SENDER);
3020 }
3021
3022 /**
3023  * g_dbus_message_set_sender:
3024  * @message: A #GDBusMessage.
3025  * @value: The value to set.
3026  *
3027  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_SENDER header field.
3028  *
3029  * Since: 2.26
3030  */
3031 void
3032 g_dbus_message_set_sender (GDBusMessage  *message,
3033                            const gchar   *value)
3034 {
3035   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3036   g_return_if_fail (value == NULL || g_dbus_is_name (value));
3037   set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SENDER, value);
3038 }
3039
3040 /* ---------------------------------------------------------------------------------------------------- */
3041
3042 /**
3043  * g_dbus_message_get_destination:
3044  * @message: A #GDBusMessage.
3045  *
3046  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION header field.
3047  *
3048  * Returns: The value.
3049  *
3050  * Since: 2.26
3051  */
3052 const gchar *
3053 g_dbus_message_get_destination (GDBusMessage  *message)
3054 {
3055   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3056   return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION);
3057 }
3058
3059 /**
3060  * g_dbus_message_set_destination:
3061  * @message: A #GDBusMessage.
3062  * @value: The value to set.
3063  *
3064  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION header field.
3065  *
3066  * Since: 2.26
3067  */
3068 void
3069 g_dbus_message_set_destination (GDBusMessage  *message,
3070                                 const gchar   *value)
3071 {
3072   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3073   g_return_if_fail (value == NULL || g_dbus_is_name (value));
3074   set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION, value);
3075 }
3076
3077 /* ---------------------------------------------------------------------------------------------------- */
3078
3079 /**
3080  * g_dbus_message_get_error_name:
3081  * @message: A #GDBusMessage.
3082  *
3083  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME header field.
3084  *
3085  * Returns: The value.
3086  *
3087  * Since: 2.26
3088  */
3089 const gchar *
3090 g_dbus_message_get_error_name (GDBusMessage  *message)
3091 {
3092   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3093   return get_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME);
3094 }
3095
3096 /**
3097  * g_dbus_message_set_error_name:
3098  * @message: A #GDBusMessage.
3099  * @value: The value to set.
3100  *
3101  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME header field.
3102  *
3103  * Since: 2.26
3104  */
3105 void
3106 g_dbus_message_set_error_name (GDBusMessage  *message,
3107                                const gchar   *value)
3108 {
3109   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3110   g_return_if_fail (value == NULL || g_dbus_is_interface_name (value));
3111   set_string_header (message, G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME, value);
3112 }
3113
3114 /* ---------------------------------------------------------------------------------------------------- */
3115
3116 /**
3117  * g_dbus_message_get_signature:
3118  * @message: A #GDBusMessage.
3119  *
3120  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE header field.
3121  *
3122  * Returns: The value.
3123  *
3124  * Since: 2.26
3125  */
3126 const gchar *
3127 g_dbus_message_get_signature (GDBusMessage  *message)
3128 {
3129   const gchar *ret;
3130   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3131   ret = get_signature_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE);
3132   if (ret == NULL)
3133     ret = "";
3134   return ret;
3135 }
3136
3137 /**
3138  * g_dbus_message_set_signature:
3139  * @message: A #GDBusMessage.
3140  * @value: The value to set.
3141  *
3142  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE header field.
3143  *
3144  * Since: 2.26
3145  */
3146 void
3147 g_dbus_message_set_signature (GDBusMessage  *message,
3148                               const gchar   *value)
3149 {
3150   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3151   g_return_if_fail (value == NULL || g_variant_is_signature (value));
3152   set_signature_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, value);
3153 }
3154
3155 /* ---------------------------------------------------------------------------------------------------- */
3156
3157 /**
3158  * g_dbus_message_get_arg0:
3159  * @message: A #GDBusMessage.
3160  *
3161  * Convenience to get the first item in the body of @message.
3162  *
3163  * Returns: The string item or %NULL if the first item in the body of
3164  * @message is not a string.
3165  *
3166  * Since: 2.26
3167  */
3168 const gchar *
3169 g_dbus_message_get_arg0 (GDBusMessage  *message)
3170 {
3171   const gchar *ret;
3172
3173   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3174
3175   ret = NULL;
3176
3177   if (message->body != NULL && g_variant_is_of_type (message->body, G_VARIANT_TYPE_TUPLE))
3178     {
3179       GVariant *item;
3180       item = g_variant_get_child_value (message->body, 0);
3181       if (g_variant_is_of_type (item, G_VARIANT_TYPE_STRING))
3182         ret = g_variant_get_string (item, NULL);
3183       g_variant_unref (item);
3184     }
3185
3186   return ret;
3187 }
3188
3189 /* ---------------------------------------------------------------------------------------------------- */
3190
3191 /**
3192  * g_dbus_message_get_num_unix_fds:
3193  * @message: A #GDBusMessage.
3194  *
3195  * Convenience getter for the %G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS header field.
3196  *
3197  * Returns: The value.
3198  *
3199  * Since: 2.26
3200  */
3201 guint32
3202 g_dbus_message_get_num_unix_fds (GDBusMessage *message)
3203 {
3204   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), 0);
3205   return get_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS);
3206 }
3207
3208 /**
3209  * g_dbus_message_set_num_unix_fds:
3210  * @message: A #GDBusMessage.
3211  * @value: The value to set.
3212  *
3213  * Convenience setter for the %G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS header field.
3214  *
3215  * Since: 2.26
3216  */
3217 void
3218 g_dbus_message_set_num_unix_fds (GDBusMessage  *message,
3219                                  guint32        value)
3220 {
3221   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3222   set_uint32_header (message, G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS, value);
3223 }
3224
3225 /* ---------------------------------------------------------------------------------------------------- */
3226
3227 /**
3228  * g_dbus_message_to_gerror:
3229  * @message: A #GDBusMessage.
3230  * @error: The #GError to set.
3231  *
3232  * If @message is not of type %G_DBUS_MESSAGE_TYPE_ERROR does
3233  * nothing and returns %FALSE.
3234  *
3235  * Otherwise this method encodes the error in @message as a #GError
3236  * using g_dbus_error_set_dbus_error() using the information in the
3237  * %G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME header field of @message as
3238  * well as the first string item in @message's body.
3239  *
3240  * Returns: %TRUE if @error was set, %FALSE otherwise.
3241  *
3242  * Since: 2.26
3243  */
3244 gboolean
3245 g_dbus_message_to_gerror (GDBusMessage   *message,
3246                           GError        **error)
3247 {
3248   gboolean ret;
3249   const gchar *error_name;
3250
3251   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
3252
3253   ret = FALSE;
3254   if (message->type != G_DBUS_MESSAGE_TYPE_ERROR)
3255     goto out;
3256
3257   error_name = g_dbus_message_get_error_name (message);
3258   if (error_name != NULL)
3259     {
3260       GVariant *body;
3261
3262       body = g_dbus_message_get_body (message);
3263
3264       if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
3265         {
3266           const gchar *error_message;
3267           g_variant_get (body, "(&s)", &error_message);
3268           g_dbus_error_set_dbus_error (error,
3269                                        error_name,
3270                                        error_message,
3271                                        NULL);
3272         }
3273       else
3274         {
3275           /* these two situations are valid, yet pretty rare */
3276           if (body != NULL)
3277             {
3278               g_dbus_error_set_dbus_error (error,
3279                                            error_name,
3280                                            "",
3281                                            _("Error return with body of type '%s'"),
3282                                            g_variant_get_type_string (body));
3283             }
3284           else
3285             {
3286               g_dbus_error_set_dbus_error (error,
3287                                            error_name,
3288                                            "",
3289                                            _("Error return with empty body"));
3290             }
3291         }
3292     }
3293   else
3294     {
3295       /* TOOD: this shouldn't happen - should check this at message serialization
3296        * time and disconnect the peer.
3297        */
3298       g_set_error (error,
3299                    G_IO_ERROR,
3300                    G_IO_ERROR_FAILED,
3301                    "Error return without error-name header!");
3302     }
3303
3304   ret = TRUE;
3305
3306  out:
3307   return ret;
3308 }
3309
3310 /* ---------------------------------------------------------------------------------------------------- */
3311
3312 static gchar *
3313 flags_to_string (GType flags_type, guint value)
3314 {
3315   GString *s;
3316   GFlagsClass *klass;
3317   guint n;
3318
3319   klass = g_type_class_ref (flags_type);
3320   s = g_string_new (NULL);
3321   for (n = 0; n < 32; n++)
3322     {
3323       if ((value & (1<<n)) != 0)
3324         {
3325           GFlagsValue *flags_value;
3326           flags_value = g_flags_get_first_value (klass, (1<<n));
3327           if (s->len > 0)
3328             g_string_append_c (s, ',');
3329           if (flags_value != NULL)
3330             g_string_append (s, flags_value->value_nick);
3331           else
3332             g_string_append_printf (s, "unknown (bit %d)", n);
3333         }
3334     }
3335   if (s->len == 0)
3336     g_string_append (s, "none");
3337   g_type_class_unref (klass);
3338   return g_string_free (s, FALSE);
3339 }
3340
3341 static gint
3342 _sort_keys_func (gconstpointer a,
3343                  gconstpointer b)
3344 {
3345   gint ia;
3346   gint ib;
3347
3348   ia = GPOINTER_TO_INT (a);
3349   ib = GPOINTER_TO_INT (b);
3350
3351   return ia - ib;
3352 }
3353
3354 /**
3355  * g_dbus_message_print:
3356  * @message: A #GDBusMessage.
3357  * @indent: Indentation level.
3358  *
3359  * Produces a human-readable multi-line description of @message.
3360  *
3361  * The contents of the description has no ABI guarantees, the contents
3362  * and formatting is subject to change at any time. Typical output
3363  * looks something like this:
3364  * |[
3365  * Type:    method-call
3366  * Flags:   none
3367  * Version: 0
3368  * Serial:  4
3369  * Headers:
3370  *   path -> objectpath '/org/gtk/GDBus/TestObject'
3371  *   interface -> 'org.gtk.GDBus.TestInterface'
3372  *   member -> 'GimmeStdout'
3373  *   destination -> ':1.146'
3374  * Body: ()
3375  * UNIX File Descriptors:
3376  *   (none)
3377  * ]|
3378  * or
3379  * |[
3380  * Type:    method-return
3381  * Flags:   no-reply-expected
3382  * Version: 0
3383  * Serial:  477
3384  * Headers:
3385  *   reply-serial -> uint32 4
3386  *   destination -> ':1.159'
3387  *   sender -> ':1.146'
3388  *   num-unix-fds -> uint32 1
3389  * Body: ()
3390  * UNIX File Descriptors:
3391  *   fd 12: dev=0:10,mode=020620,ino=5,uid=500,gid=5,rdev=136:2,size=0,atime=1273085037,mtime=1273085851,ctime=1272982635
3392  * ]|
3393  *
3394  * Returns: A string that should be freed with g_free().
3395  *
3396  * Since: 2.26
3397  */
3398 gchar *
3399 g_dbus_message_print (GDBusMessage *message,
3400                       guint         indent)
3401 {
3402   GString *str;
3403   gchar *s;
3404   GList *keys;
3405   GList *l;
3406
3407   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3408
3409   str = g_string_new (NULL);
3410
3411   s = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, message->type);
3412   g_string_append_printf (str, "%*sType:    %s\n", indent, "", s);
3413   g_free (s);
3414   s = flags_to_string (G_TYPE_DBUS_MESSAGE_FLAGS, message->flags);
3415   g_string_append_printf (str, "%*sFlags:   %s\n", indent, "", s);
3416   g_free (s);
3417   g_string_append_printf (str, "%*sVersion: %d\n", indent, "", message->major_protocol_version);
3418   g_string_append_printf (str, "%*sSerial:  %d\n", indent, "", message->serial);
3419
3420   g_string_append_printf (str, "%*sHeaders:\n", indent, "");
3421   keys = g_hash_table_get_keys (message->headers);
3422   keys = g_list_sort (keys, _sort_keys_func);
3423   if (keys != NULL)
3424     {
3425       for (l = keys; l != NULL; l = l->next)
3426         {
3427           gint key = GPOINTER_TO_INT (l->data);
3428           GVariant *value;
3429           gchar *value_str;
3430
3431           value = g_hash_table_lookup (message->headers, l->data);
3432           g_assert (value != NULL);
3433
3434           s = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_HEADER_FIELD, key);
3435           value_str = g_variant_print (value, TRUE);
3436           g_string_append_printf (str, "%*s  %s -> %s\n", indent, "", s, value_str);
3437           g_free (s);
3438           g_free (value_str);
3439         }
3440     }
3441   else
3442     {
3443       g_string_append_printf (str, "%*s  (none)\n", indent, "");
3444     }
3445   g_string_append_printf (str, "%*sBody: ", indent, "");
3446   if (message->body != NULL)
3447     {
3448       g_variant_print_string (message->body,
3449                               str,
3450                               TRUE);
3451     }
3452   else
3453     {
3454       g_string_append (str, "()");
3455     }
3456   g_string_append (str, "\n");
3457 #ifdef G_OS_UNIX
3458   g_string_append_printf (str, "%*sUNIX File Descriptors:\n", indent, "");
3459   if (message->fd_list != NULL)
3460     {
3461       gint num_fds;
3462       const gint *fds;
3463       gint n;
3464
3465       fds = g_unix_fd_list_peek_fds (message->fd_list, &num_fds);
3466       if (num_fds > 0)
3467         {
3468           for (n = 0; n < num_fds; n++)
3469             {
3470               GString *fs;
3471               struct stat statbuf;
3472               fs = g_string_new (NULL);
3473               if (fstat (fds[n], &statbuf) == 0)
3474                 {
3475                   g_string_append_printf (fs, "%s" "dev=%d:%d", fs->len > 0 ? "," : "",
3476                                           major (statbuf.st_dev), minor (statbuf.st_dev));
3477                   g_string_append_printf (fs, "%s" "mode=0%o", fs->len > 0 ? "," : "",
3478                                           statbuf.st_mode);
3479                   g_string_append_printf (fs, "%s" "ino=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3480                                           (guint64) statbuf.st_ino);
3481                   g_string_append_printf (fs, "%s" "uid=%u", fs->len > 0 ? "," : "",
3482                                           (guint) statbuf.st_uid);
3483                   g_string_append_printf (fs, "%s" "gid=%u", fs->len > 0 ? "," : "",
3484                                           (guint) statbuf.st_gid);
3485                   g_string_append_printf (fs, "%s" "rdev=%d:%d", fs->len > 0 ? "," : "",
3486                                           major (statbuf.st_rdev), minor (statbuf.st_rdev));
3487                   g_string_append_printf (fs, "%s" "size=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3488                                           (guint64) statbuf.st_size);
3489                   g_string_append_printf (fs, "%s" "atime=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3490                                           (guint64) statbuf.st_atime);
3491                   g_string_append_printf (fs, "%s" "mtime=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3492                                           (guint64) statbuf.st_mtime);
3493                   g_string_append_printf (fs, "%s" "ctime=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "",
3494                                           (guint64) statbuf.st_ctime);
3495                 }
3496               else
3497                 {
3498                   g_string_append_printf (fs, "(fstat failed: %s)", strerror (errno));
3499                 }
3500               g_string_append_printf (str, "%*s  fd %d: %s\n", indent, "", fds[n], fs->str);
3501               g_string_free (fs, TRUE);
3502             }
3503         }
3504       else
3505         {
3506           g_string_append_printf (str, "%*s  (empty)\n", indent, "");
3507         }
3508     }
3509   else
3510     {
3511       g_string_append_printf (str, "%*s  (none)\n", indent, "");
3512     }
3513 #endif
3514
3515   return g_string_free (str, FALSE);
3516 }
3517
3518 /**
3519  * g_dbus_message_get_locked:
3520  * @message: A #GDBusMessage.
3521  *
3522  * Checks whether @message is locked. To monitor changes to this
3523  * value, conncet to the #GObject::notify signal to listen for changes
3524  * on the #GDBusMessage:locked property.
3525  *
3526  * Returns: %TRUE if @message is locked, %FALSE otherwise.
3527  *
3528  * Since: 2.26
3529  */
3530 gboolean
3531 g_dbus_message_get_locked (GDBusMessage *message)
3532 {
3533   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
3534   return message->locked;
3535 }
3536
3537 /**
3538  * g_dbus_message_lock:
3539  * @message: A #GDBusMessage.
3540  *
3541  * If @message is locked, does nothing. Otherwise locks the message.
3542  *
3543  * Since: 2.26
3544  */
3545 void
3546 g_dbus_message_lock (GDBusMessage *message)
3547 {
3548   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
3549
3550   if (message->locked)
3551     goto out;
3552
3553   message->locked = TRUE;
3554   g_object_notify (G_OBJECT (message), "locked");
3555
3556  out:
3557   ;
3558 }
3559
3560 /**
3561  * g_dbus_message_copy:
3562  * @message: A #GDBusMessage.
3563  * @error: Return location for error or %NULL.
3564  *
3565  * Copies @message. The copy is a deep copy and the returned
3566  * #GDBusMessage is completely identical except that it is guaranteed
3567  * to not be locked.
3568  *
3569  * This operation can fail if e.g. @message contains file descriptors
3570  * and the per-process or system-wide open files limit is reached.
3571  *
3572  * Returns: (transfer full): A new #GDBusMessage or %NULL if @error is set.
3573  *     Free with g_object_unref().
3574  *
3575  * Since: 2.26
3576  */
3577 GDBusMessage *
3578 g_dbus_message_copy (GDBusMessage  *message,
3579                      GError       **error)
3580 {
3581   GDBusMessage *ret;
3582   GHashTableIter iter;
3583   gpointer header_key;
3584   GVariant *header_value;
3585
3586   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
3587   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
3588
3589   ret = g_dbus_message_new ();
3590   ret->type                   = message->type;
3591   ret->flags                  = message->flags;
3592   ret->byte_order             = message->byte_order;
3593   ret->major_protocol_version = message->major_protocol_version;
3594   ret->serial                 = message->serial;
3595
3596 #ifdef G_OS_UNIX
3597   if (message->fd_list != NULL)
3598     {
3599       gint n;
3600       gint num_fds;
3601       const gint *fds;
3602
3603       ret->fd_list = g_unix_fd_list_new ();
3604       fds = g_unix_fd_list_peek_fds (message->fd_list, &num_fds);
3605       for (n = 0; n < num_fds; n++)
3606         {
3607           if (g_unix_fd_list_append (ret->fd_list,
3608                                      fds[n],
3609                                      error) == -1)
3610             {
3611               g_object_unref (ret);
3612               ret = NULL;
3613               goto out;
3614             }
3615         }
3616     }
3617 #endif
3618
3619   /* see https://bugzilla.gnome.org/show_bug.cgi?id=624546#c8 for why it's fine
3620    * to just ref (as opposed to deep-copying) the GVariant instances
3621    */
3622   ret->body = message->body != NULL ? g_variant_ref (message->body) : NULL;
3623   g_hash_table_iter_init (&iter, message->headers);
3624   while (g_hash_table_iter_next (&iter, &header_key, (gpointer) &header_value))
3625     g_hash_table_insert (ret->headers, header_key, g_variant_ref (header_value));
3626
3627 #ifdef G_OS_UNIX
3628  out:
3629 #endif
3630   return ret;
3631 }