diff --git a/.gitignore b/.gitignore index 4d6824c..ff7e454 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,22 @@ *.xcodeproj/ *.dSYM test +/.vs +/.vscode +/*.sln +/*.vcxproj +/*.vcxproj.filters +/*.vcxproj.user +*~ +/build +/bin +/Debug +/Release +/x64 +/libcborcpp.a +/libcborcpp_dynamic.so +/testing +/CMakeCache.txt +/CMakeFiles/ +/Makefile +/cmake_install.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d50f799..8551612 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,18 +4,27 @@ project(cborcpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_BUILD_TYPE Release) +file(GLOB HEADERS "include/cborcpp/*.h") + set(SOURCE_FILES - src/encoder.cpp - src/decoder.cpp - src/input.cpp - src/listener_debug.cpp - src/output_dynamic.cpp - src/output_static.cpp - ) + src/cborcpp/encoder.cpp + src/cborcpp/decoder.cpp + src/cborcpp/input.cpp + src/cborcpp/output_dynamic.cpp + src/cborcpp/output_static.cpp + src/cborcpp/cbor_object.cpp + src/cborcpp/output.cpp +) set(TEST_SOURCE_FILES src/tests.cpp ) +include_directories(include/) + +add_library(cborcpp_dynamic SHARED ${SOURCE_FILES} ${HEADERS}) +add_library(cborcpp STATIC ${SOURCE_FILES} ${HEADERS}) +add_executable(testing ${SOURCE_FILES} ${HEADERS} ${TEST_SOURCE_FILES}) -add_library(cborcpp SHARED ${SOURCE_FILES}) -add_executable(testing ${SOURCE_FILES} ${TEST_SOURCE_FILES}) +target_include_directories( cborcpp + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" +) diff --git a/README.md b/README.md index 015cad3..3d8a82e 100644 --- a/README.md +++ b/README.md @@ -9,27 +9,72 @@ Just a simple SAX-like Concise Binary Object Representation (CBOR). [http://tools.ietf.org/html/rfc7049](http://tools.ietf.org/html/rfc7049) +#### Dependencies + +* Boost 1.55+ + #### Examples ```C++ - cbor::output_dynamic output; - { //encoding cbor::encoder encoder(output); - encoder.write_array(5); + // [123, "bar", 321, 321, "foo", true, false, null, undefined, [123], [], {"hello": "world", "age": 18}, b"abcde"] + encoder.write_array(13); { encoder.write_int(123); encoder.write_string("bar"); encoder.write_int(321); encoder.write_int(321); encoder.write_string("foo"); + encoder.write_bool(true); + encoder.write_bool(false); + encoder.write_null(); + encoder.write_undefined(); + + encoder.write_array(1); + { + encoder.write_int(123); + } + encoder.write_array(0); + encoder.write_map(2); + { + encoder.write_string("hello"); + encoder.write_string("world"); + encoder.write_string("age"); + encoder.write_int(18); + } + encoder.write_bytes((const unsigned char*)"abcde", 5); } } { // decoding cbor::input input(output.data(), output.size()); - cbor::listener_debug listener; - cbor::decoder decoder(input, listener); - decoder.run(); + cbor::decoder decoder(input); + auto result = decoder.run(); + assert(result->type == COT_ARRAY & result->array_or_map_size == 13); + const auto& array_value = result->as(); + auto obj1 = array_value[0]->as_int(); + auto obj2 = array_value[1]->as_string(); + auto obj3 = array_value[2]->as_int(); + auto obj4 = array_value[3]->as_int(); + auto obj5 = array_value[4]->as_string(); + auto obj6 = array_value[5]->as_bool(); + auto obj7 = array_value[6]->as_bool(); + auto obj8 = array_value[7]->is_null(); + auto obj9 = array_value[8]->is_undefined(); + auto obj10 = array_value[9]->as_array(); + auto obj11 = array_value[10]->as_array(); + auto obj12 = array_value[11]->as_map(); + auto obj13 = array_value[12]->as_bytes(); + assert(obj1 == 123); + assert(obj2 == "bar"); + assert(obj3 == 321 && obj4 == 321); + assert(obj5 == "foo"); + assert(obj6 == true && obj7 == false); + assert(obj8 && obj9); + assert(obj10.size() == 1 && obj10[0]->as_int() == 123); + assert(obj11.empty()); + assert(obj12.size() == 2 && obj12["hello"]->as_string() == "world" && obj12["age"]->as_int() == 18); + assert(obj13.size() == 5 && memcmp(obj13.data(), "abcde", 5) == 0); } ``` diff --git a/src/cbor.h b/include/cborcpp/cbor.h similarity index 71% rename from src/cbor.h rename to include/cborcpp/cbor.h index 7b79c30..6220f1a 100644 --- a/src/cbor.h +++ b/include/cborcpp/cbor.h @@ -14,15 +14,13 @@ limitations under the License. */ -#ifndef CBOR_CPP_CBOR_H -#define CBOR_CPP_CBOR_H +#pragma once -#include "input.h" -#include "encoder.h" -#include "decoder.h" -#include "listener.h" -#include "output_static.h" -#include "output_dynamic.h" -#include "listener_debug.h" +#include "cborcpp/input.h" +#include "cborcpp/encoder.h" +#include "cborcpp/decoder.h" +#include "cborcpp/output_static.h" +#include "cborcpp/output_dynamic.h" +#include "cborcpp/exceptions.h" +#include "cborcpp/cbor_object.h" -#endif //CBOR_CPP_CBOR_H diff --git a/include/cborcpp/cbor_object.h b/include/cborcpp/cbor_object.h new file mode 100644 index 0000000..cd51140 --- /dev/null +++ b/include/cborcpp/cbor_object.h @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "cborcpp/exceptions.h" + +namespace cbor { + enum CborObjectType { + COT_BOOL, + COT_INT, + COT_BYTES, + COT_STRING, + COT_ARRAY, + COT_MAP, + COT_TAG, + COT_SPECIAL, + COT_UNDEFINED, + COT_NULL, + COT_ERROR, + COT_EXTRA_INT, + COT_EXTRA_TAG, + COT_EXTRA_SPECIAL + }; + struct CborObject; + typedef std::shared_ptr CborObjectP; + typedef bool CborBoolValue; + typedef int64_t CborIntValue; + typedef uint32_t CborTagValue; + typedef std::vector CborBytesValue; + typedef std::vector CborArrayValue; + typedef std::map> CborMapValue; + typedef std::string CborStringValue; + typedef std::string CborErrorValue; + typedef uint64_t CborExtraIntValue; + typedef uint32_t CborSpecialValue; + typedef uint64_t CborExtraSpecialValue; + typedef boost::variant CborObjectValue; + + struct CborObject { + CborObjectType type; + CborObjectValue value; + uint32_t array_or_map_size = 0; + bool is_positive_extra = false; + + template + const T& as() const { + return boost::get(value); + } + + inline bool is_null() const { + return COT_NULL == type; + } + inline bool is_undefined() const { + return COT_UNDEFINED == type; + } + inline bool is_int() const { + return COT_INT == type; + } + inline bool is_string() const { + return COT_STRING == type; + } + inline bool is_bytes() const { + return COT_BYTES == type; + } + inline bool is_bool() const { + return COT_BOOL == type; + } + inline bool is_array() const { + return COT_ARRAY == type; + } + inline bool is_map() const { + return COT_MAP == type; + } + inline bool is_tag() const { + return COT_TAG == type; + } + inline bool is_special() const { + return COT_SPECIAL == type; + } + inline CborObjectType object_type() const { + return type; + } + inline const CborBoolValue& as_bool() const { + return as(); + } + inline const CborIntValue& as_int() const { + return as(); + } + inline const CborTagValue& as_tag() const { + return as(); + } + inline const CborSpecialValue& as_special() const { + return as(); + } + inline const CborBytesValue& as_bytes() const { + return as(); + } + inline const CborArrayValue& as_array() const { + return as(); + } + inline const CborMapValue& as_map() const { + return as(); + } + inline const CborStringValue& as_string() const { + return as(); + } + + + static CborObjectP from_int(CborIntValue value); + static CborObjectP from_bool(CborBoolValue value); + static CborObjectP from_bytes(const CborBytesValue& value); + static CborObjectP from_string(const std::string& value); + static CborObjectP create_array(size_t size); + static CborObjectP create_map(size_t size); + static CborObjectP from_tag(CborTagValue value); + static CborObjectP create_undefined(); + static CborObjectP create_null(); + static CborObjectP from_special(uint32_t value); + static CborObjectP from_extra_integer(uint64_t value, bool sign); + static CborObjectP from_extra_tag(uint64_t value); + static CborObjectP from_extra_special(uint64_t value); + }; +} diff --git a/src/decoder.h b/include/cborcpp/decoder.h similarity index 80% rename from src/decoder.h rename to include/cborcpp/decoder.h index 5dc1c53..3996dfa 100644 --- a/src/decoder.h +++ b/include/cborcpp/decoder.h @@ -15,11 +15,10 @@ */ -#ifndef __CborDecoder_H_ -#define __CborDecoder_H_ +#pragma once -#include "listener.h" -#include "input.h" +#include "cborcpp/input.h" +#include "cborcpp/cbor_object.h" namespace cbor { typedef enum { @@ -39,18 +38,14 @@ namespace cbor { class decoder { private: - listener *_listener; + // listener *_listener; input *_in; decoder_state _state; int _currentLength; public: decoder(input &in); - decoder(input &in, listener &listener); ~decoder(); - void run(); - void set_listener(listener &listener_instance); + CborObjectP run(); + //void set_listener(listener &listener_instance); }; } - - -#endif //__CborDecoder_H_ diff --git a/src/encoder.h b/include/cborcpp/encoder.h similarity index 75% rename from src/encoder.h rename to include/cborcpp/encoder.h index 592cf20..3155a96 100644 --- a/src/encoder.h +++ b/include/cborcpp/encoder.h @@ -14,12 +14,12 @@ limitations under the License. */ +#pragma once -#ifndef __CborEncoder_H_ -#define __CborEncoder_H_ - -#include "output.h" +#include "cborcpp/output.h" +#include "cborcpp/cbor_object.h" #include +#include namespace cbor { class encoder { @@ -32,13 +32,13 @@ namespace cbor { void write_bool(bool value); - void write_int(int value); + void write_int(int32_t value); - void write_int(long long value); + void write_int(int64_t value); - void write_int(unsigned int value); + void write_int(uint32_t value); - void write_int(unsigned long long value); + void write_int(uint64_t value); void write_bytes(const unsigned char *data, unsigned int size); @@ -58,11 +58,11 @@ namespace cbor { void write_undefined(); + void write_cbor_object(CborObjectP value); + private: - void write_type_value(int major_type, unsigned int value); + void write_type_value(int major_type, uint32_t value); - void write_type_value(int major_type, unsigned long long value); + void write_type_value(int major_type, uint64_t value); }; } - -#endif //__CborEncoder_H_ diff --git a/include/cborcpp/exceptions.h b/include/cborcpp/exceptions.h new file mode 100644 index 0000000..1f14aa6 --- /dev/null +++ b/include/cborcpp/exceptions.h @@ -0,0 +1,106 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace cbor +{ +#define CBOR_DEFAULT_EXCEPTION_CODE 1 + + class CborException : public std::exception + { + protected: + int64_t _code; + std::string _name_value; + std::string _error_msg; + public: + inline CborException() : _code(0) { } + inline CborException(int64_t code, const std::string &name_value, const std::string &error_msg) + : _code(code), _name_value(name_value), _error_msg(error_msg) {} + inline CborException(const CborException& other) { + _code = other._code; + _name_value = other._name_value; + _error_msg = other._error_msg; + } + inline CborException(const char *msg) + { + _code = CBOR_DEFAULT_EXCEPTION_CODE; + _error_msg = msg; + } + inline CborException(const std::string& msg) { + _code = CBOR_DEFAULT_EXCEPTION_CODE; + _error_msg = msg; + } + inline CborException& operator=(const CborException& other) { + if (this != &other) + { + _error_msg = other._error_msg; + } + return *this; + } + inline virtual ~CborException() {} + +#ifdef _WIN32 +#ifndef CBOR_NOEXCEPT +#define CBOR_NOEXCEPT +#endif // !CBOR_NOEXCEPT +#else +#define CBOR_NOEXCEPT noexcept +#endif + + inline virtual const char* what() const CBOR_NOEXCEPT + { + return _error_msg.c_str(); + } + inline virtual int64_t code() const { + return _code; + } + inline std::string name() const + { + return _name_value; + } + inline virtual std::shared_ptr dynamic_copy_exception()const + { + return std::make_shared(*this); + } + inline virtual void dynamic_rethrow_exception()const + { + if (code() == 0) + throw *this; + else + CborException::dynamic_rethrow_exception(); + } + }; + +} + +#define CBOR_DECLARE_DERIVED_EXCEPTION(TYPE, BASE, CODE, WHAT) \ + class TYPE : public BASE \ + { \ + public: \ + explicit TYPE( int64_t code, const std::string& name_value, const std::string& what_value ) \ + :BASE( code, name_value, what_value ){} \ + explicit TYPE(const std::string& what_value ) \ + :BASE( CODE, BOOST_PP_STRINGIZE(TYPE), what_value ){} \ + explicit TYPE() \ + :BASE(CODE, BOOST_PP_STRINGIZE(TYPE), WHAT) {} \ + virtual std::shared_ptr dynamic_copy_exception()const \ + { return std::make_shared( *this ); } \ + virtual void dynamic_rethrow_exception()const \ + { if( code() == CODE ) throw *this;\ + else cbor::CborException::dynamic_rethrow_exception(); \ + } \ + }; + +#define CBOR_DECLARE_EXCEPTION(TYPE, CODE, WHAT) CBOR_DECLARE_DERIVED_EXCEPTION(TYPE, cbor::CborException, CODE, WHAT) + +namespace cbor +{ + CBOR_DECLARE_EXCEPTION(cbor_encode_exception, 101, "cbor encode exception"); + CBOR_DECLARE_EXCEPTION(cbor_decode_exception, 102, "cbor decode exception"); + CBOR_DECLARE_EXCEPTION(cbor_output_exception, 103, "cbor output exception"); +} diff --git a/src/input.h b/include/cborcpp/input.h similarity index 93% rename from src/input.h rename to include/cborcpp/input.h index 2cffa9c..175a7a2 100644 --- a/src/input.h +++ b/include/cborcpp/input.h @@ -14,8 +14,7 @@ limitations under the License. */ -#ifndef CBOR_CPP_INPUT_H -#define CBOR_CPP_INPUT_H +#pragma once namespace cbor { class input { @@ -42,4 +41,3 @@ namespace cbor { }; } -#endif // CBOR_CPP_INPUT_H diff --git a/src/output.h b/include/cborcpp/output.h similarity index 77% rename from src/output.h rename to include/cborcpp/output.h index 0901d95..b08c4d3 100644 --- a/src/output.h +++ b/include/cborcpp/output.h @@ -14,16 +14,21 @@ limitations under the License. */ +#pragma once -#ifndef __CborOutput_H_ -#define __CborOutput_H_ +#include +#include namespace cbor { class output { public: - virtual unsigned char *data() = 0; + virtual unsigned char *data() const = 0; - virtual unsigned int size() = 0; + virtual unsigned int size() const = 0; + + virtual std::vector bytes() const; + + virtual std::string hex() const; virtual void put_byte(unsigned char value) = 0; @@ -31,4 +36,3 @@ namespace cbor { }; } -#endif //__CborOutput_H_ diff --git a/src/output_dynamic.h b/include/cborcpp/output_dynamic.h similarity index 85% rename from src/output_dynamic.h rename to include/cborcpp/output_dynamic.h index 51c96e3..7efecdd 100644 --- a/src/output_dynamic.h +++ b/include/cborcpp/output_dynamic.h @@ -14,11 +14,10 @@ limitations under the License. */ -#ifndef __CborDynamicOutput_H_ -#define __CborDynamicOutput_H_ +#pragma once - -#include "output.h" +#include "cborcpp/output.h" +#include namespace cbor { class output_dynamic : public output { @@ -33,9 +32,9 @@ namespace cbor { ~output_dynamic(); - virtual unsigned char *data(); + virtual unsigned char *data() const; - virtual unsigned int size(); + virtual unsigned int size() const; virtual void put_byte(unsigned char value); @@ -46,6 +45,3 @@ namespace cbor { }; } - - -#endif //__CborDynamicOutput_H_ diff --git a/src/output_static.h b/include/cborcpp/output_static.h similarity index 83% rename from src/output_static.h rename to include/cborcpp/output_static.h index 162ec0e..bd6b4dc 100644 --- a/src/output_static.h +++ b/include/cborcpp/output_static.h @@ -14,10 +14,9 @@ limitations under the License. */ -#ifndef __CborStaticOutput_H_ -#define __CborStaticOutput_H_ +#pragma once -#include "output.h" +#include "cborcpp/output.h" namespace cbor { class output_static : public output { @@ -30,9 +29,9 @@ namespace cbor { ~output_static(); - virtual unsigned char *getData(); + virtual unsigned char *getData() const; - virtual unsigned int getSize(); + virtual unsigned int getSize() const; virtual void put_byte(unsigned char value); @@ -40,5 +39,3 @@ namespace cbor { }; } - -#endif //__CborStaticOutput_H_ diff --git a/src/cborcpp/cbor_object.cpp b/src/cborcpp/cbor_object.cpp new file mode 100644 index 0000000..477abbf --- /dev/null +++ b/src/cborcpp/cbor_object.cpp @@ -0,0 +1,83 @@ +#include "cborcpp/cbor_object.h" + +namespace cbor { + CborObjectP CborObject::from_int(CborIntValue value) { + auto result = std::make_shared(); + result->type = COT_INT; + result->value = value; + return result; + } + CborObjectP CborObject::from_bool(CborBoolValue value) { + auto result = std::make_shared(); + result->type = COT_BOOL; + result->value = value; + return result; + } + CborObjectP CborObject::from_bytes(const CborBytesValue& value) { + auto result = std::make_shared(); + result->type = COT_BYTES; + result->value = value; + return result; + } + CborObjectP CborObject::from_string(const std::string& value) { + auto result = std::make_shared(); + result->type = COT_STRING; + result->value = value; + return result; + } + CborObjectP CborObject::create_array(size_t size) { + auto result = std::make_shared(); + result->type = COT_ARRAY; + result->value = CborArrayValue(); + result->array_or_map_size = size; + return result; + } + CborObjectP CborObject::create_map(size_t size) { + auto result = std::make_shared(); + result->type = COT_MAP; + result->value = CborMapValue(); + result->array_or_map_size = size; + return result; + } + CborObjectP CborObject::from_tag(CborTagValue value) { + auto result = std::make_shared(); + result->type = COT_TAG; + result->value = value; + return result; + } + CborObjectP CborObject::create_undefined() { + auto result = std::make_shared(); + result->type = COT_UNDEFINED; + return result; + } + CborObjectP CborObject::create_null() { + auto result = std::make_shared(); + result->type = COT_NULL; + return result; + } + CborObjectP CborObject::from_special(uint32_t value) { + auto result = std::make_shared(); + result->type = COT_SPECIAL; + result->value = value; + return result; + } + CborObjectP CborObject::from_extra_integer(uint64_t value, bool sign) { + auto result = std::make_shared(); + result->type = COT_EXTRA_INT; + result->value = value; + result->is_positive_extra = sign; + return result; + } + CborObjectP CborObject::from_extra_tag(uint64_t value) { + auto result = std::make_shared(); + result->type = COT_EXTRA_TAG; + result->value = value; + return result; + } + CborObjectP CborObject::from_extra_special(uint64_t value) { + auto result = std::make_shared(); + result->type = COT_EXTRA_SPECIAL; + result->value = value; + return result; + } +} \ No newline at end of file diff --git a/src/decoder.cpp b/src/cborcpp/decoder.cpp similarity index 65% rename from src/decoder.cpp rename to src/cborcpp/decoder.cpp index 529821d..f9c66b1 100644 --- a/src/decoder.cpp +++ b/src/cborcpp/decoder.cpp @@ -14,8 +14,7 @@ limitations under the License. */ -#include "decoder.h" -#include "log.h" +#include "cborcpp/decoder.h" #include @@ -26,21 +25,74 @@ decoder::decoder(input &in) { _state = STATE_TYPE; } -decoder::decoder(input &in, listener &listener) { - _in = ∈ - _listener = &listener; - _state = STATE_TYPE; -} - decoder::~decoder() { } -void decoder::set_listener(listener &listener_instance) { - _listener = &listener_instance; +static CborObjectP cbor_object_error(const std::string& error_msg) { + auto result = std::make_shared(); + result->type = CborObjectType::COT_ERROR; + result->value = error_msg; + return result; +} + +static void put_decoded_value(CborObjectP& result, std::vector& structures_stack, bool& iter_in_map_key, CborObjectP& map_key_temp, CborObjectP value) { + auto old_structures_stack_size = structures_stack.size(); + if (structures_stack.empty()) { + if (result) + throw cbor_decode_exception("multiple cbor object when decoding"); + result = value; + + if (value->type == COT_ARRAY || value->type == COT_MAP) { + if (value->array_or_map_size > 0) { + structures_stack.push_back(value); + } + } + return; + } + auto last = structures_stack[old_structures_stack_size - 1]; + if (last->type == COT_ARRAY) { + auto& array_value = boost::get(last->value); + array_value.push_back(value); + if (array_value.size() >= last->array_or_map_size) { + // full, pop from structure + structures_stack.pop_back(); + } + } + else if (last->type == COT_MAP) { + if (iter_in_map_key) + map_key_temp = value; + else { + if (map_key_temp->type != COT_STRING) { + throw cbor_decode_exception("invalid map key type"); + } + const auto& key = boost::get(map_key_temp->value); + auto& map_value = boost::get(last->value); + map_value[key] = value; + if (map_value.size() >= last->array_or_map_size) { + // full, pop from structure + structures_stack.pop_back(); + } + } + iter_in_map_key = !iter_in_map_key; + } + else { + throw cbor_decode_exception("invalid structure type"); + } + + if (value->type == COT_ARRAY || value->type == COT_MAP) { + if (value->array_or_map_size > 0) { + structures_stack.push_back(value); + } + } } -void decoder::run() { +CborObjectP decoder::run() { + CborObjectP result; + std::vector structures_stack; + bool iter_in_map_key = true; + CborObjectP map_key_temp; + unsigned int temp; while(1) { if(_state == STATE_TYPE) { @@ -52,7 +104,7 @@ void decoder::run() { switch(majorType) { case 0: // positive integer if(minorType < 24) { - _listener->on_integer(minorType); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(minorType)); } else if(minorType == 24) { // 1 byte _currentLength = 1; _state = STATE_PINT; @@ -67,12 +119,12 @@ void decoder::run() { _state = STATE_PINT; } else { _state = STATE_ERROR; - _listener->on_error("invalid integer type"); + throw cbor_decode_exception("invalid integer type"); } break; case 1: // negative integer if(minorType < 24) { - _listener->on_integer(-1 -minorType); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(-1 - minorType)); } else if(minorType == 24) { // 1 byte _currentLength = 1; _state = STATE_NINT; @@ -87,7 +139,7 @@ void decoder::run() { _state = STATE_NINT; } else { _state = STATE_ERROR; - _listener->on_error("invalid integer type"); + throw cbor_decode_exception("invalid integer type"); } break; case 2: // bytes @@ -108,7 +160,7 @@ void decoder::run() { _state = STATE_BYTES_SIZE; } else { _state = STATE_ERROR; - _listener->on_error("invalid bytes type"); + throw cbor_decode_exception("invalid bytes type"); } break; case 3: // string @@ -129,12 +181,12 @@ void decoder::run() { _state = STATE_STRING_SIZE; } else { _state = STATE_ERROR; - _listener->on_error("invalid string type"); + throw cbor_decode_exception("invalid string type"); } break; case 4: // array if(minorType < 24) { - _listener->on_array(minorType); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_array(minorType)); } else if(minorType == 24) { _state = STATE_ARRAY; _currentLength = 1; @@ -149,12 +201,12 @@ void decoder::run() { _state = STATE_ARRAY; } else { _state = STATE_ERROR; - _listener->on_error("invalid array type"); + throw cbor_decode_exception("invalid array type"); } break; case 5: // map if(minorType < 24) { - _listener->on_map(minorType); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_map(minorType)); } else if(minorType == 24) { _state = STATE_MAP; _currentLength = 1; @@ -169,12 +221,12 @@ void decoder::run() { _state = STATE_MAP; } else { _state = STATE_ERROR; - _listener->on_error("invalid array type"); + throw cbor_decode_exception("invalid array type"); } break; case 6: // tag if(minorType < 24) { - _listener->on_tag(minorType); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_tag(minorType)); } else if(minorType == 24) { _state = STATE_TAG; _currentLength = 1; @@ -189,20 +241,20 @@ void decoder::run() { _state = STATE_TAG; } else { _state = STATE_ERROR; - _listener->on_error("invalid tag type"); + throw cbor_decode_exception("invalid tag type"); } break; case 7: // special if (minorType < 20) { - _listener->on_special(minorType); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_special(minorType)); } else if (minorType == 20) { - _listener->on_bool(false); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_bool(false)); } else if (minorType == 21) { - _listener->on_bool(true); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_bool(true)); } else if (minorType == 22) { - _listener->on_null(); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_null()); } else if (minorType == 23) { - _listener->on_undefined(); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_undefined()); } else if(minorType == 24) { _state = STATE_SPECIAL; _currentLength = 1; @@ -217,7 +269,7 @@ void decoder::run() { _state = STATE_SPECIAL; } else { _state = STATE_ERROR; - _listener->on_error("invalid special type"); + throw cbor_decode_exception("invalid special type"); } break; } @@ -226,24 +278,24 @@ void decoder::run() { if(_in->has_bytes(_currentLength)) { switch(_currentLength) { case 1: - _listener->on_integer(_in->get_byte()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(_in->get_byte())); _state = STATE_TYPE; break; case 2: - _listener->on_integer(_in->get_short()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(_in->get_short())); _state = STATE_TYPE; break; case 4: temp = _in->get_int(); if(temp <= INT_MAX) { - _listener->on_integer(temp); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(temp)); } else { - _listener->on_extra_integer(temp, 1); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_extra_integer(temp, true)); } _state = STATE_TYPE; break; case 8: - _listener->on_extra_integer(_in->get_long(), 1); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_extra_integer(_in->get_long(), true)); _state = STATE_TYPE; break; } @@ -252,24 +304,24 @@ void decoder::run() { if(_in->has_bytes(_currentLength)) { switch(_currentLength) { case 1: - _listener->on_integer(-(int) _in->get_byte() - 1); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(-(int)_in->get_byte() - 1)); _state = STATE_TYPE; break; case 2: - _listener->on_integer(-(int) _in->get_short() - 1); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(-(int) _in->get_short() - 1)); _state = STATE_TYPE; break; case 4: temp = _in->get_int(); if(temp <= INT_MAX) { - _listener->on_integer(-(int) temp - 1); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_int(-(int) temp - 1)); } else { - _listener->on_extra_integer(temp + 1, -1); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_extra_integer(temp + 1, false)); } _state = STATE_TYPE; break; case 8: - _listener->on_extra_integer(_in->get_long() + 1, -1); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_extra_integer(_in->get_long() + 1, false)); break; } } else break; @@ -290,16 +342,16 @@ void decoder::run() { break; case 8: _state = STATE_ERROR; - _listener->on_error("extra long bytes"); + throw cbor_decode_exception("extra long bytes"); break; } } else break; } else if(_state == STATE_BYTES_DATA) { if(_in->has_bytes(_currentLength)) { - unsigned char *data = new unsigned char[_currentLength]; - _in->get_bytes(data, _currentLength); + std::vector data(_currentLength); + _in->get_bytes(data.data(), _currentLength); _state = STATE_TYPE; - _listener->on_bytes(data, _currentLength); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_bytes(data)); } else break; } else if(_state == STATE_STRING_SIZE) { if(_in->has_bytes(_currentLength)) { @@ -318,36 +370,36 @@ void decoder::run() { break; case 8: _state = STATE_ERROR; - _listener->on_error("extra long array"); + throw cbor_decode_exception("extra long array"); break; } } else break; } else if(_state == STATE_STRING_DATA) { if(_in->has_bytes(_currentLength)) { - unsigned char *data = new unsigned char[_currentLength]; - _in->get_bytes(data, _currentLength); + std::vector data(_currentLength); + _in->get_bytes(data.data(), _currentLength); _state = STATE_TYPE; - std::string str((const char *)data, (size_t)_currentLength); - _listener->on_string(str); + std::string str(data.data(), (size_t)_currentLength); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_string(str)); } else break; } else if(_state == STATE_ARRAY) { if(_in->has_bytes(_currentLength)) { switch(_currentLength) { case 1: - _listener->on_array(_in->get_byte()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_array(_in->get_byte())); _state = STATE_TYPE; break; case 2: - _listener->on_array(_currentLength = _in->get_short()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_array(_in->get_short())); _state = STATE_TYPE; break; case 4: - _listener->on_array(_in->get_int()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_array(_in->get_int())); _state = STATE_TYPE; break; case 8: _state = STATE_ERROR; - _listener->on_error("extra long array"); + throw cbor_decode_exception("extra long array"); break; } } else break; @@ -355,20 +407,20 @@ void decoder::run() { if(_in->has_bytes(_currentLength)) { switch(_currentLength) { case 1: - _listener->on_map(_in->get_byte()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_map(_in->get_byte())); _state = STATE_TYPE; break; case 2: - _listener->on_map(_currentLength = _in->get_short()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_map(_currentLength = _in->get_short())); _state = STATE_TYPE; break; case 4: - _listener->on_map(_in->get_int()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::create_map(_in->get_int())); _state = STATE_TYPE; break; case 8: _state = STATE_ERROR; - _listener->on_error("extra long map"); + throw cbor_decode_exception("extra long map"); break; } } else break; @@ -376,19 +428,19 @@ void decoder::run() { if(_in->has_bytes(_currentLength)) { switch(_currentLength) { case 1: - _listener->on_tag(_in->get_byte()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_tag(_in->get_byte())); _state = STATE_TYPE; break; case 2: - _listener->on_tag(_in->get_short()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_tag(_in->get_short())); _state = STATE_TYPE; break; case 4: - _listener->on_tag(_in->get_int()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_tag(_in->get_int())); _state = STATE_TYPE; break; case 8: - _listener->on_extra_tag(_in->get_long()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_extra_tag(_in->get_long())); _state = STATE_TYPE; break; } @@ -397,19 +449,19 @@ void decoder::run() { if (_in->has_bytes(_currentLength)) { switch (_currentLength) { case 1: - _listener->on_special(_in->get_byte()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_special(_in->get_byte())); _state = STATE_TYPE; break; case 2: - _listener->on_special(_in->get_short()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_special(_in->get_short())); _state = STATE_TYPE; break; case 4: - _listener->on_special(_in->get_int()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_special(_in->get_int())); _state = STATE_TYPE; break; case 8: - _listener->on_extra_special(_in->get_long()); + put_decoded_value(result, structures_stack, iter_in_map_key, map_key_temp, CborObject::from_extra_special(_in->get_long())); _state = STATE_TYPE; break; } @@ -417,8 +469,13 @@ void decoder::run() { } else if(_state == STATE_ERROR) { break; } else { - logger("UNKNOWN STATE"); + throw cbor_decode_exception("UNKNOWN STATE"); } } + if (!result) + throw cbor_decode_exception("cbor decoded nothing"); + if (!structures_stack.empty()) + throw cbor_decode_exception("cbor decode fail with not finished structures"); + return result; } diff --git a/src/encoder.cpp b/src/cborcpp/encoder.cpp similarity index 65% rename from src/encoder.cpp rename to src/cborcpp/encoder.cpp index ceac696..cefc531 100644 --- a/src/encoder.cpp +++ b/src/cborcpp/encoder.cpp @@ -14,7 +14,8 @@ limitations under the License. */ -#include "encoder.h" +#include "cborcpp/encoder.h" +#include "cborcpp/exceptions.h" using namespace cbor; @@ -27,7 +28,7 @@ encoder::~encoder() { } -void encoder::write_type_value(int major_type, unsigned int value) { +void encoder::write_type_value(int major_type, uint32_t value) { major_type <<= 5; if(value < 24) { _out->put_byte((unsigned char) (major_type | value)); @@ -47,7 +48,7 @@ void encoder::write_type_value(int major_type, unsigned int value) { } } -void encoder::write_type_value(int major_type, unsigned long long value) { +void encoder::write_type_value(int major_type, uint64_t value) { major_type <<= 5; if(value < 24ULL) { _out->put_byte((unsigned char) (major_type | value)); @@ -77,27 +78,27 @@ void encoder::write_type_value(int major_type, unsigned long long value) { } } -void encoder::write_int(unsigned int value) { +void encoder::write_int(uint32_t value) { write_type_value(0, value); } -void encoder::write_int(unsigned long long value) { +void encoder::write_int(uint64_t value) { write_type_value(0, value); } -void encoder::write_int(long long value) { +void encoder::write_int(int64_t value) { if(value < 0) { - write_type_value(1, (unsigned long long) -(value+1)); + write_type_value(1, (uint64_t) -(value+1)); } else { - write_type_value(0, (unsigned long long) value); + write_type_value(0, (uint64_t) value); } } -void encoder::write_int(int value) { +void encoder::write_int(int32_t value) { if(value < 0) { - write_type_value(1, (unsigned int) -(value+1)); + write_type_value(1, (uint32_t) -(value+1)); } else { - write_type_value(0, (unsigned int) value); + write_type_value(0, (uint32_t) value); } } @@ -147,4 +148,66 @@ void encoder::write_null() { void encoder::write_undefined() { _out->put_byte((unsigned char) 0xf7); -} \ No newline at end of file +} + +void encoder::write_cbor_object(CborObjectP value) { + if (!value) + return; + switch (value->object_type()) { + case CborObjectType::COT_NULL: + write_null(); + return; + case CborObjectType::COT_UNDEFINED: + write_undefined(); + return; + case CborObjectType::COT_BOOL: + write_bool(value->as_bool()); + return; + case CborObjectType::COT_INT: + write_int(value->as_int()); + return; + case CborObjectType::COT_EXTRA_INT: + write_int(value->as()); + return; + case CborObjectType::COT_STRING: + write_string(value->as_string()); + return; + case CborObjectType::COT_BYTES: { + const auto& bytes = value->as_bytes(); + write_bytes((const unsigned char*)bytes.data(), bytes.size()); + return; + } + case CborObjectType::COT_TAG: + write_tag(value->as_tag()); + return; + case CborObjectType::COT_EXTRA_TAG: + write_tag(value->as()); + return; + case CborObjectType::COT_SPECIAL: + write_special(value->as_special()); + return; + case CborObjectType::COT_EXTRA_SPECIAL: + write_special(value->as()); + return; + case CborObjectType::COT_ARRAY: { + const auto& array_value = value->as_array(); + write_array(array_value.size()); + for (const auto& item : array_value) { + write_cbor_object(item); + } + return; + } + case CborObjectType::COT_MAP: { + const auto& map_value = value->as_map(); + write_map(map_value.size()); + for (const auto& p : map_value) { + write_string(p.first); + write_cbor_object(p.second); + } + return; + } + case CborObjectType::COT_ERROR: { + throw cbor_encode_exception("invalid cbor object type"); + } + } +} diff --git a/src/input.cpp b/src/cborcpp/input.cpp similarity index 98% rename from src/input.cpp rename to src/cborcpp/input.cpp index c44f283..7ad3c70 100644 --- a/src/input.cpp +++ b/src/cborcpp/input.cpp @@ -14,7 +14,7 @@ limitations under the License. */ -#include "input.h" +#include "cborcpp/input.h" #include #include diff --git a/src/cborcpp/output.cpp b/src/cborcpp/output.cpp new file mode 100644 index 0000000..0c6b030 --- /dev/null +++ b/src/cborcpp/output.cpp @@ -0,0 +1,22 @@ +#include "cborcpp/output.h" + +#include +#include +#include +#include +#include + +namespace cbor { + std::vector output::bytes() const { + std::vector result(size()); + memcpy(result.data(), data(), size()); + return result; + } + + std::string output::hex() const { + const auto& data_bytes = bytes(); + std::string res; + boost::algorithm::hex(data_bytes.begin(), data_bytes.end(), std::back_inserter(res)); + return res; + } +} \ No newline at end of file diff --git a/src/output_dynamic.cpp b/src/cborcpp/output_dynamic.cpp similarity index 91% rename from src/output_dynamic.cpp rename to src/cborcpp/output_dynamic.cpp index a9cf468..a7ccc5b 100644 --- a/src/output_dynamic.cpp +++ b/src/cborcpp/output_dynamic.cpp @@ -14,10 +14,11 @@ limitations under the License. */ -#include "output_dynamic.h" +#include "cborcpp/output_dynamic.h" #include #include +#include using namespace cbor; @@ -40,11 +41,11 @@ output_dynamic::~output_dynamic() { delete _buffer; } -unsigned char *output_dynamic::data() { +unsigned char *output_dynamic::data() const { return _buffer; } -unsigned int output_dynamic::size() { +unsigned int output_dynamic::size() const { return _offset; } diff --git a/src/output_static.cpp b/src/cborcpp/output_static.cpp similarity index 81% rename from src/output_static.cpp rename to src/cborcpp/output_static.cpp index 98bac71..dad0dac 100644 --- a/src/output_static.cpp +++ b/src/cborcpp/output_static.cpp @@ -14,8 +14,8 @@ limitations under the License. */ -#include "output_static.h" -#include "log.h" +#include "cborcpp/output_static.h" +#include "cborcpp/exceptions.h" #include @@ -35,7 +35,7 @@ void output_static::put_byte(unsigned char value) { if(_offset < _capacity) { _buffer[_offset++] = value; } else { - logger("buffer overflow error"); + throw cbor_output_exception("buffer overflow error"); } } @@ -44,14 +44,14 @@ void output_static::put_bytes(const unsigned char *data, int size) { memcpy(_buffer + _offset, data, size); _offset += size; } else { - logger("buffer overflow error"); + throw cbor_output_exception("buffer overflow error"); } } -unsigned char *output_static::getData() { +unsigned char *output_static::getData() const { return _buffer; } -unsigned int output_static::getSize() { +unsigned int output_static::getSize() const { return _offset; } diff --git a/src/listener.h b/src/listener.h deleted file mode 100644 index 562682a..0000000 --- a/src/listener.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2014-2015 Stanislav Ovsyannikov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#ifndef CBOR_CPP_LISTENER_H -#define CBOR_CPP_LISTENER_H - -#include - -namespace cbor { - class listener { - public: - virtual void on_integer(int value) = 0; - - virtual void on_bytes(unsigned char *data, int size) = 0; - - virtual void on_string(std::string &str) = 0; - - virtual void on_array(int size) = 0; - - virtual void on_map(int size) = 0; - - virtual void on_tag(unsigned int tag) = 0; - - virtual void on_special(unsigned int code) = 0; - - virtual void on_bool(bool) = 0; - - virtual void on_null() = 0; - - virtual void on_undefined() = 0; - - virtual void on_error(const char *error) = 0; - - virtual void on_extra_integer(unsigned long long value, int sign) { - } - - virtual void on_extra_tag(unsigned long long tag) { - } - - virtual void on_extra_special(unsigned long long tag) { - } - }; -} - - -#endif // CBOR_CPP_LISTENER_H diff --git a/src/listener_debug.cpp b/src/listener_debug.cpp deleted file mode 100644 index 5b79b74..0000000 --- a/src/listener_debug.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2014-2015 Stanislav Ovsyannikov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#include "listener_debug.h" - -using namespace cbor; - -void listener_debug::on_integer(int value) { - printf("integer: %d\n", value); -} - -void listener_debug::on_bytes(unsigned char *data, int size) { - printf("bytes with size: %d", size); -} - -void listener_debug::on_string(std::string &str) { - printf("string: '%.*s'\n", (int)str.size(), str.c_str()); -} - -void listener_debug::on_array(int size) { - printf("array: %d\n", size); -} - -void listener_debug::on_map(int size) { - printf("map: %d\n", size); -} - -void listener_debug::on_tag(unsigned int tag) { - printf("tag: %d\n", tag); -} - -void listener_debug::on_special(unsigned int code) { - printf("special: %d\n", code); -} - -void listener_debug::on_bool(bool value) { - printf("bool: %s\n", value ? "true" : "false"); -} - -void listener_debug::on_null() { - printf("special: null\n"); -} - -void listener_debug::on_undefined() { - printf("special: undefined\n"); -} - -void listener_debug::on_error(const char *error) { - printf("error: %s\n", error); -} - -void listener_debug::on_extra_integer(unsigned long long value, int sign) { - if(sign >= 0) { - printf("extra integer: %llu\n", value); - } else { - printf("extra integer: -%llu\n", value); - } -} - -void listener_debug::on_extra_tag(unsigned long long tag) { - printf("extra tag: %llu\n", tag); -} - -void listener_debug::on_extra_special(unsigned long long tag) { - printf("extra special: %llu\n", tag); -} diff --git a/src/listener_debug.h b/src/listener_debug.h deleted file mode 100644 index b7d2b17..0000000 --- a/src/listener_debug.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright 2014-2015 Stanislav Ovsyannikov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#ifndef __listener_debug_H_ -#define __listener_debug_H_ - -#include - -#include "listener.h" - -namespace cbor { - class listener_debug : public listener { - public: - virtual void on_integer(int value); - - virtual void on_bytes(unsigned char *data, int size); - - virtual void on_string(std::string &str); - - virtual void on_array(int size); - - virtual void on_map(int size); - - virtual void on_tag(unsigned int tag); - - virtual void on_special(unsigned int code); - - virtual void on_bool(bool); - - virtual void on_null(); - - virtual void on_undefined(); - - virtual void on_error(const char *error); - - virtual void on_extra_integer(unsigned long long value, int sign); - - virtual void on_extra_tag(unsigned long long tag); - - virtual void on_extra_special(unsigned long long tag); - }; -} - -#endif //__listener_debug_H_ diff --git a/src/log.h b/src/log.h deleted file mode 100644 index 5f651df..0000000 --- a/src/log.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - Copyright 2014-2015 Stanislav Ovsyannikov - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -#ifndef LOG_H_ -#define LOG_H_ - -#include - -#define logger(line) fprintf(stderr, "%s:%d [%s]: %s\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, line) -#define loggerf(format, ...) fprintf(stderr, "%s:%d [%s]: " format "\n", __FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__) - -#endif - diff --git a/src/tests.cpp b/src/tests.cpp index 0d0d768..dd987eb 100644 --- a/src/tests.cpp +++ b/src/tests.cpp @@ -16,14 +16,17 @@ #include -#include "cbor.h" +#include "cborcpp/cbor.h" int main() { + using namespace cbor; + cbor::output_dynamic output; { //encoding cbor::encoder encoder(output); - encoder.write_array(9); + // [123, "bar", 321, 321, "foo", true, false, null, undefined, [123], [], {"age": 18, "hello": "world"}, b"abcde"] + encoder.write_array(13); { encoder.write_int(123); encoder.write_string("bar"); @@ -34,14 +37,59 @@ int main() { encoder.write_bool(false); encoder.write_null(); encoder.write_undefined(); + + encoder.write_array(1); + { + encoder.write_int(123); + } + encoder.write_array(0); + encoder.write_map(2); + { + encoder.write_string("age"); + encoder.write_int(18); + encoder.write_string("hello"); + encoder.write_string("world"); + } + encoder.write_bytes((const unsigned char*)"abcde", 5); } } { // decoding + auto output_hex = output.hex(); cbor::input input(output.data(), output.size()); - cbor::listener_debug listener; - cbor::decoder decoder(input, listener); - decoder.run(); + cbor::decoder decoder(input); + auto result = decoder.run(); + assert(result->type == COT_ARRAY & result->array_or_map_size == 13); + const auto& array_value = result->as(); + auto obj1 = array_value[0]->as_int(); + auto obj2 = array_value[1]->as_string(); + auto obj3 = array_value[2]->as_int(); + auto obj4 = array_value[3]->as_int(); + auto obj5 = array_value[4]->as_string(); + auto obj6 = array_value[5]->as_bool(); + auto obj7 = array_value[6]->as_bool(); + auto obj8 = array_value[7]->is_null(); + auto obj9 = array_value[8]->is_undefined(); + auto obj10 = array_value[9]->as_array(); + auto obj11 = array_value[10]->as_array(); + auto obj12 = array_value[11]->as_map(); + auto obj13 = array_value[12]->as_bytes(); + assert(obj1 == 123); + assert(obj2 == "bar"); + assert(obj3 == 321 && obj4 == 321); + assert(obj5 == "foo"); + assert(obj6 == true && obj7 == false); + assert(obj8 && obj9); + assert(obj10.size() == 1 && obj10[0]->as_int() == 123); + assert(obj11.empty()); + assert(obj12.size() == 2 && obj12["hello"]->as_string() == "world" && obj12["age"]->as_int() == 18); + assert(obj13.size() == 5 && memcmp(obj13.data(), "abcde", 5) == 0); + + cbor::output_dynamic output2; + cbor::encoder encoder2(output2); + encoder2.write_cbor_object(result); + auto output2_hex = output2.hex(); + assert(output2_hex == output_hex); } return 0;