Convert a{sv} helpers from Stats into generic utility code
[platform/upstream/dbus.git] / dbus / dbus-asv-util.c
1 /* dbus-asv-util.c - utility functions for a{sv}
2  *
3  * Copyright © 2011-2012 Nokia Corporation
4  * Copyright © 2012-2013 Collabora Ltd.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24 #include <config.h>
25
26 #include <dbus/dbus.h>
27
28 #include "dbus/dbus-asv-util.h"
29
30 /**
31  * Convenience function to create a method-call reply whose type is a{sv}
32  * (map from string to variant).
33  *
34  * Append values with 0 or more sequences of _dbus_asv_open_entry(),
35  * appending a value to var_iter, and _dbus_asv_close_entry(),
36  * then close the a{sv} with _dbus_asv_close() or _dbus_asv_abandon().
37  *
38  * This must be paired with a call to _dbus_asv_close() or _dbus_asv_abandon().
39  *
40  * @param message a method call message
41  * @param iter an iterator which will be initialized to append to the message
42  * @param arr_iter an iterator which will be initialized to append to the array
43  * @returns a new message, or #NULL if not enough memory
44  */
45 DBusMessage *
46 _dbus_asv_new_method_return (DBusMessage      *message,
47                              DBusMessageIter  *iter,
48                              DBusMessageIter  *arr_iter)
49 {
50   DBusMessage *reply = dbus_message_new_method_return (message);
51
52   if (reply == NULL)
53     return NULL;
54
55   dbus_message_iter_init_append (reply, iter);
56
57   if (!dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}",
58                                          arr_iter))
59     {
60       dbus_message_unref (reply);
61       return NULL;
62     }
63
64   return reply;
65 }
66
67 /*
68  * Open a new entry in an a{sv} (map from string to variant).
69  *
70  * This must be paired with a call to either _dbus_asv_close_entry()
71  * or _dbus_asv_abandon_entry().
72  *
73  * If this function fails, the a{sv} must be abandoned, for instance
74  * with _dbus_asv_abandon().
75  *
76  * @param arr_iter the iterator which is appending to the array
77  * @param entry_iter will be initialized to append to the dict-entry
78  * @param key a UTF-8 key for the map
79  * @param type the type of the variant value, e.g. DBUS_TYPE_STRING_AS_STRING
80  * @param var_iter will be initialized to append (i.e. write) to the variant
81  * @returns #TRUE on success, or #FALSE if not enough memory
82  */
83 static dbus_bool_t
84 _dbus_asv_open_entry (DBusMessageIter *arr_iter,
85                       DBusMessageIter *entry_iter,
86                       const char      *key,
87                       const char      *type,
88                       DBusMessageIter *var_iter)
89 {
90   if (!dbus_message_iter_open_container (arr_iter, DBUS_TYPE_DICT_ENTRY,
91                                          NULL, entry_iter))
92     return FALSE;
93
94   if (!dbus_message_iter_append_basic (entry_iter, DBUS_TYPE_STRING, &key))
95     {
96       dbus_message_iter_abandon_container (arr_iter, entry_iter);
97       return FALSE;
98     }
99
100   if (!dbus_message_iter_open_container (entry_iter, DBUS_TYPE_VARIANT,
101                                          type, var_iter))
102     {
103       dbus_message_iter_abandon_container (arr_iter, entry_iter);
104       return FALSE;
105     }
106
107   return TRUE;
108 }
109
110 /*
111  * Closes an a{sv} entry after successfully appending the value.
112  *
113  * If this function fails, the a{sv} must be abandoned, for instance
114  * with _dbus_asv_abandon().
115  *
116  * @param arr_iter the iterator which is appending to the array
117  * @param entry_iter the iterator appending to the dict-entry, will be closed
118  * @param var_iter the iterator appending to the variant, will be closed
119  * @returns #TRUE on success, or #FALSE if not enough memory
120  */
121 static dbus_bool_t
122 _dbus_asv_close_entry (DBusMessageIter *arr_iter,
123                        DBusMessageIter *entry_iter,
124                        DBusMessageIter *var_iter)
125 {
126   if (!dbus_message_iter_close_container (entry_iter, var_iter))
127     {
128       dbus_message_iter_abandon_container (arr_iter, entry_iter);
129       return FALSE;
130     }
131
132   if (!dbus_message_iter_close_container (arr_iter, entry_iter))
133     return FALSE;
134
135   return TRUE;
136 }
137
138 /**
139  * Closes an a{sv} after successfully appending all values.
140  *
141  * If this function fails, you must abandon iter and whatever
142  * larger data structure (message, etc.) the a{sv} was embedded in.
143  *
144  * @param iter the iterator which is appending to the message or other data structure containing the a{sv}
145  * @param arr_iter the iterator appending to the array, will be closed
146  * @returns #TRUE on success, or #FALSE if not enough memory
147  */
148 dbus_bool_t
149 _dbus_asv_close (DBusMessageIter *iter,
150                  DBusMessageIter *arr_iter)
151 {
152   return dbus_message_iter_close_container (iter, arr_iter);
153 }
154
155 /*
156  * Closes an a{sv} entry after unsuccessfully appending a value.
157  * You must also abandon the a{sv} itself (for instance with
158  * _dbus_asv_abandon()), and abandon whatever larger data structure
159  * the a{sv} was embedded in.
160  *
161  * @param iter the iterator which is appending to the message or other data structure containing the a{sv}
162  * @param arr_iter the iterator appending to the array, will be closed
163  * @returns #TRUE on success, or #FALSE if not enough memory
164  */
165 static void
166 _dbus_asv_abandon_entry (DBusMessageIter *arr_iter,
167                          DBusMessageIter *entry_iter,
168                          DBusMessageIter *var_iter)
169 {
170   dbus_message_iter_abandon_container (entry_iter, var_iter);
171   dbus_message_iter_abandon_container (arr_iter, entry_iter);
172 }
173
174 /**
175  * Closes an a{sv} after unsuccessfully appending a value.
176  *
177  * You must also abandon whatever larger data structure (message, etc.)
178  * the a{sv} was embedded in.
179  *
180  * @param iter the iterator which is appending to the message or other data structure containing the a{sv}
181  * @param arr_iter the iterator appending to the array, will be closed
182  */
183 void
184 _dbus_asv_abandon (DBusMessageIter *iter,
185                    DBusMessageIter *arr_iter)
186 {
187   dbus_message_iter_abandon_container (iter, arr_iter);
188 }
189
190 /**
191  * Create a new entry in an a{sv} (map from string to variant)
192  * with a 32-bit unsigned integer value.
193  *
194  * If this function fails, the a{sv} must be abandoned, for instance
195  * with _dbus_asv_abandon().
196  *
197  * @param arr_iter the iterator which is appending to the array
198  * @param key a UTF-8 key for the map
199  * @param value the value
200  * @returns #TRUE on success, or #FALSE if not enough memory
201  */
202 dbus_bool_t
203 _dbus_asv_add_uint32 (DBusMessageIter *arr_iter,
204                       const char *key,
205                       dbus_uint32_t value)
206 {
207   DBusMessageIter entry_iter, var_iter;
208
209   if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key,
210                              DBUS_TYPE_UINT32_AS_STRING, &var_iter))
211     return FALSE;
212
213   if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_UINT32,
214                                        &value))
215     {
216       _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
217       return FALSE;
218     }
219
220   if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter))
221     return FALSE;
222
223   return TRUE;
224 }
225
226 /**
227  * Create a new entry in an a{sv} (map from string to variant)
228  * with a UTF-8 string value.
229  *
230  * If this function fails, the a{sv} must be abandoned, for instance
231  * with _dbus_asv_abandon().
232  *
233  * @param arr_iter the iterator which is appending to the array
234  * @param key a UTF-8 key for the map
235  * @param value the value
236  * @returns #TRUE on success, or #FALSE if not enough memory
237  */
238 dbus_bool_t
239 _dbus_asv_add_string (DBusMessageIter *arr_iter,
240                       const char *key,
241                       const char *value)
242 {
243   DBusMessageIter entry_iter, var_iter;
244
245   if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key,
246                              DBUS_TYPE_STRING_AS_STRING, &var_iter))
247     return FALSE;
248
249   if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_STRING,
250                                        &value))
251     {
252       _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
253       return FALSE;
254     }
255
256   if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter))
257     return FALSE;
258
259   return TRUE;
260 }