summaryrefslogtreecommitdiff
path: root/src/cbor_wrapper
diff options
context:
space:
mode:
Diffstat (limited to 'src/cbor_wrapper')
-rw-r--r--src/cbor_wrapper/CMakeLists.txt6
-rw-r--r--src/cbor_wrapper/cbor_decoder.cpp112
-rw-r--r--src/cbor_wrapper/cbor_encoder.cpp63
-rw-r--r--src/cbor_wrapper/include/cbor_decoder.hpp113
-rw-r--r--src/cbor_wrapper/include/cbor_encoder.hpp52
5 files changed, 346 insertions, 0 deletions
diff --git a/src/cbor_wrapper/CMakeLists.txt b/src/cbor_wrapper/CMakeLists.txt
new file mode 100644
index 00000000..cd5186e0
--- /dev/null
+++ b/src/cbor_wrapper/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_wrapper/cbor_decoder.cpp b/src/cbor_wrapper/cbor_decoder.cpp
new file mode 100644
index 00000000..a99cca02
--- /dev/null
+++ b/src/cbor_wrapper/cbor_decoder.cpp
@@ -0,0 +1,112 @@
+#include "cbor_decoder.hpp"
+
+#include <cstdint>
+#include <string>
+
+#include "cbor.h"
+#include "result.hpp"
+
+static const int kDecoderFlags = 0;
+
+namespace cbor {
+
+auto parse_stdstring(const CborValue* val, std::string* out) -> CborError {
+ char* buf;
+ size_t len;
+ CborError err = cbor_value_dup_text_string(val, &buf, &len, NULL);
+ if (err != CborNoError) {
+ return err;
+ }
+ *out = std::string(buf, len);
+ free(buf);
+ return err;
+}
+
+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, kDecoderFlags, &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::Create(CborValue& root)
+ -> cpp::result<std::unique_ptr<ArrayDecoder>, CborError> {
+ auto decoder = std::make_unique<ArrayDecoder>();
+ decoder->root_ = 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);
+}
+
+template <>
+auto ArrayDecoder::NextValue() -> cpp::result<int64_t, CborError> {
+ return NextValue(&cbor_value_is_integer, &cbor_value_get_int);
+}
+template <>
+auto ArrayDecoder::NextValue() -> cpp::result<uint64_t, CborError> {
+ return NextValue(&cbor_value_is_unsigned_integer, &cbor_value_get_uint64);
+}
+template <>
+auto ArrayDecoder::NextValue() -> cpp::result<std::string, CborError> {
+ return NextValue(&cbor_value_is_byte_string, &parse_stdstring);
+}
+
+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, kDecoderFlags, &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::Create(CborValue& root)
+ -> cpp::result<std::unique_ptr<MapDecoder>, CborError> {
+ auto decoder = std::make_unique<MapDecoder>();
+ decoder->root_ = 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);
+}
+
+template <>
+auto MapDecoder::FindValue(const std::string& key) -> std::optional<int64_t> {
+ return FindValue(key, &cbor_value_is_integer, &cbor_value_get_int);
+}
+template <>
+auto MapDecoder::FindValue(const std::string& key) -> std::optional<uint64_t> {
+ return FindValue(key, &cbor_value_is_unsigned_integer,
+ &cbor_value_get_uint64);
+}
+template <>
+auto MapDecoder::FindValue(const std::string& key)
+ -> std::optional<std::string> {
+ return FindValue(key, &cbor_value_is_byte_string, &parse_stdstring);
+}
+
+} // namespace cbor
diff --git a/src/cbor_wrapper/cbor_encoder.cpp b/src/cbor_wrapper/cbor_encoder.cpp
new file mode 100644
index 00000000..e4e8ee84
--- /dev/null
+++ b/src/cbor_wrapper/cbor_encoder.cpp
@@ -0,0 +1,63 @@
+#include "cbor_encoder.hpp"
+
+#include <cstdint>
+#include <string>
+
+#include "cbor.h"
+#include "cbor_decoder.hpp"
+#include "result.hpp"
+
+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(&root_encoder_, &container_encoder_,
+ container_len);
+ break;
+ case CONTAINER_MAP:
+ error_ = cbor_encoder_create_map(&root_encoder_, &container_encoder_,
+ container_len);
+ break;
+ }
+}
+
+auto Encoder::WriteValue(const std::string& val) -> void {
+ if (error_ != CborNoError) {
+ return;
+ }
+ error_ =
+ cbor_encode_text_string(&container_encoder_, val.c_str(), val.size());
+}
+
+auto Encoder::WriteValue(uint32_t val) -> void {
+ if (error_ != CborNoError) {
+ return;
+ }
+ error_ = cbor_encode_uint(&container_encoder_, val);
+}
+
+auto Encoder::WriteValue(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) {
+ error_ = cbor_encoder_close_container(&root_encoder_, &container_encoder_);
+ }
+ if (error_ != CborNoError) {
+ return cpp::fail(error_);
+ }
+ return cbor_encoder_get_buffer_size(&root_encoder_, buffer_);
+}
+
+} // namespace cbor
diff --git a/src/cbor_wrapper/include/cbor_decoder.hpp b/src/cbor_wrapper/include/cbor_decoder.hpp
new file mode 100644
index 00000000..193e7843
--- /dev/null
+++ b/src/cbor_wrapper/include/cbor_decoder.hpp
@@ -0,0 +1,113 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <cstdint>
+#include <string>
+
+#include "cbor.h"
+#include "result.hpp"
+
+namespace cbor {
+
+class ArrayDecoder {
+ public:
+ static auto Create(uint8_t* buffer, size_t buffer_len)
+ -> cpp::result<std::unique_ptr<ArrayDecoder>, CborError>;
+
+ static auto Create(CborValue& root)
+ -> cpp::result<std::unique_ptr<ArrayDecoder>, CborError>;
+
+ ArrayDecoder() {}
+
+ template <typename T>
+ auto NextValue() -> cpp::result<T, CborError>;
+
+ template <typename T>
+ auto NextValue(bool (*is_valid)(const CborValue*),
+ CborError (*parse)(const CborValue*, T*))
+ -> cpp::result<T, CborError> {
+ if (error_ != CborNoError) {
+ return cpp::fail(error_);
+ }
+ if (!is_valid(&it_)) {
+ error_ = CborErrorIllegalType;
+ return cpp::fail(error_);
+ }
+ T ret;
+ error_ = parse(&it_, &ret);
+ if (error_ != CborNoError) {
+ return cpp::fail(error_);
+ }
+ error_ = cbor_value_advance(&it_);
+ if (error_ != CborNoError) {
+ return cpp::fail(error_);
+ }
+ return ret;
+ }
+
+ auto Failed() -> CborError { return error_; }
+
+ auto Iterator() -> CborValue& { return it_; }
+
+ 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>;
+
+ static auto Create(CborValue& root)
+ -> cpp::result<std::unique_ptr<MapDecoder>, CborError>;
+
+ MapDecoder() {}
+
+ template <typename T>
+ auto FindValue(const std::string& key) -> std::optional<T>;
+
+ template <typename T>
+ auto FindValue(const std::string& key,
+ bool (*is_valid)(const CborValue*),
+ CborError (*parse)(const CborValue*, T*)) -> std::optional<T> {
+ if (error_ != CborNoError) {
+ return {};
+ }
+ CborValue val;
+ if (cbor_value_map_find_value(&it_, key.c_str(), &val) != CborNoError) {
+ return {};
+ }
+ if (!is_valid(&val)) {
+ error_ = CborErrorIllegalType;
+ return {};
+ }
+ T ret;
+ error_ = parse(&val, &ret);
+ if (error_ != CborNoError) {
+ return {};
+ }
+ return ret;
+ }
+
+ 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_wrapper/include/cbor_encoder.hpp b/src/cbor_wrapper/include/cbor_encoder.hpp
new file mode 100644
index 00000000..cc57e8a4
--- /dev/null
+++ b/src/cbor_wrapper/include/cbor_encoder.hpp
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <cstdint>
+#include <optional>
+#include <string>
+
+#include "cbor.h"
+#include "result.hpp"
+
+namespace cbor {
+
+enum ContainerType { CONTAINER_ARRAY, CONTAINER_MAP };
+
+class Encoder {
+ public:
+ Encoder(ContainerType type,
+ uint32_t container_len,
+ uint8_t* buffer,
+ size_t buffer_len);
+
+ auto WriteValue(const std::string& val) -> void;
+ auto WriteValue(uint32_t val) -> void;
+ auto WriteValue(int32_t val) -> void;
+
+ template <typename T>
+ auto WriteKeyValue(const std::string& key, const T&& val) -> void {
+ WriteValue(key);
+ WriteValue(val);
+ }
+
+ template <typename T>
+ auto WriteKeyValue(const std::string& key, const std::optional<T>& val)
+ -> void {
+ if (val) {
+ WriteKeyValue<T>(key, val.value());
+ }
+ }
+
+ auto Finish() -> cpp::result<size_t, CborError>;
+
+ Encoder(const Encoder&) = delete;
+ Encoder& operator=(const Encoder&) = delete;
+
+ private:
+ uint8_t* buffer_;
+ CborEncoder root_encoder_;
+ CborEncoder container_encoder_;
+
+ CborError error_ = CborNoError;
+};
+
+} // namespace cbor