diff options
author | px4dev <px4@purgatory.org> | 2012-08-19 01:30:17 -0700 |
---|---|---|
committer | px4dev <px4@purgatory.org> | 2012-08-19 01:31:27 -0700 |
commit | a9dc84231e0e02abbbfd2f13e3500d193ebdb03b (patch) | |
tree | 1bdd070cd212a0a25a4d3343e2bf69805528f7d9 /apps | |
parent | 2c850752214ea0ce3a8bebe51d09e651d6d7706d (diff) | |
download | px4-firmware-a9dc84231e0e02abbbfd2f13e3500d193ebdb03b.tar.gz px4-firmware-a9dc84231e0e02abbbfd2f13e3500d193ebdb03b.tar.bz2 px4-firmware-a9dc84231e0e02abbbfd2f13e3500d193ebdb03b.zip |
Import of the Mongo C-BSON library with light modifications for PX4.
From https://github.com/mongodb/mongo-c-driver.git at 8ae2c57e95a3939850a77fb9329c129b2bcfcd1a
Diffstat (limited to 'apps')
-rw-r--r-- | apps/systemlib/bson/bcon.c | 427 | ||||
-rw-r--r-- | apps/systemlib/bson/bcon.h | 420 | ||||
-rw-r--r-- | apps/systemlib/bson/bson.c | 1049 | ||||
-rw-r--r-- | apps/systemlib/bson/bson.h | 1044 |
4 files changed, 2940 insertions, 0 deletions
diff --git a/apps/systemlib/bson/bcon.c b/apps/systemlib/bson/bcon.c new file mode 100644 index 000000000..8fa9a2c9d --- /dev/null +++ b/apps/systemlib/bson/bcon.c @@ -0,0 +1,427 @@ +/* bcon.c */ + +/* Copyright 2009-2012 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <assert.h> +#include "bcon.h" + +/* PX4 */ +#include <debug.h> +#define assert(_x) ASSERT(_x) + +#ifndef NOT_REACHED +#define NOT_REACHED 0 +#endif + +#define ARRAY_INDEX_BUFFER_SIZE 9 + +char *bcon_errstr[] = { + "OK", + "ERROR", + "bcon document or nesting incomplete", + "bson finish error" +}; + +int bcon_error(bson *b, const bcon *bc, size_t i, bcon_error_t err) { + b->err = err; + b->errstr = bcon_errstr[err]; + return BCON_ERROR; +} + +bcon_error_t bson_append_bcon_array(bson *b, const bcon *bc); + +bcon_token_t bcon_token(char *s) { + if (s == 0) return Token_EOD; + switch (s[0]) { + case ':': if (s[1] != '\0' && s[2] != '\0' && s[3] != '\0' && s[4] == '\0' && + s[3] == ':' && (s[1] == '_' || s[1] == 'P' || s[1] == 'R')) + return Token_Typespec; break; + case '{': if (s[1] == '\0') return Token_OpenBrace; break; + case '}': if (s[1] == '\0') return Token_CloseBrace; break; + case '[': if (s[1] == '\0') return Token_OpenBracket; break; + case ']': if (s[1] == '\0') return Token_CloseBracket; break; + case '.': if (s[1] == '\0') return Token_End; break; + } + return Token_Default; +} + +bcon_error_t bson_bcon_key_value(bson *b, const char *key, const char *typespec, const bcon bci) { + bcon_error_t ret = BCON_OK; + bson_oid_t oid; + char ptype = typespec ? typespec[1] : '_'; + char utype = typespec ? typespec[2] : '_'; + switch (ptype) { + case '_': /* kv(b, key, utype, bci) */ + switch (utype) { + case '_': /* fall through */ + case 's': bson_append_string( b, key, bci.s ); break; /* common case */ + case 'f': bson_append_double( b, key, bci.f ); break; + case 'D': + bson_append_start_object( b, key ); + ret = bson_append_bcon( b, bci.D ); + bson_append_finish_object( b ); + break; + case 'A': + bson_append_start_array( b, key ); + ret = bson_append_bcon_array( b, bci.A ); + bson_append_finish_array( b ); + break; + case 'o': if (*bci.o == '\0') bson_oid_gen( &oid ); else bson_oid_from_string( &oid, bci.o ); bson_append_oid( b, key, &oid ); break; + case 'b': bson_append_bool( b, key, bci.b ); break; + case 't': bson_append_time_t( b, key, bci.t ); break; + case 'v': bson_append_null( b, key ); break; /* void */ + case 'x': bson_append_symbol( b, key, bci.x ); break; + case 'i': bson_append_int( b, key, bci.i ); break; + case 'l': bson_append_long( b, key, bci.l ); break; + default: printf("\nptype:'%c' utype:'%c'\n", ptype, utype); assert(NOT_REACHED); break; + } + break; + case 'R': /* krv(b, key, utype, bci) */ + switch (utype) { + case 'f': bson_append_double( b, key, *bci.Rf ); break; + case 's': bson_append_string( b, key, bci.Rs ); break; + case 'D': + bson_append_start_object( b, key ); + ret = bson_append_bcon( b, bci.RD ); + bson_append_finish_object( b ); + break; + case 'A': + bson_append_start_array( b, key ); + ret = bson_append_bcon_array( b, bci.RA ); + bson_append_finish_array( b ); + break; + case 'o': if (*bci.o == '\0') bson_oid_gen( &oid ); else bson_oid_from_string( &oid, bci.o ); bson_append_oid( b, key, &oid ); break; + case 'b': bson_append_bool( b, key, *bci.Rb ); break; + case 't': bson_append_time_t( b, key, *bci.Rt ); break; + case 'x': bson_append_symbol( b, key, bci.Rx ); break; + case 'i': bson_append_int( b, key, *bci.Ri ); break; + case 'l': bson_append_long( b, key, *bci.Rl ); break; + default: printf("\nptype:'%c' utype:'%c'\n", ptype, utype); assert(NOT_REACHED); break; + } + break; + case 'P': /* kpv(b, key, utype, bci) */ + if (*bci.Pv != 0) { + switch (utype) { + case 'f': bson_append_double( b, key, **bci.Pf ); break; + case 's': bson_append_string( b, key, *bci.Ps ); break; + case 'D': + bson_append_start_object( b, key ); + ret = bson_append_bcon( b, *bci.PD ); + bson_append_finish_object( b ); + break; + case 'A': + bson_append_start_array( b, key ); + ret = bson_append_bcon_array( b, *bci.PA ); + bson_append_finish_array( b ); + break; + case 'o': if (**bci.Po == '\0') bson_oid_gen( &oid ); + else bson_oid_from_string( &oid, *bci.Po ); + bson_append_oid( b, key, &oid ); + break; + case 'b': bson_append_bool( b, key, **bci.Pb ); break; + case 't': bson_append_time_t( b, key, **bci.Pt ); break; + case 'x': if (*bci.Px != 0) bson_append_symbol( b, key, *bci.Px ); break; + case 'i': bson_append_int( b, key, **bci.Pi ); break; + case 'l': bson_append_long( b, key, **bci.Pl ); break; + default: printf("\nptype:'%c' utype:'%c'\n", ptype, utype); assert(NOT_REACHED); break; + } + } + break; + default: + printf("\nptype:'%c' utype:'%c'\n", ptype, utype); assert(NOT_REACHED); + break; + } + return ret; +} + +typedef enum bcon_state_t { + State_Element, State_DocSpecValue, State_DocValue, + State_ArraySpecValue, State_ArrayValue +} bcon_state_t; + +#define DOC_STACK_SIZE 128 +#define ARRAY_INDEX_STACK_SIZE 128 + +#define DOC_PUSH_STATE(return_state) ( doc_stack[doc_stack_pointer++] = (return_state) ) +#define DOC_POP_STATE ( state = doc_stack[--doc_stack_pointer] ) +#define ARRAY_PUSH_RESET_INDEX_STATE(return_state) ( array_index_stack[array_index_stack_pointer++] = array_index, array_index = 0, DOC_PUSH_STATE(return_state) ) +#define ARRAY_POP_INDEX_STATE ( array_index = array_index_stack[--array_index_stack_pointer], DOC_POP_STATE ) + +#define ARRAY_KEY_STRING(l) (bson_numstr(array_index_buffer, (int)(l)), array_index_buffer) + +/* + * simplified FSM to parse BCON structure, uses stacks for sub-documents and sub-arrays + */ +bcon_error_t bson_append_bcon_with_state(bson *b, const bcon *bc, bcon_state_t start_state) { + bcon_error_t ret = BCON_OK; + bcon_state_t state = start_state; + char *key = 0; + char *typespec = 0; + unsigned char doc_stack[DOC_STACK_SIZE]; + size_t doc_stack_pointer = 0; + size_t array_index = 0; + unsigned int array_index_stack[ARRAY_INDEX_STACK_SIZE]; + size_t array_index_stack_pointer = 0; + char array_index_buffer[ARRAY_INDEX_BUFFER_SIZE]; /* max BSON size */ + int end_of_data; + const bcon *bcp; + for (end_of_data = 0, bcp = bc; ret == BCON_OK && !end_of_data; bcp++) { + bcon bci = *bcp; + char *s = bci.s; + switch (state) { + case State_Element: + switch (bcon_token(s)) { + case Token_CloseBrace: + bson_append_finish_object( b ); + DOC_POP_STATE; /* state = ...; */ + break; + case Token_End: + end_of_data = 1; + break; + default: + key = s; + state = State_DocSpecValue; + break; + } + break; + case State_DocSpecValue: + switch (bcon_token(s)) { + case Token_Typespec: + typespec = s; + state = State_DocValue; + break; + case Token_OpenBrace: + bson_append_start_object( b, key ); + DOC_PUSH_STATE(State_Element); + state = State_Element; + break; + case Token_OpenBracket: + bson_append_start_array( b, key ); + ARRAY_PUSH_RESET_INDEX_STATE(State_Element); + state = State_ArraySpecValue; + break; + case Token_End: + end_of_data = 1; + break; + default: + ret = bson_bcon_key_value(b, key, typespec, bci); + state = State_Element; + break; + } + break; + case State_DocValue: + ret = bson_bcon_key_value(b, key, typespec, bci); + state = State_Element; + typespec = 0; + break; + case State_ArraySpecValue: + switch (bcon_token(s)) { + case Token_Typespec: + typespec = s; + state = State_ArrayValue; + break; + case Token_OpenBrace: + key = ARRAY_KEY_STRING(array_index++); + bson_append_start_object( b, key ); + DOC_PUSH_STATE(State_ArraySpecValue); + state = State_Element; + break; + case Token_OpenBracket: + key = ARRAY_KEY_STRING(array_index++); + bson_append_start_array( b, key ); + ARRAY_PUSH_RESET_INDEX_STATE(State_ArraySpecValue); + /* state = State_ArraySpecValue; */ + break; + case Token_CloseBracket: + bson_append_finish_array( b ); + ARRAY_POP_INDEX_STATE; /* state = ...; */ + break; + case Token_End: + end_of_data = 1; + break; + default: + key = ARRAY_KEY_STRING(array_index++); + ret = bson_bcon_key_value(b, key, typespec, bci); + /* state = State_ArraySpecValue; */ + break; + } + break; + case State_ArrayValue: + key = ARRAY_KEY_STRING(array_index++); + ret = bson_bcon_key_value(b, key, typespec, bci); + state = State_ArraySpecValue; + typespec = 0; + break; + default: assert(NOT_REACHED); break; + } + } + return state == start_state ? BCON_OK : BCON_DOCUMENT_INCOMPLETE; +} + +bcon_error_t bson_append_bcon(bson *b, const bcon *bc) { + return bson_append_bcon_with_state(b, bc, State_Element); +} + +bcon_error_t bson_append_bcon_array(bson *b, const bcon *bc) { + return bson_append_bcon_with_state(b, bc, State_ArraySpecValue); +} + +/** + * Generate BSON from BCON + * @param b a BSON object + * @param bc a BCON object + * match with bson_destroy + */ +bcon_error_t bson_from_bcon(bson *b, const bcon *bc) { + bcon_error_t ret = BSON_OK; + bson_init( b ); + ret = bson_append_bcon_with_state( b, bc, State_Element ); + if (ret != BCON_OK) return ret; + ret = bson_finish( b ); + return ( ret == BSON_OK ? BCON_OK : BCON_BSON_ERROR ); +} + +void bcon_print(const bcon *bc) { /* prints internal representation, not JSON */ + char *typespec = 0; + char *delim = ""; + int end_of_data; + bcon *bcp; + putchar('{'); + for (end_of_data = 0, bcp = (bcon*)bc; !end_of_data; bcp++) { + bcon bci = *bcp; + char *typespec_next = 0; + if (typespec) { + switch (typespec[1]) { + case '_': + switch (typespec[2]) { + case 'f': printf("%s%f", delim, bci.f); break; + case 's': printf("%s\"%s\"", delim, bci.s); break; + case 'D': printf("%sPD(0x%lx,..)", delim, (unsigned long)bci.D); break; + case 'A': printf("%sPA(0x%lx,....)", delim, (unsigned long)bci.A); break; + case 'o': printf("%s\"%s\"", delim, bci.o); break; + case 'b': printf("%s%d", delim, bci.b); break; + case 't': printf("%s%ld", delim, (long)bci.t); break; + case 'v': printf("%s\"%s\"", delim, bci.v); break; + case 'x': printf("%s\"%s\"", delim, bci.x); break; + case 'i': printf("%s%d", delim, bci.i); break; + case 'l': printf("%s%ld", delim, bci.l); break; + default: printf("\ntypespec:\"%s\"\n", typespec); assert(NOT_REACHED); break; + } + break; + case 'R': + switch (typespec[2]) { + case 'f': printf("%sRf(0x%lx,%f)", delim, (unsigned long)bci.Rf, *bci.Rf); break; + case 's': printf("%sRs(0x%lx,\"%s\")", delim, (unsigned long)bci.Rs, bci.Rs); break; + case 'D': printf("%sRD(0x%lx,..)", delim, (unsigned long)bci.RD); break; + case 'A': printf("%sRA(0x%lx,....)", delim, (unsigned long)bci.RA); break; + case 'o': printf("%sRo(0x%lx,\"%s\")", delim, (unsigned long)bci.Ro, bci.Ro); break; + case 'b': printf("%sRb(0x%lx,%d)", delim, (unsigned long)bci.Rb, *bci.Rb); break; + case 't': printf("%sRt(0x%lx,%ld)", delim, (unsigned long)bci.Rt, (long)*bci.Rt); break; + case 'x': printf("%sRx(0x%lx,\"%s\")", delim, (unsigned long)bci.Rx, bci.Rx); break; + case 'i': printf("%sRi(0x%lx,%d)", delim, (unsigned long)bci.Ri, *bci.Ri); break; + case 'l': printf("%sRl(0x%lx,%ld)", delim, (unsigned long)bci.Rl, *bci.Rl); break; + default: printf("\ntypespec:\"%s\"\n", typespec); assert(NOT_REACHED); break; + } + break; + case 'P': + switch (typespec[2]) { + case 'f': printf("%sPf(0x%lx,0x%lx,%f)", delim, (unsigned long)bci.Pf, (unsigned long)(bci.Pf ? *bci.Pf : 0), bci.Pf && *bci.Pf ? **bci.Pf : 0.0); break; + case 's': printf("%sPs(0x%lx,0x%lx,\"%s\")", delim, (unsigned long)bci.Ps, (unsigned long)(bci.Ps ? *bci.Ps : 0), bci.Ps && *bci.Ps ? *bci.Ps : ""); break; + case 'D': printf("%sPD(0x%lx,0x%lx,..)", delim, (unsigned long)bci.PD, (unsigned long)(bci.PD ? *bci.PD : 0)); break; + case 'A': printf("%sPA(0x%lx,0x%lx,....)", delim, (unsigned long)bci.PA, (unsigned long)(bci.PA ? *bci.PA : 0)); break; + case 'o': printf("%sPo(0x%lx,0x%lx,\"%s\")", delim, (unsigned long)bci.Po, (unsigned long)(bci.Po ? *bci.Po : 0), bci.Po && *bci.Po ? *bci.Po : ""); break; + case 'b': printf("%sPb(0x%lx,0x%lx,%d)", delim, (unsigned long)bci.Pb, (unsigned long)(bci.Pb ? *bci.Pb : 0), bci.Pb && *bci.Pb ? **bci.Pb : 0); break; + case 't': printf("%sPt(0x%lx,0x%lx,%ld)", delim, (unsigned long)bci.Pt, (unsigned long)(bci.Pt ? *bci.Pt : 0), bci.Pt && *bci.Pt ? (long)**bci.Pt : 0); break; + case 'x': printf("%sPx(0x%lx,0x%lx,\"%s\")", delim, (unsigned long)bci.Px, (unsigned long)(bci.Px ? *bci.Px : 0), bci.Px && *bci.Px ? *bci.Px : ""); break; + case 'i': printf("%sPi(0x%lx,0x%lx,%d)", delim, (unsigned long)bci.Pi, (unsigned long)(bci.Pi ? *bci.Pi : 0), bci.Pi && *bci.Pi ? **bci.Pi : 0); break; + case 'l': printf("%sPl(0x%lx,0x%lx,%ld)", delim, (unsigned long)bci.Pl, (unsigned long)(bci.Pl ? *bci.Pl : 0), bci.Pl && *bci.Pl ? **bci.Pl : 0); break; + + default: printf("\ntypespec:\"%s\"\n", typespec); assert(NOT_REACHED); break; + } + break; + default: + printf("\ntypespec:\"%s\"\n", typespec); assert(NOT_REACHED); + break; + } + } + else { + char *s = bci.s; + switch (s[0]) { + case '.': + end_of_data = (s[1] == '\0'); + break; + case ':': + typespec_next = bcon_token(s) == Token_Typespec ? s : 0; + break; + } + printf("%s\"%s\"", delim, s); + } + typespec = typespec_next; + delim = ","; + } + putchar('}'); +} + +/* TODO - incomplete */ +void bcon_json_print(bcon *bc, int n) { + int t = 0; + int key_value_count = 0; + char *s; + int end_of_data; + bcon *bcp; + putchar('{'); + for (end_of_data = 0, bcp = bc; !end_of_data; bcp++) { + bcon bci = *bcp; + switch (t) { + case 'l': + if (key_value_count & 0x1) putchar(':'); + printf("%ld", bci.l); + t = 0; + key_value_count++; + break; + case 's': /* fall through */ + default: + s = bci.s; + switch (*s) { + case ':': + ++s; + t = *++s; + break; + case '{': + if (key_value_count & 0x1) putchar(':'); + putchar(*s); + key_value_count = 0; + break; + case '}': + putchar(*s); + key_value_count = 2; + break; + default: + if (key_value_count & 0x1) putchar(':'); + else if (key_value_count > 1) putchar(','); + printf("\"%s\"", s); + t = 0; + key_value_count++; + break; + } + break; + } + } + putchar('}'); +} diff --git a/apps/systemlib/bson/bcon.h b/apps/systemlib/bson/bcon.h new file mode 100644 index 000000000..a4a32faac --- /dev/null +++ b/apps/systemlib/bson/bcon.h @@ -0,0 +1,420 @@ +/** + * @file bcon.h + * @brief BCON (BSON C Object Notation) Declarations + */ + +/* Copyright 2009-2012 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCON_H_ +#define BCON_H_ + +#include "bson.h" + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +MONGO_EXTERN_C_START + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** + * BCON - BSON C Object Notation. + * + * Overview + * -------- + * BCON provides for JSON-like (or BSON-like) initializers in C. + * Without this, BSON must be constructed by procedural coding via explicit function calls. + * With this, you now have concise, readable, and maintainable data-driven definition of BSON documents. + * Here are a couple of introductory examples. + * + * bcon hello[] = { "hello", "world", "." }; + * bcon pi[] = { "pi", BF(3.14159), BEND }; + * + * BCON is an array of bcon union elements with the default type of char* cstring. + * A BCON document must be terminated with a char* cstring containing a single dot, i.e., ".", or the macro equivalent BEND. + * + * Cstring literals in double quotes are used for keys as well as for string values. + * There is no explicit colon (':') separator between key and value, just a comma, + * however it must be explicit or C will quietly concatenate the key and value strings for you. + * Readability may be improved by using multiple lines with a key-value pair per line. + * + * Macros are used to enclose specific types, and an internal type-specifier string prefixes a typed value. + * Macros are also used to specify interpolation of values from references (or pointers to references) of specified types. + * + * Sub-documents are framed by "{" "}" string literals, and sub-arrays are framed by "[" "]" literals. + * + * All of this is needed because C arrays and initializers are mono-typed unlike dict/array types in modern languages. + * BCON attempts to be readable and JSON-like within the context and restrictions of the C language. + * + * Specification + * ------------- + * This specification parallels the BSON specification ( http://bsonspec.org/#/specification ). + * The specific types and their corresponding macros are documented in the bcon (union bcon) structure. + * The base values use two-character macros starting with "B" for the simple initialization using static values. + * + * Examples + * -------- + * + * bcon goodbye[] = { "hello", "world", "goodbye", "world", "." }; + * bcon awesome[] = { "BSON", "[", "awesome", BF(5.05), BI(1986), "]", "." }; + * bcon contact_info[] = { + * "firstName", "John", + * "lastName" , "Smith", + * "age" , BI(25), + * "address" , + * "{", + * "streetAddress", "21 2nd Street", + * "city" , "New York", + * "state" , "NY", + * "postalCode" , "10021", + * "}", + * "phoneNumber", + * "[", + * "{", + * "type" , "home", + * "number", "212 555-1234", + * "}", + * "{", + * "type" , "fax", + * "number", "646 555-4567", + * "}", + * "]", + * BEND + * }; + * + * Comparison + * ---------- + * + * JSON: + * { "BSON" : [ "awesome", 5.05, 1986 ] } + * + * BCON: + * bcon awesome[] = { "BSON", "[", "awesome", BF(5.05), BI(1986), "]", BEND }; + * + * C driver calls: + * bson_init( b ); + * bson_append_start_array( b, "BSON" ); + * bson_append_string( b, "0", "awesome" ); + * bson_append_double( b, "1", 5.05 ); + * bson_append_int( b, "2", 1986 ); + * bson_append_finish_array( b ); + * ret = bson_finish( b ); + * bson_print( b ); + * bson_destroy( b ); + * + * Peformance + * ---------- + * With compiler optimization -O3, BCON costs about 1.1 to 1.2 times as much + * as the equivalent bson function calls required to explicitly construct the document. + * This is significantly less than the cost of parsing JSON and constructing BSON, + * and BCON allows value interpolation via pointers. + * + * Reference Interpolation + * ----------------------- + * Reference interpolation uses three-character macros starting with "BR" for simple dynamic values. + * You can change the referenced content and the new values will be interpolated when you generate BSON from BCON. + * + * bson b[1]; + * char name[] = "pi"; + * double value = 3.14159; + * bcon bc[] = { "name", BRS(name), "value", BRF(&value), BEND }; + * bson_from_bcon( b, bc ); // generates { name: "pi", "value", 3.14159 } + * strcpy(name, "e"); + * value = 2.71828; + * bson_from_bcon( b, bc ); // generates { name: "pi", "value", 3.14159 } + * + * Please remember that in C, the array type is anomalous in that an identifier is (already) a reference, + * therefore there is no ampersand '&' preceding the identifier for reference interpolation. + * This applies to BRS(cstring), BRD(doc), BRA(array), BRO(oid), and BRX(symbol). + * An ampersand '&' is needed for value types BRF(&double), BRB(&boolean), BRT(&time), BRI(&int), and BRL(&long). + * For completeness, BRS, BRD, BRA, BRO, and BRX are defined even though BS, BD, BA, BO, and BX are equivalent. + * + * Pointer Interpolation + * --------------------- + * Pointer(-to-reference) interpolation uses three-character macros starting with "BP" for _conditional_ dynamic values. + * You can change the pointer content and the new values will be interpolated when you generate BSON from BCON. + * If you set the pointer to null, the element will skipped and not inserted into the generated BSON document. + * + * bson b[1]; + * char name[] = "pi"; + * char new_name[] = "log(0)"; + * char **pname = (char**)&name; + * double value = 3.14159; + * double *pvalue = &value; + * bcon bc[] = { "name", BPS(&pname), "value", BPF(&pvalue), BEND }; + * bson_from_bcon( b, bc ); // generates { name: "pi", "value", 3.14159 } + * pname = (char**)&new_name; + * pvalue = 0; + * bson_from_bcon( b, bc ); // generates { name: "log(0)" } + * + * Pointer interpolation necessarily adds an extra level of indirection and complexity. + * All macro pointer arguments are preceded by '&'. + * Underlying pointer types are double-indirect (**) for array types and single-indirect (*) for value types. + * Char name[] is used above to highlight that the array reference is not assignable (in contrast to char *array). + * Please note the (char**)& cast-address sequence required to silence the "incompatible-pointer-types" warning. + * + * Additional Notes + * ---------------- + * Use the BS macro or the ":_s:" type specifier for string to allow string values that collide with type specifiers, braces, or square brackets. + * + * bson b[1]; + * bcon bc[] = { "spec", BS(":_s:"), BEND }; + * bson_from_bcon( b, bc ); // generates { spec: ":_s:" } + * + * BCON does not yet support the following BSON types. + * + * 05 e_name binary Binary data + * 06 e_name undefined - deprecated + * 0B e_name cstring cstring Regular expression + * 0C e_name string (byte*12) DBPointer - Deprecated + * 0D e_name string JavaScript code + * 0F e_name code_w_s JavaScript code w/ scope + * 11 e_name int64 Timestamp + * FF e_name Min key + * 7F e_name Max key + * + */ + +typedef union bcon { + char *s; /**< 02 e_name string Macro BS(v) - UTF-8 string */ /* must be first to be default */ + char *Rs; /**< 02 e_name string Macro BRS(v) - UTF-8 string reference interpolation */ + char **Ps; /**< 02 e_name string Macro BPS(v) - UTF-8 string pointer interpolation */ + double f; /**< 01 e_name double Macro BF(v) - Floating point */ + double *Rf; /**< 01 e_name double Macro BRF(v) - Floating point reference interpolation */ + double **Pf; /**< 01 e_name double Macro BPF(v) - Floating point pointer interpolation */ + union bcon *D; /**< 03 e_name document Macro BD(v) - Embedded document interpolation */ + union bcon *RD; /**< 03 e_name document Macro BRD(v) - Embedded document reference interpolation */ + union bcon **PD; /**< 03 e_name document Macro BPD(v) - Embedded document pointer interpolation */ + union bcon *A; /**< 04 e_name document Macro BA(v) - Array interpolation */ + union bcon *RA; /**< 04 e_name document Macro BRA(v) - Array reference interpolation */ + union bcon **PA; /**< 04 e_name document Macro BPA(v) - Array pointer interpolation */ + char *o; /**< 07 e_name (byte*12) Macro BO(v) - ObjectId */ + char *Ro; /**< 07 e_name (byte*12) Macro BRO(v) - ObjectId reference interpolation */ + char **Po; /**< 07 e_name (byte*12) Macro BPO(v) - ObjectId pointer interpolation */ + bson_bool_t b; /**< 08 e_name 00 Macro BB(v) - Boolean "false" + 08 e_name 01 Macro BB(v) - Boolean "true" */ + bson_bool_t *Rb; /**< 08 e_name 01 Macro BRB(v) - Boolean reference interpolation */ + bson_bool_t **Pb;/**< 08 e_name 01 Macro BPB(v) - Boolean pointer interpolation */ + time_t t; /**< 09 e_name int64 Macro BT(v) - UTC datetime */ + time_t *Rt; /**< 09 e_name int64 Macro BRT(v) - UTC datetime reference interpolation */ + time_t **Pt; /**< 09 e_name int64 Macro BPT(v) - UTC datetime pointer interpolation */ + char *v; /**< 0A e_name Macro BNULL - Null value */ + char *x; /**< 0E e_name string Macro BX(v) - Symbol */ + char *Rx; /**< 0E e_name string Macro BRX(v) - Symbol reference interpolation */ + char **Px; /**< 0E e_name string Macro BPX(v) - Symbol pointer interpolation */ + int i; /**< 10 e_name int32 Macro BI(v) - 32-bit Integer */ + int *Ri; /**< 10 e_name int32 Macro BRI(v) - 32-bit Integer reference interpolation */ + int **Pi; /**< 10 e_name int32 Macro BPI(v) - 32-bit Integer pointer interpolation */ + long l; /**< 12 e_name int64 Macro BL(v) - 64-bit Integer */ + long *Rl; /**< 12 e_name int64 Macro BRL(v) - 64-bit Integer reference interpolation */ + long **Pl; /**< 12 e_name int64 Macro BPL(v) - 64-bit Integer pointer interpolation */ + void **Pv; /* generic pointer internal */ + /* "{" "}" */ /* 03 e_name document Embedded document */ + /* "[" "]" */ /* 04 e_name document Array */ + /* 05 e_name binary Binary data */ + /* 06 e_name undefined - deprecated */ + /* 0B e_name cstring cstring Regular expression */ + /* 0C e_name string (byte*12) DBPointer - Deprecated */ + /* 0D e_name string JavaScript code */ + /* 0F e_name code_w_s JavaScript code w/ scope */ + /* 11 e_name int64 Timestamp */ + /* FF e_name Min key */ + /* 7F e_name Max key */ +} bcon; + +/** BCON document terminator */ +#define BEND "." + +/** BCON internal 01 double Floating point type-specifier */ +#define BTF ":_f:" +/** BCON internal 02 char* string type-specifier */ +#define BTS ":_s:" +/** BCON internal 03 union bcon* Embedded document interpolation type-specifier */ +#define BTD ":_D:" +/** BCON internal 04 union bcon* Array interpolation type-specifier */ +#define BTA ":_A:" +/** BCON internal 07 char* ObjectId type-specifier */ +#define BTO ":_o:" +/** BCON internal 08 int Boolean type-specifier */ +#define BTB ":_b:" +/** BCON internal 09 int64 UTC datetime type-specifier */ +#define BTT ":_t:" +/** BCON internal 0A Null type-specifier */ +#define BTN ":_v:" +/** BCON internal 0E char* Symbol type-specifier */ +#define BTX ":_x:" +/** BCON internal 10 int32 64-bit Integer type-specifier */ +#define BTI ":_i:" +/** BCON internal 12 int64 64-bit Integer type-specifier */ +#define BTL ":_l:" + +/** BCON internal 01 double* Floating point reference interpolation type-specifier */ +#define BTRF ":Rf:" +/** BCON internal 02 char* string reference interpolation type-specifier */ +#define BTRS ":Rs:" +/** BCON internal 03 union bcon* Embedded document reference interpolation type-specifier */ +#define BTRD ":RD:" +/** BCON internal 04 union bcon* Array reference interpolation type-specifier */ +#define BTRA ":RA:" +/** BCON internal 07 char* ObjectId reference interpolation type-specifier */ +#define BTRO ":Ro:" +/** BCON internal 08 int* Boolean reference interpolation type-specifier */ +#define BTRB ":Rb:" +/** BCON internal 09 int64* UTC datetime reference interpolation type-specifier */ +#define BTRT ":Rt:" +/** BCON internal 0E char* Symbol reference interpolation type-specifier */ +#define BTRX ":Rx:" +/** BCON internal 10 int32* 23-bit Integer reference interpolation type-specifier */ +#define BTRI ":Ri:" +/** BCON internal 12 int64* 64-bit Integer reference interpolation type-specifier */ +#define BTRL ":Rl:" + +/** BCON internal 01 double** Floating point pointer interpolation type-specifier */ +#define BTPF ":Pf:" +/** BCON internal 02 char** string pointer interpolation type-specifier */ +#define BTPS ":Ps:" +/** BCON internal 03 union bcon** Embedded document pointer interpolation type-specifier */ +#define BTPD ":PD:" +/** BCON internal 04 union bcon** Array pointer interpolation type-specifier */ +#define BTPA ":PA:" +/** BCON internal 07 char** ObjectId pointer interpolation type-specifier */ +#define BTPO ":Po:" +/** BCON internal 08 int** Boolean pointer interpolation type-specifier */ +#define BTPB ":Pb:" +/** BCON internal 09 int64** UTC datetime pointer interpolation type-specifier */ +#define BTPT ":Pt:" +/** BCON internal 0E char** Symbol pointer interpolation type-specifier */ +#define BTPX ":Px:" +/** BCON internal 10 int32** 23-bit Integer pointer interpolation type-specifier */ +#define BTPI ":Pi:" +/** BCON internal 12 int64** 64-bit Integer pointer interpolation type-specifier */ +#define BTPL ":Pl:" + +/** BCON 01 double Floating point value */ +#define BF(v) BTF, { .f = (v) } +/** BCON 02 char* string value */ +#define BS(v) BTS, { .s = (v) } +/** BCON 03 union bcon* Embedded document interpolation value */ +#define BD(v) BTD, { .D = (v) } +/** BCON 04 union bcon* Array interpolation value */ +#define BA(v) BTA, { .A = (v) } +/** BCON 07 char* ObjectId value */ +#define BO(v) BTO, { .o = (v) } +/** BCON 08 int Boolean value */ +#define BB(v) BTB, { .b = (v) } +/** BCON 09 int64 UTC datetime value */ +#define BT(v) BTT, { .t = (v) } +/** BCON 0A Null value */ +#define BNULL BTN, { .v = ("") } +/** BCON 0E char* Symbol value */ +#define BX(v) BTX, { .x = (v) } +/** BCON 10 int32 32-bit Integer value */ +#define BI(v) BTI, { .i = (v) } +/** BCON 12 int64 64-bit Integer value */ +#define BL(v) BTL, { .l = (v) } + +/** BCON 01 double* Floating point interpolation value */ +#define BRF(v) BTRF, { .Rf = (v) } +/** BCON 02 char* string interpolation value */ +#define BRS(v) BTRS, { .Rs = (v) } +/** BCON 03 union bcon* Embedded document interpolation value */ +#define BRD(v) BTRD, { .RD = (v) } +/** BCON 04 union bcon* Array interpolation value */ +#define BRA(v) BTRA, { .RA = (v) } +/** BCON 07 char* ObjectId interpolation value */ +#define BRO(v) BTRO, { .Ro = (v) } +/** BCON 08 int* Boolean interpolation value */ +#define BRB(v) BTRB, { .Rb = (v) } +/** BCON 09 int64* UTC datetime value */ +#define BRT(v) BTRT, { .Rt = (v) } +/** BCON 0E char* Symbol interpolation value */ +#define BRX(v) BTRX, { .Rx = (v) } +/** BCON 10 int32* 32-bit Integer interpolation value */ +#define BRI(v) BTRI, { .Ri = (v) } +/** BCON 12 int64* 64-bit Integer interpolation value */ +#define BRL(v) BTRL, { .Rl = (v) } + +/** BCON 01 double** Floating point interpolation value */ +#define BPF(v) BTPF, { .Pf = (v) } +/** BCON 02 char** string interpolation value */ +#define BPS(v) BTPS, { .Ps = ((char**)v) } +/** BCON 03 union bcon** Embedded document interpolation value */ +#define BPD(v) BTPD, { .PD = ((union bcon **)v) } +/** BCON 04 union bcon** Array interpolation value */ +#define BPA(v) BTPA, { .PA = ((union bcon **)v) } +/** BCON 07 char** ObjectId interpolation value */ +#define BPO(v) BTPO, { .Po = ((char**)v) } +/** BCON 08 int** Boolean interpolation value */ +#define BPB(v) BTPB, { .Pb = (v) } +/** BCON 09 int64** UTC datetime value */ +#define BPT(v) BTPT, { .Pt = (v) } +/** BCON 0E char** Symbol interpolation value */ +#define BPX(v) BTPX, { .Px = ((char**)v) } +/** BCON 10 int32** 32-bit Integer interpolation value */ +#define BPI(v) BTPI, { .Pi = (v) } +/** BCON 12 int64** 64-bit Integer interpolation value */ +#define BPL(v) BTPL, { .Pl = (v) } + +/* + * References on codes used for types + * http://en.wikipedia.org/wiki/Name_mangling + * http://www.agner.org/optimize/calling_conventions.pdf (page 25) + */ + +typedef enum bcon_error_t { + BCON_OK = 0, /**< OK return code */ + BCON_ERROR, /**< ERROR return code */ + BCON_DOCUMENT_INCOMPLETE, /**< bcon document or nesting incomplete */ + BCON_BSON_ERROR /**< bson finish error */ +} bcon_error_t; + +extern char *bcon_errstr[]; /**< bcon_error_t text messages */ + +/** + * Append a BCON object to a BSON object. + * + * @param b a BSON object + * @param bc a BCON object + */ +MONGO_EXPORT bcon_error_t bson_append_bcon(bson *b, const bcon *bc); + +/** + * Generate a BSON object from a BCON object. + * + * @param b a BSON object + * @param bc a BCON object + */ +MONGO_EXPORT bcon_error_t bson_from_bcon( bson *b, const bcon *bc ); + +/** + * Print a string representation of a BCON object. + * + * @param bc the BCON object to print. + */ +MONGO_EXPORT void bcon_print( const bcon *bc ); + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +MONGO_EXTERN_C_END + +typedef enum bcon_token_t { + Token_Default, Token_End, Token_Typespec, + Token_OpenBrace, Token_CloseBrace, Token_OpenBracket, Token_CloseBracket, + Token_EOD +} bcon_token_t; + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +#endif diff --git a/apps/systemlib/bson/bson.c b/apps/systemlib/bson/bson.c new file mode 100644 index 000000000..2cca3874d --- /dev/null +++ b/apps/systemlib/bson/bson.c @@ -0,0 +1,1049 @@ +/* bson.c */ + +/* Copyright 2009, 2010 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <time.h> +#include <limits.h> + +#include "bson.h" +#if 0 /* PX4 */ +#include "encoding.h" +#else +# define bson_check_field_name(_b, _s, _l) BSON_OK +# define bson_check_string(_b, _s, _l) BSON_OK +#endif + +const int initialBufferSize = 128; + +/* only need one of these */ +static const int zero = 0; + +/* Custom standard function pointers. */ +void *( *bson_malloc_func )( size_t ) = malloc; +void *( *bson_realloc_func )( void *, size_t ) = realloc; +void ( *bson_free_func )( void * ) = free; +#ifdef R_SAFETY_NET +bson_printf_func bson_printf; +#else +bson_printf_func bson_printf = printf; +#endif +bson_fprintf_func bson_fprintf = fprintf; +bson_sprintf_func bson_sprintf = sprintf; + +static int _bson_errprintf( const char *, ... ); +bson_printf_func bson_errprintf = _bson_errprintf; + +/* ObjectId fuzz functions. */ +static int ( *oid_fuzz_func )( void ) = NULL; +static int ( *oid_inc_func )( void ) = NULL; + +/* ---------------------------- + READING + ------------------------------ */ + +MONGO_EXPORT bson* bson_create( void ) { + return (bson*)bson_malloc(sizeof(bson)); +} + +MONGO_EXPORT void bson_dispose(bson* b) { + bson_free(b); +} + +MONGO_EXPORT bson *bson_empty( bson *obj ) { + static char *data = "\005\0\0\0\0"; + bson_init_data( obj, data ); + obj->finished = 1; + obj->err = 0; + obj->errstr = NULL; + obj->stackPos = 0; + return obj; +} + +MONGO_EXPORT int bson_copy( bson *out, const bson *in ) { + if ( !out || !in ) return BSON_ERROR; + if ( !in->finished ) return BSON_ERROR; + bson_init_size( out, bson_size( in ) ); + memcpy( out->data, in->data, bson_size( in ) ); + out->finished = 1; + + return BSON_OK; +} + +int bson_init_data( bson *b, char *data ) { + b->data = data; + return BSON_OK; +} + +int bson_init_finished_data( bson *b, char *data ) { + bson_init_data( b, data ); + b->finished = 1; + return BSON_OK; +} + +static void _bson_reset( bson *b ) { + b->finished = 0; + b->stackPos = 0; + b->err = 0; + b->errstr = NULL; +} + +MONGO_EXPORT int bson_size( const bson *b ) { + int i; + if ( ! b || ! b->data ) + return 0; + bson_little_endian32( &i, b->data ); + return i; +} + +MONGO_EXPORT int bson_buffer_size( const bson *b ) { + return (b->cur - b->data + 1); +} + + +MONGO_EXPORT const char *bson_data( const bson *b ) { + return (const char *)b->data; +} + +static char hexbyte( char hex ) { + if (hex >= '0' && hex <= '9') + return (hex - '0'); + else if (hex >= 'A' && hex <= 'F') + return (hex - 'A' + 10); + else if (hex >= 'a' && hex <= 'f') + return (hex - 'a' + 10); + else + return 0x0; +} + +MONGO_EXPORT void bson_oid_from_string( bson_oid_t *oid, const char *str ) { + int i; + for ( i=0; i<12; i++ ) { + oid->bytes[i] = ( hexbyte( str[2*i] ) << 4 ) | hexbyte( str[2*i + 1] ); + } +} + +MONGO_EXPORT void bson_oid_to_string( const bson_oid_t *oid, char *str ) { + static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + int i; + for ( i=0; i<12; i++ ) { + str[2*i] = hex[( oid->bytes[i] & 0xf0 ) >> 4]; + str[2*i + 1] = hex[ oid->bytes[i] & 0x0f ]; + } + str[24] = '\0'; +} + +MONGO_EXPORT void bson_set_oid_fuzz( int ( *func )( void ) ) { + oid_fuzz_func = func; +} + +MONGO_EXPORT void bson_set_oid_inc( int ( *func )( void ) ) { + oid_inc_func = func; +} + +MONGO_EXPORT void bson_oid_gen( bson_oid_t *oid ) { + static int incr = 0; + static int fuzz = 0; + int i; + int t = time( NULL ); + + if( oid_inc_func ) + i = oid_inc_func(); + else + i = incr++; + + if ( !fuzz ) { + if ( oid_fuzz_func ) + fuzz = oid_fuzz_func(); + else { + srand( t ); + fuzz = rand(); + } + } + + bson_big_endian32( &oid->ints[0], &t ); + oid->ints[1] = fuzz; + bson_big_endian32( &oid->ints[2], &i ); +} + +MONGO_EXPORT time_t bson_oid_generated_time( bson_oid_t *oid ) { + time_t out; + bson_big_endian32( &out, &oid->ints[0] ); + + return out; +} + +MONGO_EXPORT void bson_print( const bson *b ) { + bson_print_raw( b->data , 0 ); +} + +MONGO_EXPORT void bson_print_raw( const char *data , int depth ) { + bson_iterator i; + const char *key; + int temp; + bson_timestamp_t ts; + char oidhex[25]; + bson scope; + bson_iterator_from_buffer( &i, data ); + + while ( bson_iterator_next( &i ) ) { + bson_type t = bson_iterator_type( &i ); + if ( t == 0 ) + break; + key = bson_iterator_key( &i ); + + for ( temp=0; temp<=depth; temp++ ) + bson_printf( "\t" ); + bson_printf( "%s : %d \t " , key , t ); + switch ( t ) { + case BSON_DOUBLE: + bson_printf( "%f" , bson_iterator_double( &i ) ); + break; + case BSON_STRING: + bson_printf( "%s" , bson_iterator_string( &i ) ); + break; + case BSON_SYMBOL: + bson_printf( "SYMBOL: %s" , bson_iterator_string( &i ) ); + break; + case BSON_OID: + bson_oid_to_string( bson_iterator_oid( &i ), oidhex ); + bson_printf( "%s" , oidhex ); + break; + case BSON_BOOL: + bson_printf( "%s" , bson_iterator_bool( &i ) ? "true" : "false" ); + break; + case BSON_DATE: + bson_printf( "%ld" , ( long int )bson_iterator_date( &i ) ); + break; + case BSON_BINDATA: + bson_printf( "BSON_BINDATA" ); + break; + case BSON_UNDEFINED: + bson_printf( "BSON_UNDEFINED" ); + break; + case BSON_NULL: + bson_printf( "BSON_NULL" ); + break; + case BSON_REGEX: + bson_printf( "BSON_REGEX: %s", bson_iterator_regex( &i ) ); + break; + case BSON_CODE: + bson_printf( "BSON_CODE: %s", bson_iterator_code( &i ) ); + break; + case BSON_CODEWSCOPE: + bson_printf( "BSON_CODE_W_SCOPE: %s", bson_iterator_code( &i ) ); + /* bson_init( &scope ); */ /* review - stepped on by bson_iterator_code_scope? */ + bson_iterator_code_scope( &i, &scope ); + bson_printf( "\n\t SCOPE: " ); + bson_print( &scope ); + /* bson_destroy( &scope ); */ /* review - causes free error */ + break; + case BSON_INT: + bson_printf( "%d" , bson_iterator_int( &i ) ); + break; + case BSON_LONG: + bson_printf( "%lld" , ( uint64_t )bson_iterator_long( &i ) ); + break; + case BSON_TIMESTAMP: + ts = bson_iterator_timestamp( &i ); + bson_printf( "i: %d, t: %d", ts.i, ts.t ); + break; + case BSON_OBJECT: + case BSON_ARRAY: + bson_printf( "\n" ); + bson_print_raw( bson_iterator_value( &i ) , depth + 1 ); + break; + default: + bson_errprintf( "can't print type : %d\n" , t ); + } + bson_printf( "\n" ); + } +} + +/* ---------------------------- + ITERATOR + ------------------------------ */ + +MONGO_EXPORT bson_iterator* bson_iterator_create( void ) { + return ( bson_iterator* )malloc( sizeof( bson_iterator ) ); +} + +MONGO_EXPORT void bson_iterator_dispose(bson_iterator* i) { + free(i); +} + +MONGO_EXPORT void bson_iterator_init( bson_iterator *i, const bson *b ) { + i->cur = b->data + 4; + i->first = 1; +} + +MONGO_EXPORT void bson_iterator_from_buffer( bson_iterator *i, const char *buffer ) { + i->cur = buffer + 4; + i->first = 1; +} + +MONGO_EXPORT bson_type bson_find( bson_iterator *it, const bson *obj, const char *name ) { + bson_iterator_init( it, (bson *)obj ); + while( bson_iterator_next( it ) ) { + if ( strcmp( name, bson_iterator_key( it ) ) == 0 ) + break; + } + return bson_iterator_type( it ); +} + +MONGO_EXPORT bson_bool_t bson_iterator_more( const bson_iterator *i ) { + return *( i->cur ); +} + +MONGO_EXPORT bson_type bson_iterator_next( bson_iterator *i ) { + int ds; + + if ( i->first ) { + i->first = 0; + return ( bson_type )( *i->cur ); + } + + switch ( bson_iterator_type( i ) ) { + case BSON_EOO: + return BSON_EOO; /* don't advance */ + case BSON_UNDEFINED: + case BSON_NULL: + ds = 0; + break; + case BSON_BOOL: + ds = 1; + break; + case BSON_INT: + ds = 4; + break; + case BSON_LONG: + case BSON_DOUBLE: + case BSON_TIMESTAMP: + case BSON_DATE: + ds = 8; + break; + case BSON_OID: + ds = 12; + break; + case BSON_STRING: + case BSON_SYMBOL: + case BSON_CODE: + ds = 4 + bson_iterator_int_raw( i ); + break; + case BSON_BINDATA: + ds = 5 + bson_iterator_int_raw( i ); + break; + case BSON_OBJECT: + case BSON_ARRAY: + case BSON_CODEWSCOPE: + ds = bson_iterator_int_raw( i ); + break; + case BSON_DBREF: + ds = 4+12 + bson_iterator_int_raw( i ); + break; + case BSON_REGEX: { + const char *s = bson_iterator_value( i ); + const char *p = s; + p += strlen( p )+1; + p += strlen( p )+1; + ds = p-s; + break; + } + + default: { + char msg[] = "unknown type: 000000000000"; + bson_numstr( msg+14, ( unsigned )( i->cur[0] ) ); + bson_fatal_msg( 0, msg ); + return 0; + } + } + + i->cur += 1 + strlen( i->cur + 1 ) + 1 + ds; + + return ( bson_type )( *i->cur ); +} + +MONGO_EXPORT bson_type bson_iterator_type( const bson_iterator *i ) { + return ( bson_type )i->cur[0]; +} + +MONGO_EXPORT const char *bson_iterator_key( const bson_iterator *i ) { + return i->cur + 1; +} + +MONGO_EXPORT const char *bson_iterator_value( const bson_iterator *i ) { + const char *t = i->cur + 1; + t += strlen( t ) + 1; + return t; +} + +/* types */ + +int bson_iterator_int_raw( const bson_iterator *i ) { + int out; + bson_little_endian32( &out, bson_iterator_value( i ) ); + return out; +} + +double bson_iterator_double_raw( const bson_iterator *i ) { + double out; + bson_little_endian64( &out, bson_iterator_value( i ) ); + return out; +} + +int64_t bson_iterator_long_raw( const bson_iterator *i ) { + int64_t out; + bson_little_endian64( &out, bson_iterator_value( i ) ); + return out; +} + +bson_bool_t bson_iterator_bool_raw( const bson_iterator *i ) { + return bson_iterator_value( i )[0]; +} + +MONGO_EXPORT bson_oid_t *bson_iterator_oid( const bson_iterator *i ) { + return ( bson_oid_t * )bson_iterator_value( i ); +} + +MONGO_EXPORT int bson_iterator_int( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_INT: + return bson_iterator_int_raw( i ); + case BSON_LONG: + return bson_iterator_long_raw( i ); + case BSON_DOUBLE: + return bson_iterator_double_raw( i ); + default: + return 0; + } +} + +MONGO_EXPORT double bson_iterator_double( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_INT: + return bson_iterator_int_raw( i ); + case BSON_LONG: + return bson_iterator_long_raw( i ); + case BSON_DOUBLE: + return bson_iterator_double_raw( i ); + default: + return 0; + } +} + +MONGO_EXPORT int64_t bson_iterator_long( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_INT: + return bson_iterator_int_raw( i ); + case BSON_LONG: + return bson_iterator_long_raw( i ); + case BSON_DOUBLE: + return bson_iterator_double_raw( i ); + default: + return 0; + } +} + +MONGO_EXPORT bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i ) { + bson_timestamp_t ts; + bson_little_endian32( &( ts.i ), bson_iterator_value( i ) ); + bson_little_endian32( &( ts.t ), bson_iterator_value( i ) + 4 ); + return ts; +} + + +MONGO_EXPORT int bson_iterator_timestamp_time( const bson_iterator *i ) { + int time; + bson_little_endian32( &time, bson_iterator_value( i ) + 4 ); + return time; +} + + +MONGO_EXPORT int bson_iterator_timestamp_increment( const bson_iterator *i ) { + int increment; + bson_little_endian32( &increment, bson_iterator_value( i ) ); + return increment; +} + + +MONGO_EXPORT bson_bool_t bson_iterator_bool( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_BOOL: + return bson_iterator_bool_raw( i ); + case BSON_INT: + return bson_iterator_int_raw( i ) != 0; + case BSON_LONG: + return bson_iterator_long_raw( i ) != 0; + case BSON_DOUBLE: + return bson_iterator_double_raw( i ) != 0; + case BSON_EOO: + case BSON_NULL: + return 0; + default: + return 1; + } +} + +MONGO_EXPORT const char *bson_iterator_string( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_STRING: + case BSON_SYMBOL: + return bson_iterator_value( i ) + 4; + default: + return ""; + } +} + +int bson_iterator_string_len( const bson_iterator *i ) { + return bson_iterator_int_raw( i ); +} + +MONGO_EXPORT const char *bson_iterator_code( const bson_iterator *i ) { + switch ( bson_iterator_type( i ) ) { + case BSON_STRING: + case BSON_CODE: + return bson_iterator_value( i ) + 4; + case BSON_CODEWSCOPE: + return bson_iterator_value( i ) + 8; + default: + return NULL; + } +} + +MONGO_EXPORT void bson_iterator_code_scope( const bson_iterator *i, bson *scope ) { + if ( bson_iterator_type( i ) == BSON_CODEWSCOPE ) { + int code_len; + bson_little_endian32( &code_len, bson_iterator_value( i )+4 ); + bson_init_data( scope, ( void * )( bson_iterator_value( i )+8+code_len ) ); + _bson_reset( scope ); + scope->finished = 1; + } else { + bson_empty( scope ); + } +} + +MONGO_EXPORT bson_date_t bson_iterator_date( const bson_iterator *i ) { + return bson_iterator_long_raw( i ); +} + +MONGO_EXPORT time_t bson_iterator_time_t( const bson_iterator *i ) { + return bson_iterator_date( i ) / 1000; +} + +MONGO_EXPORT int bson_iterator_bin_len( const bson_iterator *i ) { + return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD ) + ? bson_iterator_int_raw( i ) - 4 + : bson_iterator_int_raw( i ); +} + +MONGO_EXPORT char bson_iterator_bin_type( const bson_iterator *i ) { + return bson_iterator_value( i )[4]; +} + +MONGO_EXPORT const char *bson_iterator_bin_data( const bson_iterator *i ) { + return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD ) + ? bson_iterator_value( i ) + 9 + : bson_iterator_value( i ) + 5; +} + +MONGO_EXPORT const char *bson_iterator_regex( const bson_iterator *i ) { + return bson_iterator_value( i ); +} + +MONGO_EXPORT const char *bson_iterator_regex_opts( const bson_iterator *i ) { + const char *p = bson_iterator_value( i ); + return p + strlen( p ) + 1; + +} + +MONGO_EXPORT void bson_iterator_subobject( const bson_iterator *i, bson *sub ) { + bson_init_data( sub, ( char * )bson_iterator_value( i ) ); + _bson_reset( sub ); + sub->finished = 1; +} + +MONGO_EXPORT void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub ) { + bson_iterator_from_buffer( sub, bson_iterator_value( i ) ); +} + +/* ---------------------------- + BUILDING + ------------------------------ */ + +static void _bson_init_size( bson *b, int size ) { + if( size == 0 ) + b->data = NULL; + else + b->data = ( char * )bson_malloc( size ); + b->dataSize = size; + b->cur = b->data + 4; + _bson_reset( b ); +} + +MONGO_EXPORT void bson_init( bson *b ) { + _bson_init_size( b, initialBufferSize ); +} + +void bson_init_size( bson *b, int size ) { + _bson_init_size( b, size ); +} + +void bson_append_byte( bson *b, char c ) { + b->cur[0] = c; + b->cur++; +} + +void bson_append( bson *b, const void *data, int len ) { + memcpy( b->cur , data , len ); + b->cur += len; +} + +void bson_append32( bson *b, const void *data ) { + bson_little_endian32( b->cur, data ); + b->cur += 4; +} + +void bson_append64( bson *b, const void *data ) { + bson_little_endian64( b->cur, data ); + b->cur += 8; +} + +int bson_ensure_space( bson *b, const int bytesNeeded ) { + int pos = b->cur - b->data; + char *orig = b->data; + int new_size; + + if ( pos + bytesNeeded <= b->dataSize ) + return BSON_OK; + + new_size = 1.5 * ( b->dataSize + bytesNeeded ); + + if( new_size < b->dataSize ) { + if( ( b->dataSize + bytesNeeded ) < INT_MAX ) + new_size = INT_MAX; + else { + b->err = BSON_SIZE_OVERFLOW; + return BSON_ERROR; + } + } + + b->data = bson_realloc( b->data, new_size ); + if ( !b->data ) + bson_fatal_msg( !!b->data, "realloc() failed" ); + + b->dataSize = new_size; + b->cur += b->data - orig; + + return BSON_OK; +} + +MONGO_EXPORT int bson_finish( bson *b ) { + int i; + + if( b->err & BSON_NOT_UTF8 ) + return BSON_ERROR; + + if ( ! b->finished ) { + if ( bson_ensure_space( b, 1 ) == BSON_ERROR ) return BSON_ERROR; + bson_append_byte( b, 0 ); + i = b->cur - b->data; + bson_little_endian32( b->data, &i ); + b->finished = 1; + } + + return BSON_OK; +} + +MONGO_EXPORT void bson_destroy( bson *b ) { + if (b) { + bson_free( b->data ); + b->err = 0; + b->data = 0; + b->cur = 0; + b->finished = 1; + } +} + +static int bson_append_estart( bson *b, int type, const char *name, const int dataSize ) { + const int len = strlen( name ) + 1; + + if ( b->finished ) { + b->err |= BSON_ALREADY_FINISHED; + return BSON_ERROR; + } + + if ( bson_ensure_space( b, 1 + len + dataSize ) == BSON_ERROR ) { + return BSON_ERROR; + } + + if( bson_check_field_name( b, ( const char * )name, len - 1 ) == BSON_ERROR ) { + bson_builder_error( b ); + return BSON_ERROR; + } + + bson_append_byte( b, ( char )type ); + bson_append( b, name, len ); + return BSON_OK; +} + +/* ---------------------------- + BUILDING TYPES + ------------------------------ */ + +MONGO_EXPORT int bson_append_int( bson *b, const char *name, const int i ) { + if ( bson_append_estart( b, BSON_INT, name, 4 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b , &i ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_long( bson *b, const char *name, const int64_t i ) { + if ( bson_append_estart( b , BSON_LONG, name, 8 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append64( b , &i ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_double( bson *b, const char *name, const double d ) { + if ( bson_append_estart( b, BSON_DOUBLE, name, 8 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append64( b , &d ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_bool( bson *b, const char *name, const bson_bool_t i ) { + if ( bson_append_estart( b, BSON_BOOL, name, 1 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append_byte( b , i != 0 ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_null( bson *b, const char *name ) { + if ( bson_append_estart( b , BSON_NULL, name, 0 ) == BSON_ERROR ) + return BSON_ERROR; + return BSON_OK; +} + +MONGO_EXPORT int bson_append_undefined( bson *b, const char *name ) { + if ( bson_append_estart( b, BSON_UNDEFINED, name, 0 ) == BSON_ERROR ) + return BSON_ERROR; + return BSON_OK; +} + +int bson_append_string_base( bson *b, const char *name, + const char *value, int len, bson_type type ) { + + int sl = len + 1; + if ( bson_check_string( b, ( const char * )value, sl - 1 ) == BSON_ERROR ) + return BSON_ERROR; + if ( bson_append_estart( b, type, name, 4 + sl ) == BSON_ERROR ) { + return BSON_ERROR; + } + bson_append32( b , &sl ); + bson_append( b , value , sl - 1 ); + bson_append( b , "\0" , 1 ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_string( bson *b, const char *name, const char *value ) { + return bson_append_string_base( b, name, value, strlen ( value ), BSON_STRING ); +} + +MONGO_EXPORT int bson_append_symbol( bson *b, const char *name, const char *value ) { + return bson_append_string_base( b, name, value, strlen ( value ), BSON_SYMBOL ); +} + +MONGO_EXPORT int bson_append_code( bson *b, const char *name, const char *value ) { + return bson_append_string_base( b, name, value, strlen ( value ), BSON_CODE ); +} + +MONGO_EXPORT int bson_append_string_n( bson *b, const char *name, const char *value, int len ) { + return bson_append_string_base( b, name, value, len, BSON_STRING ); +} + +MONGO_EXPORT int bson_append_symbol_n( bson *b, const char *name, const char *value, int len ) { + return bson_append_string_base( b, name, value, len, BSON_SYMBOL ); +} + +MONGO_EXPORT int bson_append_code_n( bson *b, const char *name, const char *value, int len ) { + return bson_append_string_base( b, name, value, len, BSON_CODE ); +} + +MONGO_EXPORT int bson_append_code_w_scope_n( bson *b, const char *name, + const char *code, int len, const bson *scope ) { + + int sl, size; + if ( !scope ) return BSON_ERROR; + sl = len + 1; + size = 4 + 4 + sl + bson_size( scope ); + if ( bson_append_estart( b, BSON_CODEWSCOPE, name, size ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b, &size ); + bson_append32( b, &sl ); + bson_append( b, code, sl ); + bson_append( b, scope->data, bson_size( scope ) ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope ) { + return bson_append_code_w_scope_n( b, name, code, strlen ( code ), scope ); +} + +MONGO_EXPORT int bson_append_binary( bson *b, const char *name, char type, const char *str, int len ) { + if ( type == BSON_BIN_BINARY_OLD ) { + int subtwolen = len + 4; + if ( bson_append_estart( b, BSON_BINDATA, name, 4+1+4+len ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b, &subtwolen ); + bson_append_byte( b, type ); + bson_append32( b, &len ); + bson_append( b, str, len ); + } else { + if ( bson_append_estart( b, BSON_BINDATA, name, 4+1+len ) == BSON_ERROR ) + return BSON_ERROR; + bson_append32( b, &len ); + bson_append_byte( b, type ); + bson_append( b, str, len ); + } + return BSON_OK; +} + +MONGO_EXPORT int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid ) { + if ( bson_append_estart( b, BSON_OID, name, 12 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b , oid , 12 ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_new_oid( bson *b, const char *name ) { + bson_oid_t oid; + bson_oid_gen( &oid ); + return bson_append_oid( b, name, &oid ); +} + +MONGO_EXPORT int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts ) { + const int plen = strlen( pattern )+1; + const int olen = strlen( opts )+1; + if ( bson_append_estart( b, BSON_REGEX, name, plen + olen ) == BSON_ERROR ) + return BSON_ERROR; + if ( bson_check_string( b, pattern, plen - 1 ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b , pattern , plen ); + bson_append( b , opts , olen ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_bson( bson *b, const char *name, const bson *bson ) { + if ( !bson ) return BSON_ERROR; + if ( bson_append_estart( b, BSON_OBJECT, name, bson_size( bson ) ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b , bson->data , bson_size( bson ) ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem ) { + bson_iterator next = *elem; + int size; + + bson_iterator_next( &next ); + size = next.cur - elem->cur; + + if ( name_or_null == NULL ) { + if( bson_ensure_space( b, size ) == BSON_ERROR ) + return BSON_ERROR; + bson_append( b, elem->cur, size ); + } else { + int data_size = size - 2 - strlen( bson_iterator_key( elem ) ); + bson_append_estart( b, elem->cur[0], name_or_null, data_size ); + bson_append( b, bson_iterator_value( elem ), data_size ); + } + + return BSON_OK; +} + +MONGO_EXPORT int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts ) { + if ( bson_append_estart( b, BSON_TIMESTAMP, name, 8 ) == BSON_ERROR ) return BSON_ERROR; + + bson_append32( b , &( ts->i ) ); + bson_append32( b , &( ts->t ) ); + + return BSON_OK; +} + +MONGO_EXPORT int bson_append_timestamp2( bson *b, const char *name, int time, int increment ) { + if ( bson_append_estart( b, BSON_TIMESTAMP, name, 8 ) == BSON_ERROR ) return BSON_ERROR; + + bson_append32( b , &increment ); + bson_append32( b , &time ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_date( bson *b, const char *name, bson_date_t millis ) { + if ( bson_append_estart( b, BSON_DATE, name, 8 ) == BSON_ERROR ) return BSON_ERROR; + bson_append64( b , &millis ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_time_t( bson *b, const char *name, time_t secs ) { + return bson_append_date( b, name, ( bson_date_t )secs * 1000 ); +} + +MONGO_EXPORT int bson_append_start_object( bson *b, const char *name ) { + if ( bson_append_estart( b, BSON_OBJECT, name, 5 ) == BSON_ERROR ) return BSON_ERROR; + b->stack[ b->stackPos++ ] = b->cur - b->data; + bson_append32( b , &zero ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_start_array( bson *b, const char *name ) { + if ( bson_append_estart( b, BSON_ARRAY, name, 5 ) == BSON_ERROR ) return BSON_ERROR; + b->stack[ b->stackPos++ ] = b->cur - b->data; + bson_append32( b , &zero ); + return BSON_OK; +} + +MONGO_EXPORT int bson_append_finish_object( bson *b ) { + char *start; + int i; + if ( bson_ensure_space( b, 1 ) == BSON_ERROR ) return BSON_ERROR; + bson_append_byte( b , 0 ); + + start = b->data + b->stack[ --b->stackPos ]; + i = b->cur - start; + bson_little_endian32( start, &i ); + + return BSON_OK; +} + +MONGO_EXPORT double bson_int64_to_double( int64_t i64 ) { + return (double)i64; +} + +MONGO_EXPORT int bson_append_finish_array( bson *b ) { + return bson_append_finish_object( b ); +} + +/* Error handling and allocators. */ + +static bson_err_handler err_handler = NULL; + +MONGO_EXPORT bson_err_handler set_bson_err_handler( bson_err_handler func ) { + bson_err_handler old = err_handler; + err_handler = func; + return old; +} + +MONGO_EXPORT void bson_free( void *ptr ) { + bson_free_func( ptr ); +} + +MONGO_EXPORT void *bson_malloc( int size ) { + void *p; + p = bson_malloc_func( size ); + bson_fatal_msg( !!p, "malloc() failed" ); + return p; +} + +void *bson_realloc( void *ptr, int size ) { + void *p; + p = bson_realloc_func( ptr, size ); + bson_fatal_msg( !!p, "realloc() failed" ); + return p; +} + +int _bson_errprintf( const char *format, ... ) { + va_list ap; + int ret; + va_start( ap, format ); +#ifndef R_SAFETY_NET + ret = vfprintf( stderr, format, ap ); +#endif + va_end( ap ); + + return ret; +} + +/** + * This method is invoked when a non-fatal bson error is encountered. + * Calls the error handler if available. + * + * @param + */ +void bson_builder_error( bson *b ) { + if( err_handler ) + err_handler( "BSON error." ); +} + +void bson_fatal( int ok ) { + bson_fatal_msg( ok, "" ); +} + +void bson_fatal_msg( int ok , const char *msg ) { + if ( ok ) + return; + + if ( err_handler ) { + err_handler( msg ); + } +#ifndef R_SAFETY_NET + bson_errprintf( "error: %s\n" , msg ); + exit( -5 ); +#endif +} + + +#if 0 /* PX4 */ +/* Efficiently copy an integer to a string. */ +extern const char bson_numstrs[1000][4]; + +void bson_numstr( char *str, int i ) { + if( i < 1000 ) + memcpy( str, bson_numstrs[i], 4 ); + else + bson_sprintf( str,"%d", i ); +} +#else +void bson_numstr( char *str, int i ) { + bson_sprintf( str,"%d", i ); +} +#endif + +MONGO_EXPORT void bson_swap_endian64( void *outp, const void *inp ) { + const char *in = ( const char * )inp; + char *out = ( char * )outp; + + out[0] = in[7]; + out[1] = in[6]; + out[2] = in[5]; + out[3] = in[4]; + out[4] = in[3]; + out[5] = in[2]; + out[6] = in[1]; + out[7] = in[0]; + +} + +MONGO_EXPORT void bson_swap_endian32( void *outp, const void *inp ) { + const char *in = ( const char * )inp; + char *out = ( char * )outp; + + out[0] = in[3]; + out[1] = in[2]; + out[2] = in[1]; + out[3] = in[0]; +} diff --git a/apps/systemlib/bson/bson.h b/apps/systemlib/bson/bson.h new file mode 100644 index 000000000..d5168cfd0 --- /dev/null +++ b/apps/systemlib/bson/bson.h @@ -0,0 +1,1044 @@ +/** + * @file bson.h + * @brief BSON Declarations + */ + +/* Copyright 2009-2012 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BSON_H_ +#define BSON_H_ + +#include <time.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> + + + +#ifdef __GNUC__ + #define MONGO_INLINE static __inline__ + #if 0 /* PX4 */ + #define MONGO_EXPORT + #else + #define MONGO_EXPORT __EXPORT + #endif +#else + #define MONGO_INLINE static + #ifdef MONGO_STATIC_BUILD + #define MONGO_EXPORT + #elif defined(MONGO_DLL_BUILD) + #define MONGO_EXPORT __declspec(dllexport) + #else + #define MONGO_EXPORT __declspec(dllimport) + #endif +#endif + +#ifdef __cplusplus +#define MONGO_EXTERN_C_START extern "C" { +#define MONGO_EXTERN_C_END } +#else +#define MONGO_EXTERN_C_START +#define MONGO_EXTERN_C_END +#endif + +#if defined(MONGO_HAVE_STDINT) || __STDC_VERSION__ >= 199901L +#include <stdint.h> +#elif defined(MONGO_HAVE_UNISTD) +#include <unistd.h> +#elif defined(MONGO_USE__INT64) +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#elif defined(MONGO_USE_LONG_LONG_INT) +typedef long long int int64_t; +typedef unsigned long long int uint64_t; +#else +#error Must compile with c99 or define MONGO_HAVE_STDINT, MONGO_HAVE_UNISTD, MONGO_USE__INT64, or MONGO_USE_LONG_LONG_INT. +#endif + +#ifdef MONGO_BIG_ENDIAN +#define bson_little_endian64(out, in) ( bson_swap_endian64(out, in) ) +#define bson_little_endian32(out, in) ( bson_swap_endian32(out, in) ) +#define bson_big_endian64(out, in) ( memcpy(out, in, 8) ) +#define bson_big_endian32(out, in) ( memcpy(out, in, 4) ) +#else +#define bson_little_endian64(out, in) ( memcpy(out, in, 8) ) +#define bson_little_endian32(out, in) ( memcpy(out, in, 4) ) +#define bson_big_endian64(out, in) ( bson_swap_endian64(out, in) ) +#define bson_big_endian32(out, in) ( bson_swap_endian32(out, in) ) +#endif + +MONGO_EXTERN_C_START + +#define BSON_OK 0 +#define BSON_ERROR -1 + +enum bson_error_t { + BSON_SIZE_OVERFLOW = 1 /**< Trying to create a BSON object larger than INT_MAX. */ +}; + +enum bson_validity_t { + BSON_VALID = 0, /**< BSON is valid and UTF-8 compliant. */ + BSON_NOT_UTF8 = ( 1<<1 ), /**< A key or a string is not valid UTF-8. */ + BSON_FIELD_HAS_DOT = ( 1<<2 ), /**< Warning: key contains '.' character. */ + BSON_FIELD_INIT_DOLLAR = ( 1<<3 ), /**< Warning: key starts with '$' character. */ + BSON_ALREADY_FINISHED = ( 1<<4 ) /**< Trying to modify a finished BSON object. */ +}; + +enum bson_binary_subtype_t { + BSON_BIN_BINARY = 0, + BSON_BIN_FUNC = 1, + BSON_BIN_BINARY_OLD = 2, + BSON_BIN_UUID = 3, + BSON_BIN_MD5 = 5, + BSON_BIN_USER = 128 +}; + +typedef enum { + BSON_EOO = 0, + BSON_DOUBLE = 1, + BSON_STRING = 2, + BSON_OBJECT = 3, + BSON_ARRAY = 4, + BSON_BINDATA = 5, + BSON_UNDEFINED = 6, + BSON_OID = 7, + BSON_BOOL = 8, + BSON_DATE = 9, + BSON_NULL = 10, + BSON_REGEX = 11, + BSON_DBREF = 12, /**< Deprecated. */ + BSON_CODE = 13, + BSON_SYMBOL = 14, + BSON_CODEWSCOPE = 15, + BSON_INT = 16, + BSON_TIMESTAMP = 17, + BSON_LONG = 18 +} bson_type; + +typedef int bson_bool_t; + +typedef struct { + const char *cur; + bson_bool_t first; +} bson_iterator; + +typedef struct { + char *data; /**< Pointer to a block of data in this BSON object. */ + char *cur; /**< Pointer to the current position. */ + int dataSize; /**< The number of bytes allocated to char *data. */ + bson_bool_t finished; /**< When finished, the BSON object can no longer be modified. */ + int stack[32]; /**< A stack used to keep track of nested BSON elements. */ + int stackPos; /**< Index of current stack position. */ + int err; /**< Bitfield representing errors or warnings on this buffer */ + char *errstr; /**< A string representation of the most recent error or warning. */ +} bson; + +#pragma pack(1) +typedef union { + char bytes[12]; + int ints[3]; +} bson_oid_t; +#pragma pack() + +typedef int64_t bson_date_t; /* milliseconds since epoch UTC */ + +typedef struct { + int i; /* increment */ + int t; /* time in seconds */ +} bson_timestamp_t; + +/* ---------------------------- + READING + ------------------------------ */ + +MONGO_EXPORT bson* bson_create( void ); +MONGO_EXPORT void bson_dispose(bson* b); + +/** + * Size of a BSON object. + * + * @param b the BSON object. + * + * @return the size. + */ +MONGO_EXPORT int bson_size( const bson *b ); +MONGO_EXPORT int bson_buffer_size( const bson *b ); + +/** + * Print a string representation of a BSON object. + * + * @param b the BSON object to print. + */ +MONGO_EXPORT void bson_print( const bson *b ); + +/** + * Return a pointer to the raw buffer stored by this bson object. + * + * @param b a BSON object + */ +MONGO_EXPORT const char *bson_data( const bson *b ); + +/** + * Print a string representation of a BSON object. + * + * @param bson the raw data to print. + * @param depth the depth to recurse the object.x + */ +MONGO_EXPORT void bson_print_raw( const char *bson , int depth ); + +/** + * Advance a bson_iterator to the named field. + * + * @param it the bson_iterator to use. + * @param obj the BSON object to use. + * @param name the name of the field to find. + * + * @return the type of the found object or BSON_EOO if it is not found. + */ +MONGO_EXPORT bson_type bson_find( bson_iterator *it, const bson *obj, const char *name ); + + +MONGO_EXPORT bson_iterator* bson_iterator_create( void ); +MONGO_EXPORT void bson_iterator_dispose(bson_iterator*); +/** + * Initialize a bson_iterator. + * + * @param i the bson_iterator to initialize. + * @param bson the BSON object to associate with the iterator. + */ +MONGO_EXPORT void bson_iterator_init( bson_iterator *i , const bson *b ); + +/** + * Initialize a bson iterator from a const char* buffer. Note + * that this is mostly used internally. + * + * @param i the bson_iterator to initialize. + * @param buffer the buffer to point to. + */ +MONGO_EXPORT void bson_iterator_from_buffer( bson_iterator *i, const char *buffer ); + +/* more returns true for eoo. best to loop with bson_iterator_next(&it) */ +/** + * Check to see if the bson_iterator has more data. + * + * @param i the iterator. + * + * @return returns true if there is more data. + */ +MONGO_EXPORT bson_bool_t bson_iterator_more( const bson_iterator *i ); + +/** + * Point the iterator at the next BSON object. + * + * @param i the bson_iterator. + * + * @return the type of the next BSON object. + */ +MONGO_EXPORT bson_type bson_iterator_next( bson_iterator *i ); + +/** + * Get the type of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the type of the current BSON object. + */ +MONGO_EXPORT bson_type bson_iterator_type( const bson_iterator *i ); + +/** + * Get the key of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the key of the current BSON object. + */ +MONGO_EXPORT const char *bson_iterator_key( const bson_iterator *i ); + +/** + * Get the value of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +MONGO_EXPORT const char *bson_iterator_value( const bson_iterator *i ); + +/* these convert to the right type (return 0 if non-numeric) */ +/** + * Get the double value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +MONGO_EXPORT double bson_iterator_double( const bson_iterator *i ); + +/** + * Get the int value of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +MONGO_EXPORT int bson_iterator_int( const bson_iterator *i ); + +/** + * Get the long value of the BSON object currently pointed to by the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +MONGO_EXPORT int64_t bson_iterator_long( const bson_iterator *i ); + +/* return the bson timestamp as a whole or in parts */ +/** + * Get the timestamp value of the BSON object currently pointed to by + * the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +MONGO_EXPORT bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i ); +MONGO_EXPORT int bson_iterator_timestamp_time( const bson_iterator *i ); +MONGO_EXPORT int bson_iterator_timestamp_increment( const bson_iterator *i ); + +/** + * Get the boolean value of the BSON object currently pointed to by + * the iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +/* false: boolean false, 0 in any type, or null */ +/* true: anything else (even empty strings and objects) */ +MONGO_EXPORT bson_bool_t bson_iterator_bool( const bson_iterator *i ); + +/** + * Get the double value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +/* these assume you are using the right type */ +double bson_iterator_double_raw( const bson_iterator *i ); + +/** + * Get the int value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +int bson_iterator_int_raw( const bson_iterator *i ); + +/** + * Get the long value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +int64_t bson_iterator_long_raw( const bson_iterator *i ); + +/** + * Get the bson_bool_t value of the BSON object currently pointed to by the + * iterator. Assumes the correct type is used. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +bson_bool_t bson_iterator_bool_raw( const bson_iterator *i ); + +/** + * Get the bson_oid_t value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +MONGO_EXPORT bson_oid_t *bson_iterator_oid( const bson_iterator *i ); + +/** + * Get the string value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON object. + */ +/* these can also be used with bson_code and bson_symbol*/ +MONGO_EXPORT const char *bson_iterator_string( const bson_iterator *i ); + +/** + * Get the string length of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the length of the current BSON object. + */ +int bson_iterator_string_len( const bson_iterator *i ); + +/** + * Get the code value of the BSON object currently pointed to by the + * iterator. Works with bson_code, bson_codewscope, and BSON_STRING + * returns NULL for everything else. + * + * @param i the bson_iterator + * + * @return the code value of the current BSON object. + */ +/* works with bson_code, bson_codewscope, and BSON_STRING */ +/* returns NULL for everything else */ +MONGO_EXPORT const char *bson_iterator_code( const bson_iterator *i ); + +/** + * Calls bson_empty on scope if not a bson_codewscope + * + * @param i the bson_iterator. + * @param scope the bson scope. + */ +/* calls bson_empty on scope if not a bson_codewscope */ +MONGO_EXPORT void bson_iterator_code_scope( const bson_iterator *i, bson *scope ); + +/** + * Get the date value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the date value of the current BSON object. + */ +/* both of these only work with bson_date */ +MONGO_EXPORT bson_date_t bson_iterator_date( const bson_iterator *i ); + +/** + * Get the time value of the BSON object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the time value of the current BSON object. + */ +MONGO_EXPORT time_t bson_iterator_time_t( const bson_iterator *i ); + +/** + * Get the length of the BSON binary object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the length of the current BSON binary object. + */ +MONGO_EXPORT int bson_iterator_bin_len( const bson_iterator *i ); + +/** + * Get the type of the BSON binary object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the type of the current BSON binary object. + */ +MONGO_EXPORT char bson_iterator_bin_type( const bson_iterator *i ); + +/** + * Get the value of the BSON binary object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON binary object. + */ +MONGO_EXPORT const char *bson_iterator_bin_data( const bson_iterator *i ); + +/** + * Get the value of the BSON regex object currently pointed to by the + * iterator. + * + * @param i the bson_iterator + * + * @return the value of the current BSON regex object. + */ +MONGO_EXPORT const char *bson_iterator_regex( const bson_iterator *i ); + +/** + * Get the options of the BSON regex object currently pointed to by the + * iterator. + * + * @param i the bson_iterator. + * + * @return the options of the current BSON regex object. + */ +MONGO_EXPORT const char *bson_iterator_regex_opts( const bson_iterator *i ); + +/* these work with BSON_OBJECT and BSON_ARRAY */ +/** + * Get the BSON subobject currently pointed to by the + * iterator. + * + * @param i the bson_iterator. + * @param sub the BSON subobject destination. + */ +MONGO_EXPORT void bson_iterator_subobject( const bson_iterator *i, bson *sub ); + +/** + * Get a bson_iterator that on the BSON subobject. + * + * @param i the bson_iterator. + * @param sub the iterator to point at the BSON subobject. + */ +MONGO_EXPORT void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub ); + +/* str must be at least 24 hex chars + null byte */ +/** + * Create a bson_oid_t from a string. + * + * @param oid the bson_oid_t destination. + * @param str a null terminated string comprised of at least 24 hex chars. + */ +MONGO_EXPORT void bson_oid_from_string( bson_oid_t *oid, const char *str ); + +/** + * Create a string representation of the bson_oid_t. + * + * @param oid the bson_oid_t source. + * @param str the string representation destination. + */ +MONGO_EXPORT void bson_oid_to_string( const bson_oid_t *oid, char *str ); + +/** + * Create a bson_oid object. + * + * @param oid the destination for the newly created bson_oid_t. + */ +MONGO_EXPORT void bson_oid_gen( bson_oid_t *oid ); + +/** + * Set a function to be used to generate the second four bytes + * of an object id. + * + * @param func a pointer to a function that returns an int. + */ +MONGO_EXPORT void bson_set_oid_fuzz( int ( *func )( void ) ); + +/** + * Set a function to be used to generate the incrementing part + * of an object id (last four bytes). If you need thread-safety + * in generating object ids, you should set this function. + * + * @param func a pointer to a function that returns an int. + */ +MONGO_EXPORT void bson_set_oid_inc( int ( *func )( void ) ); + +/** + * Get the time a bson_oid_t was created. + * + * @param oid the bson_oid_t. + */ +MONGO_EXPORT time_t bson_oid_generated_time( bson_oid_t *oid ); /* Gives the time the OID was created */ + +/* ---------------------------- + BUILDING + ------------------------------ */ + +/** + * Initialize a new bson object. If not created + * with bson_new, you must initialize each new bson + * object using this function. + * + * @note When finished, you must pass the bson object to + * bson_destroy( ). + */ +MONGO_EXPORT void bson_init( bson *b ); + +/** + * Initialize a BSON object, and point its data + * pointer to the provided char*. + * + * @param b the BSON object to initialize. + * @param data the raw BSON data. + * + * @return BSON_OK or BSON_ERROR. + */ +int bson_init_data( bson *b , char *data ); +int bson_init_finished_data( bson *b, char *data ) ; + +/** + * Initialize a BSON object, and set its + * buffer to the given size. + * + * @param b the BSON object to initialize. + * @param size the initial size of the buffer. + * + * @return BSON_OK or BSON_ERROR. + */ +void bson_init_size( bson *b, int size ); + +/** + * Grow a bson object. + * + * @param b the bson to grow. + * @param bytesNeeded the additional number of bytes needed. + * + * @return BSON_OK or BSON_ERROR with the bson error object set. + * Exits if allocation fails. + */ +int bson_ensure_space( bson *b, const int bytesNeeded ); + +/** + * Finalize a bson object. + * + * @param b the bson object to finalize. + * + * @return the standard error code. To deallocate memory, + * call bson_destroy on the bson object. + */ +MONGO_EXPORT int bson_finish( bson *b ); + +/** + * Destroy a bson object. + * + * @param b the bson object to destroy. + * + */ +MONGO_EXPORT void bson_destroy( bson *b ); + +/** + * Returns a pointer to a static empty BSON object. + * + * @param obj the BSON object to initialize. + * + * @return the empty initialized BSON object. + */ +/* returns pointer to static empty bson object */ +MONGO_EXPORT bson *bson_empty( bson *obj ); + +/** + * Make a complete copy of the a BSON object. + * The source bson object must be in a finished + * state; otherwise, the copy will fail. + * + * @param out the copy destination BSON object. + * @param in the copy source BSON object. + */ +MONGO_EXPORT int bson_copy( bson *out, const bson *in ); /* puts data in new buffer. NOOP if out==NULL */ + +/** + * Append a previously created bson_oid_t to a bson object. + * + * @param b the bson to append to. + * @param name the key for the bson_oid_t. + * @param oid the bson_oid_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid ); + +/** + * Append a bson_oid_t to a bson. + * + * @param b the bson to append to. + * @param name the key for the bson_oid_t. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_new_oid( bson *b, const char *name ); + +/** + * Append an int to a bson. + * + * @param b the bson to append to. + * @param name the key for the int. + * @param i the int to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_int( bson *b, const char *name, const int i ); + +/** + * Append an long to a bson. + * + * @param b the bson to append to. + * @param name the key for the long. + * @param i the long to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_long( bson *b, const char *name, const int64_t i ); + +/** + * Append an double to a bson. + * + * @param b the bson to append to. + * @param name the key for the double. + * @param d the double to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_double( bson *b, const char *name, const double d ); + +/** + * Append a string to a bson. + * + * @param b the bson to append to. + * @param name the key for the string. + * @param str the string to append. + * + * @return BSON_OK or BSON_ERROR. +*/ +MONGO_EXPORT int bson_append_string( bson *b, const char *name, const char *str ); + +/** + * Append len bytes of a string to a bson. + * + * @param b the bson to append to. + * @param name the key for the string. + * @param str the string to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_string_n( bson *b, const char *name, const char *str, int len ); + +/** + * Append a symbol to a bson. + * + * @param b the bson to append to. + * @param name the key for the symbol. + * @param str the symbol to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_symbol( bson *b, const char *name, const char *str ); + +/** + * Append len bytes of a symbol to a bson. + * + * @param b the bson to append to. + * @param name the key for the symbol. + * @param str the symbol to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_symbol_n( bson *b, const char *name, const char *str, int len ); + +/** + * Append code to a bson. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the code to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_code( bson *b, const char *name, const char *str ); + +/** + * Append len bytes of code to a bson. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the code to append. + * @param len the number of bytes from str to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_code_n( bson *b, const char *name, const char *str, int len ); + +/** + * Append code to a bson with scope. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the string to append. + * @param scope a BSON object containing the scope. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope ); + +/** + * Append len bytes of code to a bson with scope. + * + * @param b the bson to append to. + * @param name the key for the code. + * @param str the string to append. + * @param len the number of bytes from str to append. + * @param scope a BSON object containing the scope. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_code_w_scope_n( bson *b, const char *name, const char *code, int size, const bson *scope ); + +/** + * Append binary data to a bson. + * + * @param b the bson to append to. + * @param name the key for the data. + * @param type the binary data type. + * @param str the binary data. + * @param len the length of the data. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_binary( bson *b, const char *name, char type, const char *str, int len ); + +/** + * Append a bson_bool_t to a bson. + * + * @param b the bson to append to. + * @param name the key for the boolean value. + * @param v the bson_bool_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_bool( bson *b, const char *name, const bson_bool_t v ); + +/** + * Append a null value to a bson. + * + * @param b the bson to append to. + * @param name the key for the null value. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_null( bson *b, const char *name ); + +/** + * Append an undefined value to a bson. + * + * @param b the bson to append to. + * @param name the key for the undefined value. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_undefined( bson *b, const char *name ); + +/** + * Append a regex value to a bson. + * + * @param b the bson to append to. + * @param name the key for the regex value. + * @param pattern the regex pattern to append. + * @param the regex options. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts ); + +/** + * Append bson data to a bson. + * + * @param b the bson to append to. + * @param name the key for the bson data. + * @param bson the bson object to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_bson( bson *b, const char *name, const bson *bson ); + +/** + * Append a BSON element to a bson from the current point of an iterator. + * + * @param b the bson to append to. + * @param name_or_null the key for the BSON element, or NULL. + * @param elem the bson_iterator. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem ); + +/** + * Append a bson_timestamp_t value to a bson. + * + * @param b the bson to append to. + * @param name the key for the timestampe value. + * @param ts the bson_timestamp_t value to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts ); +MONGO_EXPORT int bson_append_timestamp2( bson *b, const char *name, int time, int increment ); + +/* these both append a bson_date */ +/** + * Append a bson_date_t value to a bson. + * + * @param b the bson to append to. + * @param name the key for the date value. + * @param millis the bson_date_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_date( bson *b, const char *name, bson_date_t millis ); + +/** + * Append a time_t value to a bson. + * + * @param b the bson to append to. + * @param name the key for the date value. + * @param secs the time_t to append. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_time_t( bson *b, const char *name, time_t secs ); + +/** + * Start appending a new object to a bson. + * + * @param b the bson to append to. + * @param name the name of the new object. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_start_object( bson *b, const char *name ); + +/** + * Start appending a new array to a bson. + * + * @param b the bson to append to. + * @param name the name of the new array. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_start_array( bson *b, const char *name ); + +/** + * Finish appending a new object or array to a bson. + * + * @param b the bson to append to. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_finish_object( bson *b ); + +/** + * Finish appending a new object or array to a bson. This + * is simply an alias for bson_append_finish_object. + * + * @param b the bson to append to. + * + * @return BSON_OK or BSON_ERROR. + */ +MONGO_EXPORT int bson_append_finish_array( bson *b ); + +void bson_numstr( char *str, int i ); + +void bson_incnumstr( char *str ); + +/* Error handling and standard library function over-riding. */ +/* -------------------------------------------------------- */ + +/* bson_err_handlers shouldn't return!!! */ +typedef void( *bson_err_handler )( const char *errmsg ); + +typedef int (*bson_printf_func)( const char *, ... ); +typedef int (*bson_fprintf_func)( FILE *, const char *, ... ); +typedef int (*bson_sprintf_func)( char *, const char *, ... ); + +extern void *( *bson_malloc_func )( size_t ); +extern void *( *bson_realloc_func )( void *, size_t ); +extern void ( *bson_free_func )( void * ); + +extern bson_printf_func bson_printf; +extern bson_fprintf_func bson_fprintf; +extern bson_sprintf_func bson_sprintf; +extern bson_printf_func bson_errprintf; + +MONGO_EXPORT void bson_free( void *ptr ); + +/** + * Allocates memory and checks return value, exiting fatally if malloc() fails. + * + * @param size bytes to allocate. + * + * @return a pointer to the allocated memory. + * + * @sa malloc(3) + */ +MONGO_EXPORT void *bson_malloc( int size ); + +/** + * Changes the size of allocated memory and checks return value, + * exiting fatally if realloc() fails. + * + * @param ptr pointer to the space to reallocate. + * @param size bytes to allocate. + * + * @return a pointer to the allocated memory. + * + * @sa realloc() + */ +void *bson_realloc( void *ptr, int size ); + +/** + * Set a function for error handling. + * + * @param func a bson_err_handler function. + * + * @return the old error handling function, or NULL. + */ +MONGO_EXPORT bson_err_handler set_bson_err_handler( bson_err_handler func ); + +/* does nothing if ok != 0 */ +/** + * Exit fatally. + * + * @param ok exits if ok is equal to 0. + */ +void bson_fatal( int ok ); + +/** + * Exit fatally with an error message. + * + * @param ok exits if ok is equal to 0. + * @param msg prints to stderr before exiting. + */ +void bson_fatal_msg( int ok, const char *msg ); + +/** + * Invoke the error handler, but do not exit. + * + * @param b the buffer object. + */ +void bson_builder_error( bson *b ); + +/** + * Cast an int64_t to double. This is necessary for embedding in + * certain environments. + * + */ +MONGO_EXPORT double bson_int64_to_double( int64_t i64 ); + +MONGO_EXPORT void bson_swap_endian32( void *outp, const void *inp ); +MONGO_EXPORT void bson_swap_endian64( void *outp, const void *inp ); + +MONGO_EXTERN_C_END +#endif |