From c522b5446dd4e692d15b37de8ad199765259e35b Mon Sep 17 00:00:00 2001 From: px4dev Date: Sat, 27 Oct 2012 20:39:37 -0700 Subject: Work in progress on to/from memory BSON coding. --- apps/systemlib/bson/tinybson.c | 183 +++++++++++++++++++++++++++++++++++------ apps/systemlib/bson/tinybson.h | 80 +++++++++++++++++- 2 files changed, 234 insertions(+), 29 deletions(-) (limited to 'apps/systemlib/bson') diff --git a/apps/systemlib/bson/tinybson.c b/apps/systemlib/bson/tinybson.c index 75578d2ec..10598e645 100644 --- a/apps/systemlib/bson/tinybson.c +++ b/apps/systemlib/bson/tinybson.c @@ -43,40 +43,60 @@ #include "tinybson.h" - #if 0 # 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) +#define CODER_CHECK(_c) do { if (_c->dead) return -1; } while(0) +#define CODER_KILL(_c, _reason) do { debug("killed: %s", _reason); _c->dead = true; return -1; } while(0) + +static int +read_x(bson_decoder_t decoder, void *p, size_t s) +{ + CODER_CHECK(decoder); + + if (decoder->fd > 0) + return (read(decoder->fd, p, s) == s) ? 0 : -1; + + if (decoder->buf != NULL) { + unsigned newpos = decoder->bufpos + s; + if (newpos <= decoder->bufsize) { + memcpy(p, (decoder->buf + decoder->bufpos), s); + decoder->bufpos = newpos; + return 0; + } + } + return -1; +} static int read_int8(bson_decoder_t decoder, int8_t *b) { - return (read(decoder->fd, b, sizeof(*b)) == sizeof(*b)) ? 0 : -1; + return read_x(decoder, b, sizeof(*b)); } static int read_int32(bson_decoder_t decoder, int32_t *i) { - return (read(decoder->fd, i, sizeof(*i)) == sizeof(*i)) ? 0 : -1; + return read_x(decoder, i, sizeof(*i)); } static int read_double(bson_decoder_t decoder, double *d) { - return (read(decoder->fd, d, sizeof(*d)) == sizeof(*d)) ? 0 : -1; + return read_x(decoder, d, sizeof(*d)); } int -bson_decoder_init(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *private) +bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *private) { int32_t junk; decoder->fd = fd; + decoder->buf = NULL; + decoder->dead = false; decoder->callback = callback; decoder->private = private; decoder->nesting = 1; @@ -91,6 +111,32 @@ bson_decoder_init(bson_decoder_t decoder, int fd, bson_decoder_callback callback return 0; } +int +bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_decoder_callback callback, void *private) +{ + int32_t len; + + decoder->fd = -1; + decoder->buf = (uint8_t *)buf; + decoder->dead = false; + decoder->bufsize = bufsize; + decoder->bufpos = 0; + 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, &len)) + CODER_KILL(decoder, "failed reading length"); + if (len > bufsize) + CODER_KILL(decoder, "document length larger than buffer"); + + /* ready for decoding */ + return 0; +} + int bson_decoder_next(bson_decoder_t decoder) { @@ -154,6 +200,12 @@ bson_decoder_next(bson_decoder_t decoder) debug("got name '%s'", decoder->node.name); switch (decoder->node.type) { + case BSON_BOOL: + if (read_int8(decoder, &tbyte)) + CODER_KILL(decoder, "read error on BSON_BOOL"); + node->b = (tbyte != 0); + break; + case BSON_INT: if (read_int32(decoder, &decoder->node.i)) CODER_KILL(decoder, "read error on BSON_INT"); @@ -199,14 +251,10 @@ bson_decoder_copy_data(bson_decoder_t decoder, void *buf) CODER_CHECK(decoder); - /* if data already copied, return zero bytes */ - if (decoder->pending == 0) - return 0; + /* copy data */ + result = read_x(decoder, buf, decoder->pending); - /* copy bytes per the node size */ - result = read(decoder->fd, buf, decoder->pending); - - if (result != decoder->pending) + if (result != 0) CODER_KILL(decoder, "read error on copy_data"); /* pending count is discharged */ @@ -220,25 +268,48 @@ bson_decoder_data_pending(bson_decoder_t decoder) return decoder->pending; } +static int +write_x(bson_encoder_t encoder, void *p, size_t s) +{ + CODER_CHECK(encoder); + + if (encoder->fd > -1) + return (write(encoder->fd, p, s) == s) ? 0 : -1; + + /* do we need to extend the buffer? */ + while ((encoder->bufpos + s) > encoder->bufsize) { + if (!encoder->realloc_ok) + CODER_KILL(encoder); + + int8_t *newbuf = realloc(encoder->buf, encoder->bufsize + BSON_BUF_INCREMENT); + if (newbuf == NULL) + CODER_KILL(encoder); + + encoder->bufsize += BSON_BUF_INCREMENT; + } + + memcpy(encoder->buf + encoder->bufpos, p, s); + encoder->bufpos += s; + + return 0; +} + 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; + return write_x(encoder, &b, sizeof(b)); } 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; + return write_x(encoder, &i, sizeof(i)); } static int write_double(bson_encoder_t encoder, double d) { - debug("write_double"); - return (write(encoder->fd, &d, sizeof(d)) == sizeof(d)) ? 0 : -1; + return write_x(encoder, &d, sizeof(d)); } static int @@ -249,14 +320,15 @@ write_name(bson_encoder_t encoder, const char *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; + return write_x(encoder, name, len + 1); } int -bson_encoder_init(bson_encoder_t encoder, int fd) +bson_encoder_init_file(bson_encoder_t encoder, int fd) { encoder->fd = fd; + encoder->buf = NULL; + encoder->dead = false; if (write_int32(encoder, 0)) CODER_KILL(encoder, "write error on document length"); @@ -264,6 +336,27 @@ bson_encoder_init(bson_encoder_t encoder, int fd) return 0; } +int +bson_encoder_init_buf(bson_encoder_t encoder, void *buf, unsigned bufsize) +{ + encoder->fd = -1; + encoder->buf = (uint8_t *)buf; + encoder->bufpos = 0; + encoder->dead = false; + if (encoder->buf == NULL) { + encoder->bufsize = 0; + encoder->realloc_ok = true; + } else { + encoder->bufsize = bufsize; + encoder->realloc_ok = false; + } + + if (write_int32(encoder, 0)) + CODER_KILL(encoder, "write error on document length"); + + return 0; +} + int bson_encoder_fini(bson_encoder_t encoder) { @@ -272,6 +365,46 @@ bson_encoder_fini(bson_encoder_t encoder) if (write_int8(encoder, BSON_EOO)) CODER_KILL(encoder, "write error on document terminator"); + /* hack to fix up length for in-buffer documents */ + if (encoder->buf != NULL) { + int32_t len = bson_encoder_buf_size(encoder); + memcpy(encoder->buf, &len, sizeof(len)); + } + + return 0; +} + +int +bson_encoder_buf_size(bson_encoder_t encoder) +{ + CODER_CHECK(encoder); + + if (encoder->fd > -1) + return -1; + + return encoder->bufpos; +} + +int +bson_encoder_buf_data(bson_encoder_t encoder) +{ + /* note, no CODER_CHECK here as the caller has to clean up dead buffers */ + + if (encoder->fd > -1) + return NULL; + + return encoder->buf; +} + +int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool value) +{ + CODER_CHECK(encoder); + + if (write_int8(encoder, BSON_INT) || + write_name(encoder, name) || + write_int(encoder, value ? 1 : 0)) + CODER_KILL(encoder, "write error on BSON_BOOL"); + return 0; } @@ -314,7 +447,7 @@ bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char if (write_int8(encoder, BSON_DOUBLE) || write_name(encoder, name) || write_int32(encoder, len) || - write(encoder->fd, name, len + 1) != (int)(len + 1)) + write_x(encoder, name, len + 1)) CODER_KILL(encoder, "write error on BSON_STRING"); return 0; @@ -329,7 +462,7 @@ bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary write_name(encoder, name) || write_int32(encoder, size) || write_int8(encoder, subtype) || - write(encoder->fd, data, size) != (int)(size)) + write_x(encoder, data, size)) CODER_KILL(encoder, "write error on BSON_BINDATA"); return 0; diff --git a/apps/systemlib/bson/tinybson.h b/apps/systemlib/bson/tinybson.h index b6229dc50..833bbf6c4 100644 --- a/apps/systemlib/bson/tinybson.h +++ b/apps/systemlib/bson/tinybson.h @@ -74,6 +74,11 @@ typedef enum bson_binary_subtype { */ #define BSON_MAXNAME 32 +/** + * Buffer growth increment when writing to a buffer. + */ +#define BSON_BUF_INCREMENT 128 + /** * Node structure passed to the callback. */ @@ -92,11 +97,21 @@ typedef struct bson_decoder_s *bson_decoder_t; /** * Node callback. + * + * The node callback function's return value is returned by bson_decoder_next. */ typedef int (* bson_decoder_callback)(bson_decoder_t decoder, void *private, bson_node_t node); struct bson_decoder_s { + /* file reader state */ int fd; + + /* buffer reader state */ + uint8_t *buf; + size_t bufsize; + unsigned bufpos; + + bool dead; bson_decoder_callback callback; void *private; unsigned nesting; @@ -105,7 +120,7 @@ struct bson_decoder_s { }; /** - * Initialise the decoder. + * Initialise the decoder to read from a file. * * @param decoder Decoder state structure to be initialised. * @param fd File to read BSON data from. @@ -113,7 +128,19 @@ struct bson_decoder_s { * @param private Callback private data, stored in node. * @return Zero on success. */ -__EXPORT int bson_decoder_init(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *private); +__EXPORT int bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *private); + +/** + * Initialise the decoder to read from a buffer in memory. + * + * @param decoder Decoder state structure to be initialised. + * @param buf Buffer to read from. + * @param bufsize Size of the buffer (BSON object may be smaller). + * @param callback Callback to be invoked by bson_decoder_next + * @param private Callback private data, stored in node. + * @return Zero on success. + */ +__EXPORT int bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_decoder_callback callback, void *private); /** * Process the next node from the stream and invoke the callback. @@ -142,20 +169,65 @@ __EXPORT size_t bson_decoder_data_pending(bson_decoder_t decoder); * Encoder state structure. */ typedef struct bson_encoder_s { + /* file writer state */ int fd; + /* buffer writer state */ + uint8_t *buf; + unsigned bufsize; + unsigned bufpos; + + bool realloc_ok; + bool dead; + } *bson_encoder_t; /** - * Initialze the encoder. + * Initialze the encoder for writing to a file. + * + * @param encoder Encoder state structure to be initialised. + * @param fd File to write to. + * @return Zero on success. + */ +__EXPORT int bson_encoder_init_file(bson_encoder_t encoder, int fd); + +/** + * Initialze the encoder for writing to a buffer. + * + * @param encoder Encoder state structure to be initialised. + * @param buf Buffer pointer to use, or NULL if the buffer + * should be allocated by the encoder. + * @param bufsize Maximum buffer size, or zero for no limit. If + * the buffer is supplied, the size of the supplied buffer. + * @return Zero on success. */ -__EXPORT int bson_encoder_init(bson_encoder_t encoder, int fd); +__EXPORT int bson_encoder_init_buf(bson_encoder_t encoder, void *buf, unsigned bufsize); /** * Finalise the encoded stream. + * + * @param encoder The encoder to finalise. */ __EXPORT int bson_encoder_fini(bson_encoder_t encoder); +/** + * Fetch the size of the encoded object; only valid for buffer operations. + */ +__EXPORT int bson_encoder_buf_size(bson_encoder_t encoder); + +/** + * Get a pointer to the encoded object buffer. + * + * Note that if the buffer was allocated by the encoder, it is the caller's responsibility + * to free this buffer. + */ +__EXPORT void *bson_encoder_buf_data(bson_encoder_t encoder); + +/** + * Append a boolean to the encoded stream. + */ +__EXPORT int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool value); + /** * Append an integer to the encoded stream. */ -- cgit v1.2.3 From 3d750bc38c2ef5f147475cc8a54f605cbf9f772a Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 28 Oct 2012 00:21:17 -0700 Subject: Build fixes --- apps/systemlib/bson/tinybson.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'apps/systemlib/bson') diff --git a/apps/systemlib/bson/tinybson.c b/apps/systemlib/bson/tinybson.c index 10598e645..a28217fc4 100644 --- a/apps/systemlib/bson/tinybson.c +++ b/apps/systemlib/bson/tinybson.c @@ -39,6 +39,7 @@ #include #include +#include #include #include "tinybson.h" @@ -58,7 +59,7 @@ read_x(bson_decoder_t decoder, void *p, size_t s) CODER_CHECK(decoder); if (decoder->fd > 0) - return (read(decoder->fd, p, s) == s) ? 0 : -1; + return (read(decoder->fd, p, s) == (int)s) ? 0 : -1; if (decoder->buf != NULL) { unsigned newpos = decoder->bufpos + s; @@ -130,7 +131,7 @@ bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_ /* read and discard document size */ if (read_int32(decoder, &len)) CODER_KILL(decoder, "failed reading length"); - if (len > bufsize) + if (len > (int)bufsize) CODER_KILL(decoder, "document length larger than buffer"); /* ready for decoding */ @@ -203,7 +204,7 @@ bson_decoder_next(bson_decoder_t decoder) case BSON_BOOL: if (read_int8(decoder, &tbyte)) CODER_KILL(decoder, "read error on BSON_BOOL"); - node->b = (tbyte != 0); + decoder->node.b = (tbyte != 0); break; case BSON_INT: @@ -269,21 +270,21 @@ bson_decoder_data_pending(bson_decoder_t decoder) } static int -write_x(bson_encoder_t encoder, void *p, size_t s) +write_x(bson_encoder_t encoder, const void *p, size_t s) { CODER_CHECK(encoder); if (encoder->fd > -1) - return (write(encoder->fd, p, s) == s) ? 0 : -1; + return (write(encoder->fd, p, s) == (int)s) ? 0 : -1; /* do we need to extend the buffer? */ while ((encoder->bufpos + s) > encoder->bufsize) { if (!encoder->realloc_ok) - CODER_KILL(encoder); + CODER_KILL(encoder, "fixed-size buffer overflow"); int8_t *newbuf = realloc(encoder->buf, encoder->bufsize + BSON_BUF_INCREMENT); if (newbuf == NULL) - CODER_KILL(encoder); + CODER_KILL(encoder, "could not grow buffer"); encoder->bufsize += BSON_BUF_INCREMENT; } @@ -385,7 +386,7 @@ bson_encoder_buf_size(bson_encoder_t encoder) return encoder->bufpos; } -int +void * bson_encoder_buf_data(bson_encoder_t encoder) { /* note, no CODER_CHECK here as the caller has to clean up dead buffers */ @@ -402,7 +403,7 @@ int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool valu if (write_int8(encoder, BSON_INT) || write_name(encoder, name) || - write_int(encoder, value ? 1 : 0)) + write_int8(encoder, value ? 1 : 0)) CODER_KILL(encoder, "write error on BSON_BOOL"); return 0; -- cgit v1.2.3 From 4c18aced369b91ce5ba14c471e1677c9a28e8707 Mon Sep 17 00:00:00 2001 From: px4dev Date: Sun, 28 Oct 2012 15:42:27 -0700 Subject: BSON coder unit tests, fixes arising from test failures. --- apps/px4/tests/test_bson.c | 146 ++++++++++++++++++++++++++++------------- apps/systemlib/bson/tinybson.c | 88 ++++++++++++++++++------- apps/systemlib/bson/tinybson.h | 31 +++++++-- apps/systemlib/param/param.c | 6 +- 4 files changed, 196 insertions(+), 75 deletions(-) (limited to 'apps/systemlib/bson') diff --git a/apps/px4/tests/test_bson.c b/apps/px4/tests/test_bson.c index 4ca765e53..d03a8d332 100644 --- a/apps/px4/tests/test_bson.c +++ b/apps/px4/tests/test_bson.c @@ -39,34 +39,36 @@ */ #include -#include +#include +#include +#include #include + #include "tests.h" -static const bool test_bool = true; -static const int32_t test_int = 32; -static const double test_double = 2.5; -static const char *test_string = "this is a test"; -static const uint8_t test_data[256]; -static const char *test_filename = "/fs/microsd/bson.test"; +static const bool sample_bool = true; +static const int32_t sample_small_int = 123; +static const int64_t sample_big_int = (int64_t)INT_MAX + 123LL; +static const double sample_double = 2.5f; +static const char *sample_string = "this is a test"; +static const uint8_t sample_data[256]; +//static const char *sample_filename = "/fs/microsd/bson.test"; static int encode(bson_encoder_t encoder) { - - if (bson_encoder_append_int(encoder, "thisisanillegalbsonpropertynamebecauseitistoolong", 0) == 0) - warnx("FAIL: encoder: too-long node name not rejected"); - - if (bson_encoder_append_int(encoder, "bool1", test_bool) != 0) + if (bson_encoder_append_bool(encoder, "bool1", sample_bool) != 0) warnx("FAIL: encoder: append bool failed"); - if (bson_encoder_append_int(encoder, "int1", test_int) != 0) + if (bson_encoder_append_int(encoder, "int1", sample_small_int) != 0) warnx("FAIL: encoder: append int failed"); - if (bson_encoder_append_double(encoder, "double1", test_double) != 0) + if (bson_encoder_append_int(encoder, "int2", sample_big_int) != 0) + warnx("FAIL: encoder: append int failed"); + if (bson_encoder_append_double(encoder, "double1", sample_double) != 0) warnx("FAIL: encoder: append double failed"); - if (bson_encoder_append_string(encoder, "string1", test_string) != 0) + if (bson_encoder_append_string(encoder, "string1", sample_string) != 0) warnx("FAIL: encoder: append string failed"); - if (bson_encoder_append_binary(encoder, "data1", test_data) != 0) + if (bson_encoder_append_binary(encoder, "data1", BSON_BIN_BINARY, sizeof(sample_data), sample_data) != 0) warnx("FAIL: encoder: append data failed"); bson_encoder_fini(encoder); @@ -77,29 +79,70 @@ encode(bson_encoder_t encoder) static int decode_callback(bson_decoder_t decoder, void *private, bson_node_t node) { + unsigned len; + if (!strcmp(node->name, "bool1")) { - if (node->b != test_bool) + if (node->type != BSON_BOOL) { + warnx("FAIL: decoder: bool1 type %d, expected %d", node->type, BSON_BOOL); + return 1; + } + if (node->b != sample_bool) { warnx("FAIL: decoder: bool1 value %s, expected %s", (node->b ? "true" : "false"), - (test_bool ? "true" : "false")); + (sample_bool ? "true" : "false")); + return 1; + } + warnx("PASS: decoder: bool1"); return 1; } if (!strcmp(node->name, "int1")) { - if (node->i != test_int) - warnx("FAIL: decoder: int1 value %d, expected %d", node->i, test_int); + if (node->type != BSON_INT32) { + warnx("FAIL: decoder: int1 type %d, expected %d", node->type, BSON_INT32); + return 1; + } + if (node->i != sample_small_int) { + warnx("FAIL: decoder: int1 value %lld, expected %d", node->i, sample_small_int); + return 1; + } + warnx("PASS: decoder: int1"); + return 1; + } + if (!strcmp(node->name, "int2")) { + if (node->type != BSON_INT64) { + warnx("FAIL: decoder: int2 type %d, expected %d", node->type, BSON_INT64); + return 1; + } + if (node->i != sample_big_int) { + warnx("FAIL: decoder: int2 value %lld, expected %lld", node->i, sample_big_int); + return 1; + } + warnx("PASS: decoder: int2"); return 1; } if (!strcmp(node->name, "double1")) { - if (node->d != test_double) - warnx("FAIL: decoder: double1 value %f, expected %f", node->d, test_double); + if (node->type != BSON_DOUBLE) { + warnx("FAIL: decoder: double1 type %d, expected %d", node->type, BSON_DOUBLE); + return 1; + } + if (node->d != sample_double) { + warnx("FAIL: decoder: double1 value %f, expected %f", node->d, sample_double); + return 1; + } + warnx("PASS: decoder: double1"); return 1; } if (!strcmp(node->name, "string1")) { - unsigned len = bson_decoder_data_pending(decoder); + if (node->type != BSON_STRING) { + warnx("FAIL: decoder: string1 type %d, expected %d", node->type, BSON_STRING); + return 1; + } - if (len != (strlen(test_string) + 1)) { - warnx("FAIL: decoder: string1 length %d wrong, expected %d", len, strlen(test_string) + 1); + len = bson_decoder_data_pending(decoder); + + if (len != strlen(sample_string) + 1) { + warnx("FAIL: decoder: string1 length %d wrong, expected %d", len, strlen(sample_string) + 1); return 1; + } char sbuf[len]; @@ -115,20 +158,31 @@ decode_callback(bson_decoder_t decoder, void *private, bson_node_t node) warnx("FAIL: decoder: string1 not 0-terminated"); return 1; } - if (strcmp(sbuf, test_string)) { - warnx("FAIL: decoder: string1 value '%s', expected '%s'", sbuf, test_string); + if (strcmp(sbuf, sample_string)) { + warnx("FAIL: decoder: string1 value '%s', expected '%s'", sbuf, sample_string); return 1; } + warnx("PASS: decoder: string1"); return 1; } if (!strcmp(node->name, "data1")) { - unsigned len = bson_decoder_data_pending(decoder); + if (node->type != BSON_BINDATA) { + warnx("FAIL: decoder: data1 type %d, expected %d", node->type, BSON_BINDATA); + return 1; + } + + len = bson_decoder_data_pending(decoder); - if (len != sizeof(test_data)) { - warnx("FAIL: decoder: data1 length %d, expected %d", len, sizeof(test_data)); + if (len != sizeof(sample_data)) { + warnx("FAIL: decoder: data1 length %d, expected %d", len, sizeof(sample_data)); return 1; } + if (node->subtype != BSON_BIN_BINARY) { + warnx("FAIL: decoder: data1 subtype %d, expected %d", node->subtype, BSON_BIN_BINARY); + return 1; + } + uint8_t dbuf[len]; if (bson_decoder_copy_data(decoder, dbuf)) { @@ -139,18 +193,20 @@ decode_callback(bson_decoder_t decoder, void *private, bson_node_t node) warnx("FAIL: decoder: data1 copy did not exhaust all data"); return 1; } - if (memcmp(test_data, dbuf, len)) { + if (memcmp(sample_data, dbuf, len)) { warnx("FAIL: decoder: data1 compare fail"); return 1; } + warnx("PASS: decoder: data1"); return 1; } - warnx("FAIL: decoder: unexpected node name '%s'", node->name); + if (node->type != BSON_EOO) + warnx("FAIL: decoder: unexpected node name '%s'", node->name); return 1; } -static int +static void decode(bson_decoder_t decoder) { int result; @@ -163,24 +219,26 @@ decode(bson_decoder_t decoder) int test_bson(int argc, char *argv[]) { - bson_encoder_t encoder; - bson_decoder_t decoder; + struct bson_encoder_s encoder; + struct bson_decoder_s decoder; void *buf; - int len, fd; + int len; /* encode data to a memory buffer */ if (bson_encoder_init_buf(&encoder, NULL, 0)) - errx("FAIL: bson_encoder_init_buf"); - encode(encoder); - len = bson_encoder_buf_size(encoder); + errx(1, "FAIL: bson_encoder_init_buf"); + encode(&encoder); + len = bson_encoder_buf_size(&encoder); if (len <= 0) - errx("FAIL: bson_encoder_buf_len"); - buf = bson_encoder_buf_data(encoder); + errx(1, "FAIL: bson_encoder_buf_len"); + buf = bson_encoder_buf_data(&encoder); + if (buf == NULL) + errx(1, "FAIL: bson_encoder_buf_data"); /* now test-decode it */ - if (bson_decoder_init_buf(&decoder, buf, len)) - errx("FAIL: bson_decoder_init_buf"); - decode(decoder); + if (bson_decoder_init_buf(&decoder, buf, len, decode_callback, NULL)) + errx(1, "FAIL: bson_decoder_init_buf"); + decode(&decoder); free(buf); exit(0); diff --git a/apps/systemlib/bson/tinybson.c b/apps/systemlib/bson/tinybson.c index a28217fc4..e1a9324a2 100644 --- a/apps/systemlib/bson/tinybson.c +++ b/apps/systemlib/bson/tinybson.c @@ -50,7 +50,7 @@ # define debug(fmt, args...) do { } while(0) #endif -#define CODER_CHECK(_c) do { if (_c->dead) return -1; } while(0) +#define CODER_CHECK(_c) do { if (_c->dead) { debug("coder dead"); return -1; }} while(0) #define CODER_KILL(_c, _reason) do { debug("killed: %s", _reason); _c->dead = true; return -1; } while(0) static int @@ -58,17 +58,20 @@ read_x(bson_decoder_t decoder, void *p, size_t s) { CODER_CHECK(decoder); - if (decoder->fd > 0) + if (decoder->fd > -1) return (read(decoder->fd, p, s) == (int)s) ? 0 : -1; if (decoder->buf != NULL) { - unsigned newpos = decoder->bufpos + s; - if (newpos <= decoder->bufsize) { - memcpy(p, (decoder->buf + decoder->bufpos), s); - decoder->bufpos = newpos; - return 0; - } + /* staged operations to avoid integer overflow for corrupt data */ + if (s >= decoder->bufsize) + CODER_KILL(decoder, "buffer too small for read"); + if ((decoder->bufsize - s) < decoder->bufpos) + CODER_KILL(decoder, "not enough data for read"); + memcpy(p, (decoder->buf + decoder->bufpos), s); + decoder->bufpos += s; + return 0; } + debug("no source"); return -1; } @@ -84,6 +87,12 @@ read_int32(bson_decoder_t decoder, int32_t *i) return read_x(decoder, i, sizeof(*i)); } +static int +read_int64(bson_decoder_t decoder, int64_t *i) +{ + return read_x(decoder, i, sizeof(*i)); +} + static int read_double(bson_decoder_t decoder, double *d) { @@ -106,7 +115,7 @@ bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder_callback cal /* read and discard document size */ if (read_int32(decoder, &junk)) - CODER_KILL(decoder, "failed reading length"); + CODER_KILL(decoder, "failed discarding length"); /* ready for decoding */ return 0; @@ -117,6 +126,10 @@ bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_ { int32_t len; + /* argument sanity */ + if ((buf == NULL) || (bufsize < 5) || (callback == NULL)) + return -1; + decoder->fd = -1; decoder->buf = (uint8_t *)buf; decoder->dead = false; @@ -142,6 +155,7 @@ int bson_decoder_next(bson_decoder_t decoder) { int8_t tbyte; + int32_t tint; unsigned nlen; CODER_CHECK(decoder); @@ -180,7 +194,9 @@ bson_decoder_next(bson_decoder_t decoder) debug("got type byte 0x%02x", decoder->node.type); /* EOO is special; it has no name/data following */ - if (decoder->node.type != BSON_EOO) { + if (decoder->node.type == BSON_EOO) { + decoder->node.name[0] = '\0'; + } else { /* get the node name */ nlen = 0; @@ -207,8 +223,14 @@ bson_decoder_next(bson_decoder_t decoder) decoder->node.b = (tbyte != 0); break; - case BSON_INT: - if (read_int32(decoder, &decoder->node.i)) + case BSON_INT32: + if (read_int32(decoder, &tint)) + CODER_KILL(decoder, "read error on BSON_INT"); + decoder->node.i = tint; + break; + + case BSON_INT64: + if (read_int64(decoder, &decoder->node.i)) CODER_KILL(decoder, "read error on BSON_INT"); break; @@ -222,7 +244,6 @@ bson_decoder_next(bson_decoder_t decoder) case BSON_STRING: if (read_int32(decoder, &decoder->pending)) CODER_KILL(decoder, "read error on BSON_STRING length"); - break; case BSON_BINDATA: @@ -282,15 +303,18 @@ write_x(bson_encoder_t encoder, const void *p, size_t s) if (!encoder->realloc_ok) CODER_KILL(encoder, "fixed-size buffer overflow"); - int8_t *newbuf = realloc(encoder->buf, encoder->bufsize + BSON_BUF_INCREMENT); + uint8_t *newbuf = realloc(encoder->buf, encoder->bufsize + BSON_BUF_INCREMENT); if (newbuf == NULL) CODER_KILL(encoder, "could not grow buffer"); + encoder->buf = newbuf; encoder->bufsize += BSON_BUF_INCREMENT; + debug("allocated %d bytes", BSON_BUF_INCREMENT); } memcpy(encoder->buf + encoder->bufpos, p, s); encoder->bufpos += s; + debug("appended %d bytes", s); return 0; } @@ -307,6 +331,12 @@ write_int32(bson_encoder_t encoder, int32_t i) return write_x(encoder, &i, sizeof(i)); } +static int +write_int64(bson_encoder_t encoder, int64_t i) +{ + return write_x(encoder, &i, sizeof(i)); +} + static int write_double(bson_encoder_t encoder, double d) { @@ -319,7 +349,7 @@ write_name(bson_encoder_t encoder, const char *name) size_t len = strlen(name); if (len > BSON_MAXNAME) - return -1; + CODER_KILL(encoder, "node name too long"); return write_x(encoder, name, len + 1); } @@ -401,7 +431,7 @@ int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool valu { CODER_CHECK(encoder); - if (write_int8(encoder, BSON_INT) || + if (write_int8(encoder, BSON_BOOL) || write_name(encoder, name) || write_int8(encoder, value ? 1 : 0)) CODER_KILL(encoder, "write error on BSON_BOOL"); @@ -410,13 +440,25 @@ int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool valu } int -bson_encoder_append_int(bson_encoder_t encoder, const char *name, int32_t value) +bson_encoder_append_int(bson_encoder_t encoder, const char *name, int64_t value) { + bool result; + CODER_CHECK(encoder); - if (write_int8(encoder, BSON_INT) || - write_name(encoder, name) || - write_int32(encoder, value)) + /* use the smallest encoding that will hold the value */ + if (value == (int32_t)value) { + debug("encoding %lld as int32", value); + result = write_int8(encoder, BSON_INT32) || + write_name(encoder, name) || + write_int32(encoder, value); + } else { + debug("encoding %lld as int64", value); + result = write_int8(encoder, BSON_INT64) || + write_name(encoder, name) || + write_int64(encoder, value); + } + if (result) CODER_KILL(encoder, "write error on BSON_INT"); return 0; @@ -443,12 +485,12 @@ bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char CODER_CHECK(encoder); - len = strlen(string); + len = strlen(string) + 1; /* include trailing nul */ - if (write_int8(encoder, BSON_DOUBLE) || + if (write_int8(encoder, BSON_STRING) || write_name(encoder, name) || write_int32(encoder, len) || - write_x(encoder, name, len + 1)) + write_x(encoder, string, len)) CODER_KILL(encoder, "write error on BSON_STRING"); return 0; diff --git a/apps/systemlib/bson/tinybson.h b/apps/systemlib/bson/tinybson.h index 833bbf6c4..d820aa7b9 100644 --- a/apps/systemlib/bson/tinybson.h +++ b/apps/systemlib/bson/tinybson.h @@ -59,9 +59,8 @@ typedef enum { BSON_BOOL = 8, BSON_DATE = 9, BSON_NULL = 10, - BSON_INT = 16, - BSON_TIMESTAMP = 17, - BSON_LONG = 18 + BSON_INT32 = 16, + BSON_INT64 = 18 } bson_type_t; typedef enum bson_binary_subtype { @@ -87,7 +86,7 @@ typedef struct bson_node_s { bson_type_t type; bson_binary_subtype_t subtype; union { - int32_t i; + int64_t i; double d; bool b; }; @@ -225,26 +224,48 @@ __EXPORT void *bson_encoder_buf_data(bson_encoder_t encoder); /** * Append a boolean to the encoded stream. + * + * @param encoder Encoder state. + * @param name Node name. + * @param value Value to be encoded. */ __EXPORT int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool value); /** * Append an integer to the encoded stream. + * + * @param encoder Encoder state. + * @param name Node name. + * @param value Value to be encoded. */ -__EXPORT int bson_encoder_append_int(bson_encoder_t encoder, const char *name, int32_t value); +__EXPORT int bson_encoder_append_int(bson_encoder_t encoder, const char *name, int64_t value); /** * Append a double to the encoded stream + * + * @param encoder Encoder state. + * @param name Node name. + * @param value Value to be encoded. */ __EXPORT int bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value); /** * Append a string to the encoded stream. + * + * @param encoder Encoder state. + * @param name Node name. + * @param string Nul-terminated C string. */ __EXPORT int bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char *string); /** * Append a binary blob to the encoded stream. + * + * @param encoder Encoder state. + * @param name Node name. + * @param subtype Binary data subtype. + * @param size Data size. + * @param data Buffer containing data to be encoded. */ __EXPORT int bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype, size_t size, const void *data); diff --git a/apps/systemlib/param/param.c b/apps/systemlib/param/param.c index eeb867f11..44f05047a 100644 --- a/apps/systemlib/param/param.c +++ b/apps/systemlib/param/param.c @@ -452,7 +452,7 @@ param_reset(param_t param) /* if we found one, erase it */ if (s != NULL) { - int pos = utarry_eltidx(param_values, s); + int pos = utarray_eltidx(param_values, s); utarray_erase(param_values, pos, 1); } } @@ -489,7 +489,7 @@ param_export(int fd, bool only_unsaved) param_lock(); - bson_encoder_init(&encoder, fd); + bson_encoder_init_file(&encoder, fd); /* no modified parameters -> we are done */ if (param_values == NULL) { @@ -680,7 +680,7 @@ param_import_internal(int fd, bool mark_saved) int result = -1; struct param_import_state state; - if (bson_decoder_init(&decoder, fd, param_import_callback, &state)) { + if (bson_decoder_init_file(&decoder, fd, param_import_callback, &state)) { debug("decoder init failed"); goto out; } -- cgit v1.2.3 From 7203ba797e40b146e7b85b83a6f691e260245a58 Mon Sep 17 00:00:00 2001 From: px4dev Date: Mon, 29 Oct 2012 18:00:32 -0700 Subject: bson-based boardinfo working --- apps/systemcmds/boardinfo/boardinfo.c | 234 +++++++++++++++++++++++++++++++++- apps/systemlib/bson/tinybson.c | 2 +- 2 files changed, 233 insertions(+), 3 deletions(-) (limited to 'apps/systemlib/bson') diff --git a/apps/systemcmds/boardinfo/boardinfo.c b/apps/systemcmds/boardinfo/boardinfo.c index bce8c27e7..9e6189fec 100644 --- a/apps/systemcmds/boardinfo/boardinfo.c +++ b/apps/systemcmds/boardinfo/boardinfo.c @@ -37,17 +37,246 @@ * autopilot and carrier board information app */ - #include #include #include #include #include -#include "systemlib/systemlib.h" +#include + +#include +#include +#include __EXPORT int boardinfo_main(int argc, char *argv[]); +#if 1 + +struct eeprom_info_s +{ + unsigned bus; + unsigned address; + unsigned page_size; + unsigned page_count; + unsigned page_write_delay; +}; + +/* XXX currently code below only supports 8-bit addressing */ +const struct eeprom_info_s eeprom_info[] = { + {3, 0x57, 8, 16, 3300}, + {0, 0, 0, 0, 0} +}; + +struct board_parameter_s { + const char *name; + bson_type_t type; +}; + +const struct board_parameter_s board_parameters[] = { + {"name", BSON_STRING}, /* ascii board name */ + {"vers", BSON_INT32}, /* board version (major << 8) | minor */ + {"date", BSON_INT32}, /* manufacture date */ + {"build", BSON_INT32} /* build code (fab << 8) | tester */ +}; + +const unsigned num_parameters = sizeof(board_parameters) / sizeof(board_parameters[0]); + +static int +eeprom_write(const struct eeprom_info_s *eeprom, uint8_t *buf, unsigned size) +{ + int result = -1; + + struct i2c_dev_s *dev = up_i2cinitialize(eeprom->bus); + if (dev == NULL) { + warnx("failed to init bus %d for EEPROM", eeprom->bus); + goto out; + } + I2C_SETFREQUENCY(dev, 400000); + + /* loop until all data has been transferred */ + for (unsigned address = 0; address < size; ) { + + uint8_t pagebuf[eeprom->page_size + 1]; + + /* how many bytes available to transfer? */ + unsigned count = size - address; + + /* constrain writes to the page size */ + if (count > eeprom->page_size) + count = eeprom->page_size; + + pagebuf[0] = address & 0xff; + memcpy(pagebuf + 1, buf + address, count); + + struct i2c_msg_s msgv[1] = { + { + .addr = eeprom->address, + .flags = 0, + .buffer = pagebuf, + .length = count + 1 + } + }; + + warnx("write 0x%02x/%u", address, count); + result = I2C_TRANSFER(dev, msgv, 1); + if (result != OK) { + warnx("EEPROM write failed: %d", result); + goto out; + } + usleep(eeprom->page_write_delay); + address += count; + } + +out: + if (dev != NULL) + up_i2cuninitialize(dev); + return result; +} + +static int +eeprom_read(const struct eeprom_info_s *eeprom, uint8_t *buf, unsigned size) +{ + int result = -1; + + struct i2c_dev_s *dev = up_i2cinitialize(eeprom->bus); + if (dev == NULL) { + warnx("failed to init bus %d for EEPROM", eeprom->bus); + goto out; + } + I2C_SETFREQUENCY(dev, 400000); + + /* loop until all data has been transferred */ + for (unsigned address = 0; address < size; ) { + + /* how many bytes available to transfer? */ + unsigned count = size - address; + + /* constrain transfers to the page size (bus anti-hog) */ + if (count > eeprom->page_size) + count = eeprom->page_size; + + uint8_t addr = address; + struct i2c_msg_s msgv[2] = { + { + .addr = eeprom->address, + .flags = 0, + .buffer = &addr, + .length = 1 + }, + { + .addr = eeprom->address, + .flags = I2C_M_READ, + .buffer = buf + address, + .length = count + } + }; + + warnx("read 0x%02x/%u", address, count); + result = I2C_TRANSFER(dev, msgv, 2); + if (result != OK) { + warnx("EEPROM read failed: %d", result); + goto out; + } + address += count; + } + +out: + if (dev != NULL) + up_i2cuninitialize(dev); + return result; +} + +static void +boardinfo_set(const struct eeprom_info_s *eeprom, char *spec) +{ + struct bson_encoder_s encoder; + int result = 1; + char *state, *token; + unsigned i; + + /* create the encoder and make a writable copy of the spec */ + bson_encoder_init_buf(&encoder, NULL, 0); + + for (i = 0, token = strtok_r(spec, ",", &state); + token && (i < num_parameters); + i++, token = strtok_r(NULL, ",", &state)) { + + switch (board_parameters[i].type) { + case BSON_STRING: + result = bson_encoder_append_string(&encoder, board_parameters[i].name, token); + break; + case BSON_INT32: + result = bson_encoder_append_int(&encoder, board_parameters[i].name, strtoul(token, NULL, 0)); + break; + default: + result = 1; + } + if (result) { + warnx("bson append failed for %s<%s>", board_parameters[i].name, token); + goto out; + } + } + bson_encoder_fini(&encoder); + if (i != num_parameters) { + warnx("incorrect parameter list, expected: \",,\""); + result = 1; + goto out; + } + if (bson_encoder_buf_size(&encoder) > (int)(eeprom->page_size * eeprom->page_count)) { + warnx("data too large for EEPROM"); + result = 1; + goto out; + } + if (*(uint32_t *)bson_encoder_buf_data(&encoder) != bson_encoder_buf_size(&encoder)) { + warnx("buffer length mismatch"); + result = 1; + goto out; + } + warnx("writing %p/%u", bson_encoder_buf_data(&encoder), bson_encoder_buf_size(&encoder)); + + result = eeprom_write(eeprom, (uint8_t *)bson_encoder_buf_data(&encoder), bson_encoder_buf_size(&encoder)); + if (result < 0) { + warnc(-result, "error writing EEPROM"); + result = 1; + } else { + result = 0; + } + +out: + free(bson_encoder_buf_data(&encoder)); + + exit(result); +} + +static void +boardinfo_show(const struct eeprom_info_s *eeprom) +{ + uint32_t size = 0xffffffff; + int result; + + result = eeprom_read(eeprom, (uint8_t *)&size, sizeof(size)); + if (result != 0) { + warnx("failed reading ID ROM length"); + } + warnx("data length 0x%08x", size); + + exit(0); +} + +int +boardinfo_main(int argc, char *argv[]) +{ + if (!strcmp(argv[1], "set")) + boardinfo_set(&eeprom_info[0], argv[2]); + + if (!strcmp(argv[1], "show")) + boardinfo_show(&eeprom_info[0]); + + errx(1, "missing/unrecognised command, try one of 'set', 'show', 'test'"); +} + +#else /** * Reads out the board information * @@ -265,3 +494,4 @@ int boardinfo_main(int argc, char *argv[]) } +#endif \ No newline at end of file diff --git a/apps/systemlib/bson/tinybson.c b/apps/systemlib/bson/tinybson.c index e1a9324a2..1b5a1e1ee 100644 --- a/apps/systemlib/bson/tinybson.c +++ b/apps/systemlib/bson/tinybson.c @@ -144,7 +144,7 @@ bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_ /* read and discard document size */ if (read_int32(decoder, &len)) CODER_KILL(decoder, "failed reading length"); - if (len > (int)bufsize) + if ((len > 0) && (len > (int)bufsize)) CODER_KILL(decoder, "document length larger than buffer"); /* ready for decoding */ -- cgit v1.2.3 From 0616d5834039cc08057b862f80f8129a7b4948af Mon Sep 17 00:00:00 2001 From: px4dev Date: Mon, 29 Oct 2012 21:46:56 -0700 Subject: Add 'show' and 'test' verbs to the boardinfo command. Teach rcS how to use the new version. --- ROMFS/scripts/rcS | 4 +- apps/systemcmds/boardinfo/boardinfo.c | 156 +++++++++++++++++++++++++++++++--- apps/systemlib/bson/tinybson.c | 11 ++- apps/systemlib/bson/tinybson.h | 4 +- 4 files changed, 159 insertions(+), 16 deletions(-) (limited to 'apps/systemlib/bson') diff --git a/ROMFS/scripts/rcS b/ROMFS/scripts/rcS index b5fbfe0f5..4152494e0 100755 --- a/ROMFS/scripts/rcS +++ b/ROMFS/scripts/rcS @@ -83,7 +83,7 @@ else # # Are we attached to a PX4IOAR (AR.Drone carrier board)? # - if boardinfo -t 7 + if boardinfo test name PX4IOAR then set BOARD PX4IOAR if [ -f /etc/init.d/rc.PX4IOAR ] @@ -99,7 +99,7 @@ else # # Are we attached to a PX4IO? # - if boardinfo -t 6 + if boardinfo test name PX4IO then set BOARD PX4IO if [ -f /etc/init.d/rc.PX4IO ] diff --git a/apps/systemcmds/boardinfo/boardinfo.c b/apps/systemcmds/boardinfo/boardinfo.c index 9e6189fec..fb9c0b3a4 100644 --- a/apps/systemcmds/boardinfo/boardinfo.c +++ b/apps/systemcmds/boardinfo/boardinfo.c @@ -118,7 +118,6 @@ eeprom_write(const struct eeprom_info_s *eeprom, uint8_t *buf, unsigned size) } }; - warnx("write 0x%02x/%u", address, count); result = I2C_TRANSFER(dev, msgv, 1); if (result != OK) { warnx("EEPROM write failed: %d", result); @@ -172,7 +171,6 @@ eeprom_read(const struct eeprom_info_s *eeprom, uint8_t *buf, unsigned size) } }; - warnx("read 0x%02x/%u", address, count); result = I2C_TRANSFER(dev, msgv, 2); if (result != OK) { warnx("EEPROM read failed: %d", result); @@ -187,6 +185,41 @@ out: return result; } +static void * +idrom_read(const struct eeprom_info_s *eeprom) +{ + uint32_t size = 0xffffffff; + int result; + void *buf = NULL; + + result = eeprom_read(eeprom, (uint8_t *)&size, sizeof(size)); + if (result != 0) { + warnx("failed reading ID ROM length"); + goto fail; + } + if (size > (eeprom->page_size * eeprom->page_count)) { + warnx("ID ROM not programmed"); + goto fail; + } + + buf = malloc(size); + if (buf == NULL) { + warnx("could not allocate %d bytes for ID ROM", size); + goto fail; + } + result = eeprom_read(eeprom, buf, size); + if (result != 0) { + warnx("failed reading ID ROM"); + goto fail; + } + return buf; + +fail: + if (buf != NULL) + free(buf); + return NULL; +} + static void boardinfo_set(const struct eeprom_info_s *eeprom, char *spec) { @@ -228,7 +261,7 @@ boardinfo_set(const struct eeprom_info_s *eeprom, char *spec) result = 1; goto out; } - if (*(uint32_t *)bson_encoder_buf_data(&encoder) != bson_encoder_buf_size(&encoder)) { + if ((int)*(uint32_t *)bson_encoder_buf_data(&encoder) != bson_encoder_buf_size(&encoder)) { warnx("buffer length mismatch"); result = 1; goto out; @@ -249,21 +282,121 @@ out: exit(result); } +static int +boardinfo_print(bson_decoder_t decoder, void *private, bson_node_t node) +{ + switch (node->type) { + case BSON_INT32: + printf("%s: %d / 0x%08x\n", node->name, (int)node->i, (unsigned)node->i); + break; + case BSON_STRING: { + char buf[bson_decoder_data_pending(decoder)]; + bson_decoder_copy_data(decoder, buf); + printf("%s: %s\n", node->name, buf); + break; + } + case BSON_EOO: + break; + default: + warnx("unexpected node type %d", node->type); + break; + } + return 1; +} + static void boardinfo_show(const struct eeprom_info_s *eeprom) { - uint32_t size = 0xffffffff; - int result; + struct bson_decoder_s decoder; + void *buf; - result = eeprom_read(eeprom, (uint8_t *)&size, sizeof(size)); - if (result != 0) { - warnx("failed reading ID ROM length"); - } - warnx("data length 0x%08x", size); + buf = idrom_read(eeprom); + if (buf == NULL) + errx(1, "ID ROM read failed"); + if (bson_decoder_init_buf(&decoder, buf, 0, boardinfo_print, NULL) == 0) { + while (bson_decoder_next(&decoder) > 0) + ; + } else { + warnx("failed to init decoder"); + } + free(buf); exit(0); } +struct { + const char *property; + const char *value; +} test_args; + +static int +boardinfo_test_callback(bson_decoder_t decoder, void *private, bson_node_t node) +{ + /* reject nodes with non-matching names */ + if (strcmp(node->name, test_args.property)) + return 1; + + /* compare node values to check for a match */ + switch (node->type) { + case BSON_STRING: { + char buf[bson_decoder_data_pending(decoder)]; + bson_decoder_copy_data(decoder, buf); + + /* check for a match */ + if (!strcmp(test_args.value, buf)) { + return 2; + } + break; + } + + case BSON_INT32: { + int32_t val = strtol(test_args.value, NULL, 0); + + /* check for a match */ + if (node->i == val) { + return 2; + } + break; + } + + default: + break; + } + + return 1; +} + +static void +boardinfo_test(const struct eeprom_info_s *eeprom, const char *property, const char *value) +{ + struct bson_decoder_s decoder; + void *buf; + int result = -1; + + if ((property == NULL) || (strlen(property) == 0) || + (value == NULL) || (strlen(value) == 0)) + errx(1, "missing property name or value"); + + test_args.property = property; + test_args.value = value; + + buf = idrom_read(eeprom); + if (buf == NULL) + errx(1, "ID ROM read failed"); + + if (bson_decoder_init_buf(&decoder, buf, 0, boardinfo_test_callback, NULL) == 0) { + do { + result = bson_decoder_next(&decoder); + } while (result == 1); + } else { + warnx("failed to init decoder"); + } + free(buf); + + /* if we matched, we exit with zero success */ + exit((result == 2) ? 0 : 1); +} + int boardinfo_main(int argc, char *argv[]) { @@ -273,6 +406,9 @@ boardinfo_main(int argc, char *argv[]) if (!strcmp(argv[1], "show")) boardinfo_show(&eeprom_info[0]); + if (!strcmp(argv[1], "test")) + boardinfo_test(&eeprom_info[0], argv[2], argv[3]); + errx(1, "missing/unrecognised command, try one of 'set', 'show', 'test'"); } diff --git a/apps/systemlib/bson/tinybson.c b/apps/systemlib/bson/tinybson.c index 1b5a1e1ee..321466f87 100644 --- a/apps/systemlib/bson/tinybson.c +++ b/apps/systemlib/bson/tinybson.c @@ -127,13 +127,18 @@ bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_ int32_t len; /* argument sanity */ - if ((buf == NULL) || (bufsize < 5) || (callback == NULL)) + if ((buf == NULL) || (callback == NULL)) return -1; decoder->fd = -1; decoder->buf = (uint8_t *)buf; decoder->dead = false; - decoder->bufsize = bufsize; + if (bufsize == 0) { + decoder->bufsize = *(uint32_t *)buf; + debug("auto-detected %u byte object", decoder->bufsize); + } else { + decoder->bufsize = bufsize; + } decoder->bufpos = 0; decoder->callback = callback; decoder->private = private; @@ -144,7 +149,7 @@ bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_ /* read and discard document size */ if (read_int32(decoder, &len)) CODER_KILL(decoder, "failed reading length"); - if ((len > 0) && (len > (int)bufsize)) + if ((len > 0) && (len > (int)decoder->bufsize)) CODER_KILL(decoder, "document length larger than buffer"); /* ready for decoding */ diff --git a/apps/systemlib/bson/tinybson.h b/apps/systemlib/bson/tinybson.h index d820aa7b9..666f8191a 100644 --- a/apps/systemlib/bson/tinybson.h +++ b/apps/systemlib/bson/tinybson.h @@ -134,7 +134,9 @@ __EXPORT int bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder * * @param decoder Decoder state structure to be initialised. * @param buf Buffer to read from. - * @param bufsize Size of the buffer (BSON object may be smaller). + * @param bufsize Size of the buffer (BSON object may be smaller). May be + * passed as zero if the buffer size should be extracted from the + * BSON header only. * @param callback Callback to be invoked by bson_decoder_next * @param private Callback private data, stored in node. * @return Zero on success. -- cgit v1.2.3