mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-14 10:07:39 +08:00
Goodbye to the Mongo BSON codec; too big. Hello to a really small SAX-style decoder and matching encoder.
This commit is contained in:
parent
a9dd3564ed
commit
26c2c2d2cf
@ -39,8 +39,7 @@ CSRCS = err.c \
|
||||
hx_stream.c \
|
||||
perf_counter.c \
|
||||
param/param.c \
|
||||
bson/bson.c \
|
||||
bson/bcon.c
|
||||
bson/tinybson.c
|
||||
|
||||
#
|
||||
# XXX this really should be a CONFIG_* test
|
||||
|
||||
@ -1,427 +0,0 @@
|
||||
/* 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('}');
|
||||
}
|
||||
@ -1,420 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
313
apps/systemlib/bson/tinybson.c
Normal file
313
apps/systemlib/bson/tinybson.c
Normal file
@ -0,0 +1,313 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file tinybson.c
|
||||
*
|
||||
* A simple subset SAX-style BSON parser and generator.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "tinybson.h"
|
||||
|
||||
|
||||
#if 1
|
||||
# define debug(fmt, args...) do { warnx("BSON:" fmt, ##args); } while(0)
|
||||
#else
|
||||
# define debug(fmt, args...) do { } while(0)
|
||||
#endif
|
||||
|
||||
#define CODER_CHECK(_c) do { if (_c->fd == -1) return -1; } while(0)
|
||||
#define CODER_KILL(_c, _reason) do { debug("killed:%s", _reason); _c->fd = -1; return -1; } while(0)
|
||||
|
||||
static int
|
||||
read_int8(bson_decoder_t decoder, int8_t *b)
|
||||
{
|
||||
return (read(decoder->fd, b, sizeof(*b)) == sizeof(*b)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
read_int32(bson_decoder_t decoder, int32_t *i)
|
||||
{
|
||||
return (read(decoder->fd, i, sizeof(*i)) == sizeof(*i)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
read_double(bson_decoder_t decoder, double *d)
|
||||
{
|
||||
return (read(decoder->fd, d, sizeof(*d)) == sizeof(*d)) ? 0 : -1;
|
||||
}
|
||||
|
||||
int
|
||||
bson_decoder_init(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *private)
|
||||
{
|
||||
int32_t junk;
|
||||
|
||||
decoder->fd = fd;
|
||||
decoder->callback = callback;
|
||||
decoder->private = private;
|
||||
decoder->nesting = 1;
|
||||
decoder->pending = 0;
|
||||
decoder->node.type = BSON_UNDEFINED;
|
||||
|
||||
/* read and discard document size */
|
||||
if (read_int32(decoder, &junk))
|
||||
CODER_KILL(decoder, "failed reading length");
|
||||
|
||||
/* ready for decoding */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bson_decoder_next(bson_decoder_t decoder)
|
||||
{
|
||||
int8_t tbyte;
|
||||
unsigned nlen;
|
||||
|
||||
CODER_CHECK(decoder);
|
||||
|
||||
/* if the previous node was EOO, pop a nesting level */
|
||||
if (decoder->node.type == BSON_EOO) {
|
||||
if (decoder->nesting > 0)
|
||||
decoder->nesting--;
|
||||
|
||||
/* if the nesting level is now zero, the top-level document is done */
|
||||
if (decoder->nesting == 0)
|
||||
CODER_KILL(decoder, "nesting is zero, document is done");
|
||||
}
|
||||
|
||||
/* if there are unread bytes pending in the stream, discard them */
|
||||
while (decoder->pending != 0) {
|
||||
if (read_int8(decoder, &tbyte))
|
||||
CODER_KILL(decoder, "read error discarding pending bytes");
|
||||
decoder->pending--;
|
||||
}
|
||||
|
||||
/* get the type byte */
|
||||
if (read_int8(decoder, &tbyte))
|
||||
CODER_KILL(decoder, "read error on type byte");
|
||||
decoder->node.type = tbyte;
|
||||
decoder->pending = 0;
|
||||
|
||||
/* get the node name */
|
||||
nlen = 0;
|
||||
for (;;) {
|
||||
if (nlen >= BSON_MAXNAME)
|
||||
CODER_KILL(decoder, "node name overflow");
|
||||
if (read_int8(decoder, (int8_t *)&decoder->node.name[nlen]))
|
||||
CODER_KILL(decoder, "read error on node name");
|
||||
if (decoder->node.name[nlen] == 0)
|
||||
break;
|
||||
nlen++;
|
||||
}
|
||||
|
||||
switch (decoder->node.type) {
|
||||
case BSON_EOO:
|
||||
/* nothing special to do here as we don't support nested objects yet */
|
||||
break;
|
||||
case BSON_INT:
|
||||
if (read_int32(decoder, &decoder->node.i)) {
|
||||
CODER_KILL(decoder, "read error on BSON_INT");
|
||||
}
|
||||
break;
|
||||
case BSON_DOUBLE:
|
||||
if (read_double(decoder, &decoder->node.d))
|
||||
CODER_KILL(decoder, "read error on BSON_DOUBLE");
|
||||
break;
|
||||
case BSON_STRING:
|
||||
if (read_int32(decoder, &decoder->pending))
|
||||
CODER_KILL(decoder, "read error on BSON_STRING length");
|
||||
break;
|
||||
case BSON_BINDATA:
|
||||
if (read_int32(decoder, &decoder->pending))
|
||||
CODER_KILL(decoder, "read error on BSON_BINDATA size");
|
||||
if (read_int8(decoder, &tbyte))
|
||||
CODER_KILL(decoder, "read error on BSON_BINDATA subtype");
|
||||
decoder->node.subtype = tbyte;
|
||||
break;
|
||||
|
||||
/* XXX currently not supporting other types */
|
||||
default:
|
||||
CODER_KILL(decoder, "unsupported node type");
|
||||
}
|
||||
|
||||
/* call the callback and pass its results back */
|
||||
return decoder->callback(decoder, decoder->private, &decoder->node);
|
||||
}
|
||||
|
||||
int
|
||||
bson_decoder_copy_data(bson_decoder_t decoder, void *buf)
|
||||
{
|
||||
int result;
|
||||
|
||||
CODER_CHECK(decoder);
|
||||
|
||||
/* if data already copied, return zero bytes */
|
||||
if (decoder->pending == 0)
|
||||
return 0;
|
||||
|
||||
/* copy bytes per the node size */
|
||||
result = read(decoder->fd, buf, decoder->pending);
|
||||
if (result != decoder->pending)
|
||||
CODER_KILL(decoder, "read error on copy_data");
|
||||
|
||||
/* pending count is discharged */
|
||||
decoder->pending = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
bson_decoder_data_pending(bson_decoder_t decoder)
|
||||
{
|
||||
return decoder->pending;
|
||||
}
|
||||
|
||||
static int
|
||||
write_int8(bson_encoder_t encoder, int8_t b)
|
||||
{
|
||||
debug("write_int8 %d", b);
|
||||
return (write(encoder->fd, &b, sizeof(b)) == sizeof(b)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
write_int32(bson_encoder_t encoder, int32_t i)
|
||||
{
|
||||
debug("write_int32 %d", i);
|
||||
return (write(encoder->fd, &i, sizeof(i)) == sizeof(i)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
write_double(bson_encoder_t encoder, double d)
|
||||
{
|
||||
debug("write_double");
|
||||
return (write(encoder->fd, &d, sizeof(d)) == sizeof(d)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
write_name(bson_encoder_t encoder, const char *name)
|
||||
{
|
||||
size_t len = strlen(name);
|
||||
|
||||
if (len > BSON_MAXNAME)
|
||||
return -1;
|
||||
debug("write name '%s' len %d", name, len);
|
||||
return (write(encoder->fd, name, len + 1) == (int)(len + 1)) ? 0 : -1;
|
||||
}
|
||||
|
||||
int
|
||||
bson_encoder_init(bson_encoder_t encoder, int fd)
|
||||
{
|
||||
encoder->fd = fd;
|
||||
|
||||
if (write_int32(encoder, 0))
|
||||
CODER_KILL(encoder, "write error on document length");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bson_encoder_fini(bson_encoder_t encoder)
|
||||
{
|
||||
CODER_CHECK(encoder);
|
||||
|
||||
if (write_int8(encoder, 0))
|
||||
CODER_KILL(encoder, "write error on document terminator");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bson_encoder_append_int(bson_encoder_t encoder, const char *name, int32_t value)
|
||||
{
|
||||
CODER_CHECK(encoder);
|
||||
|
||||
if (write_name(encoder, name))
|
||||
CODER_KILL(encoder, "write error on BSON_INT name");
|
||||
if (write_int32(encoder, value))
|
||||
CODER_KILL(encoder, "write error on BSON_INT value");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value)
|
||||
{
|
||||
CODER_CHECK(encoder);
|
||||
|
||||
if (write_name(encoder, name))
|
||||
CODER_KILL(encoder, "write error on BSON_DOUBLE name");
|
||||
|
||||
if (write_double(encoder, value))
|
||||
CODER_KILL(encoder, "write error on BSON_DOUBLE value");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char *string)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
CODER_CHECK(encoder);
|
||||
|
||||
if (write_name(encoder, name))
|
||||
CODER_KILL(encoder, "write error on BSON_STRING name");
|
||||
|
||||
len = strlen(string);
|
||||
if (write_int32(encoder, len))
|
||||
CODER_KILL(encoder, "write error on BSON_STRING length");
|
||||
if (write(encoder->fd, name, len + 1) != (int)(len + 1))
|
||||
CODER_KILL(encoder, "write error on BSON_STRING data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype, size_t size, const void *data)
|
||||
{
|
||||
CODER_CHECK(encoder);
|
||||
|
||||
if (write_name(encoder, name))
|
||||
CODER_KILL(encoder, "write error on BSON_BINDATA name");
|
||||
if (write_int32(encoder, size))
|
||||
CODER_KILL(encoder, "write error on BSON_BINDATA size");
|
||||
if (write_int8(encoder, subtype))
|
||||
CODER_KILL(encoder, "write error on BSON_BINDATA subtype");
|
||||
if (write(encoder->fd, data, size) != (int)(size))
|
||||
CODER_KILL(encoder, "write error on BSON_BINDATA data");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
169
apps/systemlib/bson/tinybson.h
Normal file
169
apps/systemlib/bson/tinybson.h
Normal file
@ -0,0 +1,169 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file tinybson.h
|
||||
*
|
||||
* A simple subset SAX-style BSON parser and generator.
|
||||
*
|
||||
* Some types and defines taken from the standalone BSON parser/generator
|
||||
* in the Mongo C connector.
|
||||
*/
|
||||
|
||||
#ifndef _TINYBSON_H
|
||||
#define _TINYBSON_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/** subset of the BSON node types we might care about */
|
||||
typedef enum {
|
||||
BSON_EOO = 0,
|
||||
BSON_DOUBLE = 1,
|
||||
BSON_STRING = 2,
|
||||
BSON_OBJECT = 3,
|
||||
BSON_ARRAY = 4,
|
||||
BSON_BINDATA = 5,
|
||||
BSON_UNDEFINED = 6,
|
||||
BSON_BOOL = 8,
|
||||
BSON_DATE = 9,
|
||||
BSON_NULL = 10,
|
||||
BSON_INT = 16,
|
||||
BSON_TIMESTAMP = 17,
|
||||
BSON_LONG = 18
|
||||
} bson_type_t;
|
||||
|
||||
typedef enum bson_binary_subtype {
|
||||
BSON_BIN_BINARY = 0,
|
||||
BSON_BIN_USER = 128
|
||||
} bson_binary_subtype_t;
|
||||
|
||||
/**
|
||||
* Maximum node name length.
|
||||
*/
|
||||
#define BSON_MAXNAME 32
|
||||
|
||||
/**
|
||||
* Node structure passed to the callback.
|
||||
*/
|
||||
typedef struct bson_node_s
|
||||
{
|
||||
char name[BSON_MAXNAME];
|
||||
bson_type_t type;
|
||||
bson_binary_subtype_t subtype;
|
||||
union {
|
||||
int32_t i;
|
||||
double d;
|
||||
bool b;
|
||||
};
|
||||
} *bson_node_t;
|
||||
|
||||
typedef struct bson_decoder_s *bson_decoder_t;
|
||||
|
||||
/**
|
||||
* Node callback.
|
||||
*/
|
||||
typedef int (* bson_decoder_callback)(bson_decoder_t decoder, void *private, bson_node_t node);
|
||||
|
||||
struct bson_decoder_s
|
||||
{
|
||||
int fd;
|
||||
bson_decoder_callback callback;
|
||||
void *private;
|
||||
unsigned nesting;
|
||||
struct bson_node_s node;
|
||||
int32_t pending;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise the decoder.
|
||||
*/
|
||||
__EXPORT int bson_decoder_init(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *private);
|
||||
|
||||
/**
|
||||
* Process the next node from the stream and invoke the callback.
|
||||
*/
|
||||
__EXPORT int bson_decoder_next(bson_decoder_t decoder);
|
||||
|
||||
/**
|
||||
* Copy node data.
|
||||
*/
|
||||
__EXPORT int bson_decoder_copy_data(bson_decoder_t decoder, void *buf);
|
||||
|
||||
/**
|
||||
* Report copyable data size.
|
||||
*/
|
||||
__EXPORT size_t bson_decoder_data_pending(bson_decoder_t decoder);
|
||||
|
||||
/**
|
||||
* Encoder state structure.
|
||||
*/
|
||||
typedef struct bson_encoder_s
|
||||
{
|
||||
int fd;
|
||||
|
||||
} *bson_encoder_t;
|
||||
|
||||
/**
|
||||
* Initialze the encoder.
|
||||
*/
|
||||
__EXPORT int bson_encoder_init(bson_encoder_t encoder, int fd);
|
||||
|
||||
/**
|
||||
* Finalise the encoded stream.
|
||||
*/
|
||||
__EXPORT int bson_encoder_fini(bson_encoder_t encoder);
|
||||
|
||||
/**
|
||||
* Append an integer to the encoded stream.
|
||||
*/
|
||||
__EXPORT int bson_encoder_append_int(bson_encoder_t encoder, const char *name, int32_t value);
|
||||
|
||||
/**
|
||||
* Append a double to the encoded stream
|
||||
*/
|
||||
__EXPORT int bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value);
|
||||
|
||||
/**
|
||||
* Append a string to the encoded stream.
|
||||
*/
|
||||
__EXPORT int bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char *string);
|
||||
|
||||
/**
|
||||
* Append a binary blob to the encoded stream.
|
||||
*/
|
||||
__EXPORT int bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype, size_t size, const void *data);
|
||||
|
||||
|
||||
#endif
|
||||
Loading…
x
Reference in New Issue
Block a user