From 9176ef187227ffb56c249c5f321cd1bf50d4cfcc Mon Sep 17 00:00:00 2001 From: jacqueline Date: Tue, 22 Nov 2022 17:05:02 +1100 Subject: Add cbor wrapper, and chunk streaming util --- src/cbor/CMakeLists.txt | 6 ++ src/cbor/cbor_decoder.cpp | 158 ++++++++++++++++++++++++++++++++++++++ src/cbor/cbor_encoder.cpp | 53 +++++++++++++ src/cbor/include/cbor_decoder.hpp | 47 ++++++++++++ src/cbor/include/cbor_encoder.hpp | 30 ++++++++ 5 files changed, 294 insertions(+) create mode 100644 src/cbor/CMakeLists.txt create mode 100644 src/cbor/cbor_decoder.cpp create mode 100644 src/cbor/cbor_encoder.cpp create mode 100644 src/cbor/include/cbor_decoder.hpp create mode 100644 src/cbor/include/cbor_encoder.hpp (limited to 'src/cbor') diff --git a/src/cbor/CMakeLists.txt b/src/cbor/CMakeLists.txt new file mode 100644 index 00000000..cd5186e0 --- /dev/null +++ b/src/cbor/CMakeLists.txt @@ -0,0 +1,6 @@ +idf_component_register( + SRCS "cbor_decoder.cpp" "cbor_encoder.cpp" + INCLUDE_DIRS "include" + REQUIRES "cbor" "result") + +target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/cbor/cbor_decoder.cpp b/src/cbor/cbor_decoder.cpp new file mode 100644 index 00000000..eb43e163 --- /dev/null +++ b/src/cbor/cbor_decoder.cpp @@ -0,0 +1,158 @@ +#include "cbor_decoder.hpp" +#include +#include "esp-idf/components/cbor/tinycbor/src/cbor.h" +#include "include/cbor_decoder.hpp" + +namespace cbor { + +static auto ArrayDecoder::Create(uint8_t *buffer, size_t buffer_len) -> cpp::result, CborError> { + auto decoder = std::make_unique(); + cbor_parser_init(buffer, buffer_len, &decoder->parser_, &decoder->root_); + if (!cbor_value_is_array(&decoder->root_)) { + return cpp::fail(CborErrorIllegalType); + } + CborError err = cbor_value_enter_container(&decoder->root_, &decoder->it_); + if (err != CborNoError) { + return cpp::fail(err); + } + return std::move(decoder); +} + + +auto ArrayDecoder::ParseString() -> cpp::result { + if (error_ != CborNoError) { + return cpp::fail(error_); + } + + if (!cbor_value_is_byte_string(&it_)) { + error_ = CborErrorIllegalType; + return cpp::fail(error_); + } + uint8_t *buf; size_t len; CborValue new_val; + error_ = cbor_value_dup_byte_string(&it_, &buf, &len, &new_val); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + std::string ret(buf, len); + free(buf); + val_ = new_val; + return ret; +} + +auto ArrayDecoder::ParseUnsigned() -> cpp::result { + if (error_ != CborNoError) { + return cpp::fail(error_); + } + + if (!cbor_value_is_unsigned_integer(&it_)) { + error_ = CborErrorIllegalType; + return cpp::fail(error_); + } + uint64_t ret; + error_ = cbor_value_get_uint64(&it_, &ret); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + error_ = cbor_value_advance(&it_); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + return ret; +} + +auto ArrayDecoder::ParseSigned() -> cpp::result { + if (error_ != CborNoError) { + return cpp::fail(error_); + } + if (!cbor_value_is_unsigned_integer(&it_)) { + error_ = CborErrorIllegalType; + return cpp::fail(error_); + } + uint64_t ret; + error_ = cbor_value_get_uint64(&it_, &ret); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + error_ = cbor_value_advance(&it_); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + return ret; +} + +static auto MapDecoder::Create(uint8_t *buffer, size_t buffer_len) -> cpp::result, CborError> { + auto decoder = std::make_unique(); + cbor_parser_init(buffer, buffer_len, &decoder->parser_, &decoder->root_); + if (!cbor_value_is_map(&decoder->root_)) { + return cpp::fail(CborErrorIllegalType); + } + CborError err = cbor_value_enter_container(&decoder->root_, &decoder->it_); + if (err != CborNoError) { + return cpp::fail(err); + } + return std::move(decoder); +} + +auto MapDecoder::FindString(const std::string &key) -> std::optional { + CborValue val; + if (error_ != CborNoError) { + return {}; + } + if (cbor_value_map_find_value(&it_, key.c_str(), &val) != CborNoError) { + return {}; + } + if (!cbor_value_is_byte_string(&val)) { + error_ = CborErrorIllegalType; + return {}; + } + uint8_t *buf; size_t len; + error_ = cbor_value_dup_byte_string(&val, &buf, &len, NULL); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + std::string ret(buf, len); + free(buf); + return ret; +} + +auto MapDecoder::FindUnsigned(const std::string &key) -> std::optional { + CborValue val; + if (error_ != CborNoError) { + return {}; + } + if (cbor_value_map_find_value(&it_, key.c_str(), &val) != CborNoError) { + return {}; + } + if (!cbor_value_is_unsigned_integer(&val)) { + error_ = CborErrorIllegalType; + return {}; + } + uint64_t ret; + error_ = cbor_value_get_uint64(&val, &ret); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + return ret; +} + +auto MapDecoder::FindSigned(const std::string &key) -> std::optional { + CborValue val; + if (error_ != CborNoError) { + return {}; + } + if (cbor_value_map_find_value(&it_, key.c_str(), &val) != CborNoError) { + return {}; + } + if (!cbor_value_is_integer(&val)) { + error_ = CborErrorIllegalType; + return {}; + } + int32_t ret; + error_ = cbor_value_get_int(&val, &ret); + if (error_ != CborNoError) { + return cpp::fail(error_); + } + return ret; +} + +} // namespace cbor diff --git a/src/cbor/cbor_encoder.cpp b/src/cbor/cbor_encoder.cpp new file mode 100644 index 00000000..863597b4 --- /dev/null +++ b/src/cbor/cbor_encoder.cpp @@ -0,0 +1,53 @@ +#include "cbor_encoder.hpp" +#include +#include "esp-idf/components/cbor/tinycbor/src/cbor.h" + +namespace cbor { + + static const int kEncoderFlags = 0; + +Encoder::Encoder(ContainerType type, uint32_t container_len, uint8_t *buffer, size_t buffer_len) { + cbor_encoder_init(&root_encoder, buffer, buffer_len, kEncoderFlags); + switch (type) { + case CONTAINER_ARRAY: + error_ = cbor_encoder_create_array(&encoder, &container_encoder_, container_len); + break; + case CONTAINER_MAP: + error_ = cbor_encoder_create_map(&encoder, &container_encoder_, container_len); + break; + } +} + +auto Encoder::WriteString(const std::string &val) -> void { + if (error_ != CborNoError) { + return; + } + error_ = cbor_encode_byte_string(&container_encoder_, val.c_str(), val.size()); +} + +auto Encoder::WriteUnsigned(uint32_t val) -> void { + if (error_ != CborNoError) { + return; + } + error_ = cbor_encode_uint(&container_encoder_, val); +} + +auto Encoder::WriteSigned(int32_t val) -> void { + if (error_ != CborNoError) { + return; + } + error_ = cbor_encode_int(&container_encoder_, val); +} + +auto Encoder::Finish() -> cpp::result { + if (error_ != CborNoError) { + return cpp::fail(error_); + } + if (CborError final_error = cbor_encoder_close_container(&root_encoder, &container_encoder_) != CborNoError) { + return cpp::fail(final_error); + } + return cbor_encoder_get_buffer_size(&root_encoder); +} + +} // namespace cbor + diff --git a/src/cbor/include/cbor_decoder.hpp b/src/cbor/include/cbor_decoder.hpp new file mode 100644 index 00000000..249db9cc --- /dev/null +++ b/src/cbor/include/cbor_decoder.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +namespace cbor { + + class ArrayDecoder { + public: + static auto Create(uint8_t *buffer, size_t buffer_len) -> cpp::result, CborError>; + + auto ParseString() -> cpp::result; + auto ParseUnsigned() -> cpp::result; + auto ParseSigned() -> cpp::result; + + auto Failed() -> CborError { return error_; } + + ArrayDecoder(const ArrayDecoder&) = delete; + ArrayDecoder& operator=(const ArrayDecoder&) = delete; + private: + CborParser parser_; + CborValue root_; + + CborValue it_; + CborError error_ = CborNoError; + }; + + class MapDecoder { + public: + static auto Create(uint8_t *buffer, size_t buffer_len) -> cpp::result, CborError>; + + auto FindString(const std::string &key) -> std::optional; + auto FindUnsigned(const std::string &key) -> std::optional; + auto FindSigned(const std::string &key) -> std::optional; + + auto Failed() -> CborError { return error_; } + + MapDecoder(const MapDecoder&) = delete; + MapDecoder& operator=(const MapDecoder&) = delete; + private: + CborParser parser_; + CborValue root_; + + CborValue it_; + CborError error_ = CborNoError; + }; + + +} // namespace cbor diff --git a/src/cbor/include/cbor_encoder.hpp b/src/cbor/include/cbor_encoder.hpp new file mode 100644 index 00000000..0edbbdff --- /dev/null +++ b/src/cbor/include/cbor_encoder.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include "esp-idf/components/cbor/tinycbor/src/cbor.h" +namespace cbor { + + class Encoder { + public: + enum ContainerType { + CONTAINER_ARRAY, + CONTAINER_MAP + }; + Encoder(ContainerType type, uint32_t container_len, uint8_t *buffer, size_t buffer_len); + + auto WriteString(const std::string &val) -> void; + auto WriteUnsigned(uint32_t val) -> void; + auto WriteSigned(int32_t val) -> void; + + auto Finish() -> cpp::result; + + Encoder(const Encoder&) = delete; + Encoder& operator=(const Encoder&) = delete; + private: + CborEncoder root_encoder_; + CborEncoder container_encoder_; + + CborError error_ = CborNoError; + }; + +} // namespace cbor -- cgit v1.2.3