diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml new file mode 100644 index 0000000..38329de --- /dev/null +++ b/.github/workflows/cmake.yml @@ -0,0 +1,56 @@ +name: CMake + +on: [push] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally + # well on Windows or Mac. You can convert this to a matrix build if you need + # cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Download Conan package manager. + run: | + pwd + pip3 install wheel setuptools + pip3 install conan + export PATH=$PATH:/home/runner/.local/bin + echo $PATH + conan --version + ls + + - name: Create Build Environment + # Some projects don't allow in-source building, so create a separate build directory + # We'll use this as our working directory for all subsequent commands + run: cmake -E make_directory ${{github.workspace}}/build + + - name: Configure CMake + # Use a bash shell so we can use the same syntax for environment variable + # access regardless of the host operating system + shell: bash + working-directory: ${{github.workspace}}/build + # Note the current convention is to use the -S and -B options here to specify source + # and build directories, but this is only available with CMake 3.13 and higher. + # The CMake binaries on the Github Actions machines are (as of this writing) 3.12 + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build + working-directory: ${{github.workspace}}/build + shell: bash + # Execute the build. You can specify a specific target with "--target " + run: cmake --build . --config $BUILD_TYPE + + - name: Test + working-directory: ${{github.workspace}}/build + shell: bash + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest -C $BUILD_TYPE diff --git a/.gitignore b/.gitignore index 4d6824c..1f84a48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .idea/ *.xcodeproj/ *.dSYM -test + diff --git a/CMakeLists.txt b/CMakeLists.txt index d50f799..9c26096 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,41 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.15) project(cborcpp) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +include(cmake/StandardProjectSettings.cmake) + +# Link this 'library' to set the c++ standard / compile-time options requested +add_library(project_options INTERFACE) +target_compile_features(project_options INTERFACE cxx_std_14) + +# Link this 'library' to use the warnings specified in CompilerWarnings.cmake +add_library(project_warnings INTERFACE) +# standard compiler warnings +include(cmake/CompilerWarnings.cmake) +set_project_warnings(project_warnings) + set(CMAKE_BUILD_TYPE Release) +set(EXPORT_COMPILE_COMMANDS ON) +option(BUILD_SHARED_LIBS "Enable compilation of shared libraries" OFF) + +# Set up some extra Conan dependencies based on our needs before loading Conan +set(CONAN_EXTRA_REQUIRES "") +set(CONAN_EXTRA_OPTIONS "") +include(cmake/Conan.cmake) +run_conan() + set(SOURCE_FILES src/encoder.cpp src/decoder.cpp src/input.cpp src/listener_debug.cpp - src/output_dynamic.cpp - src/output_static.cpp - ) - -set(TEST_SOURCE_FILES - src/tests.cpp + src/output.cpp ) add_library(cborcpp SHARED ${SOURCE_FILES}) -add_executable(testing ${SOURCE_FILES} ${TEST_SOURCE_FILES}) +target_link_libraries(cborcpp INTERFACE project_options) +target_include_directories(cborcpp PUBLIC src) +set_property(TARGET cborcpp PROPERTY CXX_STANDARD 14) + +enable_testing() +add_subdirectory(test) \ No newline at end of file diff --git a/src/LICENSE b/LICENSE similarity index 100% rename from src/LICENSE rename to LICENSE diff --git a/README.md b/README.md index 015cad3..f182a36 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ cbor-cpp [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/naphaso/cbor-cpp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +![cmake](https://github.com/Magolves/cbor-cpp/actions/workflows/cmake.yml/badge.svg) + CBOR C++ serialization library Just a simple SAX-like Concise Binary Object Representation (CBOR). diff --git a/cmake/Cache.cmake b/cmake/Cache.cmake new file mode 100644 index 0000000..31f5e7e --- /dev/null +++ b/cmake/Cache.cmake @@ -0,0 +1,29 @@ +option(ENABLE_CACHE "Enable cache if available" ON) +if(NOT ENABLE_CACHE) + return() +endif() + +set(CACHE_OPTION + "ccache" + CACHE STRING "Compiler cache to be used") +set(CACHE_OPTION_VALUES "ccache" "sccache") +set_property(CACHE CACHE_OPTION PROPERTY STRINGS ${CACHE_OPTION_VALUES}) +list( + FIND + CACHE_OPTION_VALUES + ${CACHE_OPTION} + CACHE_OPTION_INDEX) + +if(${CACHE_OPTION_INDEX} EQUAL -1) + message( + STATUS + "Using custom compiler cache system: '${CACHE_OPTION}', explicitly supported entries are ${CACHE_OPTION_VALUES}") +endif() + +find_program(CACHE_BINARY ${CACHE_OPTION}) +if(CACHE_BINARY) + message(STATUS "${CACHE_OPTION} found and enabled") + set(CMAKE_CXX_COMPILER_LAUNCHER ${CACHE_BINARY}) +else() + message(WARNING "${CACHE_OPTION} is enabled but was not found. Not using it") +endif() diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake new file mode 100644 index 0000000..8243154 --- /dev/null +++ b/cmake/CompilerWarnings.cmake @@ -0,0 +1,78 @@ +# from here: +# +# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md + +function(set_project_warnings project_name) + option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" TRUE) + + set(MSVC_WARNINGS + /W4 # Baseline reasonable warnings + /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data + /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /w14263 # 'function': member function does not override any base class virtual member function + /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not + # be destructed correctly + /w14287 # 'operator': unsigned/negative constant mismatch + /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside + # the for-loop scope + /w14296 # 'operator': expression is always 'boolean_value' + /w14311 # 'variable': pointer truncation from 'type1' to 'type2' + /w14545 # expression before comma evaluates to a function which is missing an argument list + /w14546 # function call before comma missing argument list + /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect + /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? + /w14555 # expression has no effect; expected expression with side- effect + /w14619 # pragma warning: there is no warning number 'number' + /w14640 # Enable warning on thread un-safe static member initialization + /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior. + /w14905 # wide string literal cast to 'LPSTR' + /w14906 # string literal cast to 'LPWSTR' + /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied + /permissive- # standards conformance mode for MSVC compiler. + ) + + set(CLANG_WARNINGS + -Wall + -Wextra # reasonable and standard + -Wshadow # warn the user if a variable declaration shadows one from a parent context + -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps + # catch hard to track down memory errors + -Wold-style-cast # warn for c-style casts + -Wcast-align # warn for potential performance problem casts + -Wunused # warn on anything being unused + -Woverloaded-virtual # warn if you overload (not override) a virtual function + -Wpedantic # warn if non-standard C++ is used + -Wconversion # warn on type conversions that may lose data + -Wsign-conversion # warn on sign conversions + -Wnull-dereference # warn if a null dereference is detected + -Wdouble-promotion # warn if float is implicit promoted to double + -Wformat=2 # warn on security issues around functions that format output (ie printf) + ) + + if(WARNINGS_AS_ERRORS) + set(CLANG_WARNINGS ${CLANG_WARNINGS} -Werror) + set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX) + endif() + + set(GCC_WARNINGS + ${CLANG_WARNINGS} + -Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist + -Wduplicated-cond # warn if if / else chain has duplicated conditions + -Wduplicated-branches # warn if if / else branches have duplicated code + -Wlogical-op # warn about logical operations being used where bitwise were probably wanted + -Wuseless-cast # warn if you perform a cast to the same type + ) + + if(MSVC) + set(PROJECT_WARNINGS ${MSVC_WARNINGS}) + elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(PROJECT_WARNINGS ${CLANG_WARNINGS}) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(PROJECT_WARNINGS ${GCC_WARNINGS}) + else() + message(AUTHOR_WARNING "No compiler warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.") + endif() + + target_compile_options(${project_name} INTERFACE ${PROJECT_WARNINGS}) + +endfunction() diff --git a/cmake/Conan.cmake b/cmake/Conan.cmake new file mode 100644 index 0000000..fc91b65 --- /dev/null +++ b/cmake/Conan.cmake @@ -0,0 +1,29 @@ +macro(run_conan) + # Download automatically, you can also just copy the conan.cmake file + if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") + message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") + file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.15/conan.cmake" "${CMAKE_BINARY_DIR}/conan.cmake") + endif() + + include(${CMAKE_BINARY_DIR}/conan.cmake) + + conan_add_remote( + NAME + bincrafters + URL + https://api.bintray.com/conan/bincrafters/public-conan) + + conan_cmake_run( + REQUIRES + ${CONAN_EXTRA_REQUIRES} + catch2/2.13.3 + #docopt.cpp/0.6.2 + #fmt/6.2.0 + #spdlog/1.5.0 + OPTIONS + ${CONAN_EXTRA_OPTIONS} + BASIC_SETUP + CMAKE_TARGETS # individual targets to link to + BUILD + missing) +endmacro() diff --git a/cmake/Doxygen.cmake b/cmake/Doxygen.cmake new file mode 100644 index 0000000..4dad807 --- /dev/null +++ b/cmake/Doxygen.cmake @@ -0,0 +1,11 @@ +function(enable_doxygen) + option(ENABLE_DOXYGEN "Enable doxygen doc builds of source" OFF) + if(ENABLE_DOXYGEN) + set(DOXYGEN_CALLER_GRAPH YES) + set(DOXYGEN_CALL_GRAPH YES) + set(DOXYGEN_EXTRACT_ALL YES) + find_package(Doxygen REQUIRED dot) + doxygen_add_docs(doxygen-docs ${PROJECT_SOURCE_DIR}) + + endif() +endfunction() diff --git a/cmake/PreventInSourceBuilds.cmake b/cmake/PreventInSourceBuilds.cmake new file mode 100644 index 0000000..57d9c59 --- /dev/null +++ b/cmake/PreventInSourceBuilds.cmake @@ -0,0 +1,18 @@ +# +# This function will prevent in-source builds +function(AssureOutOfSourceBuilds) + # make sure the user doesn't play dirty with symlinks + get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) + get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) + + # disallow in-source builds + if("${srcdir}" STREQUAL "${bindir}") + message("######################################################") + message("Warning: in-source builds are disabled") + message("Please create a separate build directory and run cmake from there") + message("######################################################") + message(FATAL_ERROR "Quitting configuration") + endif() +endfunction() + +assureoutofsourcebuilds() diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake new file mode 100644 index 0000000..6c6ff8f --- /dev/null +++ b/cmake/Sanitizers.cmake @@ -0,0 +1,66 @@ +function(enable_sanitizers project_name) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" FALSE) + + if(ENABLE_COVERAGE) + target_compile_options(${project_name} INTERFACE --coverage -O0 -g) + target_link_libraries(${project_name} INTERFACE --coverage) + endif() + + set(SANITIZERS "") + + option(ENABLE_SANITIZER_ADDRESS "Enable address sanitizer" FALSE) + if(ENABLE_SANITIZER_ADDRESS) + list(APPEND SANITIZERS "address") + endif() + + option(ENABLE_SANITIZER_LEAK "Enable leak sanitizer" FALSE) + if(ENABLE_SANITIZER_LEAK) + list(APPEND SANITIZERS "leak") + endif() + + option(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR "Enable undefined behavior sanitizer" FALSE) + if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) + list(APPEND SANITIZERS "undefined") + endif() + + option(ENABLE_SANITIZER_THREAD "Enable thread sanitizer" FALSE) + if(ENABLE_SANITIZER_THREAD) + if("address" IN_LIST SANITIZERS OR "leak" IN_LIST SANITIZERS) + message(WARNING "Thread sanitizer does not work with Address and Leak sanitizer enabled") + else() + list(APPEND SANITIZERS "thread") + endif() + endif() + + option(ENABLE_SANITIZER_MEMORY "Enable memory sanitizer" FALSE) + if(ENABLE_SANITIZER_MEMORY AND CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + if("address" IN_LIST SANITIZERS + OR "thread" IN_LIST SANITIZERS + OR "leak" IN_LIST SANITIZERS) + message(WARNING "Memory sanitizer does not work with Address, Thread and Leak sanitizer enabled") + else() + list(APPEND SANITIZERS "memory") + endif() + endif() + + list( + JOIN + SANITIZERS + "," + LIST_OF_SANITIZERS) + + endif() + + if(LIST_OF_SANITIZERS) + if(NOT + "${LIST_OF_SANITIZERS}" + STREQUAL + "") + target_compile_options(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + target_link_options(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + endif() + endif() + +endfunction() diff --git a/cmake/StandardProjectSettings.cmake b/cmake/StandardProjectSettings.cmake new file mode 100644 index 0000000..52e859a --- /dev/null +++ b/cmake/StandardProjectSettings.cmake @@ -0,0 +1,24 @@ +# Set a default build type if none was specified +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.") + set(CMAKE_BUILD_TYPE + RelWithDebInfo + CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui, ccmake + set_property( + CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "MinSizeRel" + "RelWithDebInfo") +endif() + +# Generate compile_commands.json to make it easier to work with clang based tools +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# On Mac OS 'CXX_STANDARD' is not evaluated +# Instead we have to set the compiler flag +if (APPLE) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") +endif() diff --git a/cmake/StaticAnalyzers.cmake b/cmake/StaticAnalyzers.cmake new file mode 100644 index 0000000..4396444 --- /dev/null +++ b/cmake/StaticAnalyzers.cmake @@ -0,0 +1,37 @@ +option(ENABLE_CPPCHECK "Enable static analysis with cppcheck" OFF) +option(ENABLE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF) +option(ENABLE_INCLUDE_WHAT_YOU_USE "Enable static analysis with include-what-you-use" OFF) + +if(ENABLE_CPPCHECK) + find_program(CPPCHECK cppcheck) + if(CPPCHECK) + set(CMAKE_CXX_CPPCHECK + ${CPPCHECK} + --suppress=missingInclude + --enable=all + --inline-suppr + --inconclusive + -i + ${CMAKE_SOURCE_DIR}/imgui/lib) + else() + message(SEND_ERROR "cppcheck requested but executable not found") + endif() +endif() + +if(ENABLE_CLANG_TIDY) + find_program(CLANGTIDY clang-tidy) + if(CLANGTIDY) + set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) + else() + message(SEND_ERROR "clang-tidy requested but executable not found") + endif() +endif() + +if(ENABLE_INCLUDE_WHAT_YOU_USE) + find_program(INCLUDE_WHAT_YOU_USE include-what-you-use) + if(INCLUDE_WHAT_YOU_USE) + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${INCLUDE_WHAT_YOU_USE}) + else() + message(SEND_ERROR "include-what-you-use requested but executable not found") + endif() +endif() diff --git a/src/cbor.h b/src/cbor.h index 7b79c30..aa5635a 100644 --- a/src/cbor.h +++ b/src/cbor.h @@ -14,15 +14,11 @@ limitations under the License. */ -#ifndef CBOR_CPP_CBOR_H -#define CBOR_CPP_CBOR_H +#pragma once #include "input.h" +#include "output.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/decoder.cpp b/src/decoder.cpp index 529821d..7f0cb91 100644 --- a/src/decoder.cpp +++ b/src/decoder.cpp @@ -15,409 +15,390 @@ */ #include "decoder.h" -#include "log.h" #include +#include using namespace cbor; -decoder::decoder(input &in) { - _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; -} - -void decoder::run() { +void decoder::run(input& input, listener& listener) { unsigned int temp; + int m_currentLength {}; + m_state = decoder_state::type; + while(1) { - if(_state == STATE_TYPE) { - if(_in->has_bytes(1)) { - unsigned char type = _in->get_byte(); - unsigned char majorType = type >> 5; - unsigned char minorType = (unsigned char) (type & 31); + if(m_state == decoder_state::type) { + if(input.has_bytes(1)) { + uint8_t type = input.get_byte(); + uint8_t majorType = type >> 5; + uint8_t minorType = (uint8_t) (type & 31); switch(majorType) { case 0: // positive integer if(minorType < 24) { - _listener->on_integer(minorType); + listener.on_integer(minorType); } else if(minorType == 24) { // 1 byte - _currentLength = 1; - _state = STATE_PINT; + m_currentLength = 1; + m_state = decoder_state::pint; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_PINT; + m_currentLength = 2; + m_state = decoder_state::pint; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_PINT; + m_currentLength = 4; + m_state = decoder_state::pint; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_PINT; + m_currentLength = 8; + m_state = decoder_state::pint; } else { - _state = STATE_ERROR; - _listener->on_error("invalid integer type"); + m_state = decoder_state::error; + listener.on_error("invalid integer type"); } break; case 1: // negative integer if(minorType < 24) { - _listener->on_integer(-1 -minorType); + listener.on_integer(-1 -minorType); } else if(minorType == 24) { // 1 byte - _currentLength = 1; - _state = STATE_NINT; + m_currentLength = 1; + m_state = decoder_state::nint; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_NINT; + m_currentLength = 2; + m_state = decoder_state::nint; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_NINT; + m_currentLength = 4; + m_state = decoder_state::nint; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_NINT; + m_currentLength = 8; + m_state = decoder_state::nint; } else { - _state = STATE_ERROR; - _listener->on_error("invalid integer type"); + m_state = decoder_state::error; + listener.on_error("invalid integer type"); } break; case 2: // bytes if(minorType < 24) { - _state = STATE_BYTES_DATA; - _currentLength = minorType; + m_state = decoder_state::bytes_data; + m_currentLength = minorType; } else if(minorType == 24) { - _state = STATE_BYTES_SIZE; - _currentLength = 1; + m_state = decoder_state::bytes_size; + m_currentLength = 1; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_BYTES_SIZE; + m_currentLength = 2; + m_state = decoder_state::bytes_size; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_BYTES_SIZE; + m_currentLength = 4; + m_state = decoder_state::bytes_size; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_BYTES_SIZE; + m_currentLength = 8; + m_state = decoder_state::bytes_size; } else { - _state = STATE_ERROR; - _listener->on_error("invalid bytes type"); + m_state = decoder_state::error; + listener.on_error("invalid bytes type"); } break; case 3: // string if(minorType < 24) { - _state = STATE_STRING_DATA; - _currentLength = minorType; + m_state = decoder_state::string_data; + m_currentLength = minorType; } else if(minorType == 24) { - _state = STATE_STRING_SIZE; - _currentLength = 1; + m_state = decoder_state::string_size; + m_currentLength = 1; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_STRING_SIZE; + m_currentLength = 2; + m_state = decoder_state::string_size; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_STRING_SIZE; + m_currentLength = 4; + m_state = decoder_state::string_size; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_STRING_SIZE; + m_currentLength = 8; + m_state = decoder_state::string_size; } else { - _state = STATE_ERROR; - _listener->on_error("invalid string type"); + m_state = decoder_state::error; + listener.on_error("invalid string type"); } break; case 4: // array if(minorType < 24) { - _listener->on_array(minorType); + listener.on_array(minorType); } else if(minorType == 24) { - _state = STATE_ARRAY; - _currentLength = 1; + m_state = decoder_state::array; + m_currentLength = 1; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_ARRAY; + m_currentLength = 2; + m_state = decoder_state::array; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_ARRAY; + m_currentLength = 4; + m_state = decoder_state::array; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_ARRAY; + m_currentLength = 8; + m_state = decoder_state::array; } else { - _state = STATE_ERROR; - _listener->on_error("invalid array type"); + m_state = decoder_state::error; + listener.on_error("invalid array type"); } break; case 5: // map if(minorType < 24) { - _listener->on_map(minorType); + listener.on_map(minorType); } else if(minorType == 24) { - _state = STATE_MAP; - _currentLength = 1; + m_state = decoder_state::map; + m_currentLength = 1; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_MAP; + m_currentLength = 2; + m_state = decoder_state::map; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_MAP; + m_currentLength = 4; + m_state = decoder_state::map; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_MAP; + m_currentLength = 8; + m_state = decoder_state::map; } else { - _state = STATE_ERROR; - _listener->on_error("invalid array type"); + m_state = decoder_state::error; + listener.on_error("invalid array type"); } break; case 6: // tag if(minorType < 24) { - _listener->on_tag(minorType); + listener.on_tag(minorType); } else if(minorType == 24) { - _state = STATE_TAG; - _currentLength = 1; + m_state = decoder_state::tag; + m_currentLength = 1; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_TAG; + m_currentLength = 2; + m_state = decoder_state::tag; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_TAG; + m_currentLength = 4; + m_state = decoder_state::tag; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_TAG; + m_currentLength = 8; + m_state = decoder_state::tag; } else { - _state = STATE_ERROR; - _listener->on_error("invalid tag type"); + m_state = decoder_state::error; + listener.on_error("invalid tag type"); } break; case 7: // special if (minorType < 20) { - _listener->on_special(minorType); + listener.on_special(minorType); } else if (minorType == 20) { - _listener->on_bool(false); + listener.on_bool(false); } else if (minorType == 21) { - _listener->on_bool(true); + listener.on_bool(true); } else if (minorType == 22) { - _listener->on_null(); + listener.on_null(); } else if (minorType == 23) { - _listener->on_undefined(); + listener.on_undefined(); } else if(minorType == 24) { - _state = STATE_SPECIAL; - _currentLength = 1; + m_state = decoder_state::special; + m_currentLength = 1; } else if(minorType == 25) { // 2 byte - _currentLength = 2; - _state = STATE_SPECIAL; + m_currentLength = 2; + m_state = decoder_state::special; } else if(minorType == 26) { // 4 byte - _currentLength = 4; - _state = STATE_SPECIAL; + m_currentLength = 4; + m_state = decoder_state::special; } else if(minorType == 27) { // 8 byte - _currentLength = 8; - _state = STATE_SPECIAL; + m_currentLength = 8; + m_state = decoder_state::special; } else { - _state = STATE_ERROR; - _listener->on_error("invalid special type"); + m_state = decoder_state::error; + listener.on_error("invalid special type"); } break; } } else break; - } else if(_state == STATE_PINT) { - if(_in->has_bytes(_currentLength)) { - switch(_currentLength) { + } else if(m_state == decoder_state::pint) { + if(input.has_bytes(m_currentLength)) { + switch(m_currentLength) { case 1: - _listener->on_integer(_in->get_byte()); - _state = STATE_TYPE; + listener.on_integer(input.get_byte()); + m_state = decoder_state::type; break; case 2: - _listener->on_integer(_in->get_short()); - _state = STATE_TYPE; + listener.on_integer(input.get_short()); + m_state = decoder_state::type; break; case 4: - temp = _in->get_int(); + temp = input.get_int(); if(temp <= INT_MAX) { - _listener->on_integer(temp); + listener.on_integer(temp); } else { - _listener->on_extra_integer(temp, 1); + listener.on_extra_integer(temp, 1); } - _state = STATE_TYPE; + m_state = decoder_state::type; break; case 8: - _listener->on_extra_integer(_in->get_long(), 1); - _state = STATE_TYPE; + listener.on_extra_integer(input.get_long(), 1); + m_state = decoder_state::type; break; } } else break; - } else if(_state == STATE_NINT) { - if(_in->has_bytes(_currentLength)) { - switch(_currentLength) { + } else if(m_state == decoder_state::nint) { + if(input.has_bytes(m_currentLength)) { + switch(m_currentLength) { case 1: - _listener->on_integer(-(int) _in->get_byte() - 1); - _state = STATE_TYPE; + listener.on_integer(-(int) input.get_byte() - 1); + m_state = decoder_state::type; break; case 2: - _listener->on_integer(-(int) _in->get_short() - 1); - _state = STATE_TYPE; + listener.on_integer(-(int) input.get_short() - 1); + m_state = decoder_state::type; break; case 4: - temp = _in->get_int(); + temp = input.get_int(); if(temp <= INT_MAX) { - _listener->on_integer(-(int) temp - 1); + listener.on_integer(-(int) temp - 1); } else { - _listener->on_extra_integer(temp + 1, -1); + listener.on_extra_integer(temp + 1, -1); } - _state = STATE_TYPE; + m_state = decoder_state::type; break; case 8: - _listener->on_extra_integer(_in->get_long() + 1, -1); + listener.on_extra_integer(input.get_long() + 1, -1); break; } } else break; - } else if(_state == STATE_BYTES_SIZE) { - if(_in->has_bytes(_currentLength)) { - switch(_currentLength) { + } else if(m_state == decoder_state::bytes_size) { + if(input.has_bytes(m_currentLength)) { + switch(m_currentLength) { case 1: - _currentLength = _in->get_byte(); - _state = STATE_BYTES_DATA; + m_currentLength = input.get_byte(); + m_state = decoder_state::bytes_data; break; case 2: - _currentLength = _in->get_short(); - _state = STATE_BYTES_DATA; + m_currentLength = input.get_short(); + m_state = decoder_state::bytes_data; break; case 4: - _currentLength = _in->get_int(); - _state = STATE_BYTES_DATA; + m_currentLength = input.get_int(); + m_state = decoder_state::bytes_data; break; case 8: - _state = STATE_ERROR; - _listener->on_error("extra long bytes"); + m_state = decoder_state::error; + listener.on_error("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); - _state = STATE_TYPE; - _listener->on_bytes(data, _currentLength); + } else if(m_state == decoder_state::bytes_data) { + if(input.has_bytes(m_currentLength)) { + auto data = input.get_bytes(m_currentLength); + m_state = decoder_state::type; + listener.on_bytes(data.data(), m_currentLength); } else break; - } else if(_state == STATE_STRING_SIZE) { - if(_in->has_bytes(_currentLength)) { - switch(_currentLength) { + } else if(m_state == decoder_state::string_size) { + if(input.has_bytes(m_currentLength)) { + switch(m_currentLength) { case 1: - _currentLength = _in->get_byte(); - _state = STATE_STRING_DATA; + m_currentLength = input.get_byte(); + m_state = decoder_state::string_data; break; case 2: - _currentLength = _in->get_short(); - _state = STATE_STRING_DATA; + m_currentLength = input.get_short(); + m_state = decoder_state::string_data; break; case 4: - _currentLength = _in->get_int(); - _state = STATE_STRING_DATA; + m_currentLength = input.get_int(); + m_state = decoder_state::string_data; break; case 8: - _state = STATE_ERROR; - _listener->on_error("extra long array"); + m_state = decoder_state::error; + listener.on_error("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); - _state = STATE_TYPE; - std::string str((const char *)data, (size_t)_currentLength); - _listener->on_string(str); + } else if(m_state == decoder_state::string_data) { + if(input.has_bytes(m_currentLength)) { + m_state = decoder_state::type; + listener.on_string(input.get_str(m_currentLength)); } else break; - } else if(_state == STATE_ARRAY) { - if(_in->has_bytes(_currentLength)) { - switch(_currentLength) { + } else if(m_state == decoder_state::array) { + if(input.has_bytes(m_currentLength)) { + switch(m_currentLength) { case 1: - _listener->on_array(_in->get_byte()); - _state = STATE_TYPE; + listener.on_array(input.get_byte()); + m_state = decoder_state::type; break; case 2: - _listener->on_array(_currentLength = _in->get_short()); - _state = STATE_TYPE; + listener.on_array(m_currentLength = input.get_short()); + m_state = decoder_state::type; break; case 4: - _listener->on_array(_in->get_int()); - _state = STATE_TYPE; + listener.on_array(input.get_int()); + m_state = decoder_state::type; break; case 8: - _state = STATE_ERROR; - _listener->on_error("extra long array"); + m_state = decoder_state::error; + listener.on_error("extra long array"); break; } } else break; - } else if(_state == STATE_MAP) { - if(_in->has_bytes(_currentLength)) { - switch(_currentLength) { + } else if(m_state == decoder_state::map) { + if(input.has_bytes(m_currentLength)) { + switch(m_currentLength) { case 1: - _listener->on_map(_in->get_byte()); - _state = STATE_TYPE; + listener.on_map(input.get_byte()); + m_state = decoder_state::type; break; case 2: - _listener->on_map(_currentLength = _in->get_short()); - _state = STATE_TYPE; + listener.on_map(m_currentLength = input.get_short()); + m_state = decoder_state::type; break; case 4: - _listener->on_map(_in->get_int()); - _state = STATE_TYPE; + listener.on_map(input.get_int()); + m_state = decoder_state::type; break; case 8: - _state = STATE_ERROR; - _listener->on_error("extra long map"); + m_state = decoder_state::error; + listener.on_error("extra long map"); break; } } else break; - } else if(_state == STATE_TAG) { - if(_in->has_bytes(_currentLength)) { - switch(_currentLength) { + } else if(m_state == decoder_state::tag) { + if(input.has_bytes(m_currentLength)) { + switch(m_currentLength) { case 1: - _listener->on_tag(_in->get_byte()); - _state = STATE_TYPE; + listener.on_tag(input.get_byte()); + m_state = decoder_state::type; break; case 2: - _listener->on_tag(_in->get_short()); - _state = STATE_TYPE; + listener.on_tag(input.get_short()); + m_state = decoder_state::type; break; case 4: - _listener->on_tag(_in->get_int()); - _state = STATE_TYPE; + listener.on_tag(input.get_int()); + m_state = decoder_state::type; break; case 8: - _listener->on_extra_tag(_in->get_long()); - _state = STATE_TYPE; + listener.on_extra_tag(input.get_long()); + m_state = decoder_state::type; break; } } else break; - } else if(_state == STATE_SPECIAL) { - if (_in->has_bytes(_currentLength)) { - switch (_currentLength) { + } else if(m_state == decoder_state::special) { + if (input.has_bytes(m_currentLength)) { + switch (m_currentLength) { case 1: - _listener->on_special(_in->get_byte()); - _state = STATE_TYPE; + listener.on_special(input.get_byte()); + m_state = decoder_state::type; break; case 2: - _listener->on_special(_in->get_short()); - _state = STATE_TYPE; + listener.on_special(input.get_short()); + m_state = decoder_state::type; break; case 4: - _listener->on_special(_in->get_int()); - _state = STATE_TYPE; + listener.on_special(input.get_int()); + m_state = decoder_state::type; break; case 8: - _listener->on_extra_special(_in->get_long()); - _state = STATE_TYPE; + listener.on_extra_special(input.get_long()); + m_state = decoder_state::type; break; } } else break; - } else if(_state == STATE_ERROR) { + } else if(m_state == decoder_state::error) { break; } else { - logger("UNKNOWN STATE"); + std::cerr << "UNKNOWN STATE"; + exit(2); } } } diff --git a/src/decoder.h b/src/decoder.h index 5dc1c53..ecd9ac1 100644 --- a/src/decoder.h +++ b/src/decoder.h @@ -15,42 +15,31 @@ */ -#ifndef __CborDecoder_H_ -#define __CborDecoder_H_ +#pragma once #include "listener.h" #include "input.h" namespace cbor { - typedef enum { - STATE_TYPE, - STATE_PINT, - STATE_NINT, - STATE_BYTES_SIZE, - STATE_BYTES_DATA, - STATE_STRING_SIZE, - STATE_STRING_DATA, - STATE_ARRAY, - STATE_MAP, - STATE_TAG, - STATE_SPECIAL, - STATE_ERROR - } decoder_state; - - class decoder { + + enum class decoder_state : uint8_t { + type, + pint, + nint, + bytes_size, + bytes_data, + string_size, + string_data, + array, + map, + tag, + special, + error + }; + + struct decoder { + void run(input& input, listener& listener); private: - 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); + decoder_state m_state; }; } - - -#endif //__CborDecoder_H_ diff --git a/src/encoder.cpp b/src/encoder.cpp index 529cfd0..019d204 100644 --- a/src/encoder.cpp +++ b/src/encoder.cpp @@ -20,7 +20,7 @@ using namespace cbor; encoder::encoder(output &out) { - _out = &out; + m_out = &out; } encoder::~encoder() { @@ -30,50 +30,50 @@ encoder::~encoder() { void encoder::write_type_value(int major_type, unsigned int value) { major_type <<= 5; if(value < 24) { - _out->put_byte((unsigned char) (major_type | value)); + m_out->put_byte((uint8_t) (major_type | value)); } else if(value < 256) { - _out->put_byte((unsigned char) (major_type | 24)); - _out->put_byte((unsigned char) value); + m_out->put_byte((uint8_t) (major_type | 24)); + m_out->put_byte((uint8_t) value); } else if(value < 65536) { - _out->put_byte((unsigned char) (major_type | 25)); - _out->put_byte((unsigned char) (value >> 8)); - _out->put_byte((unsigned char) value); + m_out->put_byte((uint8_t) (major_type | 25)); + m_out->put_byte((uint8_t) (value >> 8)); + m_out->put_byte((uint8_t) value); } else { - _out->put_byte((unsigned char) (major_type | 26)); - _out->put_byte((unsigned char) (value >> 24)); - _out->put_byte((unsigned char) (value >> 16)); - _out->put_byte((unsigned char) (value >> 8)); - _out->put_byte((unsigned char) value); + m_out->put_byte((uint8_t) (major_type | 26)); + m_out->put_byte((uint8_t) (value >> 24)); + m_out->put_byte((uint8_t) (value >> 16)); + m_out->put_byte((uint8_t) (value >> 8)); + m_out->put_byte((uint8_t) value); } } void encoder::write_type_value(int major_type, unsigned long long value) { major_type <<= 5; if(value < 24ULL) { - _out->put_byte((unsigned char) (major_type | value)); + m_out->put_byte((uint8_t) (major_type | value)); } else if(value < 256ULL) { - _out->put_byte((unsigned char) (major_type | 24)); - _out->put_byte((unsigned char) value); + m_out->put_byte((uint8_t) (major_type | 24)); + m_out->put_byte((uint8_t) value); } else if(value < 65536ULL) { - _out->put_byte((unsigned char) (major_type | 25)); - _out->put_byte((unsigned char) (value >> 8)); - _out->put_byte((unsigned char) value); + m_out->put_byte((uint8_t) (major_type | 25)); + m_out->put_byte((uint8_t) (value >> 8)); + m_out->put_byte((uint8_t) value); } else if(value < 4294967296ULL) { - _out->put_byte((unsigned char) (major_type | 26)); - _out->put_byte((unsigned char) (value >> 24)); - _out->put_byte((unsigned char) (value >> 16)); - _out->put_byte((unsigned char) (value >> 8)); - _out->put_byte((unsigned char) value); + m_out->put_byte((uint8_t) (major_type | 26)); + m_out->put_byte((uint8_t) (value >> 24)); + m_out->put_byte((uint8_t) (value >> 16)); + m_out->put_byte((uint8_t) (value >> 8)); + m_out->put_byte((uint8_t) value); } else { - _out->put_byte((unsigned char) (major_type | 27)); - _out->put_byte((unsigned char) (value >> 56)); - _out->put_byte((unsigned char) (value >> 48)); - _out->put_byte((unsigned char) (value >> 40)); - _out->put_byte((unsigned char) (value >> 32)); - _out->put_byte((unsigned char) (value >> 24)); - _out->put_byte((unsigned char) (value >> 16)); - _out->put_byte((unsigned char) (value >> 8)); - _out->put_byte((unsigned char) value); + m_out->put_byte((uint8_t) (major_type | 27)); + m_out->put_byte((uint8_t) (value >> 56)); + m_out->put_byte((uint8_t) (value >> 48)); + m_out->put_byte((uint8_t) (value >> 40)); + m_out->put_byte((uint8_t) (value >> 32)); + m_out->put_byte((uint8_t) (value >> 24)); + m_out->put_byte((uint8_t) (value >> 16)); + m_out->put_byte((uint8_t) (value >> 8)); + m_out->put_byte((uint8_t) value); } } @@ -103,39 +103,39 @@ void encoder::write_int(int value) { void encoder::write_float(float value) { void* punny = &value; - _out->put_byte((unsigned char) (7<<5) | 26); - _out->put_byte(*((uint8_t*) punny+3)); - _out->put_byte(*((uint8_t*) punny+2)); - _out->put_byte(*((uint8_t*) punny+1)); - _out->put_byte(*((uint8_t*) punny+0)); + m_out->put_byte((uint8_t) (7<<5) | 26); + m_out->put_byte(*((uint8_t*) punny+3)); + m_out->put_byte(*((uint8_t*) punny+2)); + m_out->put_byte(*((uint8_t*) punny+1)); + m_out->put_byte(*((uint8_t*) punny+0)); } void encoder::write_double(double value) { void* punny = &value; - _out->put_byte((unsigned char) (7<<5) | 27); - _out->put_byte(*((uint8_t*) punny+7)); - _out->put_byte(*((uint8_t*) punny+6)); - _out->put_byte(*((uint8_t*) punny+5)); - _out->put_byte(*((uint8_t*) punny+4)); - _out->put_byte(*((uint8_t*) punny+3)); - _out->put_byte(*((uint8_t*) punny+2)); - _out->put_byte(*((uint8_t*) punny+1)); - _out->put_byte(*((uint8_t*) punny+0)); -} - -void encoder::write_bytes(const unsigned char *data, unsigned int size) { + m_out->put_byte((uint8_t) (7<<5) | 27); + m_out->put_byte(*((uint8_t*) punny+7)); + m_out->put_byte(*((uint8_t*) punny+6)); + m_out->put_byte(*((uint8_t*) punny+5)); + m_out->put_byte(*((uint8_t*) punny+4)); + m_out->put_byte(*((uint8_t*) punny+3)); + m_out->put_byte(*((uint8_t*) punny+2)); + m_out->put_byte(*((uint8_t*) punny+1)); + m_out->put_byte(*((uint8_t*) punny+0)); +} + +void encoder::write_bytes(const uint8_t *data, unsigned int size) { write_type_value(2, size); - _out->put_bytes(data, size); + m_out->put_bytes(data, size); } void encoder::write_string(const char *data, unsigned int size) { write_type_value(3, size); - _out->put_bytes((const unsigned char *) data, size); + m_out->put_bytes((const uint8_t *) data, size); } void encoder::write_string(const std::string str) { write_type_value(3, (unsigned int) str.size()); - _out->put_bytes((const unsigned char *) str.c_str(), (int) str.size()); + m_out->put_bytes((const uint8_t *) str.c_str(), (int) str.size()); } @@ -157,16 +157,16 @@ void encoder::write_special(int special) { void encoder::write_bool(bool value) { if (value == true) { - _out->put_byte((unsigned char) 0xf5); + m_out->put_byte((uint8_t) 0xf5); } else { - _out->put_byte((unsigned char) 0xf4); + m_out->put_byte((uint8_t) 0xf4); } } void encoder::write_null() { - _out->put_byte((unsigned char) 0xf6); + m_out->put_byte((uint8_t) 0xf6); } void encoder::write_undefined() { - _out->put_byte((unsigned char) 0xf7); + m_out->put_byte((uint8_t) 0xf7); } diff --git a/src/encoder.h b/src/encoder.h index 6b41e1a..4937926 100644 --- a/src/encoder.h +++ b/src/encoder.h @@ -15,8 +15,7 @@ */ -#ifndef __CborEncoder_H_ -#define __CborEncoder_H_ +#pragma once #include "output.h" #include @@ -24,9 +23,9 @@ namespace cbor { class encoder { private: - output *_out; + output *m_out; public: - encoder(output &out); + explicit encoder(output &out); ~encoder(); @@ -40,7 +39,7 @@ namespace cbor { void write_int(unsigned long long value); - void write_bytes(const unsigned char *data, unsigned int size); + void write_bytes(const uint8_t *data, unsigned int size); void write_string(const char *data, unsigned int size); @@ -68,5 +67,3 @@ namespace cbor { void write_type_value(int major_type, unsigned long long value); }; } - -#endif //__CborEncoder_H_ diff --git a/src/input.cpp b/src/input.cpp index ffd75df..a5a4f94 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -19,80 +19,84 @@ #include #include #include +#include +#include using namespace cbor; -input::input(void *data, int size) { - _data = (unsigned char *)data; - _size = size; - _offset = 0; -} - -input::~input() { - -} - bool input::has_bytes(int count) { - return _size - _offset >= count; + return m_data.size() - m_offset >= count; } -unsigned char input::get_byte() { - return _data[_offset++]; +uint8_t input::get_byte() { + return m_data[m_offset++]; } unsigned short input::get_short() { - unsigned short value = ((unsigned short) _data[_offset] << 8) | ((unsigned short) _data[_offset + 1]); - _offset += 2; + unsigned short value = ((unsigned short) m_data[m_offset] << 8) | ((unsigned short) m_data[m_offset + 1]); + m_offset += 2; return value; } unsigned int input::get_int() { unsigned int value = \ - ((unsigned int) _data[_offset ] << 24) | - ((unsigned int) _data[_offset + 1] << 16) | - ((unsigned int) _data[_offset + 2] << 8 ) | - ((unsigned int) _data[_offset + 3]); - _offset += 4; + ((unsigned int) m_data[m_offset ] << 24) | + ((unsigned int) m_data[m_offset + 1] << 16) | + ((unsigned int) m_data[m_offset + 2] << 8 ) | + ((unsigned int) m_data[m_offset + 3]); + m_offset += 4; return value; } float input::get_float() { uint8_t value[4] = { - _data[_offset + 3], - _data[_offset + 2], - _data[_offset + 1], - _data[_offset + 0] + m_data[m_offset + 3], + m_data[m_offset + 2], + m_data[m_offset + 1], + m_data[m_offset + 0] }; - _offset += 4; + m_offset += 4; return *((float*) (&value[0])); } double input::get_double() { double ret; uint8_t* ptr = (uint8_t*)(void*) &ret; - *(ptr + 0) = _data[_offset + 7]; - *(ptr + 1) = _data[_offset + 6]; - *(ptr + 2) = _data[_offset + 5]; - *(ptr + 3) = _data[_offset + 4]; - *(ptr + 4) = _data[_offset + 3]; - *(ptr + 5) = _data[_offset + 2]; - *(ptr + 6) = _data[_offset + 1]; - *(ptr + 7) = _data[_offset + 0]; - _offset += 8; + *(ptr + 0) = m_data[m_offset + 7]; + *(ptr + 1) = m_data[m_offset + 6]; + *(ptr + 2) = m_data[m_offset + 5]; + *(ptr + 3) = m_data[m_offset + 4]; + *(ptr + 4) = m_data[m_offset + 3]; + *(ptr + 5) = m_data[m_offset + 2]; + *(ptr + 6) = m_data[m_offset + 1]; + *(ptr + 7) = m_data[m_offset + 0]; + m_offset += 8; return ret; } unsigned long long input::get_long() { - unsigned long long value = ((unsigned long long) _data[_offset] << 56) | - ((unsigned long long) _data[_offset +1] << 48) | ((unsigned long long) _data[_offset +2] << 40) | - ((unsigned long long) _data[_offset +3] << 32) | ((unsigned long long) _data[_offset +4] << 24) | - ((unsigned long long) _data[_offset +5] << 16) | ((unsigned long long) _data[_offset +6] << 8 ) | - ((unsigned long long) _data[_offset +7]); - _offset += 8; + unsigned long long value = ((unsigned long long) m_data[m_offset] << 56) | + ((unsigned long long) m_data[m_offset +1] << 48) | ((unsigned long long) m_data[m_offset +2] << 40) | + ((unsigned long long) m_data[m_offset +3] << 32) | ((unsigned long long) m_data[m_offset +4] << 24) | + ((unsigned long long) m_data[m_offset +5] << 16) | ((unsigned long long) m_data[m_offset +6] << 8 ) | + ((unsigned long long) m_data[m_offset +7]); + m_offset += 8; return value; } -void input::get_bytes(void *to, int count) { - memcpy(to, _data + _offset, count); - _offset += count; +std::vector input::get_bytes(int count) { + auto start = m_data.begin() + m_offset; + return std::vector(start, start + count); } + +std::string input::get_str(int count) { + std::stringstream ss; + auto begin = m_data.begin() + m_offset; + auto end = m_data.begin() + m_offset + count; + for(auto it = begin; it != m_data.end() && it != end; it++) { + ss << *it; + m_offset++; + } + + return ss.str(); +} \ No newline at end of file diff --git a/src/input.h b/src/input.h index 6cda2be..8a9fe47 100644 --- a/src/input.h +++ b/src/input.h @@ -14,23 +14,21 @@ limitations under the License. */ -#ifndef CBOR_CPP_INPUT_H -#define CBOR_CPP_INPUT_H +#pragma once + +#include +#include +#include namespace cbor { - class input { - private: - unsigned char *_data; - int _size; - int _offset; - public: - input(void *data, int size); + - ~input(); + struct input { + explicit input(const std::vector& data) : m_data(data), m_offset(0) {} bool has_bytes(int count); - unsigned char get_byte(); + uint8_t get_byte(); unsigned short get_short(); @@ -40,8 +38,11 @@ namespace cbor { unsigned long long get_long(); - void get_bytes(void *to, int count); + std::vector get_bytes(int count); + + std::string get_str(int count); + private: + std::vector m_data{}; + size_t m_offset{}; }; } - -#endif // CBOR_CPP_INPUT_H diff --git a/src/listener.h b/src/listener.h index b25e0ca..647c1dd 100644 --- a/src/listener.h +++ b/src/listener.h @@ -7,56 +7,64 @@ 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. + 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 +#pragma once +#include #include namespace cbor { - class listener { - public: - virtual void on_integer(int value) = 0; - virtual void on_float32(float value) = 0; - virtual void on_double(double value) = 0; +struct listener { + virtual ~listener() = default; - virtual void on_bytes(unsigned char *data, int size) = 0; + virtual void on_integer(int ) const noexcept {} - virtual void on_string(std::string &str) = 0; + virtual void on_float32(float ) const noexcept {} + virtual void on_double(double ) const noexcept {} - virtual void on_array(int size) = 0; + virtual void on_bytes(uint8_t *, int ) const noexcept {} - virtual void on_map(int size) = 0; + virtual void on_string(const std::string &) const noexcept {} - virtual void on_tag(unsigned int tag) = 0; + virtual void on_array(int ) const noexcept {} - 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_map(int ) const noexcept {} - virtual void on_error(const char *error) = 0; + virtual void on_tag(unsigned int ) const noexcept {} - virtual void on_extra_integer(unsigned long long value, int sign) { - } + virtual void on_special(unsigned int ) const noexcept {} - virtual void on_extra_tag(unsigned long long tag) { - } + virtual void on_bool(bool) const noexcept {} - virtual void on_extra_special(unsigned long long tag) { - } - }; + virtual void on_null() const noexcept {} + + virtual void on_undefined() const noexcept {} + + virtual void on_error(const char *) const noexcept {} + + virtual void on_extra_integer(unsigned long long , + int ) const noexcept {} + + virtual void on_extra_tag(unsigned long long) const noexcept {} + + virtual void on_extra_special(unsigned long long) const noexcept {} + +protected: +}; + +template inline void p(const std::string &tag, const T &value) { + std::cout << "[" << tag << sizeof(T) << " = " << value << "]\n"; } +template <> inline void p(const std::string &tag, const std::string &value) { + std::cout << "[" << tag << value.length() << " = '" << value << "']\n"; +} -#endif // CBOR_CPP_LISTENER_H +} // namespace cbor diff --git a/src/listener_debug.cpp b/src/listener_debug.cpp index 5b79b74..c475e9f 100644 --- a/src/listener_debug.cpp +++ b/src/listener_debug.cpp @@ -18,62 +18,63 @@ using namespace cbor; -void listener_debug::on_integer(int value) { - printf("integer: %d\n", value); +void listener_debug::on_integer(int value) const noexcept { + p("i", value); } -void listener_debug::on_bytes(unsigned char *data, int size) { - printf("bytes with size: %d", size); +void listener_debug::on_bytes(uint8_t *data, int size) const noexcept { + p("b", data); + p("len", size); } -void listener_debug::on_string(std::string &str) { - printf("string: '%.*s'\n", (int)str.size(), str.c_str()); +void listener_debug::on_string(const std::string &str) const noexcept { + p("s", str); } -void listener_debug::on_array(int size) { - printf("array: %d\n", size); +void listener_debug::on_array(int size) const noexcept { + p("array n", size); } -void listener_debug::on_map(int size) { - printf("map: %d\n", size); +void listener_debug::on_map(int size) const noexcept { + p("map", size); } -void listener_debug::on_tag(unsigned int tag) { - printf("tag: %d\n", tag); +void listener_debug::on_tag(unsigned int tag) const noexcept { + p("t", tag); } -void listener_debug::on_special(unsigned int code) { - printf("special: %d\n", code); +void listener_debug::on_special(unsigned int code) const noexcept { + p("spc", code); } -void listener_debug::on_bool(bool value) { - printf("bool: %s\n", value ? "true" : "false"); +void listener_debug::on_bool(bool value) const noexcept { + p("b", value); } -void listener_debug::on_null() { - printf("special: null\n"); +void listener_debug::on_null() const noexcept { + p("spc", "null"); } -void listener_debug::on_undefined() { - printf("special: undefined\n"); +void listener_debug::on_undefined() const noexcept { + p("spc", "undef"); } -void listener_debug::on_error(const char *error) { - printf("error: %s\n", error); +void listener_debug::on_error(const char *error) const noexcept { + p("err", error); } -void listener_debug::on_extra_integer(unsigned long long value, int sign) { +void listener_debug::on_extra_integer(unsigned long long value, int sign) const noexcept { if(sign >= 0) { - printf("extra integer: %llu\n", value); + p("exint", value); } else { - printf("extra integer: -%llu\n", value); + p("exint", -value); } } -void listener_debug::on_extra_tag(unsigned long long tag) { - printf("extra tag: %llu\n", tag); +void listener_debug::on_extra_tag(unsigned long long tag) const noexcept { + p("ext", tag); } -void listener_debug::on_extra_special(unsigned long long tag) { - printf("extra special: %llu\n", tag); +void listener_debug::on_extra_special(unsigned long long tag) const noexcept { + p("extspc", tag); } diff --git a/src/listener_debug.h b/src/listener_debug.h index b7d2b17..676045a 100644 --- a/src/listener_debug.h +++ b/src/listener_debug.h @@ -1,7 +1,7 @@ /* Copyright 2014-2015 Stanislav Ovsyannikov - Licensed under the Apache License, Version 2.0 (the "License"); + Licensed under the Apache License, Version 2.0 (the "License") const noexcept override; you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -14,8 +14,7 @@ limitations under the License. */ -#ifndef __listener_debug_H_ -#define __listener_debug_H_ +#pragma once #include @@ -24,34 +23,32 @@ namespace cbor { class listener_debug : public listener { public: - virtual void on_integer(int value); + virtual void on_integer(int value) const noexcept override; - virtual void on_bytes(unsigned char *data, int size); + virtual void on_bytes(uint8_t *data, int size) const noexcept override; - virtual void on_string(std::string &str); + virtual void on_string(const std::string &str) const noexcept override; - virtual void on_array(int size); + virtual void on_array(int size) const noexcept override; - virtual void on_map(int size); + virtual void on_map(int size) const noexcept override; - virtual void on_tag(unsigned int tag); + virtual void on_tag(unsigned int tag) const noexcept override; - virtual void on_special(unsigned int code); + virtual void on_special(unsigned int code) const noexcept override; - virtual void on_bool(bool); + virtual void on_bool(bool) const noexcept override; - virtual void on_null(); + virtual void on_null() const noexcept override; - virtual void on_undefined(); + virtual void on_undefined() const noexcept override; - virtual void on_error(const char *error); + virtual void on_error(const char *error) const noexcept override; - virtual void on_extra_integer(unsigned long long value, int sign); + virtual void on_extra_integer(unsigned long long value, int sign) const noexcept override; - virtual void on_extra_tag(unsigned long long tag); + virtual void on_extra_tag(unsigned long long tag) const noexcept override; - virtual void on_extra_special(unsigned long long tag); + virtual void on_extra_special(unsigned long long tag) const noexcept override; }; } - -#endif //__listener_debug_H_ diff --git a/src/log.h b/src/output.cpp similarity index 55% rename from src/log.h rename to src/output.cpp index 5f651df..e0df5a8 100644 --- a/src/log.h +++ b/src/output.cpp @@ -13,14 +13,31 @@ See the License for the specific language governing permissions and limitations under the License. */ - -#ifndef LOG_H_ -#define LOG_H_ -#include +#include "output.h" -#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__) +#include +#include -#endif +using namespace cbor; +output::output(unsigned int initalCapacity) : m_buffer(initalCapacity) { +} + +std::vector output::data() { + return m_buffer; +} + +size_t output::size() { + return m_buffer.size(); +} + +void output::put_byte(uint8_t value) { + m_buffer.push_back(value); +} + +void output::put_bytes(const uint8_t *data, int size) { + for(auto i = 0; i < size; i++) { + m_buffer.push_back(data[i]); + } +} diff --git a/src/output.h b/src/output.h index 0901d95..496b9a7 100644 --- a/src/output.h +++ b/src/output.h @@ -14,21 +14,28 @@ limitations under the License. */ +#pragma once -#ifndef __CborOutput_H_ -#define __CborOutput_H_ +#include +#include + +#include "output.h" namespace cbor { - class output { - public: - virtual unsigned char *data() = 0; + const int default_capacity = 256; + + struct output { + explicit output(unsigned int inital_capacity = default_capacity); + + std::vector data(); - virtual unsigned int size() = 0; + size_t size(); - virtual void put_byte(unsigned char value) = 0; + void put_byte(uint8_t value); - virtual void put_bytes(const unsigned char *data, int size) = 0; + void put_bytes(const uint8_t *data, int size); + + private: + std::vector m_buffer; }; } - -#endif //__CborOutput_H_ diff --git a/src/output_dynamic.cpp b/src/output_dynamic.cpp deleted file mode 100644 index 290b166..0000000 --- a/src/output_dynamic.cpp +++ /dev/null @@ -1,69 +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 "output_dynamic.h" - -#include -#include - -using namespace cbor; - - -void output_dynamic::init(unsigned int initalCapacity) { - this->_capacity = initalCapacity; - this->_buffer = new unsigned char[initalCapacity]; - this->_offset = 0; -} - -output_dynamic::output_dynamic() { - init(256); -} - -output_dynamic::output_dynamic(unsigned int inital_capacity) { - init(inital_capacity); -} - -output_dynamic::~output_dynamic() { - delete[] _buffer; -} - -unsigned char *output_dynamic::data() { - return _buffer; -} - -unsigned int output_dynamic::size() { - return _offset; -} - -void output_dynamic::put_byte(unsigned char value) { - if(_offset < _capacity) { - _buffer[_offset++] = value; - } else { - _capacity *= 2; - _buffer = (unsigned char *) realloc(_buffer, _capacity); - _buffer[_offset++] = value; - } -} - -void output_dynamic::put_bytes(const unsigned char *data, int size) { - while(_offset + size > _capacity) { - _capacity *= 2; - _buffer = (unsigned char *) realloc(_buffer, _capacity); - } - - memcpy(_buffer + _offset, data, size); - _offset += size; -} diff --git a/src/output_dynamic.h b/src/output_dynamic.h deleted file mode 100644 index 51c96e3..0000000 --- a/src/output_dynamic.h +++ /dev/null @@ -1,51 +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 __CborDynamicOutput_H_ -#define __CborDynamicOutput_H_ - - -#include "output.h" - -namespace cbor { - class output_dynamic : public output { - private: - unsigned char *_buffer; - unsigned int _capacity; - unsigned int _offset; - public: - output_dynamic(); - - output_dynamic(unsigned int inital_capacity); - - ~output_dynamic(); - - virtual unsigned char *data(); - - virtual unsigned int size(); - - virtual void put_byte(unsigned char value); - - virtual void put_bytes(const unsigned char *data, int size); - - private: - void init(unsigned int initalCapacity); - }; -} - - - -#endif //__CborDynamicOutput_H_ diff --git a/src/output_static.cpp b/src/output_static.cpp deleted file mode 100644 index 98bac71..0000000 --- a/src/output_static.cpp +++ /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. -*/ - -#include "output_static.h" -#include "log.h" - -#include - -using namespace cbor; - -output_static::output_static(unsigned int capacity) { - this->_capacity = capacity; - this->_buffer = new unsigned char[capacity]; - this->_offset = 0; -} - -output_static::~output_static() { - delete _buffer; -} - -void output_static::put_byte(unsigned char value) { - if(_offset < _capacity) { - _buffer[_offset++] = value; - } else { - logger("buffer overflow error"); - } -} - -void output_static::put_bytes(const unsigned char *data, int size) { - if(_offset + size - 1 < _capacity) { - memcpy(_buffer + _offset, data, size); - _offset += size; - } else { - logger("buffer overflow error"); - } -} - -unsigned char *output_static::getData() { - return _buffer; -} - -unsigned int output_static::getSize() { - return _offset; -} diff --git a/src/output_static.h b/src/output_static.h deleted file mode 100644 index 162ec0e..0000000 --- a/src/output_static.h +++ /dev/null @@ -1,44 +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 __CborStaticOutput_H_ -#define __CborStaticOutput_H_ - -#include "output.h" - -namespace cbor { - class output_static : public output { - private: - unsigned char *_buffer; - unsigned int _capacity; - unsigned int _offset; - public: - output_static(unsigned int capacity); - - ~output_static(); - - virtual unsigned char *getData(); - - virtual unsigned int getSize(); - - virtual void put_byte(unsigned char value); - - virtual void put_bytes(const unsigned char *data, int size); - }; -} - - -#endif //__CborStaticOutput_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..699a72b --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,13 @@ +# Automatically enable catch2 to generate ctest targets +if(CONAN_CATCH2_ROOT_DEBUG) + include(${CONAN_CATCH2_ROOT_DEBUG}/lib/cmake/Catch2/Catch.cmake) +else() + include(${CONAN_CATCH2_ROOT}/lib/cmake/Catch2/Catch.cmake) +endif() + +add_library(catch_main STATIC catch_main.cpp) +target_link_libraries(catch_main PUBLIC CONAN_PKG::catch2) +target_link_libraries(catch_main PRIVATE project_options) + +add_executable(tests tests.cpp) +target_link_libraries(tests PUBLIC cborcpp PRIVATE project_warnings project_options catch_main) diff --git a/test/catch_main.cpp b/test/catch_main.cpp new file mode 100644 index 0000000..d8d2eca --- /dev/null +++ b/test/catch_main.cpp @@ -0,0 +1,5 @@ +#define CATCH_CONFIG_MAIN // This tells the catch header to generate a main + +#include + + diff --git a/src/tests.cpp b/test/tests.cpp similarity index 88% rename from src/tests.cpp rename to test/tests.cpp index 0d0d768..de2faad 100644 --- a/src/tests.cpp +++ b/test/tests.cpp @@ -19,7 +19,7 @@ #include "cbor.h" int main() { - cbor::output_dynamic output; + cbor::output output; { //encoding cbor::encoder encoder(output); @@ -38,10 +38,10 @@ int main() { } { // decoding - cbor::input input(output.data(), output.size()); + cbor::input input(output.data()); cbor::listener_debug listener; - cbor::decoder decoder(input, listener); - decoder.run(); + cbor::decoder decoder; + decoder.run(input, listener); } return 0;