libmongo-client 0.1.4
src/bson.c
Go to the documentation of this file.
00001 /* bson.c - libmongo-client's BSON implementation
00002  * Copyright 2011 Gergely Nagy <algernon@balabit.hu>
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00021 #include <glib.h>
00022 #include <errno.h>
00023 #include <string.h>
00024 #include <stdarg.h>
00025 
00026 #include "bson.h"
00027 #include "libmongo-macros.h"
00028 #include "libmongo-private.h"
00029 
00032 struct _bson_cursor
00033 {
00034   const bson *obj; 
00035   const gchar *key; 
00037   size_t pos; 
00039   size_t value_pos; 
00042 };
00043 
00049 static inline void
00050 _bson_append_byte (bson *b, const guint8 byte)
00051 {
00052   b->data = g_byte_array_append (b->data, &byte, sizeof (byte));
00053 }
00054 
00060 static inline void
00061 _bson_append_int32 (bson *b, const gint32 i)
00062 {
00063   b->data = g_byte_array_append (b->data, (const guint8 *)&i, sizeof (gint32));
00064 }
00065 
00071 static inline void
00072 _bson_append_int64 (bson *b, const gint64 i)
00073 {
00074   b->data = g_byte_array_append (b->data, (const guint8 *)&i, sizeof (gint64));
00075 }
00076 
00089 static inline gboolean
00090 _bson_append_element_header (bson *b, bson_type type, const gchar *name)
00091 {
00092   if (!name || !b)
00093     return FALSE;
00094 
00095   if (b->finished)
00096     return FALSE;
00097 
00098   _bson_append_byte (b, (guint8) type);
00099   b->data = g_byte_array_append (b->data, (const guint8 *)name,
00100                                  strlen (name) + 1);
00101 
00102   return TRUE;
00103 }
00104 
00122 static gboolean
00123 _bson_append_string_element (bson *b, bson_type type, const gchar *name,
00124                              const gchar *val, gint32 length)
00125 {
00126   size_t len;
00127 
00128   if (!val || !length || length < -1)
00129     return FALSE;
00130 
00131   len = (length != -1) ? (size_t)length + 1: strlen (val) + 1;
00132 
00133   if (!_bson_append_element_header (b, type, name))
00134     return FALSE;
00135 
00136   _bson_append_int32 (b, GINT32_TO_LE (len));
00137 
00138   b->data = g_byte_array_append (b->data, (const guint8 *)val, len - 1);
00139   _bson_append_byte (b, 0);
00140 
00141   return TRUE;
00142 }
00143 
00161 static gboolean
00162 _bson_append_document_element (bson *b, bson_type type, const gchar *name,
00163                                const bson *doc)
00164 {
00165   if (bson_size (doc) < 0)
00166     return FALSE;
00167 
00168   if (!_bson_append_element_header (b, type, name))
00169     return FALSE;
00170 
00171   b->data = g_byte_array_append (b->data, bson_data (doc), bson_size (doc));
00172   return TRUE;
00173 }
00174 
00184 static inline gboolean
00185 _bson_append_int64_element (bson *b, bson_type type, const gchar *name,
00186                             gint64 i)
00187 {
00188   if (!_bson_append_element_header (b, type, name))
00189     return FALSE;
00190 
00191   _bson_append_int64 (b, GINT64_TO_LE (i));
00192   return TRUE;
00193 }
00194 
00195 /********************
00196  * Public interface *
00197  ********************/
00198 
00199 const gchar *
00200 bson_type_as_string (bson_type type)
00201 {
00202   switch (type)
00203     {
00204     case BSON_TYPE_NONE:
00205       return "BSON_TYPE_NONE";
00206     case BSON_TYPE_DOUBLE:
00207       return "BSON_TYPE_DOUBLE";
00208     case BSON_TYPE_STRING:
00209       return "BSON_TYPE_STRING";
00210     case BSON_TYPE_DOCUMENT:
00211       return "BSON_TYPE_DOCUMENT";
00212     case BSON_TYPE_ARRAY:
00213       return "BSON_TYPE_ARRAY";
00214     case BSON_TYPE_BINARY:
00215       return "BSON_TYPE_BINARY";
00216     case BSON_TYPE_UNDEFINED:
00217       return "BSON_TYPE_UNDEFINED";
00218     case BSON_TYPE_OID:
00219       return "BSON_TYPE_OID";
00220     case BSON_TYPE_BOOLEAN:
00221       return "BSON_TYPE_BOOLEAN";
00222     case BSON_TYPE_UTC_DATETIME:
00223       return "BSON_TYPE_UTC_DATETIME";
00224     case BSON_TYPE_NULL:
00225       return "BSON_TYPE_NULL";
00226     case BSON_TYPE_REGEXP:
00227       return "BSON_TYPE_REGEXP";
00228     case BSON_TYPE_DBPOINTER:
00229       return "BSON_TYPE_DBPOINTER";
00230     case BSON_TYPE_JS_CODE:
00231       return "BSON_TYPE_JS_CODE";
00232     case BSON_TYPE_SYMBOL:
00233       return "BSON_TYPE_SYMBOL";
00234     case BSON_TYPE_JS_CODE_W_SCOPE:
00235       return "BSON_TYPE_JS_CODE_W_SCOPE";
00236     case BSON_TYPE_INT32:
00237       return "BSON_TYPE_INT32";
00238     case BSON_TYPE_TIMESTAMP:
00239       return "BSON_TYPE_TIMESTAMP";
00240     case BSON_TYPE_INT64:
00241       return "BSON_TYPE_INT64";
00242     case BSON_TYPE_MIN:
00243       return "BSON_TYPE_MIN";
00244     case BSON_TYPE_MAX:
00245       return "BSON_TYPE_MAX";
00246     default:
00247       return NULL;
00248   }
00249 }
00250 
00251 bson *
00252 bson_new (void)
00253 {
00254   return bson_new_sized (0);
00255 }
00256 
00257 bson *
00258 bson_new_sized (gint32 size)
00259 {
00260   bson *b = g_new0 (bson, 1);
00261 
00262   b->data = g_byte_array_sized_new (size + sizeof (gint32) + sizeof (guint8));
00263   _bson_append_int32 (b, 0);
00264 
00265   return b;
00266 }
00267 
00268 bson *
00269 bson_new_from_data (const guint8 *data, gint32 size)
00270 {
00271   bson *b;
00272 
00273   if (!data || size <= 0)
00274     return NULL;
00275 
00276   b = g_new0 (bson, 1);
00277   b->data = g_byte_array_sized_new (size + sizeof (guint8));
00278   b->data = g_byte_array_append (b->data, data, size);
00279 
00280   return b;
00281 }
00282 
00298 #define _bson_build_add_single(b,type,name,free_after,ap)               \
00299   {                                                                     \
00300     single_result = TRUE;                                               \
00301     switch (type)                                                       \
00302       {                                                                 \
00303       case BSON_TYPE_NONE:                                              \
00304       case BSON_TYPE_UNDEFINED:                                         \
00305       case BSON_TYPE_DBPOINTER:                                         \
00306         single_result = FALSE;                                          \
00307         break;                                                          \
00308       case BSON_TYPE_MIN:                                               \
00309       case BSON_TYPE_MAX:                                               \
00310       default:                                                          \
00311         single_result = FALSE;                                          \
00312         break;                                                          \
00313       case BSON_TYPE_DOUBLE:                                            \
00314         {                                                               \
00315           gdouble d = (gdouble)va_arg (ap, gdouble);                    \
00316           bson_append_double (b, name, d);                              \
00317           break;                                                        \
00318         }                                                               \
00319       case BSON_TYPE_STRING:                                            \
00320         {                                                               \
00321           gchar *s = (gchar *)va_arg (ap, gpointer);                    \
00322           gint32 l = (gint32)va_arg (ap, gint32);                       \
00323           bson_append_string (b, name, s, l);                           \
00324           if (free_after)                                               \
00325             g_free (s);                                                 \
00326           break;                                                        \
00327         }                                                               \
00328       case BSON_TYPE_DOCUMENT:                                          \
00329         {                                                               \
00330           bson *d = (bson *)va_arg (ap, gpointer);                      \
00331           if (free_after && bson_size (d) < 0)                          \
00332             bson_finish (d);                                            \
00333           bson_append_document (b, name, d);                            \
00334           if (free_after)                                               \
00335             bson_free (d);                                              \
00336           break;                                                        \
00337         }                                                               \
00338       case BSON_TYPE_ARRAY:                                             \
00339         {                                                               \
00340           bson *d = (bson *)va_arg (ap, gpointer);                      \
00341           if (free_after && bson_size (d) < 0)                          \
00342             bson_finish (d);                                            \
00343           bson_append_array (b, name, d);                               \
00344           if (free_after)                                               \
00345             bson_free (d);                                              \
00346           break;                                                        \
00347         }                                                               \
00348       case BSON_TYPE_BINARY:                                            \
00349         {                                                               \
00350           bson_binary_subtype s =                                       \
00351             (bson_binary_subtype)va_arg (ap, guint);                    \
00352           guint8 *d = (guint8 *)va_arg (ap, gpointer);                  \
00353           gint32 l = (gint32)va_arg (ap, gint32);                       \
00354           bson_append_binary (b, name, s, d, l);                        \
00355           if (free_after)                                               \
00356             g_free (d);                                                 \
00357           break;                                                        \
00358         }                                                               \
00359       case BSON_TYPE_OID:                                               \
00360         {                                                               \
00361           guint8 *oid = (guint8 *)va_arg (ap, gpointer);                \
00362           bson_append_oid (b, name, oid);                               \
00363           if (free_after)                                               \
00364             g_free (oid);                                               \
00365           break;                                                        \
00366         }                                                               \
00367       case BSON_TYPE_BOOLEAN:                                           \
00368         {                                                               \
00369           gboolean v = (gboolean)va_arg (ap, guint);                    \
00370           bson_append_boolean (b, name, v);                             \
00371           break;                                                        \
00372         }                                                               \
00373       case BSON_TYPE_UTC_DATETIME:                                      \
00374         {                                                               \
00375           gint64 ts = (gint64)va_arg (ap, gint64);                      \
00376           bson_append_utc_datetime (b, name, ts);                       \
00377           break;                                                        \
00378         }                                                               \
00379       case BSON_TYPE_NULL:                                              \
00380         {                                                               \
00381           bson_append_null (b, name);                                   \
00382           break;                                                        \
00383         }                                                               \
00384       case BSON_TYPE_REGEXP:                                            \
00385         {                                                               \
00386           gchar *r = (gchar *)va_arg (ap, gpointer);                    \
00387           gchar *o = (gchar *)va_arg (ap, gpointer);                    \
00388           bson_append_regex (b, name, r, o);                            \
00389           if (free_after)                                               \
00390             {                                                           \
00391               g_free (r);                                               \
00392               g_free (o);                                               \
00393             }                                                           \
00394           break;                                                        \
00395       }                                                                 \
00396       case BSON_TYPE_JS_CODE:                                           \
00397         {                                                               \
00398           gchar *s = (gchar *)va_arg (ap, gpointer);                    \
00399           gint32 l = (gint32)va_arg (ap, gint32);                       \
00400           bson_append_javascript (b, name, s, l);                       \
00401           if (free_after)                                               \
00402             g_free (s);                                                 \
00403           break;                                                        \
00404         }                                                               \
00405       case BSON_TYPE_SYMBOL:                                            \
00406         {                                                               \
00407           gchar *s = (gchar *)va_arg (ap, gpointer);                    \
00408           gint32 l = (gint32)va_arg (ap, gint32);                       \
00409           bson_append_symbol (b, name, s, l);                           \
00410           if (free_after)                                               \
00411             g_free (s);                                                 \
00412           break;                                                        \
00413         }                                                               \
00414       case BSON_TYPE_JS_CODE_W_SCOPE:                                   \
00415         {                                                               \
00416           gchar *s = (gchar *)va_arg (ap, gpointer);                    \
00417           gint32 l = (gint32)va_arg (ap, gint32);                       \
00418           bson *scope = (bson *)va_arg (ap, gpointer);                  \
00419           if (free_after && bson_size (scope) < 0)                      \
00420             bson_finish (scope);                                        \
00421           bson_append_javascript_w_scope (b, name, s, l, scope);        \
00422           if (free_after)                                               \
00423             bson_free (scope);                                          \
00424           break;                                                        \
00425         }                                                               \
00426       case BSON_TYPE_INT32:                                             \
00427         {                                                               \
00428           gint32 l = (gint32)va_arg (ap, gint32);                       \
00429           bson_append_int32 (b, name, l);                               \
00430           break;                                                        \
00431         }                                                               \
00432       case BSON_TYPE_TIMESTAMP:                                         \
00433         {                                                               \
00434           gint64 ts = (gint64)va_arg (ap, gint64);                      \
00435           bson_append_timestamp (b, name, ts);                          \
00436           break;                                                        \
00437         }                                                               \
00438       case BSON_TYPE_INT64:                                             \
00439         {                                                               \
00440           gint64 l = (gint64)va_arg (ap, gint64);                       \
00441           bson_append_int64 (b, name, l);                               \
00442           break;                                                        \
00443         }                                                               \
00444       }                                                                 \
00445   }
00446 
00447 bson *
00448 bson_build (bson_type type, const gchar *name, ...)
00449 {
00450   va_list ap;
00451   bson_type t;
00452   const gchar *n;
00453   bson *b;
00454   gboolean single_result;
00455 
00456   b = bson_new ();
00457   va_start (ap, name);
00458   _bson_build_add_single (b, type, name, FALSE, ap);
00459 
00460   if (!single_result)
00461     {
00462       bson_free (b);
00463       va_end (ap);
00464       return NULL;
00465     }
00466 
00467   while ((t = (bson_type)va_arg (ap, gint)))
00468     {
00469       n = (const gchar *)va_arg (ap, gpointer);
00470       _bson_build_add_single (b, t, n, FALSE, ap);
00471       if (!single_result)
00472         {
00473           bson_free (b);
00474           va_end (ap);
00475           return NULL;
00476         }
00477     }
00478   va_end (ap);
00479 
00480   return b;
00481 }
00482 
00483 bson *
00484 bson_build_full (bson_type type, const gchar *name, gboolean free_after, ...)
00485 {
00486   va_list ap;
00487   bson_type t;
00488   const gchar *n;
00489   gboolean f;
00490   bson *b;
00491   gboolean single_result;
00492 
00493   b = bson_new ();
00494   va_start (ap, free_after);
00495   _bson_build_add_single (b, type, name, free_after, ap);
00496   if (!single_result)
00497     {
00498       bson_free (b);
00499       va_end (ap);
00500       return NULL;
00501     }
00502 
00503   while ((t = (bson_type)va_arg (ap, gint)))
00504     {
00505       n = (const gchar *)va_arg (ap, gpointer);
00506       f = (gboolean)va_arg (ap, gint);
00507       _bson_build_add_single (b, t, n, f, ap);
00508       if (!single_result)
00509         {
00510           bson_free (b);
00511           va_end (ap);
00512           return NULL;
00513         }
00514     }
00515   va_end (ap);
00516 
00517   return b;
00518 }
00519 
00520 gboolean
00521 bson_finish (bson *b)
00522 {
00523   gint32 *i;
00524 
00525   if (!b)
00526     return FALSE;
00527 
00528   if (b->finished)
00529     return TRUE;
00530 
00531   _bson_append_byte (b, 0);
00532 
00533   i = (gint32 *) (&b->data->data[0]);
00534   *i = GINT32_TO_LE ((gint32) (b->data->len));
00535 
00536   b->finished = TRUE;
00537 
00538   return TRUE;
00539 }
00540 
00541 gint32
00542 bson_size (const bson *b)
00543 {
00544   if (!b)
00545     return -1;
00546 
00547   if (b->finished)
00548     return b->data->len;
00549   else
00550     return -1;
00551 }
00552 
00553 const guint8 *
00554 bson_data (const bson *b)
00555 {
00556   if (!b)
00557     return NULL;
00558 
00559   if (b->finished)
00560     return b->data->data;
00561   else
00562     return NULL;
00563 }
00564 
00565 gboolean
00566 bson_reset (bson *b)
00567 {
00568   if (!b)
00569     return FALSE;
00570 
00571   b->finished = FALSE;
00572   g_byte_array_set_size (b->data, 0);
00573   _bson_append_int32 (b, 0);
00574 
00575   return TRUE;
00576 }
00577 
00578 void
00579 bson_free (bson *b)
00580 {
00581   if (!b)
00582     return;
00583 
00584   if (b->data)
00585     g_byte_array_free (b->data, TRUE);
00586   g_free (b);
00587 }
00588 
00589 gboolean
00590 bson_validate_key (const gchar *key, gboolean forbid_dots,
00591                    gboolean no_dollar)
00592 {
00593   if (!key)
00594     {
00595       errno = EINVAL;
00596       return FALSE;
00597     }
00598   errno = 0;
00599 
00600   if (no_dollar && key[0] == '$')
00601     return FALSE;
00602 
00603   if (forbid_dots && strchr (key, '.') != NULL)
00604     return FALSE;
00605 
00606   return TRUE;
00607 }
00608 
00609 /*
00610  * Append elements
00611  */
00612 
00613 gboolean
00614 bson_append_double (bson *b, const gchar *name, gdouble val)
00615 {
00616   gdouble d = GDOUBLE_TO_LE (val);
00617 
00618   if (!_bson_append_element_header (b, BSON_TYPE_DOUBLE, name))
00619     return FALSE;
00620 
00621   b->data = g_byte_array_append (b->data, (const guint8 *)&d, sizeof (val));
00622   return TRUE;
00623 }
00624 
00625 gboolean
00626 bson_append_string (bson *b, const gchar *name, const gchar *val,
00627                     gint32 length)
00628 {
00629   return _bson_append_string_element (b, BSON_TYPE_STRING, name, val, length);
00630 }
00631 
00632 gboolean
00633 bson_append_document (bson *b, const gchar *name, const bson *doc)
00634 {
00635   return _bson_append_document_element (b, BSON_TYPE_DOCUMENT, name, doc);
00636 }
00637 
00638 gboolean
00639 bson_append_array (bson *b, const gchar *name, const bson *array)
00640 {
00641   return _bson_append_document_element (b, BSON_TYPE_ARRAY, name, array);
00642 }
00643 
00644 gboolean
00645 bson_append_binary (bson *b, const gchar *name, bson_binary_subtype subtype,
00646                     const guint8 *data, gint32 size)
00647 {
00648   if (!data || !size || size <= 0)
00649     return FALSE;
00650 
00651   if (!_bson_append_element_header (b, BSON_TYPE_BINARY, name))
00652     return FALSE;
00653 
00654   _bson_append_int32 (b, GINT32_TO_LE (size));
00655   _bson_append_byte (b, (guint8)subtype);
00656 
00657   b->data = g_byte_array_append (b->data, data, size);
00658   return TRUE;
00659 }
00660 
00661 gboolean
00662 bson_append_oid (bson *b, const gchar *name, const guint8 *oid)
00663 {
00664   if (!oid)
00665     return FALSE;
00666 
00667   if (!_bson_append_element_header (b, BSON_TYPE_OID, name))
00668     return FALSE;
00669 
00670   b->data = g_byte_array_append (b->data, oid, 12);
00671   return TRUE;
00672 }
00673 
00674 gboolean
00675 bson_append_boolean (bson *b, const gchar *name, gboolean value)
00676 {
00677   if (!_bson_append_element_header (b, BSON_TYPE_BOOLEAN, name))
00678     return FALSE;
00679 
00680   _bson_append_byte (b, (guint8)value);
00681   return TRUE;
00682 }
00683 
00684 gboolean
00685 bson_append_utc_datetime (bson *b, const gchar *name, gint64 ts)
00686 {
00687   return _bson_append_int64_element (b, BSON_TYPE_UTC_DATETIME, name, ts);
00688 }
00689 
00690 gboolean
00691 bson_append_null (bson *b, const gchar *name)
00692 {
00693   return _bson_append_element_header (b, BSON_TYPE_NULL, name);
00694 }
00695 
00696 gboolean
00697 bson_append_regex (bson *b, const gchar *name, const gchar *regexp,
00698                    const gchar *options)
00699 {
00700   if (!regexp || !options)
00701     return FALSE;
00702 
00703   if (!_bson_append_element_header (b, BSON_TYPE_REGEXP, name))
00704     return FALSE;
00705 
00706   b->data = g_byte_array_append (b->data, (const guint8 *)regexp,
00707                                  strlen (regexp) + 1);
00708   b->data = g_byte_array_append (b->data, (const guint8 *)options,
00709                                  strlen (options) + 1);
00710 
00711   return TRUE;
00712 }
00713 
00714 gboolean
00715 bson_append_javascript (bson *b, const gchar *name, const gchar *js,
00716                         gint32 len)
00717 {
00718   return _bson_append_string_element (b, BSON_TYPE_JS_CODE, name, js, len);
00719 }
00720 
00721 gboolean
00722 bson_append_symbol (bson *b, const gchar *name, const gchar *symbol,
00723                     gint32 len)
00724 {
00725   return _bson_append_string_element (b, BSON_TYPE_SYMBOL, name, symbol, len);
00726 }
00727 
00728 gboolean
00729 bson_append_javascript_w_scope (bson *b, const gchar *name,
00730                                 const gchar *js, gint32 len,
00731                                 const bson *scope)
00732 {
00733   gint size;
00734   size_t length;
00735 
00736   if (!js || !scope || bson_size (scope) < 0 || len < -1)
00737     return FALSE;
00738 
00739   if (!_bson_append_element_header (b, BSON_TYPE_JS_CODE_W_SCOPE, name))
00740     return FALSE;
00741 
00742   length = (len != -1) ? (size_t)len + 1: strlen (js) + 1;
00743 
00744   size = length + sizeof (gint32) + sizeof (gint32) + bson_size (scope);
00745 
00746   _bson_append_int32 (b, GINT32_TO_LE (size));
00747 
00748   /* Append the JS code */
00749   _bson_append_int32 (b, GINT32_TO_LE (length));
00750   b->data = g_byte_array_append (b->data, (const guint8 *)js, length - 1);
00751   _bson_append_byte (b, 0);
00752 
00753   /* Append the scope */
00754   b->data = g_byte_array_append (b->data, bson_data (scope),
00755                                  bson_size (scope));
00756 
00757   return TRUE;
00758 }
00759 
00760 gboolean
00761 bson_append_int32 (bson *b, const gchar *name, gint32 i)
00762 {
00763   if (!_bson_append_element_header (b, BSON_TYPE_INT32, name))
00764     return FALSE;
00765 
00766   _bson_append_int32 (b, GINT32_TO_LE (i));
00767   return TRUE;
00768  }
00769 
00770 gboolean
00771 bson_append_timestamp (bson *b, const gchar *name, gint64 ts)
00772 {
00773   return _bson_append_int64_element (b, BSON_TYPE_TIMESTAMP, name, ts);
00774 }
00775 
00776 gboolean
00777 bson_append_int64 (bson *b, const gchar *name, gint64 i)
00778 {
00779   return _bson_append_int64_element (b, BSON_TYPE_INT64, name, i);
00780 }
00781 
00782 /*
00783  * Find & retrieve data
00784  */
00785 bson_cursor *
00786 bson_cursor_new (const bson *b)
00787 {
00788   bson_cursor *c;
00789 
00790   if (bson_size (b) == -1)
00791     return NULL;
00792 
00793   c = (bson_cursor *)g_new0 (bson_cursor, 1);
00794   c->obj = b;
00795 
00796   return c;
00797 }
00798 
00799 void
00800 bson_cursor_free (bson_cursor *c)
00801 {
00802   g_free (c);
00803 }
00804 
00816 static gint32
00817 _bson_get_block_size (bson_type type, const guint8 *data)
00818 {
00819   glong l;
00820 
00821   switch (type)
00822     {
00823     case BSON_TYPE_STRING:
00824     case BSON_TYPE_JS_CODE:
00825     case BSON_TYPE_SYMBOL:
00826       return bson_stream_doc_size (data, 0) + sizeof (gint32);
00827     case BSON_TYPE_DOCUMENT:
00828     case BSON_TYPE_ARRAY:
00829     case BSON_TYPE_JS_CODE_W_SCOPE:
00830       return bson_stream_doc_size (data, 0);
00831     case BSON_TYPE_DOUBLE:
00832       return sizeof (gdouble);
00833     case BSON_TYPE_BINARY:
00834       return bson_stream_doc_size (data, 0) +
00835         sizeof (gint32) + sizeof (guint8);
00836     case BSON_TYPE_OID:
00837       return 12;
00838     case BSON_TYPE_BOOLEAN:
00839       return 1;
00840     case BSON_TYPE_UTC_DATETIME:
00841     case BSON_TYPE_TIMESTAMP:
00842     case BSON_TYPE_INT64:
00843       return sizeof (gint64);
00844     case BSON_TYPE_NULL:
00845     case BSON_TYPE_UNDEFINED:
00846     case BSON_TYPE_MIN:
00847     case BSON_TYPE_MAX:
00848       return 0;
00849     case BSON_TYPE_REGEXP:
00850       l = strlen((gchar *)data);
00851       return l + strlen((gchar *)(data + l + 1)) + 2;
00852     case BSON_TYPE_INT32:
00853       return sizeof (gint32);
00854     case BSON_TYPE_DBPOINTER:
00855       return bson_stream_doc_size (data, 0) + sizeof (gint32) + 12;
00856     case BSON_TYPE_NONE:
00857     default:
00858       return -1;
00859     }
00860 }
00861 
00862 gboolean
00863 bson_cursor_next (bson_cursor *c)
00864 {
00865   const guint8 *d;
00866   gint32 pos, bs;
00867 
00868   if (!c)
00869     return FALSE;
00870 
00871   d = bson_data (c->obj);
00872 
00873   if (c->pos == 0)
00874     pos = sizeof (guint32);
00875   else
00876     {
00877       bs = _bson_get_block_size (bson_cursor_type (c), d + c->value_pos);
00878       if (bs == -1)
00879         return FALSE;
00880       pos = c->value_pos + bs;
00881     }
00882 
00883   if (pos >= bson_size (c->obj) - 1)
00884     return FALSE;
00885 
00886   c->pos = pos;
00887   c->key = (gchar *) &d[c->pos + 1];
00888   c->value_pos = c->pos + strlen (c->key) + 2;
00889 
00890   return TRUE;
00891 }
00892 
00893 static inline gboolean
00894 _bson_cursor_find (const bson *b, const gchar *name, size_t start_pos,
00895                    gint32 end_pos, gboolean wrap_over, bson_cursor *dest_c)
00896 {
00897   gint32 pos = start_pos, bs;
00898   const guint8 *d;
00899   gint32 name_len;
00900 
00901   name_len = strlen (name);
00902 
00903   d = bson_data (b);
00904 
00905   while (pos < end_pos)
00906     {
00907       bson_type t = (bson_type) d[pos];
00908       const gchar *key = (gchar *) &d[pos + 1];
00909       gint32 key_len = strlen (key);
00910       gint32 value_pos = pos + key_len + 2;
00911 
00912       if (!memcmp (key, name, (name_len <= key_len) ? name_len : key_len))
00913         {
00914           dest_c->obj = b;
00915           dest_c->key = key;
00916           dest_c->pos = pos;
00917           dest_c->value_pos = value_pos;
00918 
00919           return TRUE;
00920         }
00921       bs = _bson_get_block_size (t, &d[value_pos]);
00922       if (bs == -1)
00923         return FALSE;
00924       pos = value_pos + bs;
00925     }
00926 
00927   if (wrap_over)
00928     return _bson_cursor_find (b, name, sizeof (gint32), start_pos,
00929                               FALSE, dest_c);
00930 
00931   return FALSE;
00932 }
00933 
00934 gboolean
00935 bson_cursor_find (bson_cursor *c, const gchar *name)
00936 {
00937   if (!c || !name)
00938     return FALSE;
00939 
00940   return _bson_cursor_find (c->obj, name, c->pos, bson_size (c->obj) - 1,
00941                             TRUE, c);
00942 }
00943 
00944 gboolean
00945 bson_cursor_find_next (bson_cursor *c, const gchar *name)
00946 {
00947   if (!c || !name)
00948     return FALSE;
00949 
00950   return _bson_cursor_find (c->obj, name, c->pos, bson_size (c->obj) - 1,
00951                             FALSE, c);
00952 }
00953 
00954 bson_cursor *
00955 bson_find (const bson *b, const gchar *name)
00956 {
00957   bson_cursor *c;
00958 
00959   if (bson_size (b) == -1 || !name)
00960     return NULL;
00961 
00962   c = bson_cursor_new (b);
00963   if (_bson_cursor_find (b, name, sizeof (gint32), bson_size (c->obj) - 1,
00964                          FALSE, c))
00965     return c;
00966   bson_cursor_free (c);
00967   return NULL;
00968 }
00969 
00970 bson_type
00971 bson_cursor_type (const bson_cursor *c)
00972 {
00973   if (!c || c->pos < sizeof (gint32))
00974     return BSON_TYPE_NONE;
00975 
00976   return (bson_type)(bson_data (c->obj)[c->pos]);
00977 }
00978 
00979 const gchar *
00980 bson_cursor_type_as_string (const bson_cursor *c)
00981 {
00982   if (!c || c->pos < sizeof (gint32))
00983     return NULL;
00984 
00985   return bson_type_as_string (bson_cursor_type (c));
00986 }
00987 
00988 const gchar *
00989 bson_cursor_key (const bson_cursor *c)
00990 {
00991   if (!c)
00992     return NULL;
00993 
00994   return c->key;
00995 }
00996 
01002 #define BSON_CURSOR_CHECK_TYPE(c,type)          \
01003   if (bson_cursor_type(c) != type)              \
01004     return FALSE;
01005 
01006 gboolean
01007 bson_cursor_get_string (const bson_cursor *c, const gchar **dest)
01008 {
01009   if (!dest)
01010     return FALSE;
01011 
01012   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_STRING);
01013 
01014   *dest = (gchar *)(bson_data (c->obj) + c->value_pos + sizeof (gint32));
01015 
01016   return TRUE;
01017 }
01018 
01019 gboolean
01020 bson_cursor_get_double (const bson_cursor *c, gdouble *dest)
01021 {
01022   if (!dest)
01023     return FALSE;
01024 
01025   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_DOUBLE);
01026 
01027   memcpy (dest, bson_data (c->obj) + c->value_pos, sizeof (gdouble));
01028   *dest = GDOUBLE_FROM_LE (*dest);
01029 
01030   return TRUE;
01031 }
01032 
01033 gboolean
01034 bson_cursor_get_document (const bson_cursor *c, bson **dest)
01035 {
01036   bson *b;
01037   gint32 size;
01038 
01039   if (!dest)
01040     return FALSE;
01041 
01042   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_DOCUMENT);
01043 
01044   size = bson_stream_doc_size (bson_data(c->obj), c->value_pos) -
01045     sizeof (gint32) - 1;
01046   b = bson_new_sized (size);
01047   b->data = g_byte_array_append (b->data,
01048                                  bson_data (c->obj) + c->value_pos +
01049                                  sizeof (gint32), size);
01050   bson_finish (b);
01051 
01052   *dest = b;
01053 
01054   return TRUE;
01055 }
01056 
01057 gboolean
01058 bson_cursor_get_array (const bson_cursor *c, bson **dest)
01059 {
01060   bson *b;
01061   gint32 size;
01062 
01063   if (!dest)
01064     return FALSE;
01065 
01066   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_ARRAY);
01067 
01068   size = bson_stream_doc_size (bson_data(c->obj), c->value_pos) -
01069     sizeof (gint32) - 1;
01070   b = bson_new_sized (size);
01071   b->data = g_byte_array_append (b->data,
01072                                  bson_data (c->obj) + c->value_pos +
01073                                  sizeof (gint32), size);
01074   bson_finish (b);
01075 
01076   *dest = b;
01077 
01078   return TRUE;
01079 }
01080 
01081 gboolean
01082 bson_cursor_get_binary (const bson_cursor *c,
01083                         bson_binary_subtype *subtype,
01084                         const guint8 **data, gint32 *size)
01085 {
01086   if (!subtype || !size || !data)
01087     return FALSE;
01088 
01089   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_BINARY);
01090 
01091   *size = bson_stream_doc_size (bson_data(c->obj), c->value_pos);
01092   *subtype = (bson_binary_subtype)(bson_data (c->obj)[c->value_pos +
01093                                                       sizeof (gint32)]);
01094   *data = (guint8 *)(bson_data (c->obj) + c->value_pos + sizeof (gint32) + 1);
01095 
01096   return TRUE;
01097 }
01098 
01099 gboolean
01100 bson_cursor_get_oid (const bson_cursor *c, const guint8 **dest)
01101 {
01102   if (!dest)
01103     return FALSE;
01104 
01105   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_OID);
01106 
01107   *dest = (guint8 *)(bson_data (c->obj) + c->value_pos);
01108 
01109   return TRUE;
01110 }
01111 
01112 gboolean
01113 bson_cursor_get_boolean (const bson_cursor *c, gboolean *dest)
01114 {
01115   if (!dest)
01116     return FALSE;
01117 
01118   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_BOOLEAN);
01119 
01120   *dest = (gboolean)(bson_data (c->obj) + c->value_pos)[0];
01121 
01122   return TRUE;
01123 }
01124 
01125 gboolean
01126 bson_cursor_get_utc_datetime (const bson_cursor *c,
01127                               gint64 *dest)
01128 {
01129   if (!dest)
01130     return FALSE;
01131 
01132   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_UTC_DATETIME);
01133 
01134   memcpy (dest, bson_data (c->obj) + c->value_pos, sizeof (gint64));
01135   *dest = GINT64_FROM_LE (*dest);
01136 
01137   return TRUE;
01138 }
01139 
01140 gboolean
01141 bson_cursor_get_regex (const bson_cursor *c, const gchar **regex,
01142                        const gchar **options)
01143 {
01144   if (!regex || !options)
01145     return FALSE;
01146 
01147   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_REGEXP);
01148 
01149   *regex = (gchar *)(bson_data (c->obj) + c->value_pos);
01150   *options = (gchar *)(*regex + strlen(*regex) + 1);
01151 
01152   return TRUE;
01153 }
01154 
01155 gboolean
01156 bson_cursor_get_javascript (const bson_cursor *c, const gchar **dest)
01157 {
01158   if (!dest)
01159     return FALSE;
01160 
01161   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_JS_CODE);
01162 
01163   *dest = (gchar *)(bson_data (c->obj) + c->value_pos + sizeof (gint32));
01164 
01165   return TRUE;
01166 }
01167 
01168 gboolean
01169 bson_cursor_get_symbol (const bson_cursor *c, const gchar **dest)
01170 {
01171   if (!dest)
01172     return FALSE;
01173 
01174   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_SYMBOL);
01175 
01176   *dest = (gchar *)(bson_data (c->obj) + c->value_pos + sizeof (gint32));
01177 
01178   return TRUE;
01179 }
01180 
01181 gboolean
01182 bson_cursor_get_javascript_w_scope (const bson_cursor *c,
01183                                     const gchar **js,
01184                                     bson **scope)
01185 {
01186   bson *b;
01187   gint32 size, docpos;
01188 
01189   if (!js || !scope)
01190     return FALSE;
01191 
01192   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_JS_CODE_W_SCOPE);
01193 
01194   docpos = bson_stream_doc_size (bson_data (c->obj),
01195                                   c->value_pos + sizeof (gint32)) +
01196     sizeof (gint32) * 2;
01197   size = bson_stream_doc_size (bson_data (c->obj), c->value_pos + docpos) -
01198     sizeof (gint32) - 1;
01199   b = bson_new_sized (size);
01200   b->data = g_byte_array_append (b->data,
01201                                  bson_data (c->obj) + c->value_pos + docpos +
01202                                  sizeof (gint32), size);
01203   bson_finish (b);
01204 
01205   *scope = b;
01206   *js = (gchar *)(bson_data (c->obj) + c->value_pos + sizeof (gint32) * 2);
01207 
01208   return TRUE;
01209 }
01210 
01211 gboolean
01212 bson_cursor_get_int32 (const bson_cursor *c, gint32 *dest)
01213 {
01214   if (!dest)
01215     return FALSE;
01216 
01217   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_INT32);
01218 
01219   memcpy (dest, bson_data (c->obj) + c->value_pos, sizeof (gint32));
01220   *dest = GINT32_FROM_LE (*dest);
01221 
01222   return TRUE;
01223 }
01224 
01225 gboolean
01226 bson_cursor_get_timestamp (const bson_cursor *c, gint64 *dest)
01227 {
01228   if (!dest)
01229     return FALSE;
01230 
01231   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_TIMESTAMP);
01232 
01233   memcpy (dest, bson_data (c->obj) + c->value_pos, sizeof (gint64));
01234   *dest = GINT64_FROM_LE (*dest);
01235 
01236   return TRUE;
01237 }
01238 
01239 gboolean
01240 bson_cursor_get_int64 (const bson_cursor *c, gint64 *dest)
01241 {
01242   if (!dest)
01243     return FALSE;
01244 
01245   BSON_CURSOR_CHECK_TYPE (c, BSON_TYPE_INT64);
01246 
01247   memcpy (dest, bson_data (c->obj) + c->value_pos, sizeof (gint64));
01248   *dest = GINT64_FROM_LE (*dest);
01249 
01250   return TRUE;
01251 }
 All Data Structures Files Functions Variables Enumerations Enumerator Defines