From 2e8c7ccbe60894d4f5a03010624ee606e6742ca9 Mon Sep 17 00:00:00 2001 From: zoowii <1992zhouwei@gmail.com> Date: Thu, 18 Oct 2018 15:14:14 +0800 Subject: [PATCH 1/6] decode to CborObject instead of using listener --- .gitignore | 12 +++ README.md | 57 +++++++++++-- src/cbor.h | 2 - src/cbor_object.cpp | 83 +++++++++++++++++++ src/cbor_object.h | 118 +++++++++++++++++++++++++++ src/decoder.cpp | 178 +++++++++++++++++++++++++++-------------- src/decoder.h | 15 ++-- src/exceptions.h | 105 ++++++++++++++++++++++++ src/listener.h | 59 -------------- src/listener_debug.cpp | 79 ------------------ src/listener_debug.h | 57 ------------- src/log.h | 4 + src/tests.cpp | 49 +++++++++++- 13 files changed, 541 insertions(+), 277 deletions(-) create mode 100644 src/cbor_object.cpp create mode 100644 src/cbor_object.h create mode 100644 src/exceptions.h delete mode 100644 src/listener.h delete mode 100644 src/listener_debug.cpp delete mode 100644 src/listener_debug.h diff --git a/.gitignore b/.gitignore index 4d6824c..e53b108 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,15 @@ *.xcodeproj/ *.dSYM test +/.vs +/.vscode +/*.sln +/*.vcxproj +/*.vcxproj.filters +/*.vcxproj.user +*~ +/build +/bin +/Debug +/Release +/x64 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/src/cbor.h index 7b79c30..c50293b 100644 --- a/src/cbor.h +++ b/src/cbor.h @@ -20,9 +20,7 @@ #include "input.h" #include "encoder.h" #include "decoder.h" -#include "listener.h" #include "output_static.h" #include "output_dynamic.h" -#include "listener_debug.h" #endif //CBOR_CPP_CBOR_H diff --git a/src/cbor_object.cpp b/src/cbor_object.cpp new file mode 100644 index 0000000..db722c2 --- /dev/null +++ b/src/cbor_object.cpp @@ -0,0 +1,83 @@ +#include "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/cbor_object.h b/src/cbor_object.h new file mode 100644 index 0000000..d0f0cc1 --- /dev/null +++ b/src/cbor_object.h @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "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 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 CborObjectType object_type() const { + return type; + } + inline CborBoolValue as_bool() const { + return as(); + } + inline CborIntValue as_int() const { + return as(); + } + inline CborTagValue as_tag() 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); + }; +} \ No newline at end of file diff --git a/src/decoder.cpp b/src/decoder.cpp index 529821d..718af51 100644 --- a/src/decoder.cpp +++ b/src/decoder.cpp @@ -26,21 +26,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 +105,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 +120,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 +140,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 +161,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 +182,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 +202,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 +222,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 +242,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 +270,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 +279,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 +305,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 +343,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,7 +371,7 @@ 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; @@ -328,26 +381,26 @@ void decoder::run() { _in->get_bytes(data, _currentLength); _state = STATE_TYPE; std::string str((const char *)data, (size_t)_currentLength); - _listener->on_string(str); + 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 +408,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 +429,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 +450,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 +470,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/decoder.h b/src/decoder.h index 5dc1c53..425e8b3 100644 --- a/src/decoder.h +++ b/src/decoder.h @@ -15,11 +15,10 @@ */ -#ifndef __CborDecoder_H_ -#define __CborDecoder_H_ +#pragma once -#include "listener.h" #include "input.h" +#include "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/exceptions.h b/src/exceptions.h new file mode 100644 index 0000000..858ce13 --- /dev/null +++ b/src/exceptions.h @@ -0,0 +1,105 @@ +#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"); +} 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 index 5f651df..aeb9cf5 100644 --- a/src/log.h +++ b/src/log.h @@ -19,6 +19,10 @@ #include +#ifndef __PRETTY_FUNCTION__ +#define __PRETTY_FUNCTION__ __FUNCTION__ +#endif + #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__) diff --git a/src/tests.cpp b/src/tests.cpp index 0d0d768..348dcb6 100644 --- a/src/tests.cpp +++ b/src/tests.cpp @@ -19,11 +19,14 @@ #include "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], [], {"hello": "world", "age": 18}, b"abcde"] + encoder.write_array(13); { encoder.write_int(123); encoder.write_string("bar"); @@ -34,14 +37,52 @@ 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("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); } return 0; From 5e3fc7a4873a78dbd19ac80b01d33c52fe9d1faa Mon Sep 17 00:00:00 2001 From: zoowii <1992zhouwei@gmail.com> Date: Thu, 18 Oct 2018 15:15:45 +0800 Subject: [PATCH 2/6] update cmakelists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d50f799..4aa000c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,9 @@ 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/cbor_object.cpp ) set(TEST_SOURCE_FILES From 7c431b17788596a32c4e3642326120e4bcfcb455 Mon Sep 17 00:00:00 2001 From: zoowii <1992zhouwei@gmail.com> Date: Thu, 18 Oct 2018 15:23:03 +0800 Subject: [PATCH 3/6] fix a bug of memory leak --- src/decoder.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/decoder.cpp b/src/decoder.cpp index 718af51..4fe8f5d 100644 --- a/src/decoder.cpp +++ b/src/decoder.cpp @@ -377,10 +377,10 @@ CborObjectP decoder::run() { } 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); + 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) { From 553b07d2a66ea76184903545c519902438d971a4 Mon Sep 17 00:00:00 2001 From: zoowii <1992zhouwei@gmail.com> Date: Thu, 18 Oct 2018 15:44:36 +0800 Subject: [PATCH 4/6] add hex and bytes func in output class --- src/output_dynamic.cpp | 13 +++++++++++++ src/output_dynamic.h | 11 +++++------ src/tests.cpp | 1 + 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/output_dynamic.cpp b/src/output_dynamic.cpp index a9cf468..4dbcc6c 100644 --- a/src/output_dynamic.cpp +++ b/src/output_dynamic.cpp @@ -18,6 +18,7 @@ #include #include +#include using namespace cbor; @@ -48,6 +49,18 @@ unsigned int output_dynamic::size() { return _offset; } +std::vector output_dynamic::bytes() { + std::vector result(size()); + memcpy(result.data(), data(), size()); + return result; +} +std::string output_dynamic::hex() { + const auto& data_bytes = bytes(); + std::string res; + boost::algorithm::hex(data_bytes.begin(), data_bytes.end(), std::back_inserter(res)); + return res; +} + void output_dynamic::put_byte(unsigned char value) { if(_offset < _capacity) { _buffer[_offset++] = value; diff --git a/src/output_dynamic.h b/src/output_dynamic.h index 51c96e3..094a7f4 100644 --- a/src/output_dynamic.h +++ b/src/output_dynamic.h @@ -14,11 +14,10 @@ limitations under the License. */ -#ifndef __CborDynamicOutput_H_ -#define __CborDynamicOutput_H_ - +#pragma once #include "output.h" +#include namespace cbor { class output_dynamic : public output { @@ -37,6 +36,9 @@ namespace cbor { virtual unsigned int size(); + virtual std::vector bytes(); + virtual std::string hex(); + virtual void put_byte(unsigned char value); virtual void put_bytes(const unsigned char *data, int size); @@ -46,6 +48,3 @@ namespace cbor { }; } - - -#endif //__CborDynamicOutput_H_ diff --git a/src/tests.cpp b/src/tests.cpp index 348dcb6..ceb0466 100644 --- a/src/tests.cpp +++ b/src/tests.cpp @@ -55,6 +55,7 @@ int main() { } { // decoding + auto output_hex = output.hex(); cbor::input input(output.data(), output.size()); cbor::decoder decoder(input); auto result = decoder.run(); From 05ad60422e599ce561c927b0ade52a3e6ca96ce4 Mon Sep 17 00:00:00 2001 From: zoowii <1992zhouwei@gmail.com> Date: Fri, 19 Oct 2018 11:18:26 +0800 Subject: [PATCH 5/6] add encoder to write cbor object directly --- CMakeLists.txt | 19 ++++--- {src => include/cborcpp}/cbor.h | 16 +++--- {src => include/cborcpp}/cbor_object.h | 12 ++++- {src => include/cborcpp}/decoder.h | 4 +- {src => include/cborcpp}/encoder.h | 11 ++-- {src => include/cborcpp}/exceptions.h | 1 + {src => include/cborcpp}/input.h | 4 +- {src => include/cborcpp}/output.h | 14 +++-- {src => include/cborcpp}/output_dynamic.h | 9 ++-- {src => include/cborcpp}/output_static.h | 11 ++-- src/{ => cborcpp}/cbor_object.cpp | 2 +- src/{ => cborcpp}/decoder.cpp | 3 +- src/{ => cborcpp}/encoder.cpp | 65 ++++++++++++++++++++++- src/{ => cborcpp}/input.cpp | 2 +- src/cborcpp/output.cpp | 22 ++++++++ src/{ => cborcpp}/output_dynamic.cpp | 18 ++----- src/{ => cborcpp}/output_static.cpp | 12 ++--- src/log.h | 30 ----------- src/tests.cpp | 14 +++-- 19 files changed, 162 insertions(+), 107 deletions(-) rename {src => include/cborcpp}/cbor.h (72%) rename {src => include/cborcpp}/cbor_object.h (89%) rename {src => include/cborcpp}/decoder.h (95%) rename {src => include/cborcpp}/encoder.h (92%) rename {src => include/cborcpp}/exceptions.h (97%) rename {src => include/cborcpp}/input.h (93%) rename {src => include/cborcpp}/output.h (77%) rename {src => include/cborcpp}/output_dynamic.h (86%) rename {src => include/cborcpp}/output_static.h (83%) rename src/{ => cborcpp}/cbor_object.cpp (98%) rename src/{ => cborcpp}/decoder.cpp (99%) rename src/{ => cborcpp}/encoder.cpp (73%) rename src/{ => cborcpp}/input.cpp (98%) create mode 100644 src/cborcpp/output.cpp rename src/{ => cborcpp}/output_dynamic.cpp (78%) rename src/{ => cborcpp}/output_static.cpp (81%) delete mode 100644 src/log.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4aa000c..c3b2a15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,18 +4,21 @@ 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/output_dynamic.cpp - src/output_static.cpp - src/cbor_object.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 ) -add_library(cborcpp SHARED ${SOURCE_FILES}) -add_executable(testing ${SOURCE_FILES} ${TEST_SOURCE_FILES}) +add_library(cborcpp SHARED ${SOURCE_FILES} ${HEADERS}) +add_executable(testing ${SOURCE_FILES} ${HEADERS} ${TEST_SOURCE_FILES}) diff --git a/src/cbor.h b/include/cborcpp/cbor.h similarity index 72% rename from src/cbor.h rename to include/cborcpp/cbor.h index c50293b..6220f1a 100644 --- a/src/cbor.h +++ b/include/cborcpp/cbor.h @@ -14,13 +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 "output_static.h" -#include "output_dynamic.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/src/cbor_object.h b/include/cborcpp/cbor_object.h similarity index 89% rename from src/cbor_object.h rename to include/cborcpp/cbor_object.h index d0f0cc1..fcb0b2e 100644 --- a/src/cbor_object.h +++ b/include/cborcpp/cbor_object.h @@ -5,7 +5,7 @@ #include #include #include -#include "exceptions.h" +#include "cborcpp/exceptions.h" namespace cbor { enum CborObjectType { @@ -31,10 +31,12 @@ namespace cbor { typedef uint32_t CborTagValue; typedef std::vector CborBytesValue; typedef std::vector CborArrayValue; - typedef std::map CborMapValue; + 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 { @@ -75,6 +77,9 @@ namespace cbor { 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; } @@ -87,6 +92,9 @@ namespace cbor { inline CborTagValue as_tag() const { return as(); } + inline CborSpecialValue as_special() const { + return as(); + } inline const CborBytesValue& as_bytes() const { return as(); } diff --git a/src/decoder.h b/include/cborcpp/decoder.h similarity index 95% rename from src/decoder.h rename to include/cborcpp/decoder.h index 425e8b3..3996dfa 100644 --- a/src/decoder.h +++ b/include/cborcpp/decoder.h @@ -17,8 +17,8 @@ #pragma once -#include "input.h" -#include "cbor_object.h" +#include "cborcpp/input.h" +#include "cborcpp/cbor_object.h" namespace cbor { typedef enum { diff --git a/src/encoder.h b/include/cborcpp/encoder.h similarity index 92% rename from src/encoder.h rename to include/cborcpp/encoder.h index 592cf20..892df20 100644 --- a/src/encoder.h +++ b/include/cborcpp/encoder.h @@ -14,11 +14,10 @@ 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 namespace cbor { @@ -58,11 +57,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, unsigned long long value); }; } - -#endif //__CborEncoder_H_ diff --git a/src/exceptions.h b/include/cborcpp/exceptions.h similarity index 97% rename from src/exceptions.h rename to include/cborcpp/exceptions.h index 858ce13..1f14aa6 100644 --- a/src/exceptions.h +++ b/include/cborcpp/exceptions.h @@ -102,4 +102,5 @@ 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 86% rename from src/output_dynamic.h rename to include/cborcpp/output_dynamic.h index 094a7f4..7efecdd 100644 --- a/src/output_dynamic.h +++ b/include/cborcpp/output_dynamic.h @@ -16,7 +16,7 @@ #pragma once -#include "output.h" +#include "cborcpp/output.h" #include namespace cbor { @@ -32,12 +32,9 @@ namespace cbor { ~output_dynamic(); - virtual unsigned char *data(); + virtual unsigned char *data() const; - virtual unsigned int size(); - - virtual std::vector bytes(); - virtual std::string hex(); + virtual unsigned int size() const; virtual void put_byte(unsigned char value); 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/cbor_object.cpp b/src/cborcpp/cbor_object.cpp similarity index 98% rename from src/cbor_object.cpp rename to src/cborcpp/cbor_object.cpp index db722c2..477abbf 100644 --- a/src/cbor_object.cpp +++ b/src/cborcpp/cbor_object.cpp @@ -1,4 +1,4 @@ -#include "cbor_object.h" +#include "cborcpp/cbor_object.h" namespace cbor { CborObjectP CborObject::from_int(CborIntValue value) { diff --git a/src/decoder.cpp b/src/cborcpp/decoder.cpp similarity index 99% rename from src/decoder.cpp rename to src/cborcpp/decoder.cpp index 4fe8f5d..73b01ff 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 diff --git a/src/encoder.cpp b/src/cborcpp/encoder.cpp similarity index 73% rename from src/encoder.cpp rename to src/cborcpp/encoder.cpp index ceac696..78a54b6 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; @@ -147,4 +148,66 @@ void encoder::write_null() { void encoder::write_undefined() { _out->put_byte((unsigned char) 0xf7); +} + +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"); + } + } } \ No newline at end of file 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 78% rename from src/output_dynamic.cpp rename to src/cborcpp/output_dynamic.cpp index 4dbcc6c..a7ccc5b 100644 --- a/src/output_dynamic.cpp +++ b/src/cborcpp/output_dynamic.cpp @@ -14,7 +14,7 @@ limitations under the License. */ -#include "output_dynamic.h" +#include "cborcpp/output_dynamic.h" #include #include @@ -41,26 +41,14 @@ 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; } -std::vector output_dynamic::bytes() { - std::vector result(size()); - memcpy(result.data(), data(), size()); - return result; -} -std::string output_dynamic::hex() { - const auto& data_bytes = bytes(); - std::string res; - boost::algorithm::hex(data_bytes.begin(), data_bytes.end(), std::back_inserter(res)); - return res; -} - void output_dynamic::put_byte(unsigned char value) { if(_offset < _capacity) { _buffer[_offset++] = value; 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/log.h b/src/log.h deleted file mode 100644 index aeb9cf5..0000000 --- a/src/log.h +++ /dev/null @@ -1,30 +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 - -#ifndef __PRETTY_FUNCTION__ -#define __PRETTY_FUNCTION__ __FUNCTION__ -#endif - -#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 ceb0466..dd987eb 100644 --- a/src/tests.cpp +++ b/src/tests.cpp @@ -16,7 +16,7 @@ #include -#include "cbor.h" +#include "cborcpp/cbor.h" int main() { using namespace cbor; @@ -25,7 +25,7 @@ int main() { { //encoding cbor::encoder encoder(output); - // [123, "bar", 321, 321, "foo", true, false, null, undefined, [123], [], {"hello": "world", "age": 18}, b"abcde"] + // [123, "bar", 321, 321, "foo", true, false, null, undefined, [123], [], {"age": 18, "hello": "world"}, b"abcde"] encoder.write_array(13); { encoder.write_int(123); @@ -45,10 +45,10 @@ int main() { 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_string("hello"); + encoder.write_string("world"); } encoder.write_bytes((const unsigned char*)"abcde", 5); } @@ -84,6 +84,12 @@ int main() { 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; From 9345ca7c56022f1908c6639a86ff6cd0ae0b5cd6 Mon Sep 17 00:00:00 2001 From: zoowii <1992zhouwei@gmail.com> Date: Fri, 19 Oct 2018 15:23:58 +0800 Subject: [PATCH 6/6] add support for linux --- .gitignore | 7 +++++++ CMakeLists.txt | 14 ++++++++++---- include/cborcpp/cbor_object.h | 12 ++++++------ include/cborcpp/encoder.h | 13 +++++++------ src/cborcpp/decoder.cpp | 4 ++-- src/cborcpp/encoder.cpp | 22 +++++++++++----------- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index e53b108..ff7e454 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,10 @@ test /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 c3b2a15..8551612 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,13 +12,19 @@ set(SOURCE_FILES src/cborcpp/input.cpp src/cborcpp/output_dynamic.cpp src/cborcpp/output_static.cpp - src/cborcpp/cbor_object.cpp - src/cborcpp/output.cpp - ) + src/cborcpp/cbor_object.cpp + src/cborcpp/output.cpp +) set(TEST_SOURCE_FILES src/tests.cpp ) +include_directories(include/) -add_library(cborcpp SHARED ${SOURCE_FILES} ${HEADERS}) +add_library(cborcpp_dynamic SHARED ${SOURCE_FILES} ${HEADERS}) +add_library(cborcpp STATIC ${SOURCE_FILES} ${HEADERS}) add_executable(testing ${SOURCE_FILES} ${HEADERS} ${TEST_SOURCE_FILES}) + +target_include_directories( cborcpp + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" +) diff --git a/include/cborcpp/cbor_object.h b/include/cborcpp/cbor_object.h index fcb0b2e..cd51140 100644 --- a/include/cborcpp/cbor_object.h +++ b/include/cborcpp/cbor_object.h @@ -47,7 +47,7 @@ namespace cbor { template const T& as() const { - return boost::get(value); + return boost::get(value); } inline bool is_null() const { @@ -83,16 +83,16 @@ namespace cbor { inline CborObjectType object_type() const { return type; } - inline CborBoolValue as_bool() const { + inline const CborBoolValue& as_bool() const { return as(); } - inline CborIntValue as_int() const { + inline const CborIntValue& as_int() const { return as(); } - inline CborTagValue as_tag() const { + inline const CborTagValue& as_tag() const { return as(); } - inline CborSpecialValue as_special() const { + inline const CborSpecialValue& as_special() const { return as(); } inline const CborBytesValue& as_bytes() const { @@ -123,4 +123,4 @@ namespace cbor { static CborObjectP from_extra_tag(uint64_t value); static CborObjectP from_extra_special(uint64_t value); }; -} \ No newline at end of file +} diff --git a/include/cborcpp/encoder.h b/include/cborcpp/encoder.h index 892df20..3155a96 100644 --- a/include/cborcpp/encoder.h +++ b/include/cborcpp/encoder.h @@ -19,6 +19,7 @@ #include "cborcpp/output.h" #include "cborcpp/cbor_object.h" #include +#include namespace cbor { class encoder { @@ -31,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); @@ -60,8 +61,8 @@ namespace cbor { 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); }; } diff --git a/src/cborcpp/decoder.cpp b/src/cborcpp/decoder.cpp index 73b01ff..f9c66b1 100644 --- a/src/cborcpp/decoder.cpp +++ b/src/cborcpp/decoder.cpp @@ -52,7 +52,7 @@ static void put_decoded_value(CborObjectP& result, std::vector& str } auto last = structures_stack[old_structures_stack_size - 1]; if (last->type == COT_ARRAY) { - auto& array_value = boost::get(last->value); + 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 @@ -67,7 +67,7 @@ static void put_decoded_value(CborObjectP& result, std::vector& str throw cbor_decode_exception("invalid map key type"); } const auto& key = boost::get(map_key_temp->value); - auto& map_value = boost::get(last->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 diff --git a/src/cborcpp/encoder.cpp b/src/cborcpp/encoder.cpp index 78a54b6..cefc531 100644 --- a/src/cborcpp/encoder.cpp +++ b/src/cborcpp/encoder.cpp @@ -28,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)); @@ -48,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)); @@ -78,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); } } @@ -210,4 +210,4 @@ void encoder::write_cbor_object(CborObjectP value) { throw cbor_encode_exception("invalid cbor object type"); } } -} \ No newline at end of file +}