9 #if SATCAT5_CBOR_ENABLE
20 Writeable* dst, QCBOREncodeContext* encode,
21 u8* buff,
unsigned size,
bool automap)
26 , m_auto_close(automap ? QCBOR_TYPE_MAP : QCBOR_TYPE_NONE)
30 QCBOREncode_Init(
cbor, {buff, size});
31 if (automap) { QCBOREncode_OpenMap(
cbor); }
38 case QCBOR_TYPE_MAP: QCBOREncode_CloseMap(
cbor);
break;
39 case QCBOR_TYPE_ARRAY: QCBOREncode_CloseArray(
cbor);
break;
42 QCBORError error = QCBOREncode_Finish(
cbor, &encoded);
43 if (error != QCBOR_SUCCESS) {
return false; }
64 QCBOREncode_AddInt64(cbor, key);
70 QCBOREncode_AddSZString(cbor, key);
74 void ListWriter::add_array(u32 len,
const bool* value)
const {
75 QCBOREncode_OpenArray(cbor);
76 for (
unsigned a = 0; a < len; ++a)
77 { QCBOREncode_AddBool(cbor, value[a]); }
78 QCBOREncode_CloseArray(cbor);
81 template <
typename KEYTYPE>
84 QCBOREncode_OpenArray(cbor);
85 for (
unsigned a = 0; a < len; ++a)
86 { QCBOREncode_AddBool(cbor, value[a]); }
87 QCBOREncode_CloseArray(cbor);
92 void CborWriter::add_unsigned_array(
unsigned len,
const T* value)
const {
93 QCBOREncode_OpenArray(cbor);
94 for (
unsigned a = 0; a < len; ++a)
95 { QCBOREncode_AddUInt64(cbor, value[a]); }
96 QCBOREncode_CloseArray(cbor);
100 template <
typename T>
101 void CborWriter::add_signed_array(
unsigned len,
const T* value)
const {
102 QCBOREncode_OpenArray(cbor);
103 for (
unsigned a = 0; a < len; ++a)
104 { QCBOREncode_AddInt64(cbor, value[a]); }
105 QCBOREncode_CloseArray(cbor);
109 void ListWriter::add_array(u32 len,
const float* value)
const {
110 QCBOREncode_OpenArray(cbor);
111 for (
unsigned a = 0; a < len; ++a)
112 { QCBOREncode_AddFloat(cbor, value[a]); }
113 QCBOREncode_CloseArray(cbor);
116 template <
typename KEYTYPE>
119 QCBOREncode_OpenArray(cbor);
120 for (
unsigned a = 0; a < len; ++a)
121 { QCBOREncode_AddFloat(cbor, value[a]); }
122 QCBOREncode_CloseArray(cbor);
126 void ListWriter::add_array(u32 len,
const double* value)
const {
127 QCBOREncode_OpenArray(cbor);
128 for (
unsigned a = 0; a < len; ++a)
129 { QCBOREncode_AddFloat(cbor, value[a]); }
130 QCBOREncode_CloseArray(cbor);
133 template <
typename KEYTYPE>
136 QCBOREncode_OpenArray(cbor);
137 for (
unsigned a = 0; a < len; ++a)
138 { QCBOREncode_AddDouble(cbor, value[a]); }
139 QCBOREncode_CloseArray(cbor);
143 QCBOREncodeContext* ListWriter::open_list() {
144 QCBOREncode_OpenArray(cbor);
150 QCBOREncode_OpenArrayInMapN(cbor, key);
156 QCBOREncode_OpenArrayInMap(cbor, key);
161 QCBOREncodeContext* ListWriter::open_map() {
162 QCBOREncode_OpenMap(cbor);
168 QCBOREncode_OpenMapInMapN(cbor, key);
174 QCBOREncode_OpenMapInMap(cbor, key);
179 CborReader::CborReader(
180 Readable* src, QCBORDecodeContext* decode,
181 u8* buff,
unsigned size)
184 unsigned src_len = size;
187 if (src_len > size || !src->
read_bytes(src_len, buff))
188 {
cbor->uLastError = QCBOR_ERR_BUFFER_TOO_SMALL;
return; }
191 QCBORDecode_Init(
cbor, {buff, src_len}, QCBOR_DECODE_MODE_NORMAL);
198 size_t idx_dat = UsefulInputBuf_Tell(&
cbor->InBuf);
199 QCBORDecode_VGetNextConsume(
cbor, &item);
200 QCBORError err = QCBORDecode_GetError(
cbor);
201 if (err != QCBOR_SUCCESS) {
202 if (err == QCBOR_ERR_NO_MORE_ITEMS)
203 { QCBORDecode_GetAndResetError(
cbor); }
206 size_t idx_end = UsefulInputBuf_Tell(&
cbor->InBuf);
208 const u8* ptr_dat = (
const u8*)
cbor->InBuf.UB.ptr + idx_dat;
209 const u8* ptr_end = (
const u8*)
cbor->InBuf.UB.ptr + idx_end;
212 if (item.uLabelType == QCBOR_TYPE_INT64 ||
213 item.uLabelType == QCBOR_TYPE_UINT64) {
215 QCBOREncode_AddEncoded(dst, UsefulBufC{ptr_dat, len_key});
217 }
else if (item.uLabelType == QCBOR_TYPE_TEXT_STRING) {
218 const u8* ptr_mid = (
const u8*)item.label.string.ptr + item.label.string.len;
219 QCBOREncode_AddEncoded(dst, UsefulBufC{ptr_dat, size_t(ptr_mid - ptr_dat)});
223 QCBOREncode_AddEncoded(dst, UsefulBufC{ptr_dat, size_t(ptr_end - ptr_dat)});
232 if (QCBORDecode_GetError(
cbor) == QCBOR_ERR_NO_MORE_ITEMS)
233 { QCBORDecode_GetAndResetError(
cbor); }
240 const u8 tmp = (*rdptr) & 0xDF;
241 if (tmp >= 0x1C)
return 0;
242 if (tmp == 0x1B)
return 9;
243 if (tmp == 0x1A)
return 5;
244 if (tmp == 0x19)
return 3;
245 if (tmp == 0x18)
return 2;
254 bool key_found(QCBORDecodeContext* cbor) {
255 switch (QCBORDecode_GetError(cbor)) {
258 case QCBOR_ERR_LABEL_NOT_FOUND:
259 case QCBOR_ERR_UNEXPECTED_TYPE:
260 QCBORDecode_GetAndResetError(cbor);
267 template <
typename T>
268 inline optional<T> val_if_found(QCBORDecodeContext* cbor, T val) {
274 Readable* src, QCBORDecodeContext* decode,
275 u8* buff,
unsigned size)
282 template <
typename KEYTYPE>
284 Readable* src, QCBORDecodeContext* decode,
285 u8* buff,
unsigned size)
294 QCBORDecode_GetNext(
cbor, &item);
295 return val_if_found(
cbor, item);
301 QCBORDecode_GetBool(
cbor, &val);
302 return val_if_found(
cbor, val);
308 QCBORDecode_GetBoolInMapN(cbor, key, &val);
309 return val_if_found(cbor, val);
315 QCBORDecode_GetBoolInMapSZ(cbor, key, &val);
316 return val_if_found(cbor, val);
322 QCBORDecode_GetInt64(cbor, &val);
323 return val_if_found(cbor, val);
329 QCBORDecode_GetInt64InMapN(cbor, key, &val);
330 return val_if_found(cbor, val);
336 QCBORDecode_GetInt64InMapSZ(cbor, key, &val);
337 return val_if_found(cbor, val);
342 QCBORDecode_GetUInt64(cbor, &val);
343 return val_if_found(cbor, val);
349 QCBORDecode_GetUInt64InMapN(cbor, key, &val);
350 return val_if_found(cbor, val);
356 QCBORDecode_GetUInt64InMapSZ(cbor, key, &val);
357 return val_if_found(cbor, val);
363 QCBORDecode_GetDouble(cbor, &val);
364 return val_if_found(cbor, val);
370 QCBORDecode_GetDoubleInMapN(cbor, key, &val);
371 return val_if_found(cbor, val);
377 QCBORDecode_GetDoubleInMapSZ(cbor, key, &val);
378 return val_if_found(cbor, val);
383 bool MapReader<s64>::is_null(s64 key)
const {
384 QCBORDecode_GetNullInMapN(cbor, key);
385 return val_if_found(cbor,
true).has_value();
390 QCBORDecode_GetNullInMapSZ(cbor, key);
391 return val_if_found(cbor,
true).has_value();
397 QCBORDecode_GetTextString(cbor, &buf);
398 return val_if_found(cbor,
ArrayRead(buf.ptr, buf.len));
404 QCBORDecode_GetTextStringInMapN(cbor, key, &buf);
405 return val_if_found(cbor,
ArrayRead(buf.ptr, buf.len));
411 QCBORDecode_GetTextStringInMapSZ(cbor, key, &buf);
412 return val_if_found(cbor,
ArrayRead(buf.ptr, buf.len));
417 QCBORDecode_GetByteString(cbor, &buf);
418 return val_if_found(cbor,
ArrayRead(buf.ptr, buf.len));
424 QCBORDecode_GetByteStringInMapN(cbor, key, &buf);
425 return val_if_found(cbor,
ArrayRead(buf.ptr, buf.len));
431 QCBORDecode_GetByteStringInMapSZ(cbor, key, &buf);
432 return val_if_found(cbor,
ArrayRead(buf.ptr, buf.len));
435 QCBORDecodeContext* ListReader::open_list()
const {
436 QCBORDecode_EnterArray(cbor,
nullptr);
437 return key_found(cbor) ? cbor :
nullptr;
442 QCBORDecode_EnterArrayFromMapN(cbor, key);
443 return key_found(cbor) ? cbor :
nullptr;
448 QCBORDecode_EnterArrayFromMapSZ(cbor, key);
449 return key_found(cbor) ? cbor :
nullptr;
452 QCBORDecodeContext* ListReader::open_map()
const {
453 QCBORDecode_EnterMap(cbor,
nullptr);
454 return key_found(cbor) ? cbor :
nullptr;
459 QCBORDecode_EnterMapFromMapN(cbor, key);
460 return key_found(cbor) ? cbor :
nullptr;
465 QCBORDecode_EnterMapFromMapSZ(cbor, key);
466 return key_found(cbor) ? cbor :
nullptr;
470 QCBORDecode_EnterArray(cbor,
nullptr);
471 return get_array_internal(dst, QCBOR_TYPE_FALSE, 1);
476 QCBORDecode_EnterArrayFromMapN(cbor, key);
477 return get_array_internal(dst, QCBOR_TYPE_FALSE, 1);
482 QCBORDecode_EnterArrayFromMapSZ(cbor, key);
483 return get_array_internal(dst, QCBOR_TYPE_FALSE, 1);
487 QCBORDecode_EnterArray(cbor,
nullptr);
488 return get_array_internal(dst, QCBOR_TYPE_INT64,
sizeof(u64));
493 QCBORDecode_EnterArrayFromMapN(cbor, key);
494 return get_array_internal(dst, QCBOR_TYPE_INT64,
sizeof(u64));
499 QCBORDecode_EnterArrayFromMapSZ(cbor, key);
500 return get_array_internal(dst, QCBOR_TYPE_INT64,
sizeof(u64));
503 int ListReader::get_double_array(
Writeable& dst)
const {
504 QCBORDecode_EnterArray(cbor,
nullptr);
505 return get_array_internal(dst, QCBOR_TYPE_FLOAT,
sizeof(
double));
510 QCBORDecode_EnterArrayFromMapN(cbor, key);
511 return get_array_internal(dst, QCBOR_TYPE_FLOAT,
sizeof(
double));
516 QCBORDecode_EnterArrayFromMapSZ(cbor, key);
517 return get_array_internal(dst, QCBOR_TYPE_FLOAT,
sizeof(
double));
520 int CborReader::get_array_internal(
Writeable& dst, u8 qcbor_type, u8 type_size)
const {
522 QCBORError err = QCBORDecode_GetError(cbor);
523 if (err == QCBOR_ERR_LABEL_NOT_FOUND)
524 { QCBORDecode_GetAndResetError(cbor);
return ERR_NOT_FOUND; }
525 if (err == QCBOR_ERR_UNEXPECTED_TYPE)
526 { QCBORDecode_GetAndResetError(cbor);
return ERR_BAD_TYPE; }
527 if (err != QCBOR_SUCCESS) {
return ERR_QCBOR_INT; }
534 const u8 type_mask = 0xFE;
535 qcbor_type &= type_mask;
539 QCBORDecode_GetNext(cbor, &item);
541 while (QCBORDecode_GetError(cbor) == QCBOR_SUCCESS &&
542 item.uDataType != QCBOR_TYPE_NONE) {
547 QCBORDecode_ExitArray(cbor);
550 if ((item.uDataType & type_mask) != qcbor_type) {
552 QCBORDecode_ExitArray(cbor);
558 if (qcbor_type == QCBOR_TYPE_FALSE) {
559 dst.
write_u8(item.uDataType == QCBOR_TYPE_TRUE ?
true :
false);
566 QCBORDecode_GetNext(cbor, &item);
570 QCBORDecode_ExitArray(cbor);
572 return (QCBORDecode_GetError(cbor) == QCBOR_SUCCESS) ?
573 num_elems : ERR_QCBOR_INT;
577 const int CborReader::ERR_NOT_FOUND = -1;
578 const int CborReader::ERR_OVERFLOW = -2;
579 const int CborReader::ERR_BAD_TYPE = -3;
580 const int CborReader::ERR_QCBOR_INT = -4;
587 template void CborWriter::add_unsigned_array<u8>(
unsigned len,
const u8* value)
const;
588 template void CborWriter::add_unsigned_array<u16>(
unsigned len,
const u16* value)
const;
589 template void CborWriter::add_unsigned_array<u32>(
unsigned len,
const u32* value)
const;
590 template void CborWriter::add_unsigned_array<u64>(
unsigned len,
const u64* value)
const;
591 template void CborWriter::add_signed_array<s8>(
unsigned len,
const s8* value)
const;
592 template void CborWriter::add_signed_array<s16>(
unsigned len,
const s16* value)
const;
593 template void CborWriter::add_signed_array<s32>(
unsigned len,
const s32* value)
const;
594 template void CborWriter::add_signed_array<s64>(
unsigned len,
const s64* value)
const;
601 if (m_item.uLabelType == QCBOR_TYPE_INT64) {
602 wr.
wr_s64(m_item.label.int64);
604 }
else if (m_item.uLabelType == QCBOR_TYPE_BYTE_STRING
605 || m_item.uLabelType == QCBOR_TYPE_TEXT_STRING) {
606 wr.
wr_fix((
const char*)m_item.label.string.ptr, m_item.label.string.len);
611 if (m_item.uDataType == QCBOR_TYPE_INT64) {
612 wr.
wr_s64(m_item.val.int64);
613 }
else if (m_item.uDataType == QCBOR_TYPE_UINT64) {
614 wr.
wr_d64(m_item.val.uint64);
615 }
else if (m_item.uDataType == QCBOR_TYPE_ARRAY) {
617 }
else if (m_item.uDataType == QCBOR_TYPE_MAP) {
619 }
else if (m_item.uDataType == QCBOR_TYPE_BYTE_STRING) {
620 const u8* data = (
const u8*)m_item.val.string.ptr;
622 for (
unsigned a = 0 ; a < m_item.val.string.len ; ++a) {
625 }
else if (m_item.uDataType == QCBOR_TYPE_TEXT_STRING
626 || m_item.uDataType == QCBOR_TYPE_URI) {
628 wr.
wr_fix((
const char*)m_item.val.string.ptr, m_item.val.string.len);
630 }
else if (m_item.uDataType == QCBOR_TYPE_FALSE) {
632 }
else if (m_item.uDataType == QCBOR_TYPE_TRUE) {
634 }
else if (m_item.uDataType == QCBOR_TYPE_NULL) {
Creates an ephemeral reader for the Concise Binary Object Representation (CBOR, IETF RFC8949),...
unsigned peek_integer_len(const u8 *rdptr) const
Predict the length of the next integer value.
bool copy_item(QCBOREncodeContext *dst)
Copy the next CBOR item to the specified destination.
QCBORDecodeContext *const cbor
QCBOR context pointer.
unsigned copy_all(QCBOREncodeContext *dst)
Copy all remaining CBOR item(s) to the specified destination.
QCBORItem m_item
QCBOR Decoder item.
unsigned m_encoded_len
Encoded length.
bool close()
Close the QCBOR encoder by calling QCBOREncode_Finish and copy the resulting bytes to m_dst,...
CborWriter(satcat5::io::Writeable *dst, QCBOREncodeContext *encode, u8 *buff, unsigned size, bool automap=false)
Constructor requires child class to provide a working buffer.
satcat5::io::ArrayRead m_read
Reads working buffer.
const u8 * m_encoded
Encoded data.
UsefulBufC get_encoded()
Get encoded data as a UsefulBuf, useful if no dst was given.
satcat5::io::Readable * get_buffer()
Get encoded data as a Readable, useful if no dst was given.
u8 m_auto_close
Auto-close QCBOR Type.
QCBOREncodeContext *const cbor
QCBOR context pointer.
satcat5::io::Writeable *const m_dst
Writeable sink.
satcat5::util::optional< QCBORItem > get_item() const
Read the next scalar value from the List.
satcat5::util::optional< bool > get_bool() const
Read the next scalar value from the List.
constexpr ListReader(QCBORDecodeContext *decode)
Create a ListReader from an existing decoder context.
Reads a series of key-value pairs from a CBOR Map.
satcat5::util::optional< satcat5::io::ArrayRead > get_bytes(const char * key) const
Read a byte sequence from the Map.
int get_double_array(const char * key, satcat5::io::Writeable &dst) const
Read an array of floating-point values from the Map, always written as doubles to cover any precision...
QCBORDecodeContext * open_map(const char * key) const
Read a nested dictionary from the Map.
satcat5::util::optional< s64 > get_int(const char * key) const
QCBORDecodeContext * open_list(const char * key) const
Read a nested list from the Map.
satcat5::util::optional< bool > get_bool(KEYTYPE key) const
Read a scalar value from the Map.
int get_bool_array(const char * key, satcat5::io::Writeable &dst) const
Read an array of boolean values from the Map, always written as u8 values regardless of platform size...
constexpr MapReader(QCBORDecodeContext *decode)
Create a MapReader from an existing decoder context.
satcat5::util::optional< double > get_double(const char * key) const
int get_s64_array(const char * key, satcat5::io::Writeable &dst) const
Read an array of integer values from the Map, always written as 64-bit length signed values (s64) to ...
bool is_null(const char * key) const
Check if a key in the Map exists and is NULL.
satcat5::util::optional< satcat5::io::ArrayRead > get_string(const char * key) const
Read a string from the Map.
Write a series of key-value pairs to a CBOR Map.
void add_key(KEYTYPE key) const
Templated function to write the correct key type to the Map.
QCBOREncodeContext * open_list(const char * key)
Add a list to the Map.
QCBOREncodeContext * open_map(const char * key)
Add a nested dictionary to the Map.
Ephemeral Readable interface for a simple array.
void read_reset(unsigned len)
Reset read position to the start of the backing array, and set the readable length to the specified v...
Abstract API for reading byte-streams and packets.
virtual bool read_bytes(unsigned nbytes, void *dst)
Read 0 or more bytes into a buffer.
virtual void read_finalize()
Consume any remaining bytes in this frame, if applicable.
virtual unsigned get_read_ready() const =0
How many bytes can be read without blocking?
Abstract API for writing byte-streams and packets.
virtual unsigned get_write_space() const =0
How many bytes can be written without blocking?
virtual void write_bytes(unsigned nbytes, const void *src)
Write 0 or more bytes from a buffer.
virtual void write_abort()
If possible, abort the current partially-written packet.
void write_u8(u8 data)
One of many functions for writing integer/floating point values, see details.
virtual bool write_finalize()
Mark end of frame and release temporary working data.
Internal buffer used by the Log class.
void wr_d64(u64 val, unsigned zpad=0)
Write an unsigned integer (u64) in decimal format.
void wr_s64(s64 val, unsigned zpad=0)
Write a signed integer (s64) in decimal format.
void wr_h32(u32 val, unsigned nhex=8)
Write an integer (u32) in hexadecimal format.
void wr_fix(const char *str, unsigned len)
Write a fixed-length UTF-8 string.
void wr_str(const char *str)
Write a null-terminated UTF-8 string.
CBOR (IETF RFC8949) Readable/Writeable interface.
Diagnostic logging to UART and/or Ethernet ports.
An optional field that may be filled or empty.