#include <stdarg.h>
#include <string.h>
#include <math.h>
#include "b64_ntop.h"
#include "bson.h"
#include "bson-private.h"
#include "bson-string.h"
#ifndef BSON_MAX_RECURSION
# define BSON_MAX_RECURSION 100
#endif
typedef
enum
{
BSON_VALIDATE_PHASE_START,
BSON_VALIDATE_PHASE_TOP,
BSON_VALIDATE_PHASE_LF_REF_KEY,
BSON_VALIDATE_PHASE_LF_REF_UTF8,
BSON_VALIDATE_PHASE_LF_ID_KEY,
BSON_VALIDATE_PHASE_LF_DB_KEY,
BSON_VALIDATE_PHASE_LF_DB_UTF8,
BSON_VALIDATE_PHASE_NOT_DBREF,
} bson_validate_phase_t;
typedef
struct
{
bson_validate_flags_t flags;
ssize_t err_offset;
bson_validate_phase_t phase;
} bson_validate_state_t;
static
const
uint8_t gZero;
static
bool
_bson_impl_inline_grow (bson_impl_inline_t *impl,
size_t
size)
{
bson_impl_alloc_t *alloc = (bson_impl_alloc_t *)impl;
uint8_t *data;
size_t
req;
BSON_ASSERT (impl);
BSON_ASSERT (!(impl->flags & BSON_FLAG_RDONLY));
BSON_ASSERT (!(impl->flags & BSON_FLAG_CHILD));
if
(((
size_t
)impl->len + size) <=
sizeof
impl->data) {
return
true
;
}
req = bson_next_power_of_two (impl->len + size);
if
(req <= INT32_MAX) {
data = bson_malloc (req);
memcpy
(data, impl->data, impl->len);
alloc->flags &= ~BSON_FLAG_INLINE;
alloc->parent = NULL;
alloc->depth = 0;
alloc->buf = &alloc->alloc;
alloc->buflen = &alloc->alloclen;
alloc->offset = 0;
alloc->alloc = data;
alloc->alloclen = req;
alloc->
realloc
= bson_realloc_ctx;
alloc->realloc_func_ctx = NULL;
return
true
;
}
return
false
;
}
static
bool
_bson_impl_alloc_grow (bson_impl_alloc_t *impl,
size_t
size)
{
size_t
req;
BSON_ASSERT (impl);
req = (impl->offset + impl->len + size + impl->depth);
if
(req <= *impl->buflen) {
return
true
;
}
req = bson_next_power_of_two (req);
if
((req <= INT32_MAX) && impl->
realloc
) {
*impl->buf = impl->
realloc
(*impl->buf, req, impl->realloc_func_ctx);
*impl->buflen = req;
return
true
;
}
return
false
;
}
static
bool
_bson_grow (bson_t *bson,
uint32_t size)
{
BSON_ASSERT (bson);
BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY));
if
((bson->flags & BSON_FLAG_INLINE)) {
return
_bson_impl_inline_grow ((bson_impl_inline_t *)bson, size);
}
return
_bson_impl_alloc_grow ((bson_impl_alloc_t *)bson, size);
}
static
BSON_INLINE uint8_t *
_bson_data (
const
bson_t *bson)
{
if
((bson->flags & BSON_FLAG_INLINE)) {
return
((bson_impl_inline_t *)bson)->data;
}
else
{
bson_impl_alloc_t *impl = (bson_impl_alloc_t *)bson;
return
(*impl->buf) + impl->offset;
}
}
static
BSON_INLINE
void
_bson_encode_length (bson_t *bson)
{
#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN
memcpy
(_bson_data (bson), &bson->len,
sizeof
(bson->len));
#else
uint32_t length_le = BSON_UINT32_TO_LE (bson->len);
memcpy
(_bson_data (bson), &length_le,
sizeof
(length_le));
#endif
}
static
BSON_INLINE
bool
_bson_append_va (bson_t *bson,
uint32_t n_bytes,
uint32_t n_pairs,
uint32_t first_len,
const
uint8_t *first_data,
va_list
args)
{
const
uint8_t *data;
uint32_t data_len;
uint8_t *buf;
BSON_ASSERT (bson);
BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD));
BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY));
BSON_ASSERT (n_pairs);
BSON_ASSERT (first_len);
BSON_ASSERT (first_data);
if
(BSON_UNLIKELY (!_bson_grow (bson, n_bytes))) {
return
false
;
}
data = first_data;
data_len = first_len;
buf = _bson_data (bson) + bson->len - 1;
do
{
n_pairs--;
memcpy
(buf, data, data_len);
bson->len += data_len;
buf += data_len;
if
(n_pairs) {
data_len =
va_arg
(args, uint32_t);
data =
va_arg
(args,
const
uint8_t *);
}
}
while
(n_pairs);
_bson_encode_length (bson);
*buf =
'\0'
;
return
true
;
}
static
bool
_bson_append (bson_t *bson,
uint32_t n_pairs,
uint32_t n_bytes,
uint32_t first_len,
const
uint8_t *first_data,
...)
{
va_list
args;
bool
ok;
BSON_ASSERT (bson);
BSON_ASSERT (n_pairs);
BSON_ASSERT (first_len);
BSON_ASSERT (first_data);
if
(BSON_UNLIKELY (n_bytes > (BSON_MAX_SIZE - bson->len))) {
return
false
;
}
va_start
(args, first_data);
ok = _bson_append_va (bson, n_bytes, n_pairs, first_len, first_data, args);
va_end
(args);
return
ok;
}
static
bool
_bson_append_bson_begin (bson_t *bson,
const
char
*key,
int
key_length,
bson_type_t child_type,
bson_t *child)
{
const
uint8_t type = child_type;
const
uint8_t empty[5] = { 5 };
bson_impl_alloc_t *aparent = (bson_impl_alloc_t *)bson;
bson_impl_alloc_t *achild = (bson_impl_alloc_t *)child;
BSON_ASSERT (bson);
BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY));
BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD));
BSON_ASSERT (key);
BSON_ASSERT ((child_type == BSON_TYPE_DOCUMENT) ||
(child_type == BSON_TYPE_ARRAY));
BSON_ASSERT (child);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
if
((bson->flags & BSON_FLAG_INLINE)) {
BSON_ASSERT (bson->len <= 120);
if
(!_bson_grow (bson, 128 - bson->len)) {
return
false
;
}
BSON_ASSERT (!(bson->flags & BSON_FLAG_INLINE));
}
if
(!_bson_append (bson, 4,
(1 + key_length + 1 + 5),
1, &type,
key_length, key,
1, &gZero,
5, empty)) {
return
false
;
}
bson->flags |= BSON_FLAG_IN_CHILD;
achild->flags = (BSON_FLAG_CHILD | BSON_FLAG_NO_FREE | BSON_FLAG_STATIC);
if
((bson->flags & BSON_FLAG_CHILD)) {
achild->depth = ((bson_impl_alloc_t *)bson)->depth + 1;
}
else
{
achild->depth = 1;
}
achild->parent = bson;
achild->buf = aparent->buf;
achild->buflen = aparent->buflen;
achild->offset = aparent->offset + aparent->len - 1 - 5;
achild->len = 5;
achild->alloc = NULL;
achild->alloclen = 0;
achild->
realloc
= aparent->
realloc
;
achild->realloc_func_ctx = aparent->realloc_func_ctx;
return
true
;
}
static
bool
_bson_append_bson_end (bson_t *bson,
bson_t *child)
{
BSON_ASSERT (bson);
BSON_ASSERT ((bson->flags & BSON_FLAG_IN_CHILD));
BSON_ASSERT (!(child->flags & BSON_FLAG_IN_CHILD));
bson->flags &= ~BSON_FLAG_IN_CHILD;
bson->len = (bson->len + child->len - 5);
_bson_data (bson)[bson->len - 1] =
'\0'
;
_bson_encode_length (bson);
return
true
;
}
bool
bson_append_array_begin (bson_t *bson,
const
char
*key,
int
key_length,
bson_t *child)
{
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (child,
false
);
return
_bson_append_bson_begin (bson, key, key_length, BSON_TYPE_ARRAY,
child);
}
bool
bson_append_array_end (bson_t *bson,
bson_t *child)
{
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (child,
false
);
return
_bson_append_bson_end (bson, child);
}
bool
bson_append_document_begin (bson_t *bson,
const
char
*key,
int
key_length,
bson_t *child)
{
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (child,
false
);
return
_bson_append_bson_begin (bson, key, key_length, BSON_TYPE_DOCUMENT,
child);
}
bool
bson_append_document_end (bson_t *bson,
bson_t *child)
{
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (child,
false
);
return
_bson_append_bson_end (bson, child);
}
bool
bson_append_array (bson_t *bson,
const
char
*key,
int
key_length,
const
bson_t *array)
{
static
const
uint8_t type = BSON_TYPE_ARRAY;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (array,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
if
(array && !bson_empty (array)) {
bson_iter_t iter;
if
(bson_iter_init (&iter, array) && bson_iter_next (&iter)) {
if
(0 !=
strcmp
(
"0"
, bson_iter_key (&iter))) {
fprintf
(stderr,
"%s(): invalid array detected. first element of array "
"parameter is not \"0\".\n"
,
__FUNCTION__);
}
}
}
return
_bson_append (bson, 4,
(1 + key_length + 1 + array->len),
1, &type,
key_length, key,
1, &gZero,
array->len, _bson_data (array));
}
bool
bson_append_binary (bson_t *bson,
const
char
*key,
int
key_length,
bson_subtype_t subtype,
const
uint8_t *binary,
uint32_t length)
{
static
const
uint8_t type = BSON_TYPE_BINARY;
uint32_t length_le;
uint32_t deprecated_length_le;
uint8_t subtype8 = 0;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (binary,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
subtype8 = subtype;
if
(subtype == BSON_SUBTYPE_BINARY_DEPRECATED) {
length_le = BSON_UINT32_TO_LE (length + 4);
deprecated_length_le = BSON_UINT32_TO_LE (length);
return
_bson_append (bson, 7,
(1 + key_length + 1 + 4 + 1 + 4 + length),
1, &type,
key_length, key,
1, &gZero,
4, &length_le,
1, &subtype8,
4, &deprecated_length_le,
length, binary);
}
else
{
length_le = BSON_UINT32_TO_LE (length);
return
_bson_append (bson, 6,
(1 + key_length + 1 + 4 + 1 + length),
1, &type,
key_length, key,
1, &gZero,
4, &length_le,
1, &subtype8,
length, binary);
}
}
bool
bson_append_bool (bson_t *bson,
const
char
*key,
int
key_length,
bool
value)
{
static
const
uint8_t type = BSON_TYPE_BOOL;
uint8_t byte = !!value;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
return
_bson_append (bson, 4,
(1 + key_length + 1 + 1),
1, &type,
key_length, key,
1, &gZero,
1, &byte);
}
bool
bson_append_code (bson_t *bson,
const
char
*key,
int
key_length,
const
char
*javascript)
{
static
const
uint8_t type = BSON_TYPE_CODE;
uint32_t length;
uint32_t length_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (javascript,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
length = (
int
)
strlen
(javascript) + 1;
length_le = BSON_UINT32_TO_LE (length);
return
_bson_append (bson, 5,
(1 + key_length + 1 + 4 + length),
1, &type,
key_length, key,
1, &gZero,
4, &length_le,
length, javascript);
}
bool
bson_append_code_with_scope (bson_t *bson,
const
char
*key,
int
key_length,
const
char
*javascript,
const
bson_t *scope)
{
static
const
uint8_t type = BSON_TYPE_CODEWSCOPE;
uint32_t codews_length_le;
uint32_t codews_length;
uint32_t js_length_le;
uint32_t js_length;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (javascript,
false
);
if
(bson_empty0 (scope)) {
return
bson_append_code (bson, key, key_length, javascript);
}
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
js_length = (
int
)
strlen
(javascript) + 1;
js_length_le = BSON_UINT32_TO_LE (js_length);
codews_length = 4 + 4 + js_length + scope->len;
codews_length_le = BSON_UINT32_TO_LE (codews_length);
return
_bson_append (bson, 7,
(1 + key_length + 1 + 4 + 4 + js_length + scope->len),
1, &type,
key_length, key,
1, &gZero,
4, &codews_length_le,
4, &js_length_le,
js_length, javascript,
scope->len, _bson_data (scope));
}
bool
bson_append_dbpointer (bson_t *bson,
const
char
*key,
int
key_length,
const
char
*collection,
const
bson_oid_t *oid)
{
static
const
uint8_t type = BSON_TYPE_DBPOINTER;
uint32_t length;
uint32_t length_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (collection,
false
);
bson_return_val_if_fail (oid,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
length = (
int
)
strlen
(collection) + 1;
length_le = BSON_UINT32_TO_LE (length);
return
_bson_append (bson, 6,
(1 + key_length + 1 + 4 + length + 12),
1, &type,
key_length, key,
1, &gZero,
4, &length_le,
length, collection,
12, oid);
}
bool
bson_append_document (bson_t *bson,
const
char
*key,
int
key_length,
const
bson_t *value)
{
static
const
uint8_t type = BSON_TYPE_DOCUMENT;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (value,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
return
_bson_append (bson, 4,
(1 + key_length + 1 + value->len),
1, &type,
key_length, key,
1, &gZero,
value->len, _bson_data (value));
}
bool
bson_append_double (bson_t *bson,
const
char
*key,
int
key_length,
double
value)
{
static
const
uint8_t type = BSON_TYPE_DOUBLE;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN
value = BSON_DOUBLE_TO_LE (value);
#endif
return
_bson_append (bson, 4,
(1 + key_length + 1 + 8),
1, &type,
key_length, key,
1, &gZero,
8, &value);
}
bool
bson_append_int32 (bson_t *bson,
const
char
*key,
int
key_length,
int32_t value)
{
static
const
uint8_t type = BSON_TYPE_INT32;
uint32_t value_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
value_le = BSON_UINT32_TO_LE (value);
return
_bson_append (bson, 4,
(1 + key_length + 1 + 4),
1, &type,
key_length, key,
1, &gZero,
4, &value_le);
}
bool
bson_append_int64 (bson_t *bson,
const
char
*key,
int
key_length,
int64_t value)
{
static
const
uint8_t type = BSON_TYPE_INT64;
uint64_t value_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
value_le = BSON_UINT64_TO_LE (value);
return
_bson_append (bson, 4,
(1 + key_length + 1 + 8),
1, &type,
key_length, key,
1, &gZero,
8, &value_le);
}
bool
bson_append_iter (bson_t *bson,
const
char
*key,
int
key_length,
const
bson_iter_t *iter)
{
bool
ret =
false
;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (iter,
false
);
if
(!key) {
key = bson_iter_key (iter);
key_length = -1;
}
switch
(bson_iter_type_unsafe (iter)) {
case
BSON_TYPE_EOD:
return
false
;
case
BSON_TYPE_DOUBLE:
ret = bson_append_double (bson, key, key_length, bson_iter_double (iter));
break
;
case
BSON_TYPE_UTF8:
{
uint32_t len = 0;
const
char
*str;
str = bson_iter_utf8 (iter, &len);
ret = bson_append_utf8 (bson, key, key_length, str, len);
}
break
;
case
BSON_TYPE_DOCUMENT:
{
const
uint8_t *buf = NULL;
uint32_t len = 0;
bson_t doc;
bson_iter_document (iter, &len, &buf);
if
(bson_init_static (&doc, buf, len)) {
ret = bson_append_document (bson, key, key_length, &doc);
bson_destroy (&doc);
}
}
break
;
case
BSON_TYPE_ARRAY:
{
const
uint8_t *buf = NULL;
uint32_t len = 0;
bson_t doc;
bson_iter_array (iter, &len, &buf);
if
(bson_init_static (&doc, buf, len)) {
ret = bson_append_array (bson, key, key_length, &doc);
bson_destroy (&doc);
}
}
break
;
case
BSON_TYPE_BINARY:
{
const
uint8_t *binary = NULL;
bson_subtype_t subtype = BSON_SUBTYPE_BINARY;
uint32_t len = 0;
bson_iter_binary (iter, &subtype, &len, &binary);
ret = bson_append_binary (bson, key, key_length,
subtype, binary, len);
}
break
;
case
BSON_TYPE_UNDEFINED:
ret = bson_append_undefined (bson, key, key_length);
break
;
case
BSON_TYPE_OID:
ret = bson_append_oid (bson, key, key_length, bson_iter_oid (iter));
break
;
case
BSON_TYPE_BOOL:
ret = bson_append_bool (bson, key, key_length, bson_iter_bool (iter));
break
;
case
BSON_TYPE_DATE_TIME:
ret = bson_append_date_time (bson, key, key_length,
bson_iter_date_time (iter));
break
;
case
BSON_TYPE_NULL:
ret = bson_append_null (bson, key, key_length);
break
;
case
BSON_TYPE_REGEX:
{
const
char
*regex;
const
char
*options;
regex = bson_iter_regex (iter, &options);
ret = bson_append_regex (bson, key, key_length, regex, options);
}
break
;
case
BSON_TYPE_DBPOINTER:
{
const
bson_oid_t *oid;
uint32_t len;
const
char
*collection;
bson_iter_dbpointer (iter, &len, &collection, &oid);
ret = bson_append_dbpointer (bson, key, key_length, collection, oid);
}
break
;
case
BSON_TYPE_CODE:
{
uint32_t len;
const
char
*code;
code = bson_iter_code (iter, &len);
ret = bson_append_code (bson, key, key_length, code);
}
break
;
case
BSON_TYPE_SYMBOL:
{
uint32_t len;
const
char
*symbol;
symbol = bson_iter_symbol (iter, &len);
ret = bson_append_symbol (bson, key, key_length, symbol, len);
}
break
;
case
BSON_TYPE_CODEWSCOPE:
{
const
uint8_t *scope = NULL;
uint32_t scope_len = 0;
uint32_t len = 0;
const
char
*javascript = NULL;
bson_t doc;
javascript = bson_iter_codewscope (iter, &len, &scope_len, &scope);
if
(bson_init_static (&doc, scope, scope_len)) {
ret = bson_append_code_with_scope (bson, key, key_length,
javascript, &doc);
bson_destroy (&doc);
}
}
break
;
case
BSON_TYPE_INT32:
ret = bson_append_int32 (bson, key, key_length, bson_iter_int32 (iter));
break
;
case
BSON_TYPE_TIMESTAMP:
{
uint32_t ts;
uint32_t inc;
bson_iter_timestamp (iter, &ts, &inc);
ret = bson_append_timestamp (bson, key, key_length, ts, inc);
}
break
;
case
BSON_TYPE_INT64:
ret = bson_append_int64 (bson, key, key_length, bson_iter_int64 (iter));
break
;
case
BSON_TYPE_MAXKEY:
ret = bson_append_maxkey (bson, key, key_length);
break
;
case
BSON_TYPE_MINKEY:
ret = bson_append_minkey (bson, key, key_length);
break
;
default
:
break
;
}
return
ret;
}
bool
bson_append_maxkey (bson_t *bson,
const
char
*key,
int
key_length)
{
static
const
uint8_t type = BSON_TYPE_MAXKEY;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
return
_bson_append (bson, 3,
(1 + key_length + 1),
1, &type,
key_length, key,
1, &gZero);
}
bool
bson_append_minkey (bson_t *bson,
const
char
*key,
int
key_length)
{
static
const
uint8_t type = BSON_TYPE_MINKEY;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
return
_bson_append (bson, 3,
(1 + key_length + 1),
1, &type,
key_length, key,
1, &gZero);
}
bool
bson_append_null (bson_t *bson,
const
char
*key,
int
key_length)
{
static
const
uint8_t type = BSON_TYPE_NULL;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
return
_bson_append (bson, 3,
(1 + key_length + 1),
1, &type,
key_length, key,
1, &gZero);
}
bool
bson_append_oid (bson_t *bson,
const
char
*key,
int
key_length,
const
bson_oid_t *value)
{
static
const
uint8_t type = BSON_TYPE_OID;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (value,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
return
_bson_append (bson, 4,
(1 + key_length + 1 + 12),
1, &type,
key_length, key,
1, &gZero,
12, value);
}
bool
bson_append_regex (bson_t *bson,
const
char
*key,
int
key_length,
const
char
*regex,
const
char
*options)
{
static
const
uint8_t type = BSON_TYPE_REGEX;
uint32_t regex_len;
uint32_t options_len;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
if
(!regex) {
regex =
""
;
}
if
(!options) {
options =
""
;
}
regex_len = (
int
)
strlen
(regex) + 1;
options_len = (
int
)
strlen
(options) + 1;
return
_bson_append (bson, 5,
(1 + key_length + 1 + regex_len + options_len),
1, &type,
key_length, key,
1, &gZero,
regex_len, regex,
options_len, options);
}
bool
bson_append_utf8 (bson_t *bson,
const
char
*key,
int
key_length,
const
char
*value,
int
length)
{
static
const
uint8_t type = BSON_TYPE_UTF8;
uint32_t length_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(BSON_UNLIKELY (!value)) {
return
bson_append_null (bson, key, key_length);
}
if
(BSON_UNLIKELY (key_length < 0)) {
key_length = (
int
)
strlen
(key);
}
if
(BSON_UNLIKELY (length < 0)) {
length = (
int
)
strlen
(value);
}
length_le = BSON_UINT32_TO_LE (length + 1);
return
_bson_append (bson, 6,
(1 + key_length + 1 + 4 + length + 1),
1, &type,
key_length, key,
1, &gZero,
4, &length_le,
length, value,
1, &gZero);
}
bool
bson_append_symbol (bson_t *bson,
const
char
*key,
int
key_length,
const
char
*value,
int
length)
{
static
const
uint8_t type = BSON_TYPE_SYMBOL;
uint32_t length_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(!value) {
return
bson_append_null (bson, key, key_length);
}
if
(key_length < 0) {
key_length = (
int
)
strlen
(key);
}
if
(length < 0) {
length =(
int
)
strlen
(value);
}
length_le = BSON_UINT32_TO_LE (length + 1);
return
_bson_append (bson, 6,
(1 + key_length + 1 + 4 + length + 1),
1, &type,
key_length, key,
1, &gZero,
4, &length_le,
length, value,
1, &gZero);
}
bool
bson_append_time_t (bson_t *bson,
const
char
*key,
int
key_length,
time_t
value)
{
#ifdef BSON_OS_WIN32
struct
timeval tv = { (
long
)value, 0 };
#else
struct
timeval tv = { value, 0 };
#endif
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
return
bson_append_timeval (bson, key, key_length, &tv);
}
bool
bson_append_timestamp (bson_t *bson,
const
char
*key,
int
key_length,
uint32_t timestamp,
uint32_t increment)
{
static
const
uint8_t type = BSON_TYPE_TIMESTAMP;
uint64_t value;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length =(
int
)
strlen
(key);
}
value = ((((uint64_t)timestamp) << 32) | ((uint64_t)increment));
value = BSON_UINT64_TO_LE (value);
return
_bson_append (bson, 4,
(1 + key_length + 1 + 8),
1, &type,
key_length, key,
1, &gZero,
8, &value);
}
bool
bson_append_now_utc (bson_t *bson,
const
char
*key,
int
key_length)
{
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (key_length >= -1,
false
);
return
bson_append_time_t (bson, key, key_length,
time
(NULL));
}
bool
bson_append_date_time (bson_t *bson,
const
char
*key,
int
key_length,
int64_t value)
{
static
const
uint8_t type = BSON_TYPE_DATE_TIME;
uint64_t value_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length =(
int
)
strlen
(key);
}
value_le = BSON_UINT64_TO_LE (value);
return
_bson_append (bson, 4,
(1 + key_length + 1 + 8),
1, &type,
key_length, key,
1, &gZero,
8, &value_le);
}
bool
bson_append_timeval (bson_t *bson,
const
char
*key,
int
key_length,
struct
timeval *value)
{
uint64_t unix_msec;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (value,
false
);
unix_msec = (((uint64_t)value->tv_sec) * 1000UL) +
(value->tv_usec / 1000UL);
return
bson_append_date_time (bson, key, key_length, unix_msec);
}
bool
bson_append_undefined (bson_t *bson,
const
char
*key,
int
key_length)
{
static
const
uint8_t type = BSON_TYPE_UNDEFINED;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(key_length < 0) {
key_length =(
int
)
strlen
(key);
}
return
_bson_append (bson, 3,
(1 + key_length + 1),
1, &type,
key_length, key,
1, &gZero);
}
bool
bson_append_value (bson_t *bson,
const
char
*key,
int
key_length,
const
bson_value_t *value)
{
bson_t local;
bool
ret =
false
;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
bson_return_val_if_fail (value,
false
);
switch
(value->value_type) {
case
BSON_TYPE_DOUBLE:
ret = bson_append_double (bson, key, key_length,
value->value.v_double);
break
;
case
BSON_TYPE_UTF8:
ret = bson_append_utf8 (bson, key, key_length,
value->value.v_utf8.str,
value->value.v_utf8.len);
break
;
case
BSON_TYPE_DOCUMENT:
if
(bson_init_static (&local,
value->value.v_doc.data,
value->value.v_doc.data_len)) {
ret = bson_append_document (bson, key, key_length, &local);
bson_destroy (&local);
}
break
;
case
BSON_TYPE_ARRAY:
if
(bson_init_static (&local,
value->value.v_doc.data,
value->value.v_doc.data_len)) {
ret = bson_append_array (bson, key, key_length, &local);
bson_destroy (&local);
}
break
;
case
BSON_TYPE_BINARY:
ret = bson_append_binary (bson, key, key_length,
value->value.v_binary.subtype,
value->value.v_binary.data,
value->value.v_binary.data_len);
break
;
case
BSON_TYPE_UNDEFINED:
ret = bson_append_undefined (bson, key, key_length);
break
;
case
BSON_TYPE_OID:
ret = bson_append_oid (bson, key, key_length, &value->value.v_oid);
break
;
case
BSON_TYPE_BOOL:
ret = bson_append_bool (bson, key, key_length, value->value.v_bool);
break
;
case
BSON_TYPE_DATE_TIME:
ret = bson_append_date_time (bson, key, key_length,
value->value.v_datetime);
break
;
case
BSON_TYPE_NULL:
ret = bson_append_null (bson, key, key_length);
break
;
case
BSON_TYPE_REGEX:
ret = bson_append_regex (bson, key, key_length,
value->value.v_regex.regex,
value->value.v_regex.options);
break
;
case
BSON_TYPE_DBPOINTER:
ret = bson_append_dbpointer (bson, key, key_length,
value->value.v_dbpointer.collection,
&value->value.v_dbpointer.oid);
break
;
case
BSON_TYPE_CODE:
ret = bson_append_code (bson, key, key_length,
value->value.v_code.code);
break
;
case
BSON_TYPE_SYMBOL:
ret = bson_append_symbol (bson, key, key_length,
value->value.v_symbol.symbol,
value->value.v_symbol.len);
break
;
case
BSON_TYPE_CODEWSCOPE:
if
(bson_init_static (&local,
value->value.v_codewscope.scope_data,
value->value.v_codewscope.scope_len)) {
ret = bson_append_code_with_scope (bson, key, key_length,
value->value.v_codewscope.code,
&local);
bson_destroy (&local);
}
break
;
case
BSON_TYPE_INT32:
ret = bson_append_int32 (bson, key, key_length, value->value.v_int32);
break
;
case
BSON_TYPE_TIMESTAMP:
ret = bson_append_timestamp (bson, key, key_length,
value->value.v_timestamp.timestamp,
value->value.v_timestamp.increment);
break
;
case
BSON_TYPE_INT64:
ret = bson_append_int64 (bson, key, key_length, value->value.v_int64);
break
;
case
BSON_TYPE_MAXKEY:
ret = bson_append_maxkey (bson, key, key_length);
break
;
case
BSON_TYPE_MINKEY:
ret = bson_append_minkey (bson, key, key_length);
break
;
case
BSON_TYPE_EOD:
default
:
break
;
}
return
ret;
}
void
bson_init (bson_t *bson)
{
bson_impl_inline_t *impl = (bson_impl_inline_t *)bson;
bson_return_if_fail (bson);
impl->flags = BSON_FLAG_INLINE | BSON_FLAG_STATIC;
impl->len = 5;
impl->data[0] = 5;
impl->data[1] = 0;
impl->data[2] = 0;
impl->data[3] = 0;
impl->data[4] = 0;
}
void
bson_reinit (bson_t *bson)
{
uint8_t *data;
bson_return_if_fail (bson);
data = _bson_data (bson);
bson->len = 5;
data [0] = 5;
data [1] = 0;
data [2] = 0;
data [3] = 0;
data [4] = 0;
}
bool
bson_init_static (bson_t *bson,
const
uint8_t *data,
size_t
length)
{
bson_impl_alloc_t *impl = (bson_impl_alloc_t *)bson;
uint32_t len_le;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (data,
false
);
if
((length < 5) || (length > INT_MAX)) {
return
false
;
}
memcpy
(&len_le, data,
sizeof
(len_le));
if
((
size_t
)BSON_UINT32_FROM_LE (len_le) != length) {
return
false
;
}
if
(data[length - 1]) {
return
false
;
}
impl->flags = BSON_FLAG_STATIC | BSON_FLAG_RDONLY;
impl->len = (uint32_t)length;
impl->parent = NULL;
impl->depth = 0;
impl->buf = &impl->alloc;
impl->buflen = &impl->alloclen;
impl->offset = 0;
impl->alloc = (uint8_t *)data;
impl->alloclen = length;
impl->
realloc
= NULL;
impl->realloc_func_ctx = NULL;
return
true
;
}
bson_t *
bson_new (
void
)
{
bson_impl_inline_t *impl;
bson_t *bson;
bson = bson_malloc (
sizeof
*bson);
impl = (bson_impl_inline_t *)bson;
impl->flags = BSON_FLAG_INLINE;
impl->len = 5;
impl->data[0] = 5;
impl->data[1] = 0;
impl->data[2] = 0;
impl->data[3] = 0;
impl->data[4] = 0;
return
bson;
}
bson_t *
bson_sized_new (
size_t
size)
{
bson_impl_alloc_t *impl_a;
bson_impl_inline_t *impl_i;
bson_t *b;
bson_return_val_if_fail (size <= INT32_MAX, NULL);
b = bson_malloc (
sizeof
*b);
impl_a = (bson_impl_alloc_t *)b;
impl_i = (bson_impl_inline_t *)b;
if
(size <=
sizeof
impl_i->data) {
bson_init (b);
b->flags &= ~BSON_FLAG_STATIC;
}
else
{
impl_a->flags = BSON_FLAG_NONE;
impl_a->len = 5;
impl_a->parent = NULL;
impl_a->depth = 0;
impl_a->buf = &impl_a->alloc;
impl_a->buflen = &impl_a->alloclen;
impl_a->offset = 0;
impl_a->alloclen = BSON_MAX (5, size);
impl_a->alloc = bson_malloc (impl_a->alloclen);
impl_a->alloc[0] = 5;
impl_a->alloc[1] = 0;
impl_a->alloc[2] = 0;
impl_a->alloc[3] = 0;
impl_a->alloc[4] = 0;
impl_a->
realloc
= bson_realloc_ctx;
impl_a->realloc_func_ctx = NULL;
}
return
b;
}
bson_t *
bson_new_from_data (
const
uint8_t *data,
size_t
length)
{
uint32_t len_le;
bson_t *bson;
bson_return_val_if_fail (data, NULL);
if
((length < 5) || (length > INT_MAX) || data [length - 1]) {
return
NULL;
}
memcpy
(&len_le, data,
sizeof
(len_le));
if
(length != (
size_t
)BSON_UINT32_FROM_LE (len_le)) {
return
NULL;
}
bson = bson_sized_new (length);
memcpy
(_bson_data (bson), data, length);
bson->len = (uint32_t)length;
return
bson;
}
bson_t *
bson_new_from_buffer (uint8_t **buf,
size_t
*buf_len,
bson_realloc_func realloc_func,
void
*realloc_func_ctx)
{
bson_impl_alloc_t *impl;
uint32_t len_le;
uint32_t length;
bson_t *bson;
bson_return_val_if_fail (buf, NULL);
bson_return_val_if_fail (buf_len, NULL);
if
(!realloc_func) {
realloc_func = bson_realloc_ctx;
}
bson = bson_malloc0 (
sizeof
*bson);
impl = (bson_impl_alloc_t *)bson;
if
(!*buf) {
length = 5;
len_le = BSON_UINT32_TO_LE (length);
*buf_len = 5;
*buf = realloc_func (*buf, *buf_len, realloc_func_ctx);
memcpy
(*buf, &len_le,
sizeof
(len_le));
(*buf) [4] =
'\0'
;
}
else
{
if
((*buf_len < 5) || (*buf_len > INT_MAX)) {
bson_free (bson);
return
NULL;
}
memcpy
(&len_le, *buf,
sizeof
(len_le));
length = BSON_UINT32_FROM_LE(len_le);
}
if
((*buf)[length - 1]) {
bson_free (bson);
return
NULL;
}
impl->flags = BSON_FLAG_NO_FREE;
impl->len = length;
impl->buf = buf;
impl->buflen = buf_len;
impl->
realloc
= realloc_func;
impl->realloc_func_ctx = realloc_func_ctx;
return
bson;
}
bson_t *
bson_copy (
const
bson_t *bson)
{
const
uint8_t *data;
bson_return_val_if_fail (bson, NULL);
data = _bson_data (bson);
return
bson_new_from_data (data, bson->len);
}
void
bson_copy_to (
const
bson_t *src,
bson_t *dst)
{
const
uint8_t *data;
bson_impl_alloc_t *adst;
size_t
len;
bson_return_if_fail (src);
bson_return_if_fail (dst);
if
((src->flags & BSON_FLAG_INLINE)) {
memcpy
(dst, src,
sizeof
*dst);
dst->flags = (BSON_FLAG_STATIC | BSON_FLAG_INLINE);
return
;
}
data = _bson_data (src);
len = bson_next_power_of_two ((
size_t
)src->len);
adst = (bson_impl_alloc_t *)dst;
adst->flags = BSON_FLAG_STATIC;
adst->len = src->len;
adst->parent = NULL;
adst->depth = 0;
adst->buf = &adst->alloc;
adst->buflen = &adst->alloclen;
adst->offset = 0;
adst->alloc = bson_malloc (len);
adst->alloclen = len;
adst->
realloc
= bson_realloc_ctx;
adst->realloc_func_ctx = NULL;
memcpy
(adst->alloc, data, src->len);
}
static
bool
should_ignore (
const
char
*first_exclude,
va_list
args,
const
char
*name)
{
bool
ret =
false
;
const
char
*exclude = first_exclude;
va_list
args_copy;
va_copy (args_copy, args);
do
{
if
(!
strcmp
(name, exclude)) {
ret =
true
;
break
;
}
}
while
((exclude =
va_arg
(args_copy,
const
char
*)));
va_end
(args_copy);
return
ret;
}
static
void
_bson_copy_to_excluding_va (
const
bson_t *src,
bson_t *dst,
const
char
*first_exclude,
va_list
args)
{
bson_iter_t iter;
if
(bson_iter_init (&iter, src)) {
while
(bson_iter_next (&iter)) {
if
(!should_ignore (first_exclude, args, bson_iter_key (&iter))) {
if
(!bson_append_iter (dst, NULL, 0, &iter)) {
BSON_ASSERT (
false
);
return
;
}
}
}
}
}
void
bson_copy_to_excluding (
const
bson_t *src,
bson_t *dst,
const
char
*first_exclude,
...)
{
va_list
args;
bson_return_if_fail (src);
bson_return_if_fail (dst);
bson_return_if_fail (first_exclude);
bson_init (dst);
va_start
(args, first_exclude);
_bson_copy_to_excluding_va (src, dst, first_exclude, args);
va_end
(args);
}
void
bson_copy_to_excluding_noinit (
const
bson_t *src,
bson_t *dst,
const
char
*first_exclude,
...)
{
va_list
args;
bson_return_if_fail (src);
bson_return_if_fail (dst);
bson_return_if_fail (first_exclude);
va_start
(args, first_exclude);
_bson_copy_to_excluding_va (src, dst, first_exclude, args);
va_end
(args);
}
void
bson_destroy (bson_t *bson)
{
BSON_ASSERT (bson);
if
(!(bson->flags &
(BSON_FLAG_RDONLY | BSON_FLAG_INLINE | BSON_FLAG_NO_FREE))) {
bson_free (*((bson_impl_alloc_t *)bson)->buf);
}
if
(!(bson->flags & BSON_FLAG_STATIC)) {
bson_free (bson);
}
}
uint8_t *
bson_destroy_with_steal (bson_t *bson,
bool
steal,
uint32_t *length)
{
uint8_t *ret = NULL;
bson_return_val_if_fail (bson, NULL);
if
(length) {
*length = bson->len;
}
if
(!steal) {
bson_destroy (bson);
return
NULL;
}
if
((bson->flags & (BSON_FLAG_CHILD |
BSON_FLAG_IN_CHILD |
BSON_FLAG_RDONLY))) {
}
else
if
((bson->flags & BSON_FLAG_INLINE)) {
bson_impl_inline_t *inl;
inl = (bson_impl_inline_t *)bson;
ret = bson_malloc (bson->len);
memcpy
(ret, inl->data, bson->len);
}
else
{
bson_impl_alloc_t *alloc;
alloc = (bson_impl_alloc_t *)bson;
ret = *alloc->buf;
*alloc->buf = NULL;
}
bson_destroy (bson);
return
ret;
}
const
uint8_t *
bson_get_data (
const
bson_t *bson)
{
bson_return_val_if_fail (bson, NULL);
return
_bson_data (bson);
}
uint32_t
bson_count_keys (
const
bson_t *bson)
{
uint32_t count = 0;
bson_iter_t iter;
bson_return_val_if_fail (bson, 0);
if
(bson_iter_init (&iter, bson)) {
while
(bson_iter_next (&iter)) {
count++;
}
}
return
count;
}
bool
bson_has_field (
const
bson_t *bson,
const
char
*key)
{
bson_iter_t iter;
bson_iter_t child;
bson_return_val_if_fail (bson,
false
);
bson_return_val_if_fail (key,
false
);
if
(NULL !=
strchr
(key,
'.'
)) {
return
(bson_iter_init (&iter, bson) &&
bson_iter_find_descendant (&iter, key, &child));
}
return
bson_iter_init_find (&iter, bson, key);
}
int
bson_compare (
const
bson_t *bson,
const
bson_t *other)
{
const
uint8_t *data1;
const
uint8_t *data2;
size_t
len1;
size_t
len2;
int64_t ret;
data1 = _bson_data (bson) + 4;
len1 = bson->len - 4;
data2 = _bson_data (other) + 4;
len2 = other->len - 4;
if
(len1 == len2) {
return
memcmp
(data1, data2, len1);
}
ret =
memcmp
(data1, data2, BSON_MIN (len1, len2));
if
(ret == 0) {
ret = len1 - len2;
}
return
(ret < 0) ? -1 : (ret > 0);
}
bool
bson_equal (
const
bson_t *bson,
const
bson_t *other)
{
return
!bson_compare (bson, other);
}
static
bool
_bson_iter_validate_utf8 (
const
bson_iter_t *iter,
const
char
*key,
size_t
v_utf8_len,
const
char
*v_utf8,
void
*data)
{
bson_validate_state_t *state = data;
bool
allow_null;
if
((state->flags & BSON_VALIDATE_UTF8)) {
allow_null = !!(state->flags & BSON_VALIDATE_UTF8_ALLOW_NULL);
if
(!bson_utf8_validate (v_utf8, v_utf8_len, allow_null)) {
state->err_offset = iter->off;
return
true
;
}
}
if
((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) {
if
(state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8) {
state->phase = BSON_VALIDATE_PHASE_LF_ID_KEY;
}
else
if
(state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) {
state->phase = BSON_VALIDATE_PHASE_NOT_DBREF;
}
}
return
false
;
}
static
void
_bson_iter_validate_corrupt (
const
bson_iter_t *iter,
void
*data)
{
bson_validate_state_t *state = data;
state->err_offset = iter->err_off;
}
static
bool
_bson_iter_validate_before (
const
bson_iter_t *iter,
const
char
*key,
void
*data)
{
bson_validate_state_t *state = data;
if
((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) {
if
(key[0] ==
'$'
) {
if
(state->phase == BSON_VALIDATE_PHASE_LF_REF_KEY &&
strcmp
(key,
"$ref"
) == 0) {
state->phase = BSON_VALIDATE_PHASE_LF_REF_UTF8;
}
else
if
(state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY &&
strcmp
(key,
"$id"
) == 0) {
state->phase = BSON_VALIDATE_PHASE_LF_DB_KEY;
}
else
if
(state->phase == BSON_VALIDATE_PHASE_LF_DB_KEY &&
strcmp
(key,
"$db"
) == 0) {
state->phase = BSON_VALIDATE_PHASE_LF_DB_UTF8;
}
else
{
state->err_offset = iter->off;
return
true
;
}
}
else
if
(state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY ||
state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 ||
state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) {
state->err_offset = iter->off;
return
true
;
}
else
{
state->phase = BSON_VALIDATE_PHASE_NOT_DBREF;
}
}
if
((state->flags & BSON_VALIDATE_DOT_KEYS)) {
if
(
strstr
(key,
"."
)) {
state->err_offset = iter->off;
return
true
;
}
}
return
false
;
}
static
bool
_bson_iter_validate_codewscope (
const
bson_iter_t *iter,
const
char
*key,
size_t
v_code_len,
const
char
*v_code,
const
bson_t *v_scope,
void
*data)
{
bson_validate_state_t *state = data;
size_t
offset;
if
(!bson_validate (v_scope, state->flags, &offset)) {
state->err_offset = iter->off + offset;
return
false
;
}
return
true
;
}
static
bool
_bson_iter_validate_document (
const
bson_iter_t *iter,
const
char
*key,
const
bson_t *v_document,
void
*data);
static
const
bson_visitor_t bson_validate_funcs = {
_bson_iter_validate_before,
NULL,
_bson_iter_validate_corrupt,
NULL,
_bson_iter_validate_utf8,
_bson_iter_validate_document,
_bson_iter_validate_document,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
_bson_iter_validate_codewscope,
};
static
bool
_bson_iter_validate_document (
const
bson_iter_t *iter,
const
char
*key,
const
bson_t *v_document,
void
*data)
{
bson_validate_state_t *state = data;
bson_iter_t child;
bson_validate_phase_t phase = state->phase;
if
(!bson_iter_init (&child, v_document)) {
state->err_offset = iter->off;
return
true
;
}
if
(state->phase == BSON_VALIDATE_PHASE_START) {
state->phase = BSON_VALIDATE_PHASE_TOP;
}
else
{
state->phase = BSON_VALIDATE_PHASE_LF_REF_KEY;
}
bson_iter_visit_all (&child, &bson_validate_funcs, state);
if
(state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY ||
state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 ||
state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) {
state->err_offset = iter->off;
return
true
;
}
state->phase = phase;
return
false
;
}
bool
bson_validate (
const
bson_t *bson,
bson_validate_flags_t flags,
size_t
*offset)
{
bson_validate_state_t state = { flags, -1, BSON_VALIDATE_PHASE_START };
bson_iter_t iter;
if
(!bson_iter_init (&iter, bson)) {
state.err_offset = 0;
goto
failure;
}
_bson_iter_validate_document (&iter, NULL, bson, &state);
failure:
if
(offset) {
*offset = state.err_offset;
}
return
state.err_offset < 0;
}
bool
bson_concat (bson_t *dst,
const
bson_t *src)
{
BSON_ASSERT (dst);
BSON_ASSERT (src);
if
(!bson_empty (src)) {
return
_bson_append (dst, 1, src->len - 5,
src->len - 5, _bson_data (src) + 4);
}
return
true
;
}