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; }
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; }