+++ /dev/null
-/* mongo-bson.c
- *
- * Copyright (C) 2011 Christian Hergert <christian@catch.com>
- *
- * This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This file 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-
-#include "mongo-bson.h"
-#include "mongo-debug.h"
-
-/**
- * SECTION:mongo-bson
- * @title: MongoBson
- * @short_description: BSON document structure.
- *
- * #MongoBson reprsents a BSON document that can be created, traversed,
- * and used throughout the Mongo-GLib library. They are referenced counted
- * structures that are referenced with mongo_bson_ref() and unreferenced
- * with mongo_bson_unref(). Memory allocated by the #MongoBson structure
- * is automatically released when the reference count reaches zero.
- *
- * You can iterate through the fields in a #MongoBson using the
- * mongo_bson_iter_* functions. #MongoBsonIter contains the state of
- * the iterator and is used to access the current value. You may jump
- * to the next field matching a given name using mongo_bson_iter_find().
- *
- * Keep in mind that BSON documents do not use modified UTF-8 like most
- * of GLib. Therefore, they may have %NULL characters within the target
- * string instead of the two-byte sequenced used in modified UTF-8. This
- * may change at some point to incur an extra cost for conversion to
- * modified UTF-8.
- */
-
-struct _MongoBson
-{
- volatile gint ref_count;
- GByteArray *buf;
- const guint8 *static_data;
- gsize static_len;
- GDestroyNotify static_notify;
-};
-
-typedef enum
-{
- ITER_TRUST_UTF8 = 1 << 0,
- ITER_INVALID_UTF8 = 1 << 1,
-} IterFlags;
-
-#define ITER_IS_TYPE(iter, type) \
- (GPOINTER_TO_INT(iter->user_data5) == type)
-
-/**
- * mongo_bson_dispose:
- * @bson: A #MongoBson.
- *
- * Cleans up @bson and free allocated resources.
- */
-static void
-mongo_bson_dispose (MongoBson *bson)
-{
- if (bson->buf) {
- g_byte_array_free(bson->buf, TRUE);
- } else if (bson->static_notify) {
- bson->static_notify((guint *)bson->static_data);
- }
-}
-
-/**
- * mongo_bson_new_from_data:
- * @buffer: (in): The buffer to create a #MongoBson.
- * @length: (in): The length of @buffer.
- *
- * Creates a new #MongoBson instance using the buffer and the length.
- *
- * Returns: A new #MongoBson that should be freed with mongo_bson_unref().
- */
-MongoBson *
-mongo_bson_new_from_data (const guint8 *buffer,
- gsize length)
-{
- MongoBson *bson;
- guint32 bson_len;
-
- g_return_val_if_fail(buffer != NULL, NULL);
-
- /*
- * The first 4 bytes of a BSON are the length, including the 4 bytes
- * containing said length.
- */
- memcpy(&bson_len, buffer, sizeof bson_len);
- bson_len = GUINT32_FROM_LE(bson_len);
- if (bson_len != length) {
- return NULL;
- }
-
- bson = g_slice_new0(MongoBson);
- bson->ref_count = 1;
- bson->buf = g_byte_array_sized_new(length);
- g_byte_array_append(bson->buf, buffer, length);
-
- return bson;
-}
-
-/**
- * mongo_bson_new_take_data:
- * @buffer: (in): The buffer to use when creating the #MongoBson.
- * @length: (in): The length of @buffer.
- *
- * Creates a new instance of #MongoBson using the buffers provided.
- * @buffer should be a buffer that can work with g_realloc() and
- * g_free().
- *
- * Returns: (transfer full): A newly allocated #MongoBson.
- */
-MongoBson *
-mongo_bson_new_take_data (guint8 *buffer,
- gsize length)
-{
- MongoBson *bson;
- guint32 bson_len;
-
- g_return_val_if_fail(buffer, NULL);
- g_return_val_if_fail(length >= 5, NULL);
-
- /*
- * The first 4 bytes of a BSON are the length, including the 4 bytes
- * containing said length.
- */
- memcpy(&bson_len, buffer, sizeof bson_len);
- bson_len = GUINT32_FROM_LE(bson_len);
- if (bson_len != length) {
- return NULL;
- }
-
- bson = g_slice_new0(MongoBson);
- bson->ref_count = 1;
-#if GLIB_CHECK_VERSION(2, 32, 0)
- bson->buf = g_byte_array_new_take(buffer, length);
-#else
- bson->buf = g_byte_array_new();
- bson->buf->data = buffer;
- bson->buf->len = length;
-#endif
-
- return bson;
-}
-
-/**
- * mongo_bson_new_from_static_data:
- * @buffer: (in) (transfer full): The static buffer to use.
- * @length: (in): The number of bytes in @buffer.
- * @notify: (in): A #GDestroyNotify to free @buffer.
- *
- * Creates a new #MongoBson structure using @buffer. This does not copy
- * the content of the buffer and uses it directly. Therefore, you MUST make
- * sure that the structure outlives the buffer beneath it.
- *
- * If the structure is referenced with mongo_bson_ref(), the contents of
- * the buffer will be copied.
- *
- * When the structure is released, @notify will be called to release
- * @buffer.
- *
- * You MAY NOT modify the contents of @buffer using any of the
- * mongo_bson_append methods.
- *
- * Returns: A newly created #MongoBson structure.
- */
-MongoBson *
-mongo_bson_new_from_static_data (guint8 *buffer,
- gsize length,
- GDestroyNotify notify)
-{
- MongoBson *bson;
- guint32 bson_len;
-
- g_return_val_if_fail(buffer, NULL);
- g_return_val_if_fail(length >= 5, NULL);
-
- /*
- * The first 4 bytes of a BSON are the length, including the 4 bytes
- * containing said length.
- */
- memcpy(&bson_len, buffer, sizeof bson_len);
- bson_len = GUINT32_FROM_LE(bson_len);
- if (bson_len != length) {
- return NULL;
- }
-
- bson = g_slice_new0(MongoBson);
- bson->ref_count = 1;
- bson->static_data = buffer;
- bson->static_len = length;
- bson->static_notify = notify;
-
- return bson;
-}
-
-/**
- * mongo_bson_new_empty:
- *
- * Creates a new instance of #MongoBson. This function is similar to
- * mongo_bson_new() except that it does not pre-populate the newly created
- * #MongoBson instance with an _id field.
- *
- * Returns: An empty #MongoBson that should be freed with mongo_bson_unref().
- */
-MongoBson *
-mongo_bson_new_empty (void)
-{
- MongoBson *bson;
- gint32 len = GINT_TO_LE(5);
- guint8 trailing = 0;
-
- bson = g_slice_new0(MongoBson);
- bson->ref_count = 1;
- bson->buf = g_byte_array_sized_new(16);
-
- g_byte_array_append(bson->buf, (guint8 *)&len, sizeof len);
- g_byte_array_append(bson->buf, (guint8 *)&trailing, sizeof trailing);
-
- g_assert(bson);
- g_assert(bson->buf);
- g_assert_cmpint(bson->buf->len, ==, 5);
-
- return bson;
-}
-
-/**
- * mongo_bson_new:
- *
- * Creates a new instance of #MongoBson. The #MongoBson instance is
- * pre-populated with an _id field and #MongoObjectId value. This value
- * is generated on the local machine and follows the guidelines suggested
- * by the BSON ObjectID specificiation.
- *
- * Returns: A #MongoBson that should be freed with mongo_bson_unref().
- */
-MongoBson *
-mongo_bson_new (void)
-{
- MongoObjectId *oid;
- MongoBson *bson;
-
- bson = mongo_bson_new_empty();
- oid = mongo_object_id_new();
- mongo_bson_append_object_id(bson, "_id", oid);
- mongo_object_id_free(oid);
-
- return bson;
-}
-
-/**
- * mongo_bson_dup:
- * @bson: (in): A #MongoBson.
- *
- * Creates a new #MongoBson by copying @bson.
- *
- * Returns: (transfer full): A newly allocated #MongoBson.
- */
-MongoBson *
-mongo_bson_dup (const MongoBson *bson)
-{
- const guint8 *data;
- MongoBson *ret = NULL;
- gsize data_len = 0;
-
- if (bson && (data = mongo_bson_get_data(bson, &data_len))) {
- ret = mongo_bson_new_from_data(data, data_len);
- }
-
- return ret;
-}
-
-/**
- * mongo_bson_ref:
- * @bson: (in): A #MongoBson.
- *
- * Atomically increments the reference count of @bson by one. If @bson
- * contains a static buffer, then a new structure will be returned.
- *
- * Returns: (transfer full): @bson.
- */
-MongoBson *
-mongo_bson_ref (MongoBson *bson)
-{
- g_return_val_if_fail(bson != NULL, NULL);
- g_return_val_if_fail(bson->ref_count > 0, NULL);
-
- if (G_UNLIKELY(bson->static_data)) {
- return mongo_bson_new_from_data(bson->static_data, bson->static_len);
- }
- g_atomic_int_inc(&bson->ref_count);
- return bson;
-}
-
-/**
- * mongo_bson_unref:
- * @bson: A MongoBson.
- *
- * Atomically decrements the reference count of @bson by one. When the
- * reference count reaches zero, the structure will be destroyed and
- * freed.
- */
-void
-mongo_bson_unref (MongoBson *bson)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(bson->ref_count > 0);
-
- if (g_atomic_int_dec_and_test(&bson->ref_count)) {
- mongo_bson_dispose(bson);
- g_slice_free(MongoBson, bson);
- }
-}
-
-/**
- * mongo_bson_get_empty:
- * @bson: (in): A #MongoBson.
- *
- * Checks to see if the contents of MongoBson are empty.
- *
- * Returns: None.
- * Side effects: None.
- */
-gboolean
-mongo_bson_get_empty (MongoBson *bson)
-{
- guint32 len;
- g_return_val_if_fail(bson != NULL, FALSE);
- len = bson->buf ? bson->buf->len : bson->static_len;
- return (len <= 5);
-}
-
-/**
- * mongo_bson_get_data:
- * @bson: (in): A #MongoBson.
- * @length: (out): A location for the buffer length.
- *
- * Fetches the BSON buffer.
- *
- * Returns: (transfer none): The #MongoBson buffer.
- */
-const guint8 *
-mongo_bson_get_data (const MongoBson *bson,
- gsize *length)
-{
- g_return_val_if_fail(bson != NULL, NULL);
- g_return_val_if_fail(length != NULL, NULL);
-
- if (bson->buf) {
- *length = bson->buf->len;
- return bson->buf->data;
- }
-
- *length = bson->static_len;
- return bson->static_data;
-}
-
-/**
- * mongo_bson_get_size:
- * @bson: (in): A #MongoBson.
- *
- * Retrieves the size of the #MongoBson buffer.
- *
- * Returns: A gsize.
- */
-gsize
-mongo_bson_get_size (const MongoBson *bson)
-{
- g_return_val_if_fail(bson, 0);
- return bson->buf->len;
-}
-
-/**
- * mongo_bson_get_type:
- *
- * Retrieve the #GType for the #MongoBson boxed type.
- *
- * Returns: A #GType.
- */
-GType
-mongo_bson_get_type (void)
-{
- static GType type_id = 0;
- static gsize initialized = FALSE;
-
- if (g_once_init_enter(&initialized)) {
- type_id = g_boxed_type_register_static("MongoBson",
- (GBoxedCopyFunc)mongo_bson_ref,
- (GBoxedFreeFunc)mongo_bson_unref);
- g_once_init_leave(&initialized, TRUE);
- }
-
- return type_id;
-}
-
-/**
- * mongo_bson_type_get_type:
- *
- * Fetches the #GType for a #MongoBsonType.
- *
- * Returns: A #GType.
- */
-GType
-mongo_bson_type_get_type (void)
-{
- static GType type_id = 0;
- static gsize initialized = FALSE;
- static GEnumValue values[] = {
- { MONGO_BSON_DOUBLE, "MONGO_BSON_DOUBLE", "DOUBLE" },
- { MONGO_BSON_UTF8, "MONGO_BSON_UTF8", "UTF8" },
- { MONGO_BSON_DOCUMENT, "MONGO_BSON_DOCUMENT", "DOCUMENT" },
- { MONGO_BSON_ARRAY, "MONGO_BSON_ARRAY", "ARRAY" },
- { MONGO_BSON_UNDEFINED, "MONGO_BSON_UNDEFINED", "UNDEFINED" },
- { MONGO_BSON_OBJECT_ID, "MONGO_BSON_OBJECT_ID", "OBJECT_ID" },
- { MONGO_BSON_BOOLEAN, "MONGO_BSON_BOOLEAN", "BOOLEAN" },
- { MONGO_BSON_DATE_TIME, "MONGO_BSON_DATE_TIME", "DATE_TIME" },
- { MONGO_BSON_NULL, "MONGO_BSON_NULL", "NULL" },
- { MONGO_BSON_REGEX, "MONGO_BSON_REGEX", "REGEX" },
- { MONGO_BSON_INT32, "MONGO_BSON_INT32", "INT32" },
- { MONGO_BSON_INT64, "MONGO_BSON_INT64", "INT64" },
- { 0 }
- };
-
- if (g_once_init_enter(&initialized)) {
- type_id = g_enum_register_static("MongoBsonType", values);
- g_once_init_leave(&initialized, TRUE);
- }
-
- return type_id;
-}
-
-/**
- * mongo_bson_append:
- * @bson: (in): A #MongoBson.
- * @type: (in) (type MongoBsonType): A #MongoBsonType.
- * @key: (in): The key for the field to append.
- * @data1: (in): The data for the first chunk of the data.
- * @len1: (in): The length of @data1.
- * @data2: (in): The data for the second chunk of the data.
- * @len2: (in): The length of @data2.
- *
- * This utility function helps us build a buffer for a #MongoBson given
- * the various #MongoBsonType<!-- -->'s and two-part data sections of
- * some fields.
- *
- * If @data2 is set, @data1 must also be set.
- */
-static void
-mongo_bson_append (MongoBson *bson,
- guint8 type,
- const gchar *key,
- const guint8 *data1,
- gsize len1,
- const guint8 *data2,
- gsize len2)
-{
- const guint8 trailing = 0;
- gint32 doc_len;
-
- g_return_if_fail(bson != NULL);
- g_return_if_fail(bson->buf != NULL);
- g_return_if_fail(type != 0);
- g_return_if_fail(key != NULL);
- g_return_if_fail(g_utf8_validate(key, -1, NULL));
- g_return_if_fail(data1 != NULL || len1 == 0);
- g_return_if_fail(data2 != NULL || len2 == 0);
- g_return_if_fail(!data2 || data1);
-
- /*
- * Overwrite our trailing byte with the type for this key.
- */
- bson->buf->data[bson->buf->len - 1] = type;
-
- /*
- * Append the field name as a BSON cstring.
- */
- g_byte_array_append(bson->buf, (guint8 *)key, strlen(key) + 1);
-
- /*
- * Append the data sections if needed.
- */
- if (data1) {
- g_byte_array_append(bson->buf, data1, len1);
- if (data2) {
- g_byte_array_append(bson->buf, data2, len2);
- }
- }
-
- /*
- * Append our trailing byte.
- */
- g_byte_array_append(bson->buf, &trailing, 1);
-
- /*
- * Update the document length of the buffer.
- */
- doc_len = GINT_TO_LE(bson->buf->len);
- memcpy(bson->buf->data, &doc_len, sizeof doc_len);
-}
-
-/**
- * mongo_bson_append_array:
- * @bson: (in): A #MongoBson.
- * @key: (in): The field name.
- * @value: (in): The #MongoBson array to append.
- *
- * Appends a #MongoBson containing an array. A #MongoBson array is a document
- * that contains fields with string keys containing integers incrementally.
- *
- * [[[
- * {"0": "First Value", "1": "Second Value"}
- * ]]]
- */
-void
-mongo_bson_append_array (MongoBson *bson,
- const gchar *key,
- MongoBson *value)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(value != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_ARRAY, key,
- value->buf->data, value->buf->len,
- NULL, 0);
-}
-
-/**
- * mongo_bson_append_boolean:
- * @bson: (in): A #MongoBson.
- * @key: (in): The string containing key.
- * @value: (in): A value to store in the document.
- *
- * Stores the value specified by @value as a boolean in the document
- * under @key.
- */
-void
-mongo_bson_append_boolean (MongoBson *bson,
- const gchar *key,
- gboolean value)
-{
- guint8 b = !!value;
-
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_BOOLEAN, key, &b, 1, NULL, 0);
-}
-
-/**
- * mongo_bson_append_bson:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @value: (in): A #MongoBson to store.
- *
- * Stores the #MongoBson in the document under @key.
- */
-void
-mongo_bson_append_bson (MongoBson *bson,
- const gchar *key,
- const MongoBson *value)
-{
- const guint8 *data;
- gsize data_len;
-
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(value != NULL);
-
- data = mongo_bson_get_data(value, &data_len);
- mongo_bson_append(bson, MONGO_BSON_DOCUMENT, key,
- data, data_len, NULL, 0);
-}
-
-#if GLIB_CHECK_VERSION(2, 26, 0)
-/**
- * mongo_bson_append_date_time:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @value: (in): A #GDateTime to store.
- *
- * Appends the #GDateTime to the #MongoBson under @key.
- */
-void
-mongo_bson_append_date_time (MongoBson *bson,
- const gchar *key,
- GDateTime *value)
-{
- GTimeVal tv;
-
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(value != NULL);
-
- if (!g_date_time_to_timeval(value, &tv)) {
- g_warning("GDateTime is outside of storable range, ignoring!");
- return;
- }
-
- mongo_bson_append_timeval(bson, key, &tv);
-}
-#endif
-
-/**
- * mongo_bson_append_double:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @value: (in): A #gdouble.
- *
- * Appends the #gdouble @value to the document under @key.
- */
-void
-mongo_bson_append_double (MongoBson *bson,
- const gchar *key,
- gdouble value)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_DOUBLE, key,
- (const guint8 *)&value, sizeof value,
- NULL, 0);
-}
-
-/**
- * mongo_bson_append_int:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @value: (in): A #gint32 containing the value.
- *
- * Appends @value to the document under @key.
- */
-void
-mongo_bson_append_int (MongoBson *bson,
- const gchar *key,
- gint32 value)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_INT32, key,
- (const guint8 *)&value, sizeof value,
- NULL, 0);
-}
-
-/**
- * mongo_bson_append_int64:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @value: (in): A #gint64 containing the value.
- *
- * Appends @value to the document under @key.
- */
-void
-mongo_bson_append_int64 (MongoBson *bson,
- const gchar *key,
- gint64 value)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_INT64, key,
- (const guint8 *)&value, sizeof value,
- NULL, 0);
-}
-
-/**
- * mongo_bson_append_null:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- *
- * Appends a %NULL value to the document under @key.
- */
-void
-mongo_bson_append_null (MongoBson *bson,
- const gchar *key)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_NULL, key, NULL, 0, NULL, 0);
-}
-
-/**
- * mongo_bson_append_object_id:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @object_id: (in): A #MongoObjectId.
- *
- * Appends @object_id to the document under @key.
- */
-void
-mongo_bson_append_object_id (MongoBson *bson,
- const gchar *key,
- const MongoObjectId *object_id)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(object_id != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_OBJECT_ID, key,
- (const guint8 *)object_id, 12,
- NULL, 0);
-}
-
-/**
- * mongo_bson_append_regex:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @regex: (in): A string containing a regex.
- * @options: (in): Options for the regex.
- *
- * Appends a regex to the document under @key.
- */
-void
-mongo_bson_append_regex (MongoBson *bson,
- const gchar *key,
- const gchar *regex,
- const gchar *options)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(regex != NULL);
-
- if (!options) {
- options = "";
- }
-
- mongo_bson_append(bson, MONGO_BSON_REGEX, key,
- (const guint8 *)regex, strlen(regex) + 1,
- (const guint8 *)options, strlen(options) + 1);
-}
-
-/**
- * mongo_bson_append_string:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @value: (in): A string containing the value.
- *
- * Stores the string @value in the document under @key.
- */
-void
-mongo_bson_append_string (MongoBson *bson,
- const gchar *key,
- const gchar *value)
-{
- guint32 value_len;
- guint32 value_len_swab;
-
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
- g_return_if_fail(g_utf8_validate(value, -1, NULL));
-
- value = value ? value : "";
- value_len = strlen(value) + 1;
- value_len_swab = GUINT32_TO_LE(value_len);
-
- mongo_bson_append(bson, MONGO_BSON_UTF8, key,
- (const guint8 *)&value_len_swab, sizeof value_len_swab,
- (const guint8 *)value, value_len);
-}
-
-/**
- * mongo_bson_append_timeval:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- * @value: (in): A #GTimeVal containing the date and time.
- *
- * Appends the date and time represented by @value up to milliseconds.
- * The value is stored in the document under @key.
- *
- * See also: mongo_bson_append_date_time().
- */
-void
-mongo_bson_append_timeval (MongoBson *bson,
- const gchar *key,
- GTimeVal *value)
-{
- guint64 msec;
-
- g_return_if_fail(bson);
- g_return_if_fail(key);
- g_return_if_fail(value);
-
- msec = (value->tv_sec * 1000) + (value->tv_usec / 1000);
- mongo_bson_append(bson, MONGO_BSON_DATE_TIME, key,
- (const guint8 *)&msec, sizeof msec,
- NULL, 0);
-}
-
-/**
- * mongo_bson_append_undefined:
- * @bson: (in): A #MongoBson.
- * @key: (in): A string containing the key.
- *
- * Appends a javascript "undefined" value in the document under @key.
- */
-void
-mongo_bson_append_undefined (MongoBson *bson,
- const gchar *key)
-{
- g_return_if_fail(bson != NULL);
- g_return_if_fail(key != NULL);
-
- mongo_bson_append(bson, MONGO_BSON_UNDEFINED, key,
- NULL, 0, NULL, 0);
-}
-
-/**
- * mongo_bson_iter_init:
- * @iter: an uninitialized #MongoBsonIter.
- * @bson: a #MongoBson.
- *
- * Initializes a #MongoBsonIter for iterating through a #MongoBson document.
- */
-void
-mongo_bson_iter_init (MongoBsonIter *iter,
- const MongoBson *bson)
-{
- g_return_if_fail(iter != NULL);
- g_return_if_fail(bson != NULL);
-
- memset(iter, 0, sizeof *iter);
- if (bson->static_data) {
- iter->user_data1 = (guint8 *)bson->static_data;
- iter->user_data2 = GINT_TO_POINTER(bson->static_len);
- } else {
- iter->user_data1 = bson->buf->data;
- iter->user_data2 = GINT_TO_POINTER(bson->buf->len);
- }
- iter->user_data3 = GINT_TO_POINTER(3); /* End of size buffer */
-}
-
-/**
- * mongo_bson_iter_set_trust_utf8:
- * @iter: (in): A #MongoBsonIter.
- * @trust_utf8: (in): If we should trust UTF-8.
- *
- * If the BSON document is known to have valid UTF-8 because it came
- * from a trusted source, then this may be used to disable UTF-8
- * validation. This can improve performance dramatically.
- */
-void
-mongo_bson_iter_set_trust_utf8 (MongoBsonIter *iter,
- gboolean trust_utf8)
-{
- g_return_if_fail(iter != NULL);
-
- if (trust_utf8) {
- iter->flags |= ITER_TRUST_UTF8;
- } else {
- iter->flags &= ~ITER_TRUST_UTF8;
- }
-}
-
-/**
- * mongo_bson_iter_find:
- * @iter: (in): A #MongoBsonIter.
- * @key: (in): A key to find in the BSON document.
- *
- * Iterates through all upcoming keys in a #MongoBsonIter until @key is
- * found or the end of the document has been reached.
- *
- * Returns: %TRUE if @key was found, otherwise %FALSE.
- */
-gboolean
-mongo_bson_iter_find (MongoBsonIter *iter,
- const gchar *key)
-{
- g_return_val_if_fail(iter != NULL, FALSE);
- g_return_val_if_fail(key != NULL, FALSE);
-
- while (mongo_bson_iter_next(iter)){
- if (!g_strcmp0(key, mongo_bson_iter_get_key(iter))) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- * mongo_bson_iter_get_key:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the key currently pointed to by @iter.
- *
- * Returns: A string containing the key.
- */
-const gchar *
-mongo_bson_iter_get_key (MongoBsonIter *iter)
-{
- g_return_val_if_fail(iter != NULL, NULL);
- return (const gchar *)iter->user_data4;
-}
-
-static MongoBson *
-mongo_bson_iter_get_value_document (MongoBsonIter *iter,
- MongoBsonType type)
-{
- const guint8 *buffer;
- gpointer endbuf;
- guint32 array_len;
-
- ENTRY;
-
- g_return_val_if_fail(iter != NULL, NULL);
- g_return_val_if_fail(iter->user_data1 != NULL, NULL);
- g_return_val_if_fail(iter->user_data2 != NULL, NULL);
- g_return_val_if_fail(iter->user_data6 != NULL, NULL);
- g_return_val_if_fail((type == MONGO_BSON_ARRAY) ||
- (type == MONGO_BSON_DOCUMENT), NULL);
-
- if (G_LIKELY(ITER_IS_TYPE(iter, type))) {
- endbuf = GSIZE_TO_POINTER(GPOINTER_TO_SIZE(iter->user_data1) +
- GPOINTER_TO_SIZE(iter->user_data2));
- if ((iter->user_data6 + 5) > endbuf) {
- return NULL;
- }
- memcpy(&array_len, iter->user_data6, sizeof array_len);
- array_len = GINT_FROM_LE(array_len);
- if ((iter->user_data6 + array_len) > endbuf) {
- return NULL;
- }
- buffer = iter->user_data6;
- return mongo_bson_new_from_data(buffer, array_len);
- }
-
- if (type == MONGO_BSON_ARRAY) {
- g_warning("Current key is not an array.");
- } else if (type == MONGO_BSON_DOCUMENT) {
- g_warning("Current key is not a document.");
- } else {
- g_assert_not_reached();
- }
-
- RETURN(NULL);
-}
-
-/**
- * mongo_bson_iter_get_value_array:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the array document current pointed to by @iter. This makes a
- * copy of the document and returns a new #MongoBson instance. For more
- * optimized cases, you may want to use mongo_bson_iter_recurse() to avoid
- * copying the memory if only iteration is needed.
- *
- * Returns: (transfer full): A #MongoBson.
- */
-MongoBson *
-mongo_bson_iter_get_value_array (MongoBsonIter *iter)
-{
- MongoBson *ret;
-
- ENTRY;
- ret = mongo_bson_iter_get_value_document(iter, MONGO_BSON_ARRAY);
- RETURN(ret);
-}
-
-/**
- * mongo_bson_iter_get_value_boolean:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the current value pointed to by the iterator, expecting it to
- * be a boolean.
- *
- * Returns: The current value.
- */
-gboolean
-mongo_bson_iter_get_value_boolean (MongoBsonIter *iter)
-{
- guint8 b;
-
- ENTRY;
-
- g_return_val_if_fail(iter, 0);
- g_return_val_if_fail(iter->user_data6, 0);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_BOOLEAN)) {
- memcpy(&b, iter->user_data6, sizeof b);
- RETURN(!!b);
- } else if (ITER_IS_TYPE(iter, MONGO_BSON_INT32)) {
- b = !!mongo_bson_iter_get_value_int(iter);
- RETURN(b);
- } else if (ITER_IS_TYPE(iter, MONGO_BSON_INT64)) {
- b = !!mongo_bson_iter_get_value_int64(iter);
- RETURN(b);
- } else if (ITER_IS_TYPE(iter, MONGO_BSON_DOUBLE)) {
- b = (mongo_bson_iter_get_value_double(iter) == 1.0);
- RETURN(b);
- }
-
- g_warning("Current key cannot be coerced to boolean.");
-
- RETURN(FALSE);
-}
-
-/**
- * mongo_bson_iter_get_value_bson:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the current value pointed to by @iter if it is a
- * %MONGO_BSON_DOCUMENT. The document is copied and returned as a new
- * #MongoBson instance. If you simply need to iterate the child document,
- * you may want to use mongo_bson_iter_recurse().
- *
- * Returns: (transfer full): A #MongoBson if successful; otherwise %NULL.
- */
-MongoBson *
-mongo_bson_iter_get_value_bson (MongoBsonIter *iter)
-{
- MongoBson *ret;
-
- ENTRY;
- ret = mongo_bson_iter_get_value_document(iter, MONGO_BSON_DOCUMENT);
- RETURN(ret);
-}
-
-#if GLIB_CHECK_VERSION(2, 26, 0)
-/**
- * mongo_bson_iter_get_value_date_time:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches a #GDateTime for the current value pointed to by @iter.
- *
- * Returns: A new #GDateTime which should be freed with g_date_time_unref().
- */
-GDateTime *
-mongo_bson_iter_get_value_date_time (MongoBsonIter *iter)
-{
- GTimeVal tv;
-
- g_return_val_if_fail(iter != NULL, NULL);
-
- mongo_bson_iter_get_value_timeval(iter, &tv);
- return g_date_time_new_from_timeval_utc(&tv);
-}
-#endif
-
-/**
- * mongo_bson_iter_get_value_double:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the current value pointed to by @iter if it is a
- * %MONGO_BSON_DOUBLE.
- *
- * Returns: A #gdouble.
- */
-gdouble
-mongo_bson_iter_get_value_double (MongoBsonIter *iter)
-{
- gdouble value;
-
- g_return_val_if_fail(iter != NULL, 0);
- g_return_val_if_fail(iter->user_data6 != NULL, 0);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_DOUBLE)) {
- memcpy(&value, iter->user_data6, sizeof value);
- return value;
- }
-
- g_warning("Current value is not a double.");
-
- return 0.0;
-}
-
-/**
- * mongo_bson_iter_get_value_object_id:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the current value pointed to by @iter if it is a
- * %MONGO_BSON_OBJECT_ID. The resulting #MongoObjectId should be freed
- * with mongo_object_id_free().
- *
- * Returns: (transfer full): A #MongoObjectId.
- */
-MongoObjectId *
-mongo_bson_iter_get_value_object_id (MongoBsonIter *iter)
-{
- g_return_val_if_fail(iter != NULL, NULL);
- g_return_val_if_fail(iter->user_data6 != NULL, NULL);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_OBJECT_ID)) {
- return mongo_object_id_new_from_data(iter->user_data6);
- }
-
- g_warning("Current value is not an ObjectId.");
-
- return NULL;
-}
-
-/**
- * mongo_bson_iter_get_value_int:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the current value pointed to by @iter if it is a
- * %MONGO_BSON_INT32.
- *
- * Returns: A #gint32 containing the value.
- */
-gint32
-mongo_bson_iter_get_value_int (MongoBsonIter *iter)
-{
- gint32 value;
-
- g_return_val_if_fail(iter != NULL, 0);
- g_return_val_if_fail(iter->user_data6 != NULL, 0);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_INT32)) {
- memcpy(&value, iter->user_data6, sizeof value);
- return GINT_FROM_LE(value);
- }
-
- g_warning("Current value is not an int32.");
-
- return 0;
-}
-
-/**
- * mongo_bson_iter_get_value_int64:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the current value pointed to by @iter if it is a
- * %MONGO_BSON_INT64.
- *
- * Returns: A #gint64.
- */
-gint64
-mongo_bson_iter_get_value_int64 (MongoBsonIter *iter)
-{
- gint64 value;
-
- g_return_val_if_fail(iter != NULL, 0L);
- g_return_val_if_fail(iter->user_data6 != NULL, 0L);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_INT64)) {
- memcpy(&value, iter->user_data6, sizeof value);
- return GINT64_FROM_LE(value);
- }
-
- g_warning("Current value is not an int64.");
-
- return 0L;
-}
-
-/**
- * mongo_bson_iter_get_value_regex:
- * @iter: (in): A #MongoBsonIter.
- * @regex: (out) (allow-none) (transfer none): A location for a string containing the regex.
- * @options: (out) (allow-none) (transfer none): A location for a string containing the options.
- *
- * Fetches the current value pointed to by @iter if it is a regex. The values
- * MUST NOT be modified or freed.
- */
-void
-mongo_bson_iter_get_value_regex (MongoBsonIter *iter,
- const gchar **regex,
- const gchar **options)
-{
- g_return_if_fail(iter != NULL);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_REGEX)) {
- if (regex) {
- *regex = iter->user_data6;
- }
- if (options) {
- *options = iter->user_data7;
- }
- return;
- }
-
- g_warning("Current value is not a Regex.");
-}
-
-/**
- * mongo_bson_iter_get_value_string:
- * @iter: (in): A #MongoBsonIter.
- * @length: (out) (allow-none): The length of the resulting string.
- *
- * Fetches the current value pointed to by @iter if it is a
- * %MONGO_BSON_UTF8. If @length is not %NULL, then the length of the
- * string will be stored in the location pointed to by @length.
- *
- * Returns: A string which should not be modified or freed.
- */
-const gchar *
-mongo_bson_iter_get_value_string (MongoBsonIter *iter,
- gsize *length)
-{
- gint32 real_length;
-
- g_return_val_if_fail(iter != NULL, NULL);
- g_return_val_if_fail(iter->user_data6 != NULL, NULL);
- g_return_val_if_fail(iter->user_data7 != NULL, NULL);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_UTF8)) {
- if (length) {
- memcpy(&real_length, iter->user_data6, sizeof real_length);
- if ((iter->flags & ITER_INVALID_UTF8)) {
- *length = strlen(iter->user_data7) + 1;
- } else {
- *length = GINT_FROM_LE(real_length);
- }
-
- }
- return iter->user_data7;
- }
-
- g_warning("Current value is not a String");
-
- return NULL;
-}
-
-/**
- * mongo_bson_iter_get_value_timeval:
- * @iter: (in): A #MongoBsonIter.
- * @value: (out): A location for a #GTimeVal.
- *
- * Fetches the current value pointed to by @iter as a #GTimeVal if the type
- * is a %MONGO_BSON_DATE_TIME.
- */
-void
-mongo_bson_iter_get_value_timeval (MongoBsonIter *iter,
- GTimeVal *value)
-{
- gint64 v_int64;
-
- g_return_if_fail(iter != NULL);
- g_return_if_fail(value != NULL);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_DATE_TIME)) {
- memcpy(&v_int64, iter->user_data6, sizeof v_int64);
- v_int64 = GINT64_FROM_LE(v_int64);
- value->tv_sec = v_int64 / 1000;
- value->tv_usec = v_int64 % 1000;
- return;
- }
-
- g_warning("Current value is not a DateTime");
-}
-
-/**
- * mongo_bson_iter_get_value_type:
- * @iter: (in): A #MongoBsonIter.
- *
- * Fetches the #MongoBsonType currently pointed to by @iter.
- *
- * Returns: A #MongoBsonType.
- */
-MongoBsonType
-mongo_bson_iter_get_value_type (MongoBsonIter *iter)
-{
- MongoBsonType type;
-
- g_return_val_if_fail(iter != NULL, 0);
- g_return_val_if_fail(iter->user_data5 != NULL, 0);
-
- type = GPOINTER_TO_INT(iter->user_data5);
-
- switch (type) {
- case MONGO_BSON_DOUBLE:
- case MONGO_BSON_UTF8:
- case MONGO_BSON_DOCUMENT:
- case MONGO_BSON_ARRAY:
- case MONGO_BSON_UNDEFINED:
- case MONGO_BSON_OBJECT_ID:
- case MONGO_BSON_BOOLEAN:
- case MONGO_BSON_DATE_TIME:
- case MONGO_BSON_NULL:
- case MONGO_BSON_REGEX:
- case MONGO_BSON_INT32:
- case MONGO_BSON_INT64:
- return type;
- default:
- g_warning("Unknown BSON type 0x%02x", type);
- return 0;
- }
-}
-
-/**
- * mongo_bson_iter_is_key:
- * @iter: (in): A #MongoBsonIter.
- * @key: (in): The key to check for.
- *
- * Checks to see if the iterator is on the given key.
- *
- * Returns: %TRUE if @iter is observing @key.
- */
-gboolean
-mongo_bson_iter_is_key (MongoBsonIter *iter,
- const gchar *key)
-{
- const gchar *current_key;
-
- g_return_val_if_fail(iter, FALSE);
- g_return_val_if_fail(key, FALSE);
-
- current_key = mongo_bson_iter_get_key(iter);
- return !g_strcmp0(key, current_key);
-}
-
-/**
- * mongo_bson_iter_recurse:
- * @iter: (in): A #MongoBsonIter.
- * @child: (out): A #MongoBsonIter.
- *
- * Recurses into the child BSON document found at the key currently observed
- * by the #MongoBsonIter. The @child #MongoBsonIter is initialized.
- *
- * Returns: %TRUE if @child is initialized; otherwise %FALSE.
- */
-gboolean
-mongo_bson_iter_recurse (MongoBsonIter *iter,
- MongoBsonIter *child)
-{
- gint32 buflen;
-
- g_return_val_if_fail(iter != NULL, FALSE);
- g_return_val_if_fail(iter != NULL, FALSE);
- g_return_val_if_fail(child != NULL, FALSE);
-
- if (ITER_IS_TYPE(iter, MONGO_BSON_ARRAY) ||
- ITER_IS_TYPE(iter, MONGO_BSON_DOCUMENT)) {
- memset(child, 0, sizeof *child);
- memcpy(&buflen, iter->user_data6, sizeof buflen);
- child->user_data1 = iter->user_data6;
- child->user_data2 = GINT_TO_POINTER(GINT_FROM_LE(buflen));
- child->user_data3 = GINT_TO_POINTER(3); /* End of size buffer */
- return TRUE;
- }
-
- g_warning("Current value is not a BSON document or array.");
-
- return FALSE;
-}
-
-static inline guint
-first_nul (const gchar *data,
- guint max_bytes)
-{
- guint i;
-
- for (i = 0; i < max_bytes; i++) {
- if (!data[i]) {
- return i;
- }
- }
-
- return 0;
-}
-
-/**
- * mongo_bson_iter_next:
- * @iter: (inout): A #MongoBsonIter.
- *
- * Moves @iter to the next field in the document. If no more fields exist,
- * then %FALSE is returned.
- *
- * Returns: %FALSE if there are no more fields or an error; otherwise %TRUE.
- */
-gboolean
-mongo_bson_iter_next (MongoBsonIter *iter)
-{
- const guint8 *rawbuf;
- gsize rawbuf_len;
- gsize offset;
- const gchar *key;
- MongoBsonType type;
- const guint8 *value1;
- const guint8 *value2;
- const gchar *end = NULL;
- guint32 max_len;
-
- ENTRY;
-
- g_return_val_if_fail(iter, FALSE);
-
- /*
- * Copy values onto stack from iter.
- */
- rawbuf = iter->user_data1;
- rawbuf_len = GPOINTER_TO_SIZE(iter->user_data2);
- offset = GPOINTER_TO_SIZE(iter->user_data3);
- key = (const gchar *)iter->user_data4;
- type = GPOINTER_TO_INT(iter->user_data5);
- value1 = (const guint8 *)iter->user_data6;
- value2 = (const guint8 *)iter->user_data7;
-
- /*
- * Unset the invalid utf8 field.
- */
- iter->flags &= ~ITER_INVALID_UTF8;
-
- /*
- * Check for end of buffer.
- */
- if ((offset + 1) >= rawbuf_len) {
- GOTO(failure);
- }
-
- /*
- * Get the type of the next field.
- */
- if (!(type = rawbuf[++offset])) {
- /*
- * This is the end of the iterator.
- */
- GOTO(failure);
- }
-
- /*
- * Get the key of the next field.
- */
- key = (const gchar *)&rawbuf[++offset];
- max_len = first_nul(key, rawbuf_len - offset - 1);
- if (!(iter->flags & ITER_TRUST_UTF8)) {
- if (!g_utf8_validate(key, max_len, &end)) {
- GOTO(failure);
- }
- }
- offset += strlen(key) + 1;
-
- switch (type) {
- case MONGO_BSON_UTF8:
- if ((offset + 5) < rawbuf_len) {
- value1 = &rawbuf[offset];
- offset += 4;
- value2 = &rawbuf[offset];
- max_len = GUINT32_FROM_LE(*(guint32 *)value1);
- if ((offset + max_len - 10) < rawbuf_len) {
- if (!(iter->flags & ITER_TRUST_UTF8)) {
- if ((end = (char *)u8_check((guint8 *)value2, max_len - 1))) {
- /*
- * Well, we have quite the delima here. The UTF-8 string is
- * invalid, but there was definitely a key here. Consumers
- * might need to get at data after this too. So the best
- * we can do is probably set the value to as long of a valid
- * utf-8 string as we can. We will simply NULL the end of
- * the buffer at the given error offset.
- */
- *(gchar *)end = '\0';
- offset += max_len - 1;
- iter->flags |= ITER_INVALID_UTF8;
- GOTO(success);
- }
- }
- offset += max_len - 1;
- if (value2[max_len - 1] == '\0') {
- GOTO(success);
- }
- }
- }
- GOTO(failure);
- case MONGO_BSON_DOCUMENT:
- case MONGO_BSON_ARRAY:
- if ((offset + 5) < rawbuf_len) {
- value1 = &rawbuf[offset];
- value2 = NULL;
- memcpy(&max_len, value1, sizeof max_len);
- max_len = GUINT32_FROM_LE(max_len);
- if ((offset + max_len) <= rawbuf_len) {
- offset += max_len - 1;
- GOTO(success);
- }
- }
- GOTO(failure);
- case MONGO_BSON_NULL:
- case MONGO_BSON_UNDEFINED:
- value1 = NULL;
- value2 = NULL;
- offset--;
- GOTO(success);
- case MONGO_BSON_OBJECT_ID:
- if ((offset + 12) < rawbuf_len) {
- value1 = &rawbuf[offset];
- value2 = NULL;
- offset += 11;
- GOTO(success);
- }
- GOTO(failure);
- case MONGO_BSON_BOOLEAN:
- if ((offset + 1) < rawbuf_len) {
- value1 = &rawbuf[offset];
- value2 = NULL;
- GOTO(success);
- }
- GOTO(failure);
- case MONGO_BSON_DATE_TIME:
- case MONGO_BSON_DOUBLE:
- case MONGO_BSON_INT64:
- if ((offset + 8) < rawbuf_len) {
- value1 = &rawbuf[offset];
- value2 = NULL;
- offset += 7;
- GOTO(success);
- }
- GOTO(failure);
- case MONGO_BSON_REGEX:
- value1 = &rawbuf[offset];
- max_len = first_nul((gchar *)value1, rawbuf_len - offset - 1);
- if (!(iter->flags & ITER_TRUST_UTF8)) {
- if (!g_utf8_validate((gchar *)value1, max_len, &end)) {
- GOTO(failure);
- }
- }
- offset += max_len + 1;
- if ((offset + 1) >= rawbuf_len) {
- GOTO(failure);
- }
- value2 = &rawbuf[offset];
- max_len = first_nul((gchar *)value2, rawbuf_len - offset - 1);
- if (!(iter->flags & ITER_TRUST_UTF8)) {
- if (!g_utf8_validate((gchar *)value2, max_len, &end)) {
- GOTO(failure);
- }
- }
- offset += max_len + 1;
- GOTO(success);
- case MONGO_BSON_INT32:
- if ((offset + 4) < rawbuf_len) {
- value1 = &rawbuf[offset];
- value2 = NULL;
- offset += 3;
- GOTO(success);
- }
- GOTO(failure);
- default:
- g_warning("Unknown type: %d key: %s", type, key);
- GOTO(failure);
- }
-
-success:
- iter->user_data3 = GSIZE_TO_POINTER(offset);
- iter->user_data4 = (gpointer)key;
- iter->user_data5 = GINT_TO_POINTER(type);
- iter->user_data6 = (gpointer)value1;
- iter->user_data7 = (gpointer)value2;
- RETURN(TRUE);
-
-failure:
- memset(iter, 0, sizeof *iter);
- RETURN(FALSE);
-}
-
-/**
- * mongo_clear_bson:
- * @bson: (inout) (allow-none): A pointer to a #MongoBson or %NULL.
- *
- * If @bson is a pointer to a #MongoBson, it will be freed and zeroed.
- */
-void
-mongo_clear_bson (MongoBson **bson)
-{
- if (bson && *bson) {
- mongo_bson_unref(*bson);
- *bson = NULL;
- }
-}
-
-/**
- * mongo_bson_to_string:
- * @bson: A #MongoBson.
- * @is_array: If the document should be generated as an array.
- *
- * Build a string representing the BSON document. Since BSON documents are
- * used for both documents and arrays, you can change the format using
- * @is_array.
- *
- * Returns: (transfer full): A string representing the BSON document.
- */
-gchar *
-mongo_bson_to_string (const MongoBson *bson,
- gboolean is_array)
-{
- MongoBsonIter iter;
- MongoBsonType type;
- GString *str;
- gchar *esc;
-
-
- g_return_val_if_fail(bson, NULL);
-
- str = g_string_new(is_array ? "[" : "{");
-
- mongo_bson_iter_init(&iter, bson);
- if (mongo_bson_iter_next(&iter)) {
-again:
- if (!is_array) {
- esc = g_strescape(mongo_bson_iter_get_key(&iter), NULL);
- g_string_append_printf(str, "\"%s\": ", esc);
- g_free(esc);
-
- }
- type = mongo_bson_iter_get_value_type(&iter);
- switch (type) {
- case MONGO_BSON_DOUBLE:
- g_string_append_printf(str, "%f",
- mongo_bson_iter_get_value_double(&iter));
- break;
- case MONGO_BSON_DATE_TIME:
- {
- GTimeVal tv = { 0 };
- gchar *dstr;
-
- mongo_bson_iter_get_value_timeval(&iter, &tv);
- dstr = g_time_val_to_iso8601(&tv);
- g_string_append_printf(str, "ISODate(\"%s\")", dstr);
- g_free(dstr);
- }
- break;
- case MONGO_BSON_INT32:
- g_string_append_printf(str, "NumberLong(%d)",
- mongo_bson_iter_get_value_int(&iter));
- break;
- case MONGO_BSON_INT64:
- g_string_append_printf(str, "NumberLong(%"G_GINT64_FORMAT")",
- mongo_bson_iter_get_value_int64(&iter));
- break;
- case MONGO_BSON_UTF8:
- esc = g_strescape(mongo_bson_iter_get_value_string(&iter, NULL), NULL);
- g_string_append_printf(str, "\"%s\"", esc);
- g_free(esc);
- break;
- case MONGO_BSON_ARRAY:
- {
- MongoBson *child;
- gchar *childstr;
-
- if ((child = mongo_bson_iter_get_value_array(&iter))) {
- childstr = mongo_bson_to_string(child, TRUE);
- g_string_append(str, childstr);
- mongo_bson_unref(child);
- g_free(childstr);
- }
- }
- break;
- case MONGO_BSON_DOCUMENT:
- {
- MongoBson *child;
- gchar *childstr;
-
- if ((child = mongo_bson_iter_get_value_bson(&iter))) {
- childstr = mongo_bson_to_string(child, FALSE);
- g_string_append(str, childstr);
- mongo_bson_unref(child);
- g_free(childstr);
- }
- }
- break;
- case MONGO_BSON_BOOLEAN:
- g_string_append_printf(str,
- mongo_bson_iter_get_value_boolean(&iter) ? "true" : "false");
- break;
- case MONGO_BSON_OBJECT_ID:
- {
- MongoObjectId *id;
- gchar *idstr;
-
- id = mongo_bson_iter_get_value_object_id(&iter);
- idstr = mongo_object_id_to_string(id);
- g_string_append_printf(str, "ObjectId(\"%s\")", idstr);
- mongo_object_id_free(id);
- g_free(idstr);
- }
- break;
- case MONGO_BSON_NULL:
- g_string_append(str, "null");
- break;
- case MONGO_BSON_REGEX:
- /* TODO: */
- g_assert_not_reached();
- break;
- case MONGO_BSON_UNDEFINED:
- g_string_append(str, "undefined");
- break;
- default:
- g_assert_not_reached();
- }
-
- if (mongo_bson_iter_next(&iter)) {
- g_string_append(str, ", ");
- goto again;
- }
- }
-
- g_string_append(str, is_array ? "]" : "}");
-
- return g_string_free(str, FALSE);
-}
-
-/**
- * mongo_bson_join:
- * @bson: (in): A #MongoBson.
- * @other: (in): A #MongoBson.
- *
- * Appends the contents of @other to the end of @bson.
- */
-void
-mongo_bson_join (MongoBson *bson,
- const MongoBson *other)
-{
- const guint8 *other_data;
- guint32 new_size;
- gsize other_len;
- guint offset;
-
- g_return_if_fail(bson);
- g_return_if_fail(other);
-
- if (!bson->buf) {
- g_warning("Cannot join BSON document to static BSON.");
- return;
- }
-
- g_assert(bson->buf->len >= 5);
-
- other_data = mongo_bson_get_data(other, &other_len);
- g_assert_cmpint(other_len, >=, 5);
-
- offset = bson->buf->len - 1;
- g_byte_array_set_size(bson->buf, bson->buf->len + other_len - 5);
- memcpy(&bson->buf->data[offset], other_data + 4, other_len - 4);
-
- new_size = GUINT32_TO_LE(bson->buf->len);
- memcpy(bson->buf->data, &new_size, sizeof new_size);
-}
+++ /dev/null
-/* mongo-bson.h
- *
- * Copyright (C) 2011 Christian Hergert <christian@catch.com>
- *
- * This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This file 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#if !defined (MONGO_INSIDE) && !defined (MONGO_COMPILATION)
-#error "Only <mongo-glib/mongo-glib.h> can be included directly."
-#endif
-
-#ifndef MONGO_BSON_H
-#define MONGO_BSON_H
-
-#include <glib-object.h>
-
-#include "mongo-object-id.h"
-
-G_BEGIN_DECLS
-
-#define MONGO_TYPE_BSON (mongo_bson_get_type())
-#define MONGO_TYPE_BSON_TYPE (mongo_bson_type_get_type())
-
-/**
- * MONGO_BSON_ITER_HOLDS:
- * @b: A #MongoBsonIter.
- * @t: A #MongoBsonType.
- *
- * Checks to see if @b is pointing at a field of type @t. This is
- * syntacticaly the same as checking the fields value type with
- * mongo_bson_iter_get_value_type().
- *
- * Returns: %TRUE if @b holds the requested type.
- */
-#define MONGO_BSON_ITER_HOLDS(b,t) \
- (mongo_bson_iter_get_value_type((b)) == t)
-
-/**
- * MONGO_BSON_ITER_HOLDS_DOUBLE:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_DOUBLE.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_DOUBLE(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_DOUBLE))
-
-/**
- * MONGO_BSON_ITER_HOLDS_UTF8:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_UTF8.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_UTF8(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_UTF8))
-
-/**
- * MONGO_BSON_ITER_HOLDS_DOCUMENT:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_DOCUMENT.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_DOCUMENT(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_DOCUMENT))
-
-/**
- * MONGO_BSON_ITER_HOLDS_ARRAY:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_ARRAY.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_ARRAY(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_ARRAY))
-
-/**
- * MONGO_BSON_ITER_HOLDS_UNDEFINED:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_UNDEFINED.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_UNDEFINED(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_UNDEFINED))
-
-/**
- * MONGO_BSON_ITER_HOLDS_OBJECT_ID:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_OBJECT_ID.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_OBJECT_ID(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_OBJECT_ID))
-
-/**
- * MONGO_BSON_ITER_HOLDS_BOOLEAN:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_BOOLEAN.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_BOOLEAN(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_BOOLEAN))
-
-/**
- * MONGO_BSON_ITER_HOLDS_DATE_TIME:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_DATE_TIME.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_DATE_TIME(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_DATE_TIME))
-
-/**
- * MONGO_BSON_ITER_HOLDS_NULL:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_NULL.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_NULL(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_NULL))
-
-/**
- * MONGO_BSON_ITER_HOLDS_REGEX:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_REGEX.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_REGEX(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_REGEX))
-
-/**
- * MONGO_BSON_ITER_HOLDS_INT32:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_INT32.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_INT32(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_INT32))
-
-/**
- * MONGO_BSON_ITER_HOLDS_INT64:
- * @b: A #MongoBsonIter.
- *
- * Checks to see if @b is pointing at a field of type %MONGO_BSON_INT64.
- *
- * Returns: %TRUE if the type matches.
- */
-#define MONGO_BSON_ITER_HOLDS_INT64(b) \
- (MONGO_BSON_ITER_HOLDS(b, MONGO_BSON_INT64))
-
-typedef struct _MongoBson MongoBson;
-
-/**
- * MongoBsonType:
- * @MONGO_BSON_DOUBLE: Field contains a #gdouble.
- * @MONGO_BSON_UTF8: Field contains a UTF-8 string.
- * @MONGO_BSON_DOCUMENT: Field contains a BSON document.
- * @MONGO_BSON_ARRAY: Field contains a BSON array.
- * @MONGO_BSON_UNDEFINED: Field is JavaScript undefined.
- * @MONGO_BSON_OBJECT_ID: Field contains a #MongoObjectId.
- * @MONGO_BSON_BOOLEAN: Field contains a #gboolean.
- * @MONGO_BSON_DATE_TIME: Field contains a #GDateTime.
- * @MONGO_BSON_NULL: Field contains %NULL.
- * @MONGO_BSON_REGEX: Field contains a #GRegex.
- * @MONGO_BSON_INT32: Field contains a #gint32.
- * @MONGO_BSON_INT64: Field contains a #gint64.
- *
- * These enumerations specify the field type within a #MongoBson.
- * The field type can be retrieved with mongo_bson_iter_get_value_type().
- */
-typedef enum
-{
- MONGO_BSON_DOUBLE = 0x01,
- MONGO_BSON_UTF8 = 0x02,
- MONGO_BSON_DOCUMENT = 0x03,
- MONGO_BSON_ARRAY = 0x04,
- MONGO_BSON_UNDEFINED = 0x06,
- MONGO_BSON_OBJECT_ID = 0x07,
- MONGO_BSON_BOOLEAN = 0x08,
- MONGO_BSON_DATE_TIME = 0x09,
- MONGO_BSON_NULL = 0x0A,
- MONGO_BSON_REGEX = 0x0B,
- MONGO_BSON_INT32 = 0x10,
- MONGO_BSON_INT64 = 0x12,
-} MongoBsonType;
-
-/**
- * MongoBsonIter:
- *
- * #MongoBsonIter is used to iterate through the contents of a #MongoBson.
- * It is meant to be used on the stack and can allow for reading data
- * directly out of the #MongoBson without having to malloc a copy. This
- * can be handy when dealing with lots of medium to large sized documents.
- */
-typedef struct
-{
- /*< private >*/
- gpointer user_data1; /* Raw data buffer */
- gpointer user_data2; /* Raw buffer length */
- gpointer user_data3; /* Offset */
- gpointer user_data4; /* Key */
- gpointer user_data5; /* Type */
- gpointer user_data6; /* Value1 */
- gpointer user_data7; /* Value2 */
- gint32 flags;
-} MongoBsonIter;
-
-GType mongo_bson_get_type (void) G_GNUC_CONST;
-GType mongo_bson_type_get_type (void) G_GNUC_CONST;
-const guint8 *mongo_bson_get_data (const MongoBson *bson,
- gsize *length);
-gsize mongo_bson_get_size (const MongoBson *bson);
-MongoBson *mongo_bson_new (void);
-MongoBson *mongo_bson_new_empty (void);
-MongoBson *mongo_bson_new_from_data (const guint8 *buffer,
- gsize length);
-MongoBson *mongo_bson_new_take_data (guint8 *buffer,
- gsize length);
-MongoBson *mongo_bson_new_from_static_data (guint8 *buffer,
- gsize length,
- GDestroyNotify notify);
-MongoBson *mongo_bson_dup (const MongoBson *bson);
-MongoBson *mongo_bson_ref (MongoBson *bson);
-void mongo_bson_unref (MongoBson *bson);
-void mongo_bson_append_array (MongoBson *bson,
- const gchar *key,
- MongoBson *value);
-void mongo_bson_append_boolean (MongoBson *bson,
- const gchar *key,
- gboolean value);
-void mongo_bson_append_bson (MongoBson *bson,
- const gchar *key,
- const MongoBson *value);
-#if GLIB_CHECK_VERSION(2, 26, 0)
-void mongo_bson_append_date_time (MongoBson *bson,
- const gchar *key,
- GDateTime *value);
-#endif
-void mongo_bson_append_double (MongoBson *bson,
- const gchar *key,
- gdouble value);
-void mongo_bson_append_int (MongoBson *bson,
- const gchar *key,
- gint32 value);
-void mongo_bson_append_int64 (MongoBson *bson,
- const gchar *key,
- gint64 value);
-void mongo_bson_append_null (MongoBson *bson,
- const gchar *key);
-void mongo_bson_append_object_id (MongoBson *bson,
- const gchar *key,
- const MongoObjectId *object_id);
-void mongo_bson_append_regex (MongoBson *bson,
- const gchar *key,
- const gchar *regex,
- const gchar *options);
-void mongo_bson_append_string (MongoBson *bson,
- const gchar *key,
- const gchar *value);
-void mongo_bson_append_timeval (MongoBson *bson,
- const gchar *key,
- GTimeVal *value);
-void mongo_bson_append_undefined (MongoBson *bson,
- const gchar *key);
-gboolean mongo_bson_get_empty (MongoBson *bson);
-void mongo_bson_join (MongoBson *bson,
- const MongoBson *other);
-void mongo_bson_iter_init (MongoBsonIter *iter,
- const MongoBson *bson);
-gboolean mongo_bson_iter_find (MongoBsonIter *iter,
- const gchar *key);
-const gchar *mongo_bson_iter_get_key (MongoBsonIter *iter);
-MongoBson *mongo_bson_iter_get_value_array (MongoBsonIter *iter);
-gboolean mongo_bson_iter_get_value_boolean (MongoBsonIter *iter);
-MongoBson *mongo_bson_iter_get_value_bson (MongoBsonIter *iter);
-#if GLIB_CHECK_VERSION(2, 26, 0)
-GDateTime *mongo_bson_iter_get_value_date_time (MongoBsonIter *iter);
-#endif
-gdouble mongo_bson_iter_get_value_double (MongoBsonIter *iter);
-MongoObjectId *mongo_bson_iter_get_value_object_id (MongoBsonIter *iter);
-gint32 mongo_bson_iter_get_value_int (MongoBsonIter *iter);
-gint64 mongo_bson_iter_get_value_int64 (MongoBsonIter *iter);
-void mongo_bson_iter_get_value_regex (MongoBsonIter *iter,
- const gchar **regex,
- const gchar **options);
-const gchar *mongo_bson_iter_get_value_string (MongoBsonIter *iter,
- gsize *length);
-void mongo_bson_iter_get_value_timeval (MongoBsonIter *iter,
- GTimeVal *value);
-MongoBsonType mongo_bson_iter_get_value_type (MongoBsonIter *iter);
-gboolean mongo_bson_iter_is_key (MongoBsonIter *iter,
- const gchar *key);
-gboolean mongo_bson_iter_next (MongoBsonIter *iter);
-gboolean mongo_bson_iter_recurse (MongoBsonIter *iter,
- MongoBsonIter *child);
-void mongo_bson_iter_set_trust_utf8 (MongoBsonIter *iter,
- gboolean trust_utf8);
-gchar *mongo_bson_to_string (const MongoBson *bson,
- gboolean is_array);
-void mongo_clear_bson (MongoBson **bson);
-
-
-G_END_DECLS
-
-#endif /* MONGO_BSON_H */
-
+++ /dev/null
-/* mongo-object-id.c
- *
- * Copyright (C) 2011 Christian Hergert <christian@catch.com>
- *
- * This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This file 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "maru_common.h"
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef CONFIG_WIN32
-#include <windows.h>
-#include <winsock2.h>
-#endif
-#include "mongo-object-id.h"
-
-#ifndef HOST_NAME_MAX
-#define HOST_NAME_MAX 256
-#endif
-
-/**
- * SECTION:mongo-object-id
- * @title: MongoObjectId
- * @short_description: ObjectId structure used by BSON and Mongo.
- *
- * #MongoObjectId represents an ObjectId as used by the BSON serialization
- * format and Mongo. It is a 12-byte structure designed in a way to allow
- * client side generation of unique object identifiers. The first 4 bytes
- * contain the UNIX timestamp since January 1, 1970. The following 3 bytes
- * contain the first 3 bytes of the hostname MD5 hashed. Following that are
- * 2 bytes containing the Process ID or Thread ID. The last 3 bytes contain
- * a continually incrementing counter.
- *
- * When creating a new #MongoObjectId using mongo_object_id_new(), all of
- * this data is created for you.
- *
- * To create a #MongoObjectId from an existing 12 bytes, use
- * mongo_object_id_new_from_data().
- *
- * To free an allocated #MongoObjectId, use mongo_object_id_free().
- */
-
-struct _MongoObjectId
-{
- guint8 data[12];
-};
-
-static guint8 gMachineId[3];
-static gushort gPid;
-static gint32 gIncrement;
-
-static void
-mongo_object_id_init (void)
-{
- gchar hostname[HOST_NAME_MAX] = { 0 };
- char *md5;
- int ret;
-
- if (0 != (ret = gethostname(hostname, sizeof hostname - 1))) {
- g_error("Failed to get hostname, cannot generate MongoObjectId");
- }
-
- md5 = g_compute_checksum_for_string(G_CHECKSUM_MD5, hostname,
- sizeof hostname);
- memcpy(gMachineId, md5, sizeof gMachineId);
- g_free(md5);
-
- gPid = (gushort)getpid();
-}
-
-/**
- * mongo_object_id_new:
- *
- * Create a new #MongoObjectId. The timestamp, PID, hostname, and counter
- * fields of the #MongoObjectId will be generated.
- *
- * Returns: (transfer full): A #MongoObjectId that should be freed with
- * mongo_object_id_free().
- */
-MongoObjectId *
-mongo_object_id_new (void)
-{
- static gsize initialized = FALSE;
- GTimeVal val = { 0 };
- guint32 t;
- guint8 bytes[12];
- gint32 inc;
-
- if (g_once_init_enter(&initialized)) {
- mongo_object_id_init();
- g_once_init_leave(&initialized, TRUE);
- }
-
- g_get_current_time(&val);
- t = GUINT32_TO_BE(val.tv_sec);
- if(!GLIB_CHECK_VERSION(2, 30, 0)) {
- inc = GUINT32_TO_BE(g_atomic_int_add(&gIncrement, 1));
- }
- else {
- inc = GUINT32_TO_BE(g_atomic_int_exchange_and_add(&gIncrement, 1));
- }
-
- memcpy(&bytes[0], &t, sizeof t);
- memcpy(&bytes[4], &gMachineId, sizeof gMachineId);
- memcpy(&bytes[7], &gPid, sizeof gPid);
- bytes[9] = ((guint8 *)&inc)[1];
- bytes[10] = ((guint8 *)&inc)[2];
- bytes[11] = ((guint8 *)&inc)[3];
-
- return mongo_object_id_new_from_data(bytes);
-}
-
-/**
- * mongo_object_id_new_from_data:
- * @bytes: (array): The bytes containing the object id.
- *
- * Creates a new #MongoObjectId from an array of 12 bytes. @bytes
- * MUST contain 12-bytes.
- *
- * Returns: (transfer full): A newly allocated #MongoObjectId that should
- * be freed with mongo_object_id_free().
- */
-MongoObjectId *
-mongo_object_id_new_from_data (const guint8 *bytes)
-{
- MongoObjectId *object_id;
-
- object_id = g_slice_new0(MongoObjectId);
-
- if (bytes) {
- memcpy(object_id, bytes, sizeof *object_id);
- }
-
- return object_id;
-}
-
-/**
- * mongo_object_id_new_from_string:
- * @string: A 24-character string containing the object id.
- *
- * Creates a new #MongoObjectId from a 24-character, hex-encoded, string.
- *
- * Returns: A newly created #MongoObjectId if successful; otherwise %NULL.
- */
-MongoObjectId *
-mongo_object_id_new_from_string (const gchar *string)
-{
- guint32 v;
- guint8 data[12] = { 0 };
- guint i;
-
- g_return_val_if_fail(string, NULL);
-
- if (strlen(string) != 24) {
- return NULL;
- }
-
- for (i = 0; i < 12; i++) {
- sscanf(&string[i * 2], "%02x", &v);
- data[i] = v;
- }
-
- return mongo_object_id_new_from_data(data);
-}
-
-/**
- * mongo_object_id_to_string:
- * @object_id: (in): A #MongoObjectId.
- *
- * Converts @object_id into a hex string.
- *
- * Returns: (transfer full): The ObjectId as a string.
- */
-gchar *
-mongo_object_id_to_string (const MongoObjectId *object_id)
-{
- GString *str;
- guint i;
-
- g_return_val_if_fail(object_id, NULL);
-
- str = g_string_sized_new(24);
- for (i = 0; i < sizeof object_id->data; i++) {
- g_string_append_printf(str, "%02x", object_id->data[i]);
- }
-
- return g_string_free(str, FALSE);
-}
-
-/**
- * mongo_object_id_copy:
- * @object_id: (in): A #MongoObjectId.
- *
- * Creates a new #MongoObjectId that is a copy of @object_id.
- *
- * Returns: (transfer full): A #MongoObjectId that should be freed with
- * mongo_object_id_free().
- */
-MongoObjectId *
-mongo_object_id_copy (const MongoObjectId *object_id)
-{
- MongoObjectId *copy = NULL;
-
- if (object_id) {
- copy = g_slice_new(MongoObjectId);
- memcpy(copy, object_id, sizeof *object_id);
- }
-
- return copy;
-}
-
-/**
- * mongo_object_id_compare:
- * @object_id: (in): The first #MongoObjectId.
- * @other: (in): The second #MongoObjectId.
- *
- * A qsort() style compare function that will return less than zero
- * if @object_id is less than @other, zero if they are the same, and
- * greater than one if @other is greater than @object_id.
- *
- * Returns: A qsort() style compare integer.
- */
-gint
-mongo_object_id_compare (const MongoObjectId *object_id,
- const MongoObjectId *other)
-{
- return memcmp(object_id, other, sizeof object_id->data);
-}
-
-/**
- * mongo_object_id_equal:
- * @v1: (in): A #MongoObjectId.
- * @v2: (in): A #MongoObjectId.
- *
- * Checks if @v1 and @v2 contain the same object id.
- *
- * Returns: %TRUE if @v1 and @v2 are equal.
- */
-gboolean
-mongo_object_id_equal (gconstpointer v1,
- gconstpointer v2)
-{
- return !mongo_object_id_compare(v1, v2);
-}
-
-/**
- * mongo_object_id_hash:
- * @v: (in): A #MongoObjectId.
- *
- * Hashes the bytes of the provided #MongoObjectId using DJB hash.
- * This is suitable for using as a hash function for #GHashTable.
- *
- * Returns: A hash value corresponding to the key.
- */
-guint
-mongo_object_id_hash (gconstpointer v)
-{
- const MongoObjectId *object_id = v;
- guint hash = 5381;
- guint i;
-
- g_return_val_if_fail(object_id, 5381);
-
- for (i = 0; i < G_N_ELEMENTS(object_id->data); i++) {
- hash = ((hash << 5) + hash) + object_id->data[i];
- }
-
- return hash;
-}
-
-/**
- * mongo_object_id_get_data:
- * @object_id: (in): A #MongoObjectId.
- * @length: (out) (allow-none): Then number of bytes returned.
- *
- * Gets the raw bytes for the object id. The length of the bytes is
- * returned in the out paramter @length for language bindings and
- * is always 12.
- *
- * Returns: (transfer none) (array length=length): The object id bytes.
- */
-const guint8 *
-mongo_object_id_get_data (const MongoObjectId *object_id,
- gsize *length)
-{
- g_return_val_if_fail(object_id, NULL);
- if (length)
- *length = sizeof object_id->data;
- return object_id->data;
-}
-
-/**
- * mongo_object_id_free:
- * @object_id: (in): A #MongoObjectId.
- *
- * Frees a #MongoObjectId.
- */
-void
-mongo_object_id_free (MongoObjectId *object_id)
-{
- if (object_id) {
- g_slice_free(MongoObjectId, object_id);
- }
-}
-
-/**
- * mongo_clear_object_id:
- * @object_id: (out): A pointer to a #MongoObjectId.
- *
- * Clears the pointer to a #MongoObjectId by freeing the #MongoObjectId
- * and then setting the pointer to %NULL. If no #MongoObjectId was found,
- * then no operation is performed.
- */
-void
-mongo_clear_object_id (MongoObjectId **object_id)
-{
- if (object_id && *object_id) {
- mongo_object_id_free(*object_id);
- *object_id = NULL;
- }
-}
-
-/**
- * mongo_object_id_get_type:
- *
- * Fetches the boxed #GType for #MongoObjectId.
- *
- * Returns: A #GType.
- */
-GType
-mongo_object_id_get_type (void)
-{
- static GType type_id = 0;
- static gsize initialized = FALSE;
-
- if (g_once_init_enter(&initialized)) {
- type_id = g_boxed_type_register_static(
- "MongoObjectId",
- (GBoxedCopyFunc)mongo_object_id_copy,
- (GBoxedFreeFunc)mongo_object_id_free);
- g_once_init_leave(&initialized, TRUE);
- }
-
- return type_id;
-}