/* dbus-asv-util.c - utility functions for a{sv} * * Copyright © 2011-2012 Nokia Corporation * Copyright © 2012-2013 Collabora Ltd. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA */ #include #include #include "dbus/dbus-asv-util.h" /** * Convenience function to create a method-call reply whose type is a{sv} * (map from string to variant). * * Append values with 0 or more sequences of _dbus_asv_open_entry(), * appending a value to var_iter, and _dbus_asv_close_entry(), * then close the a{sv} with _dbus_asv_close() or _dbus_asv_abandon(). * * This must be paired with a call to _dbus_asv_close() or _dbus_asv_abandon(). * * @param message a method call message * @param iter an iterator which will be initialized to append to the message * @param arr_iter an iterator which will be initialized to append to the array * @returns a new message, or #NULL if not enough memory */ DBusMessage * _dbus_asv_new_method_return (DBusMessage *message, DBusMessageIter *iter, DBusMessageIter *arr_iter) { DBusMessage *reply = dbus_message_new_method_return (message); if (reply == NULL) return NULL; dbus_message_iter_init_append (reply, iter); if (!dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}", arr_iter)) { dbus_message_unref (reply); return NULL; } return reply; } /* * Open a new entry in an a{sv} (map from string to variant). * * This must be paired with a call to either _dbus_asv_close_entry() * or _dbus_asv_abandon_entry(). * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param entry_iter will be initialized to append to the dict-entry * @param key a UTF-8 key for the map * @param type the type of the variant value, e.g. DBUS_TYPE_STRING_AS_STRING * @param var_iter will be initialized to append (i.e. write) to the variant * @returns #TRUE on success, or #FALSE if not enough memory */ static dbus_bool_t _dbus_asv_open_entry (DBusMessageIter *arr_iter, DBusMessageIter *entry_iter, const char *key, const char *type, DBusMessageIter *var_iter) { if (!dbus_message_iter_open_container (arr_iter, DBUS_TYPE_DICT_ENTRY, NULL, entry_iter)) return FALSE; if (!dbus_message_iter_append_basic (entry_iter, DBUS_TYPE_STRING, &key)) { dbus_message_iter_abandon_container (arr_iter, entry_iter); return FALSE; } if (!dbus_message_iter_open_container (entry_iter, DBUS_TYPE_VARIANT, type, var_iter)) { dbus_message_iter_abandon_container (arr_iter, entry_iter); return FALSE; } return TRUE; } /* * Closes an a{sv} entry after successfully appending the value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param entry_iter the iterator appending to the dict-entry, will be closed * @param var_iter the iterator appending to the variant, will be closed * @returns #TRUE on success, or #FALSE if not enough memory */ static dbus_bool_t _dbus_asv_close_entry (DBusMessageIter *arr_iter, DBusMessageIter *entry_iter, DBusMessageIter *var_iter) { if (!dbus_message_iter_close_container (entry_iter, var_iter)) { dbus_message_iter_abandon_container (arr_iter, entry_iter); return FALSE; } if (!dbus_message_iter_close_container (arr_iter, entry_iter)) return FALSE; return TRUE; } /** * Closes an a{sv} after successfully appending all values. * * If this function fails, you must abandon iter and whatever * larger data structure (message, etc.) the a{sv} was embedded in. * * @param iter the iterator which is appending to the message or other data structure containing the a{sv} * @param arr_iter the iterator appending to the array, will be closed * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_close (DBusMessageIter *iter, DBusMessageIter *arr_iter) { return dbus_message_iter_close_container (iter, arr_iter); } /* * Closes an a{sv} entry after unsuccessfully appending a value. * You must also abandon the a{sv} itself (for instance with * _dbus_asv_abandon()), and abandon whatever larger data structure * the a{sv} was embedded in. * * @param iter the iterator which is appending to the message or other data structure containing the a{sv} * @param arr_iter the iterator appending to the array, will be closed * @returns #TRUE on success, or #FALSE if not enough memory */ static void _dbus_asv_abandon_entry (DBusMessageIter *arr_iter, DBusMessageIter *entry_iter, DBusMessageIter *var_iter) { dbus_message_iter_abandon_container (entry_iter, var_iter); dbus_message_iter_abandon_container (arr_iter, entry_iter); } /** * Closes an a{sv} after unsuccessfully appending a value. * * You must also abandon whatever larger data structure (message, etc.) * the a{sv} was embedded in. * * @param iter the iterator which is appending to the message or other data structure containing the a{sv} * @param arr_iter the iterator appending to the array, will be closed */ void _dbus_asv_abandon (DBusMessageIter *iter, DBusMessageIter *arr_iter) { dbus_message_iter_abandon_container (iter, arr_iter); } /** * Create a new entry in an a{sv} (map from string to variant) * with a 32-bit unsigned integer value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param key a UTF-8 key for the map * @param value the value * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_add_uint32 (DBusMessageIter *arr_iter, const char *key, dbus_uint32_t value) { DBusMessageIter entry_iter, var_iter; if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, DBUS_TYPE_UINT32_AS_STRING, &var_iter)) return FALSE; if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_UINT32, &value)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter)) return FALSE; return TRUE; } /** * Create a new entry in an a{sv} (map from string to variant) * with a UTF-8 string value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param key a UTF-8 key for the map * @param value the value * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_add_string (DBusMessageIter *arr_iter, const char *key, const char *value) { DBusMessageIter entry_iter, var_iter; if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, DBUS_TYPE_STRING_AS_STRING, &var_iter)) return FALSE; if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_STRING, &value)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter)) return FALSE; return TRUE; } /** * Create a new entry in an a{sv} (map from string to variant) * with a byte array value. * * If this function fails, the a{sv} must be abandoned, for instance * with _dbus_asv_abandon(). * * @param arr_iter the iterator which is appending to the array * @param key a UTF-8 key for the map * @param value the value * @param n_elements the number of elements to append * @returns #TRUE on success, or #FALSE if not enough memory */ dbus_bool_t _dbus_asv_add_byte_array (DBusMessageIter *arr_iter, const char *key, const void *value, int n_elements) { DBusMessageIter entry_iter; DBusMessageIter var_iter; DBusMessageIter byte_array_iter; if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, "ay", &var_iter)) return FALSE; if (!dbus_message_iter_open_container (&var_iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &byte_array_iter)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!dbus_message_iter_append_fixed_array (&byte_array_iter, DBUS_TYPE_BYTE, &value, n_elements)) { dbus_message_iter_abandon_container (&var_iter, &byte_array_iter); _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!dbus_message_iter_close_container (&var_iter, &byte_array_iter)) { _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter); return FALSE; } if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter)) return FALSE; return TRUE; }