Example #1
0
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;

   g_return_val_if_fail(iter != NULL, 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;
}
Example #2
0
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;
   gint32 max_len;

   g_return_val_if_fail(iter != NULL, 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;

   /*
    * Check for end of buffer.
    */
   if ((offset + 1) >= rawbuf_len) {
      GOTO(failure);
   }

   /*
    * Get the type of the next field.
    */
   type = rawbuf[++offset];

   /*
    * Get the key of the next field.
    */
   key = (const gchar *)&rawbuf[++offset];
   max_len = first_nul(key, rawbuf_len - offset - 1);
   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 = first_nul((gchar *)value2, rawbuf_len - offset - 1);
         if (!g_utf8_validate((gchar *)value2, max_len, &end)) {
            GOTO(failure);
         }
         offset += strlen((gchar *)value2);
         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 = GINT_FROM_LE(max_len);
         if ((offset + max_len) < rawbuf_len) {
            offset += max_len;
            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 (!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 (!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:
      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;
}