summaryrefslogtreecommitdiff
path: root/src/cbor
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2022-11-22 17:05:02 +1100
committerjacqueline <me@jacqueline.id.au>2022-11-22 17:05:02 +1100
commit9176ef187227ffb56c249c5f321cd1bf50d4cfcc (patch)
treea846c8fc4e5788e97d6fca43c2807c4bf0ae0214 /src/cbor
parent9f8cfaa7a8abd885785830e03d7c417e856b8a22 (diff)
downloadtangara-fw-9176ef187227ffb56c249c5f321cd1bf50d4cfcc.tar.gz
Add cbor wrapper, and chunk streaming util
Diffstat (limited to 'src/cbor')
-rw-r--r--src/cbor/CMakeLists.txt6
-rw-r--r--src/cbor/cbor_decoder.cpp158
-rw-r--r--src/cbor/cbor_encoder.cpp53
-rw-r--r--src/cbor/include/cbor_decoder.hpp47
-rw-r--r--src/cbor/include/cbor_encoder.hpp30
5 files changed, 294 insertions, 0 deletions
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 <cstdint>
+#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<std::unique_ptr<ArrayDecoder>, CborError> {
+ auto decoder = std::make_unique<ArrayDecoder>();
+ 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<std::string, CborError> {
+ 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<uint32_t, CborError> {
+ 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<int32_t, CborError> {
+ 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<std::unique_ptr<MapDecoder>, CborError> {
+ auto decoder = std::make_unique<MapDecoder>();
+ 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<std::string> {
+ 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<uint32_t> {
+ 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<int32_t> {
+ 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 <cstdint>
+#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<size_t, CborError> {
+ 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 <cstdint>
+namespace cbor {
+
+ class ArrayDecoder {
+ public:
+ static auto Create(uint8_t *buffer, size_t buffer_len) -> cpp::result<std::unique_ptr<ArrayDecoder>, CborError>;
+
+ auto ParseString() -> cpp::result<std::string, CborError>;
+ auto ParseUnsigned() -> cpp::result<uint32_t, CborError>;
+ auto ParseSigned() -> cpp::result<int32_t, CborError>;
+
+ 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<std::unique_ptr<MapDecoder>, CborError>;
+
+ auto FindString(const std::string &key) -> std::optional<std::string>;
+ auto FindUnsigned(const std::string &key) -> std::optional<uint32_t>;
+ auto FindSigned(const std::string &key) -> std::optional<int32_t>;
+
+ 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 <cstdint>
+#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<size_t, CborError>;
+
+ Encoder(const Encoder&) = delete;
+ Encoder& operator=(const Encoder&) = delete;
+ private:
+ CborEncoder root_encoder_;
+ CborEncoder container_encoder_;
+
+ CborError error_ = CborNoError;
+ };
+
+} // namespace cbor