PX4 Firmware
PX4 Autopilot Software http://px4.io
tinybson.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (C) 2012 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file tinybson.c
36  *
37  * A simple subset SAX-style BSON parser and generator.
38  */
39 
40 #include <px4_platform_common/posix.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <systemlib/err.h>
45 
46 #include "tinybson.h"
47 
48 #if 0
49 # define debug(fmt, args...) do { PX4_INFO("BSON: " fmt, ##args); } while(0)
50 #else
51 # define debug(fmt, args...) do { } while(0)
52 #endif
53 
54 #define CODER_CHECK(_c) do { if (_c->dead) { debug("coder dead"); return -1; }} while(0)
55 #define CODER_KILL(_c, _reason) do { debug("killed: %s", _reason); _c->dead = true; return -1; } while(0)
56 
57 #define BSON_READ read
58 #define BSON_WRITE write
59 #define BSON_FSYNC fsync
60 
61 static int
62 read_x(bson_decoder_t decoder, void *p, size_t s)
63 {
64  CODER_CHECK(decoder);
65 
66  if (decoder->fd > -1) {
67  return (BSON_READ(decoder->fd, p, s) == s) ? 0 : -1;
68  }
69 
70  if (decoder->buf != nullptr) {
71  /* staged operations to avoid integer overflow for corrupt data */
72  if (s >= decoder->bufsize) {
73  CODER_KILL(decoder, "buffer too small for read");
74  }
75 
76  if ((decoder->bufsize - s) < decoder->bufpos) {
77  CODER_KILL(decoder, "not enough data for read");
78  }
79 
80  memcpy(p, (decoder->buf + decoder->bufpos), s);
81  decoder->bufpos += s;
82  return 0;
83  }
84 
85  debug("no source");
86  return -1;
87 }
88 
89 static int
90 read_int8(bson_decoder_t decoder, int8_t *b)
91 {
92  return read_x(decoder, b, sizeof(*b));
93 }
94 
95 static int
96 read_int32(bson_decoder_t decoder, int32_t *i)
97 {
98  return read_x(decoder, i, sizeof(*i));
99 }
100 
101 static int
102 read_int64(bson_decoder_t decoder, int64_t *i)
103 {
104  return read_x(decoder, i, sizeof(*i));
105 }
106 
107 static int
108 read_double(bson_decoder_t decoder, double *d)
109 {
110  return read_x(decoder, d, sizeof(*d));
111 }
112 
113 int
115 {
116  int32_t junk;
117 
118  decoder->fd = fd;
119  decoder->buf = nullptr;
120  decoder->dead = false;
121  decoder->callback = callback;
122  decoder->priv = priv;
123  decoder->nesting = 1;
124  decoder->pending = 0;
125  decoder->node.type = BSON_UNDEFINED;
126 
127  /* read and discard document size */
128  if (read_int32(decoder, &junk)) {
129  CODER_KILL(decoder, "failed discarding length");
130  }
131 
132  /* ready for decoding */
133  return 0;
134 }
135 
136 int
137 bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_decoder_callback callback,
138  void *priv)
139 {
140  int32_t len;
141 
142  /* argument sanity */
143  if ((buf == nullptr) || (callback == nullptr)) {
144  return -1;
145  }
146 
147  decoder->fd = -1;
148  decoder->buf = (uint8_t *)buf;
149  decoder->dead = false;
150 
151  if (bufsize == 0) {
152  decoder->bufsize = *(uint32_t *)buf;
153  debug("auto-detected %u byte object", decoder->bufsize);
154 
155  } else {
156  decoder->bufsize = bufsize;
157  }
158 
159  decoder->bufpos = 0;
160  decoder->callback = callback;
161  decoder->priv = priv;
162  decoder->nesting = 1;
163  decoder->pending = 0;
164  decoder->node.type = BSON_UNDEFINED;
165 
166  /* read and discard document size */
167  if (read_int32(decoder, &len)) {
168  CODER_KILL(decoder, "failed reading length");
169  }
170 
171  if ((len > 0) && (len > (int)decoder->bufsize)) {
172  CODER_KILL(decoder, "document length larger than buffer");
173  }
174 
175  /* ready for decoding */
176  return 0;
177 }
178 
179 int
181 {
182  int8_t tbyte;
183  int32_t tint;
184  unsigned nlen;
185 
186  CODER_CHECK(decoder);
187 
188  /* if the previous node was EOO, pop a nesting level */
189  if (decoder->node.type == BSON_EOO) {
190  if (decoder->nesting > 0) {
191  decoder->nesting--;
192  }
193 
194  /* if the nesting level is now zero, the top-level document is done */
195  if (decoder->nesting == 0) {
196  /* like kill but not an error */
197  debug("nesting is zero, document is done");
198  decoder->fd = -1;
199 
200  /* return end-of-file to the caller */
201  return 0;
202  }
203  }
204 
205  /* if there are unread bytes pending in the stream, discard them */
206  while (decoder->pending > 0) {
207  if (read_int8(decoder, &tbyte)) {
208  CODER_KILL(decoder, "read error discarding pending bytes");
209  }
210 
211  decoder->pending--;
212  }
213 
214  /* get the type byte */
215  if (read_int8(decoder, &tbyte)) {
216  CODER_KILL(decoder, "read error on type byte");
217  }
218 
219  decoder->node.type = (bson_type_t)tbyte;
220  decoder->pending = 0;
221 
222  debug("got type byte 0x%02x", decoder->node.type);
223 
224  /* EOO is special; it has no name/data following */
225  if (decoder->node.type == BSON_EOO) {
226  decoder->node.name[0] = '\0';
227 
228  } else {
229 
230  /* get the node name */
231  nlen = 0;
232 
233  for (;;) {
234  if (nlen >= BSON_MAXNAME) {
235  CODER_KILL(decoder, "node name overflow");
236  }
237 
238  if (read_int8(decoder, (int8_t *)&decoder->node.name[nlen])) {
239  CODER_KILL(decoder, "read error on node name");
240  }
241 
242  if (decoder->node.name[nlen] == '\0') {
243  break;
244  }
245 
246  nlen++;
247  }
248 
249  debug("got name '%s'", decoder->node.name);
250 
251  switch (decoder->node.type) {
252  case BSON_BOOL:
253  if (read_int8(decoder, &tbyte)) {
254  CODER_KILL(decoder, "read error on BSON_BOOL");
255  }
256 
257  decoder->node.b = (tbyte != 0);
258  break;
259 
260  case BSON_INT32:
261  if (read_int32(decoder, &tint)) {
262  CODER_KILL(decoder, "read error on BSON_INT");
263  }
264 
265  decoder->node.i = tint;
266  break;
267 
268  case BSON_INT64:
269  if (read_int64(decoder, &decoder->node.i)) {
270  CODER_KILL(decoder, "read error on BSON_INT");
271  }
272 
273  break;
274 
275  case BSON_DOUBLE:
276  if (read_double(decoder, &decoder->node.d)) {
277  CODER_KILL(decoder, "read error on BSON_DOUBLE");
278  }
279 
280  break;
281 
282  case BSON_STRING:
283  if (read_int32(decoder, &decoder->pending)) {
284  CODER_KILL(decoder, "read error on BSON_STRING length");
285  }
286 
287  break;
288 
289  case BSON_BINDATA:
290  if (read_int32(decoder, &decoder->pending)) {
291  CODER_KILL(decoder, "read error on BSON_BINDATA size");
292  }
293 
294  if (read_int8(decoder, &tbyte)) {
295  CODER_KILL(decoder, "read error on BSON_BINDATA subtype");
296  }
297 
298  decoder->node.subtype = (bson_binary_subtype_t)tbyte;
299  break;
300 
301  /* XXX currently not supporting other types */
302  default:
303  CODER_KILL(decoder, "unsupported node type");
304  }
305  }
306 
307  /* call the callback and pass its results back */
308  return decoder->callback(decoder, decoder->priv, &decoder->node);
309 }
310 
311 int
313 {
314  int result;
315 
316  CODER_CHECK(decoder);
317 
318  /* copy data */
319  result = read_x(decoder, buf, decoder->pending);
320 
321  if (result != 0) {
322  CODER_KILL(decoder, "read error on copy_data");
323  }
324 
325  /* pending count is discharged */
326  decoder->pending = 0;
327  return 0;
328 }
329 
330 size_t
332 {
333  return decoder->pending;
334 }
335 
336 static int
337 write_x(bson_encoder_t encoder, const void *p, size_t s)
338 {
339  CODER_CHECK(encoder);
340 
341  /* bson file encoder (non-buffered) */
342  if (encoder->fd > -1 && encoder->buf == nullptr) {
343  return (BSON_WRITE(encoder->fd, p, s) == (int)s) ? 0 : -1;
344  }
345 
346  /* do we need to extend the buffer? */
347  while ((encoder->bufpos + s) > encoder->bufsize) {
348 
349  /* bson buffered file encoder */
350  if (encoder->fd > -1) {
351  // write to disk
352  debug("writing buffer (%d) to disk", encoder->bufpos);
353  int ret = BSON_WRITE(encoder->fd, encoder->buf, encoder->bufpos);
354 
355  if (ret == (int)encoder->bufpos) {
356  // reset buffer to beginning and continue
357  encoder->bufpos = 0;
358 
359  if ((encoder->bufpos + s) > encoder->bufsize) {
360  CODER_KILL(encoder, "fixed-size buffer overflow");
361  }
362 
363  break;
364 
365  } else {
366  CODER_KILL(encoder, "file write error");
367  }
368  }
369 
370  if (!encoder->realloc_ok) {
371  CODER_KILL(encoder, "fixed-size buffer overflow");
372  }
373 
374  uint8_t *newbuf = (uint8_t *)realloc(encoder->buf, encoder->bufsize + BSON_BUF_INCREMENT);
375 
376  if (newbuf == nullptr) {
377  CODER_KILL(encoder, "could not grow buffer");
378  }
379 
380  encoder->buf = newbuf;
381  encoder->bufsize += BSON_BUF_INCREMENT;
382  debug("allocated %d bytes", BSON_BUF_INCREMENT);
383  }
384 
385  memcpy(encoder->buf + encoder->bufpos, p, s);
386  encoder->bufpos += s;
387  debug("appended %d bytes", s);
388 
389  return 0;
390 }
391 
392 static int
393 write_int8(bson_encoder_t encoder, int8_t b)
394 {
395  return write_x(encoder, &b, sizeof(b));
396 }
397 
398 static int
399 write_int32(bson_encoder_t encoder, int32_t i)
400 {
401  return write_x(encoder, &i, sizeof(i));
402 }
403 
404 static int
405 write_int64(bson_encoder_t encoder, int64_t i)
406 {
407  return write_x(encoder, &i, sizeof(i));
408 }
409 
410 static int
411 write_double(bson_encoder_t encoder, double d)
412 {
413  return write_x(encoder, &d, sizeof(d));
414 }
415 
416 static int
417 write_name(bson_encoder_t encoder, const char *name)
418 {
419  size_t len = strlen(name);
420 
421  if (len > BSON_MAXNAME) {
422  CODER_KILL(encoder, "node name too long");
423  }
424 
425  return write_x(encoder, name, len + 1);
426 }
427 
428 int
430 {
431  encoder->fd = fd;
432  encoder->buf = nullptr;
433  encoder->dead = false;
434 
435  if (write_int32(encoder, 0)) {
436  CODER_KILL(encoder, "write error on document length");
437  }
438 
439  return 0;
440 }
441 
442 int
443 bson_encoder_init_buf_file(bson_encoder_t encoder, int fd, void *buf, unsigned bufsize)
444 {
445  encoder->fd = fd;
446  encoder->buf = (uint8_t *)buf;
447  encoder->bufpos = 0;
448  encoder->bufsize = bufsize;
449  encoder->dead = false;
450  encoder->realloc_ok = false;
451 
452  if (write_int32(encoder, 0)) {
453  CODER_KILL(encoder, "write error on document length");
454  }
455 
456  return 0;
457 }
458 
459 int
460 bson_encoder_init_buf(bson_encoder_t encoder, void *buf, unsigned bufsize)
461 {
462  encoder->fd = -1;
463  encoder->buf = (uint8_t *)buf;
464  encoder->bufpos = 0;
465  encoder->dead = false;
466 
467  if (encoder->buf == nullptr) {
468  encoder->bufsize = 0;
469  encoder->realloc_ok = true;
470 
471  } else {
472  encoder->bufsize = bufsize;
473  encoder->realloc_ok = false;
474  }
475 
476  if (write_int32(encoder, 0)) {
477  CODER_KILL(encoder, "write error on document length");
478  }
479 
480  return 0;
481 }
482 
483 int
485 {
486  CODER_CHECK(encoder);
487 
488  if (write_int8(encoder, BSON_EOO)) {
489  CODER_KILL(encoder, "write error on document terminator");
490  }
491 
492  if (encoder->fd > -1 && encoder->buf != nullptr) {
493  /* write final buffer to disk */
494  int ret = BSON_WRITE(encoder->fd, encoder->buf, encoder->bufpos);
495 
496  if (ret != (int)encoder->bufpos) {
497  CODER_KILL(encoder, "write error");
498  }
499 
500  } else if (encoder->buf != nullptr) {
501  /* update buffer length */
502  int32_t len = bson_encoder_buf_size(encoder);
503  memcpy(encoder->buf, &len, sizeof(len));
504  }
505 
506  /* sync file */
507  if (encoder->fd > -1) {
508  BSON_FSYNC(encoder->fd);
509  }
510 
511  return 0;
512 }
513 
514 int
516 {
517  CODER_CHECK(encoder);
518 
519  if (encoder->fd > -1) {
520  return -1;
521  }
522 
523  return encoder->bufpos;
524 }
525 
526 void *
528 {
529  /* note, no CODER_CHECK here as the caller has to clean up dead buffers */
530 
531  if (encoder->fd > -1) {
532  return nullptr;
533  }
534 
535  return encoder->buf;
536 }
537 
538 int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool value)
539 {
540  CODER_CHECK(encoder);
541 
542  if (write_int8(encoder, BSON_BOOL) ||
543  write_name(encoder, name) ||
544  write_int8(encoder, value ? 1 : 0)) {
545  CODER_KILL(encoder, "write error on BSON_BOOL");
546  }
547 
548  return 0;
549 }
550 
551 int
552 bson_encoder_append_int(bson_encoder_t encoder, const char *name, int64_t value)
553 {
554  bool result;
555 
556  CODER_CHECK(encoder);
557 
558  /* use the smallest encoding that will hold the value */
559  if (value == (int32_t)value) {
560  debug("encoding %lld as int32", value);
561  result = write_int8(encoder, BSON_INT32) ||
562  write_name(encoder, name) ||
563  write_int32(encoder, value);
564 
565  } else {
566  debug("encoding %lld as int64", value);
567  result = write_int8(encoder, BSON_INT64) ||
568  write_name(encoder, name) ||
569  write_int64(encoder, value);
570  }
571 
572  if (result) {
573  CODER_KILL(encoder, "write error on BSON_INT");
574  }
575 
576  return 0;
577 }
578 
579 int
580 bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value)
581 {
582  CODER_CHECK(encoder);
583 
584  if (write_int8(encoder, BSON_DOUBLE) ||
585  write_name(encoder, name) ||
586  write_double(encoder, value)) {
587  CODER_KILL(encoder, "write error on BSON_DOUBLE");
588  }
589 
590 
591  return 0;
592 }
593 
594 int
595 bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char *string)
596 {
597  size_t len;
598 
599  CODER_CHECK(encoder);
600 
601  len = strlen(string) + 1; /* include trailing nul */
602 
603  if (write_int8(encoder, BSON_STRING) ||
604  write_name(encoder, name) ||
605  write_int32(encoder, len) ||
606  write_x(encoder, string, len)) {
607  CODER_KILL(encoder, "write error on BSON_STRING");
608  }
609 
610  return 0;
611 }
612 
613 int
614 bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype, size_t size,
615  const void *data)
616 {
617  CODER_CHECK(encoder);
618 
619  if (write_int8(encoder, BSON_BINDATA) ||
620  write_name(encoder, name) ||
621  write_int32(encoder, size) ||
622  write_int8(encoder, subtype) ||
623  write_x(encoder, data, size)) {
624  CODER_KILL(encoder, "write error on BSON_BINDATA");
625  }
626 
627  return 0;
628 }
int bson_encoder_init_buf_file(bson_encoder_t encoder, int fd, void *buf, unsigned bufsize)
Initialze the encoder for writing to a file.
Definition: tinybson.cpp:443
char name[BSON_MAXNAME]
Definition: tinybson.h:85
static int write_int64(bson_encoder_t encoder, int64_t i)
Definition: tinybson.cpp:405
unsigned bufsize
Definition: tinybson.h:179
unsigned bufpos
Definition: tinybson.h:180
void * bson_encoder_buf_data(bson_encoder_t encoder)
Get a pointer to the encoded object buffer.
Definition: tinybson.cpp:527
static int write_x(bson_encoder_t encoder, const void *p, size_t s)
Definition: tinybson.cpp:337
int bson_decoder_next(bson_decoder_t decoder)
Process the next node from the stream and invoke the callback.
Definition: tinybson.cpp:180
int bson_encoder_append_binary(bson_encoder_t encoder, const char *name, bson_binary_subtype_t subtype, size_t size, const void *data)
Append a binary blob to the encoded stream.
Definition: tinybson.cpp:614
int bson_decoder_init_file(bson_decoder_t decoder, int fd, bson_decoder_callback callback, void *priv)
Initialise the decoder to read from a file.
Definition: tinybson.cpp:114
#define debug(fmt, args...)
Definition: tinybson.cpp:51
static int read_double(bson_decoder_t decoder, double *d)
Definition: tinybson.cpp:108
uint8_t * buf
Definition: tinybson.h:109
size_t bufsize
Definition: tinybson.h:110
bson_binary_subtype_t subtype
Definition: tinybson.h:87
unsigned nesting
Definition: tinybson.h:116
static int write_int32(bson_encoder_t encoder, int32_t i)
Definition: tinybson.cpp:399
Encoder state structure.
Definition: tinybson.h:173
bool realloc_ok
Definition: tinybson.h:182
#define BSON_MAXNAME
Maximum node name length.
Definition: tinybson.h:74
void * priv
Definition: tinybson.h:115
struct bson_node_s node
Definition: tinybson.h:117
int bson_decoder_copy_data(bson_decoder_t decoder, void *buf)
Copy node data.
Definition: tinybson.cpp:312
static int write_double(bson_encoder_t encoder, double d)
Definition: tinybson.cpp:411
#define BSON_FSYNC
Definition: tinybson.cpp:59
int bson_encoder_append_string(bson_encoder_t encoder, const char *name, const char *string)
Append a string to the encoded stream.
Definition: tinybson.cpp:595
A simple subset SAX-style BSON parser and generator.
#define CODER_CHECK(_c)
Definition: tinybson.cpp:54
int bson_encoder_append_double(bson_encoder_t encoder, const char *name, double value)
Append a double to the encoded stream.
Definition: tinybson.cpp:580
int(* bson_decoder_callback)(bson_decoder_t decoder, void *priv, bson_node_t node)
Node callback.
Definition: tinybson.h:102
static int read_int64(bson_decoder_t decoder, int64_t *i)
Definition: tinybson.cpp:102
#define BSON_BUF_INCREMENT
Buffer growth increment when writing to a buffer.
Definition: tinybson.h:79
static int read_int32(bson_decoder_t decoder, int32_t *i)
Definition: tinybson.cpp:96
int bson_decoder_init_buf(bson_decoder_t decoder, void *buf, unsigned bufsize, bson_decoder_callback callback, void *priv)
Initialise the decoder to read from a buffer in memory.
Definition: tinybson.cpp:137
static int write_name(bson_encoder_t encoder, const char *name)
Definition: tinybson.cpp:417
uint8_t * data
Definition: dataman.cpp:149
int bson_encoder_append_bool(bson_encoder_t encoder, const char *name, bool value)
Append a boolean to the encoded stream.
Definition: tinybson.cpp:538
size_t bson_decoder_data_pending(bson_decoder_t decoder)
Report copyable data size.
Definition: tinybson.cpp:331
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
unsigned bufpos
Definition: tinybson.h:111
#define BSON_WRITE
Definition: tinybson.cpp:58
int fd
Definition: dataman.cpp:146
int bson_encoder_fini(bson_encoder_t encoder)
Finalise the encoded stream.
Definition: tinybson.cpp:484
bson_type_t type
Definition: tinybson.h:86
const char * name
Definition: tests_main.c:58
#define CODER_KILL(_c, _reason)
Definition: tinybson.cpp:55
int bson_encoder_buf_size(bson_encoder_t encoder)
Fetch the size of the encoded object; only valid for buffer operations.
Definition: tinybson.cpp:515
bson_type_t
subset of the BSON node types we might care about
Definition: tinybson.h:51
int bson_encoder_init_buf(bson_encoder_t encoder, void *buf, unsigned bufsize)
Initialze the encoder for writing to a buffer.
Definition: tinybson.cpp:460
int bson_encoder_init_file(bson_encoder_t encoder, int fd)
Initialze the encoder for writing to a file.
Definition: tinybson.cpp:429
int32_t pending
Definition: tinybson.h:118
bool b
Definition: tinybson.h:91
int64_t i
Definition: tinybson.h:89
bson_decoder_callback callback
Definition: tinybson.h:114
static int write_int8(bson_encoder_t encoder, int8_t b)
Definition: tinybson.cpp:393
#define BSON_READ
Definition: tinybson.cpp:57
uint8_t * buf
Definition: tinybson.h:178
double d
Definition: tinybson.h:90
int bson_encoder_append_int(bson_encoder_t encoder, const char *name, int64_t value)
Append an integer to the encoded stream.
Definition: tinybson.cpp:552
enum bson_binary_subtype bson_binary_subtype_t
static int read_x(bson_decoder_t decoder, void *p, size_t s)
Definition: tinybson.cpp:62
static int read_int8(bson_decoder_t decoder, int8_t *b)
Definition: tinybson.cpp:90