* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "config.h"
+
#include <glib/gvariant-core.h>
#include <glib/gvariant-serialiser.h>
#include <glib/gtestutils.h>
#include <glib/gbitlock.h>
#include <glib/gatomic.h>
-#include <glib/gbuffer.h>
+#include <glib/gbytes.h>
#include <glib/gslice.h>
#include <glib/gmem.h>
#include <string.h>
-#include "galias.h"
/*
* This file includes the structure definition for GVariant and a small
*
* #GVariant is an opaque data structure and can only be accessed
* using the following functions.
+ *
+ * Since: 2.24
**/
struct _GVariant
/* see below for field member documentation */
{
struct
{
- GBuffer *buffer;
+ GBytes *bytes;
gconstpointer data;
} serialised;
* never be changed. It is therefore valid to access
* them without holding a lock.
*
- * .buffer: the #GBuffer that contains the memory pointed to by
+ * .bytes: the #GBytes that contains the memory pointed to by
* .data, or %NULL if .data is %NULL. In the event that
* the instance was deserialised from another instance,
- * then the buffer will be shared by both of them. When
+ * then the bytes will be shared by both of them. When
* the instance is freed, this reference must be released
- * with g_buffer_unref().
+ * with g_bytes_unref().
*
* .data: the serialised data (of size 'size') of the instance.
* This pointer should not be freed or modified in any way.
- * #GBuffer is responsible for memory management.
+ * #GBytes is responsible for memory management.
*
* This pointer may be %NULL in two cases:
*
g_variant_serialise (GVariant *value,
gpointer data)
{
- GVariantSerialised serialised = { };
+ GVariantSerialised serialised = { 0, };
gpointer *children;
gsize n_children;
if (~value->state & STATE_SERIALISED)
{
- GBuffer *buffer;
+ GBytes *bytes;
gpointer data;
g_variant_ensure_size (value);
g_variant_release_children (value);
- buffer = g_buffer_new_take_data (data, value->size);
- value->contents.serialised.data = buffer->data;
- value->contents.serialised.buffer = buffer;
+ bytes = g_bytes_new_take (data, value->size);
+ value->contents.serialised.data = g_bytes_get_data (bytes, NULL);
+ value->contents.serialised.bytes = bytes;
value->state |= STATE_SERIALISED;
}
}
* @type: the type of the new instance
* @serialised: if the instance will be in serialised form
* @trusted: if the instance will be trusted
- * @returns: a new #GVariant with a floating reference
*
* Allocates a #GVariant instance and does some common work (such as
* looking up and filling in the type info), setting the state field,
* and setting the ref_count to 1.
+ *
+ * Returns: a new #GVariant with a floating reference
*/
static GVariant *
g_variant_alloc (const GVariantType *type,
return value;
}
-/* -- internal -- */
-/* < internal >
- * g_variant_new_from_buffer:
+/**
+ * g_variant_new_from_bytes:
* @type: a #GVariantType
- * @buffer: a #GBuffer
- * @trusted: if the contents of @buffer are trusted
- * @returns: a new #GVariant with a floating reference
+ * @bytes: a #GBytes
+ * @trusted: if the contents of @bytes are trusted
*
* Constructs a new serialised-mode #GVariant instance. This is the
* inner interface for creation of new serialised values that gets
* called from various functions in gvariant.c.
*
- * A reference is taken on @buffer.
+ * A reference is taken on @bytes.
+ *
+ * Returns: (transfer none): a new #GVariant with a floating reference
+ *
+ * Since: 2.36
*/
GVariant *
-g_variant_new_from_buffer (const GVariantType *type,
- GBuffer *buffer,
- gboolean trusted)
+g_variant_new_from_bytes (const GVariantType *type,
+ GBytes *bytes,
+ gboolean trusted)
{
GVariant *value;
+ guint alignment;
+ gsize size;
value = g_variant_alloc (type, TRUE, trusted);
- value->contents.serialised.buffer = g_buffer_ref (buffer);
- value->contents.serialised.data = buffer->data;
- value->size = buffer->size;
+
+ value->contents.serialised.bytes = g_bytes_ref (bytes);
+
+ g_variant_type_info_query (value->type_info,
+ &alignment, &size);
+
+ if (size && g_bytes_get_size (bytes) != size)
+ {
+ /* Creating a fixed-sized GVariant with a bytes of the wrong
+ * size.
+ *
+ * We should do the equivalent of pulling a fixed-sized child out
+ * of a brozen container (ie: data is NULL size is equal to the correct
+ * fixed size).
+ */
+ value->contents.serialised.data = NULL;
+ value->size = size;
+ }
+ else
+ {
+ value->contents.serialised.data = g_bytes_get_data (bytes, &value->size);
+ }
return value;
}
+/* -- internal -- */
+
/* < internal >
* g_variant_new_from_children:
* @type: a #GVariantType
* @children: an array of #GVariant pointers. Consumed.
* @n_children: the length of @children
* @trusted: %TRUE if every child in @children in trusted
- * @returns: a new #GVariant with a floating reference
*
* Constructs a new tree-mode #GVariant instance. This is the inner
* interface for creation of new serialised values that gets called from
*
* @children is consumed by this function. g_free() will be called on
* it some time later.
+ *
+ * Returns: a new #GVariant with a floating reference
*/
GVariant *
g_variant_new_from_children (const GVariantType *type,
/* < internal >
* g_variant_get_type_info:
* @value: a #GVariant
- * @returns: the #GVariantTypeInfo for @value
*
* Returns the #GVariantTypeInfo corresponding to the type of @value. A
* reference is not added, so the return value is only good for the
* duration of the life of @value.
+ *
+ * Returns: the #GVariantTypeInfo for @value
*/
GVariantTypeInfo *
g_variant_get_type_info (GVariant *value)
/* < internal >
* g_variant_is_trusted:
* @value: a #GVariant
- * @returns: if @value is trusted
*
* Determines if @value is trusted by #GVariant to contain only
* fully-valid data. All values constructed solely via #GVariant APIs
* skipped. For example, we don't need to check that a string is
* properly nul-terminated or that an object path is actually a
* properly-formatted object path.
+ *
+ * Returns: if @value is trusted
*/
gboolean
g_variant_is_trusted (GVariant *value)
*
* Decreases the reference count of @value. When its reference count
* drops to 0, the memory used by the variant is freed.
+ *
+ * Since: 2.24
**/
void
g_variant_unref (GVariant *value)
{
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (value->ref_count > 0);
+
if (g_atomic_int_dec_and_test (&value->ref_count))
{
if G_UNLIKELY (value->state & STATE_LOCKED)
g_variant_type_info_unref (value->type_info);
if (value->state & STATE_SERIALISED)
- g_buffer_unref (value->contents.serialised.buffer);
+ g_bytes_unref (value->contents.serialised.bytes);
else
g_variant_release_children (value);
+ memset (value, 0, sizeof (GVariant));
g_slice_free (GVariant, value);
}
}
/**
* g_variant_ref:
* @value: a #GVariant
- * @returns: the same @value
*
* Increases the reference count of @value.
+ *
+ * Returns: the same @value
+ *
+ * Since: 2.24
**/
GVariant *
g_variant_ref (GVariant *value)
{
+ g_return_val_if_fail (value != NULL, NULL);
+ g_return_val_if_fail (value->ref_count > 0, NULL);
+
g_atomic_int_inc (&value->ref_count);
return value;
/**
* g_variant_ref_sink:
* @value: a #GVariant
- * @returns: the same @value
*
* #GVariant uses a floating reference count system. All functions with
- * names starting with <literal>g_variant_new_</literal> return floating
+ * names starting with `g_variant_new_` return floating
* references.
*
* Calling g_variant_ref_sink() on a #GVariant with a floating reference
* makes certain common styles of programming much easier while still
* maintaining normal refcounting semantics in situations where values
* are not floating.
+ *
+ * Returns: the same @value
+ *
+ * Since: 2.24
**/
GVariant *
g_variant_ref_sink (GVariant *value)
{
+ g_return_val_if_fail (value != NULL, NULL);
+ g_return_val_if_fail (value->ref_count > 0, NULL);
+
g_variant_lock (value);
if (~value->state & STATE_FLOATING)
}
/**
+ * g_variant_take_ref:
+ * @value: a #GVariant
+ *
+ * If @value is floating, sink it. Otherwise, do nothing.
+ *
+ * Typically you want to use g_variant_ref_sink() in order to
+ * automatically do the correct thing with respect to floating or
+ * non-floating references, but there is one specific scenario where
+ * this function is helpful.
+ *
+ * The situation where this function is helpful is when creating an API
+ * that allows the user to provide a callback function that returns a
+ * #GVariant. We certainly want to allow the user the flexibility to
+ * return a non-floating reference from this callback (for the case
+ * where the value that is being returned already exists).
+ *
+ * At the same time, the style of the #GVariant API makes it likely that
+ * for newly-created #GVariant instances, the user can be saved some
+ * typing if they are allowed to return a #GVariant with a floating
+ * reference.
+ *
+ * Using this function on the return value of the user's callback allows
+ * the user to do whichever is more convenient for them. The caller
+ * will alway receives exactly one full reference to the value: either
+ * the one that was returned in the first place, or a floating reference
+ * that has been converted to a full reference.
+ *
+ * This function has an odd interaction when combined with
+ * g_variant_ref_sink() running at the same time in another thread on
+ * the same #GVariant instance. If g_variant_ref_sink() runs first then
+ * the result will be that the floating reference is converted to a hard
+ * reference. If g_variant_take_ref() runs first then the result will
+ * be that the floating reference is converted to a hard reference and
+ * an additional reference on top of that one is added. It is best to
+ * avoid this situation.
+ *
+ * Returns: the same @value
+ **/
+GVariant *
+g_variant_take_ref (GVariant *value)
+{
+ g_return_val_if_fail (value != NULL, NULL);
+ g_return_val_if_fail (value->ref_count > 0, NULL);
+
+ g_atomic_int_and (&value->state, ~STATE_FLOATING);
+
+ return value;
+}
+
+/**
+ * g_variant_is_floating:
+ * @value: a #GVariant
+ *
+ * Checks whether @value has a floating reference count.
+ *
+ * This function should only ever be used to assert that a given variant
+ * is or is not floating, or for debug purposes. To acquire a reference
+ * to a variant that might be floating, always use g_variant_ref_sink()
+ * or g_variant_take_ref().
+ *
+ * See g_variant_ref_sink() for more information about floating reference
+ * counts.
+ *
+ * Returns: whether @value is floating
+ *
+ * Since: 2.26
+ **/
+gboolean
+g_variant_is_floating (GVariant *value)
+{
+ g_return_val_if_fail (value != NULL, FALSE);
+
+ return (value->state & STATE_FLOATING) != 0;
+}
+
+/**
* g_variant_get_size:
* @value: a #GVariant instance
- * @returns: the serialised size of @value
*
* Determines the number of bytes that would be required to store @value
* with g_variant_store().
* then this function is O(1). Otherwise, the size is calculated, an
* operation which is approximately O(n) in the number of values
* involved.
+ *
+ * Returns: the serialised size of @value
+ *
+ * Since: 2.24
**/
gsize
g_variant_get_size (GVariant *value)
/**
* g_variant_get_data:
* @value: a #GVariant instance
- * @returns: the serialised form of @value, or %NULL
*
* Returns a pointer to the serialised form of a #GVariant instance.
- * The returned data is in machine native byte order but may not be in
- * fully-normalised form if read from an untrusted source. The returned
- * data must not be freed; it remains valid for as long as @value
- * exists.
+ * The returned data may not be in fully-normalised form if read from an
+ * untrusted source. The returned data must not be freed; it remains
+ * valid for as long as @value exists.
*
* If @value is a fixed-sized value that was deserialised from a
* corrupted serialised container then %NULL may be returned. In this
* is O(1). If the value is not already in serialised form,
* serialisation occurs implicitly and is approximately O(n) in the size
* of the result.
+ *
+ * To deserialise the data returned by this function, in addition to the
+ * serialised data, you must know the type of the #GVariant, and (if the
+ * machine might be different) the endianness of the machine that stored
+ * it. As a result, file formats or network messages that incorporate
+ * serialised #GVariants must include this information either
+ * implicitly (for instance "the file always contains a
+ * %G_VARIANT_TYPE_VARIANT and it is always in little-endian order") or
+ * explicitly (by storing the type and/or endianness in addition to the
+ * serialised data).
+ *
+ * Returns: (transfer none): the serialised form of @value, or %NULL
+ *
+ * Since: 2.24
**/
gconstpointer
g_variant_get_data (GVariant *value)
}
/**
+ * g_variant_get_data_as_bytes:
+ * @value: a #GVariant
+ *
+ * Returns a pointer to the serialised form of a #GVariant instance.
+ * The semantics of this function are exactly the same as
+ * g_variant_get_data(), except that the returned #GBytes holds
+ * a reference to the variant data.
+ *
+ * Returns: (transfer full): A new #GBytes representing the variant data
+ *
+ * Since: 2.36
+ */
+GBytes *
+g_variant_get_data_as_bytes (GVariant *value)
+{
+ const gchar *bytes_data;
+ const gchar *data;
+ gsize bytes_size;
+ gsize size;
+
+ g_variant_lock (value);
+ g_variant_ensure_serialised (value);
+ g_variant_unlock (value);
+
+ bytes_data = g_bytes_get_data (value->contents.serialised.bytes, &bytes_size);
+ data = value->contents.serialised.data;
+ size = value->size;
+
+ if (data == bytes_data && size == bytes_size)
+ return g_bytes_ref (value->contents.serialised.bytes);
+ else
+ return g_bytes_new_from_bytes (value->contents.serialised.bytes,
+ data - bytes_data, size);
+}
+
+
+/**
* g_variant_n_children:
* @value: a container #GVariant
- * @returns: the number of children in the container
*
* Determines the number of children in a container #GVariant instance.
* This includes variants, maybes, arrays, tuples and dictionary
* only on the type). For dictionary entries, it is always 2
*
* This function is O(1).
+ *
+ * Returns: the number of children in the container
+ *
+ * Since: 2.24
**/
gsize
g_variant_n_children (GVariant *value)
* g_variant_get_child_value:
* @value: a container #GVariant
* @index_: the index of the child to fetch
- * @returns: the child at the specified index
*
* Reads a child item out of a container #GVariant instance. This
* includes variants, maybes, arrays, tuples and dictionary
* It is an error if @index_ is greater than the number of child items
* in the container. See g_variant_n_children().
*
+ * The returned value is never floating. You should free it with
+ * g_variant_unref() when you're done with it.
+ *
* This function is O(1).
+ *
+ * Returns: (transfer full): the child at the specified index
+ *
+ * Since: 2.24
**/
GVariant *
g_variant_get_child_value (GVariant *value,
gsize index_)
{
- GVariant *child = NULL;
+ g_return_val_if_fail (index_ < g_variant_n_children (value), NULL);
- g_variant_lock (value);
-
- if (value->state & STATE_SERIALISED)
+ if (~g_atomic_int_get (&value->state) & STATE_SERIALISED)
{
- GVariantSerialised serialised = {
- value->type_info,
- (gpointer) value->contents.serialised.data,
- value->size
- };
- GVariantSerialised s_child;
-
- s_child = g_variant_serialised_get_child (serialised, index_);
-
- child = g_slice_new (GVariant);
- child->type_info = s_child.type_info;
- child->state = (value->state & STATE_TRUSTED) |
- STATE_SERIALISED;
- child->size = serialised.size;
- child->ref_count = 1;
- child->contents.serialised.buffer =
- g_buffer_ref (value->contents.serialised.buffer);
- child->contents.serialised.data = serialised.data;
- }
- else
- child = g_variant_ref (value->contents.tree.children[index_]);
+ g_variant_lock (value);
- g_variant_unlock (value);
+ if (~value->state & STATE_SERIALISED)
+ {
+ GVariant *child;
+
+ child = g_variant_ref (value->contents.tree.children[index_]);
+ g_variant_unlock (value);
+
+ return child;
+ }
+
+ g_variant_unlock (value);
+ }
- return child;
+ {
+ GVariantSerialised serialised = {
+ value->type_info,
+ (gpointer) value->contents.serialised.data,
+ value->size
+ };
+ GVariantSerialised s_child;
+ GVariant *child;
+
+ /* get the serialiser to extract the serialised data for the child
+ * from the serialised data for the container
+ */
+ s_child = g_variant_serialised_get_child (serialised, index_);
+
+ /* create a new serialised instance out of it */
+ child = g_slice_new (GVariant);
+ child->type_info = s_child.type_info;
+ child->state = (value->state & STATE_TRUSTED) |
+ STATE_SERIALISED;
+ child->size = s_child.size;
+ child->ref_count = 1;
+ child->contents.serialised.bytes =
+ g_bytes_ref (value->contents.serialised.bytes);
+ child->contents.serialised.data = s_child.data;
+
+ return child;
+ }
}
/**
*
* The stored data is in machine native byte order but may not be in
* fully-normalised form if read from an untrusted source. See
- * g_variant_normalise() for a solution.
+ * g_variant_get_normal_form() for a solution.
+ *
+ * As with g_variant_get_data(), to be able to deserialise the
+ * serialised variant successfully, its type and (if the destination
+ * machine might be different) its endianness must also be available.
*
* This function is approximately O(n) in the size of @data.
+ *
+ * Since: 2.24
**/
void
g_variant_store (GVariant *value,
g_variant_unlock (value);
}
-#define __G_VARIANT_CORE_C__
-#include "galiasdef.c"
+/**
+ * g_variant_is_normal_form:
+ * @value: a #GVariant instance
+ *
+ * Checks if @value is in normal form.
+ *
+ * The main reason to do this is to detect if a given chunk of
+ * serialised data is in normal form: load the data into a #GVariant
+ * using g_variant_new_from_data() and then use this function to
+ * check.
+ *
+ * If @value is found to be in normal form then it will be marked as
+ * being trusted. If the value was already marked as being trusted then
+ * this function will immediately return %TRUE.
+ *
+ * Returns: %TRUE if @value is in normal form
+ *
+ * Since: 2.24
+ **/
+gboolean
+g_variant_is_normal_form (GVariant *value)
+{
+ if (value->state & STATE_TRUSTED)
+ return TRUE;
+
+ g_variant_lock (value);
+
+ if (value->state & STATE_SERIALISED)
+ {
+ GVariantSerialised serialised = {
+ value->type_info,
+ (gpointer) value->contents.serialised.data,
+ value->size
+ };
+
+ if (g_variant_serialised_is_normal (serialised))
+ value->state |= STATE_TRUSTED;
+ }
+ else
+ {
+ gboolean normal = TRUE;
+ gsize i;
+
+ for (i = 0; i < value->contents.tree.n_children; i++)
+ normal &= g_variant_is_normal_form (value->contents.tree.children[i]);
+
+ if (normal)
+ value->state |= STATE_TRUSTED;
+ }
+
+ g_variant_unlock (value);
+
+ return (value->state & STATE_TRUSTED) != 0;
+}