diff --git a/native/V2StyxLib/modules/l5/CMakeLists.txt b/native/V2StyxLib/modules/l5/CMakeLists.txt index b295722c..a19cab26 100644 --- a/native/V2StyxLib/modules/l5/CMakeLists.txt +++ b/native/V2StyxLib/modules/l5/CMakeLists.txt @@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.22) if(BUILD_MODULE_L5) add_library(module_l5 STATIC src/BufferWriterImpl.cpp + src/BufferReaderImpl.cpp src/StyxMessage.cpp ) target_include_directories(module_l5 PUBLIC @@ -12,6 +13,7 @@ if(BUILD_MODULE_L5) add_executable(module_l5_tests test/test_BufferWriterImpl.cpp + test/test_BufferReaderImpl.cpp ) target_include_directories(module_l5_tests PRIVATE ./include/) target_link_libraries(module_l5_tests PRIVATE Catch2::Catch2WithMain module_l5) diff --git a/native/V2StyxLib/modules/l5/include/serialization/BufferReaderImpl.h b/native/V2StyxLib/modules/l5/include/serialization/BufferReaderImpl.h new file mode 100644 index 00000000..a3602439 --- /dev/null +++ b/native/V2StyxLib/modules/l5/include/serialization/BufferReaderImpl.h @@ -0,0 +1,18 @@ +#pragma once +#include "serialization/IBufferReader.h" + +class BufferReaderImpl : public IBufferReader { +private: + const StyxBuffer buffer; + Styx::Size position; + Styx::Size limit; +public: + BufferReaderImpl(const StyxBuffer &buf, Styx::Size size); + virtual ~BufferReaderImpl(); + uint8_t readUInt8() override; + uint16_t readUInt16() override; + uint32_t readUInt32() override; + uint64_t readUInt64() override; + StyxString readUTFString() override; + Styx::Size read(uint8_t* data, Styx::Size count) override; +}; diff --git a/native/V2StyxLib/modules/l5/include/serialization/IBufferReader.h b/native/V2StyxLib/modules/l5/include/serialization/IBufferReader.h new file mode 100644 index 00000000..c7640f34 --- /dev/null +++ b/native/V2StyxLib/modules/l5/include/serialization/IBufferReader.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include "data.h" + +class IBufferReader { +public: + virtual ~IBufferReader() = default; + virtual uint8_t readUInt8() = 0; + virtual uint16_t readUInt16() = 0; + virtual uint32_t readUInt32() = 0; + virtual uint64_t readUInt64() = 0; + virtual StyxString readUTFString() = 0; + virtual Styx::Size read(uint8_t* data, Styx::Size count) = 0; +}; \ No newline at end of file diff --git a/native/V2StyxLib/modules/l5/src/BufferReaderImpl.cpp b/native/V2StyxLib/modules/l5/src/BufferReaderImpl.cpp new file mode 100644 index 00000000..7f19295e --- /dev/null +++ b/native/V2StyxLib/modules/l5/src/BufferReaderImpl.cpp @@ -0,0 +1,92 @@ +#include "serialization/BufferReaderImpl.h" +#include + +BufferReaderImpl::BufferReaderImpl(const StyxBuffer &buf, Styx::Size size) + : buffer(buf), position(0), limit(size) +{ + if (buf == nullptr) { + throw std::invalid_argument("Buffer cannot be null"); + } +} + +BufferReaderImpl::~BufferReaderImpl() +{ + +} + +uint8_t BufferReaderImpl::readUInt8() +{ + if (position + sizeof(uint8_t) > limit) { + throw std::out_of_range("Buffer overflow"); + } + return buffer[position++]; +} + +uint16_t BufferReaderImpl::readUInt16() +{ + if (position + sizeof(uint16_t) > limit) { + throw std::out_of_range("Buffer overflow"); + } + uint16_t value = static_cast(buffer[position]) | + (static_cast(buffer[position + 1]) << 8); + position += sizeof(uint16_t); + return value; +} + +uint32_t BufferReaderImpl::readUInt32() +{ + if (position + sizeof(uint32_t) > limit) { + throw std::out_of_range("Buffer overflow"); + } + uint32_t value = static_cast(buffer[position]) | + (static_cast(buffer[position + 1]) << 8) | + (static_cast(buffer[position + 2]) << 16) | + (static_cast(buffer[position + 3]) << 24); + position += sizeof(uint32_t); + return value; +} + +uint64_t BufferReaderImpl::readUInt64() +{ + if (position + sizeof(uint64_t) > limit) { + throw std::out_of_range("Buffer overflow"); + } + uint64_t value = static_cast(buffer[position]) | + (static_cast(buffer[position + 1]) << 8) | + (static_cast(buffer[position + 2]) << 16) | + (static_cast(buffer[position + 3]) << 24) | + (static_cast(buffer[position + 4]) << 32) | + (static_cast(buffer[position + 5]) << 40) | + (static_cast(buffer[position + 6]) << 48) | + (static_cast(buffer[position + 7]) << 56); + position += sizeof(uint64_t); + return value; +} + +StyxString BufferReaderImpl::readUTFString() +{ + if (position + sizeof(uint16_t) > limit) { + throw std::out_of_range("Buffer overflow"); + } + uint16_t length = readUInt16(); + if (position + length > limit) { + throw std::out_of_range("Buffer overflow"); + } + StyxString result; + result.reserve(length); + for (uint16_t i = 0; i < length; ++i) { + result += static_cast(buffer[position++]); + } + return result; +} + +Styx::Size BufferReaderImpl::read(uint8_t* data, Styx::Size count) +{ + if (position + count > limit) { + throw std::out_of_range("Buffer overflow"); + } + for (Styx::Size i = 0; i < count; ++i) { + data[i] = buffer[position++]; + } + return count; +} \ No newline at end of file diff --git a/native/V2StyxLib/modules/l5/test/test_BufferReaderImpl.cpp b/native/V2StyxLib/modules/l5/test/test_BufferReaderImpl.cpp new file mode 100644 index 00000000..c83c3049 --- /dev/null +++ b/native/V2StyxLib/modules/l5/test/test_BufferReaderImpl.cpp @@ -0,0 +1,37 @@ +#include +#include "serialization/BufferReaderImpl.h" + +TEST_CASE("readUTFString", "[BufferReaderImpl]") { + uint8_t testData[] = {0x05, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G'}; + BufferReaderImpl impl(testData, sizeof(testData)); + REQUIRE("ABCDE" == impl.readUTFString()); +} + +TEST_CASE("readUInt8", "[BufferReaderImpl]") { + uint8_t testData[] = {0x05, 0x06}; + BufferReaderImpl impl(testData, sizeof(testData)); + REQUIRE(0x05 == impl.readUInt8()); + REQUIRE(0x06 == impl.readUInt8()); +} + +TEST_CASE("readUInt16", "[BufferReaderImpl]") { + uint8_t testData[] = {0x05, 0x06, 0x07, 0x08}; + BufferReaderImpl impl(testData, sizeof(testData)); + REQUIRE(0x0605 == impl.readUInt16()); + REQUIRE(0x0807 == impl.readUInt16()); +} + +TEST_CASE("readUInt32", "[BufferReaderImpl]") { + uint8_t testData[] = {0x05, 0x06, 0x07, 0x08, 0x10, 0x11, 0x12, 0x13}; + BufferReaderImpl impl(testData, sizeof(testData)); + REQUIRE(0x08070605 == impl.readUInt32()); + REQUIRE(0x13121110 == impl.readUInt32()); +} + +TEST_CASE("readUInt64", "[BufferReaderImpl]") { + uint8_t testData[] = {0x05, 0x06, 0x07, 0x08, 0x10, 0x11, 0x12, 0x13, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}; + BufferReaderImpl impl(testData, sizeof(testData)); + REQUIRE(0x1312111008070605ULL == impl.readUInt64()); + REQUIRE(0x2726252423222120ULL == impl.readUInt64()); +}