From ddcc74f1769688eb273f7c96693e8a13e3da8c94 Mon Sep 17 00:00:00 2001 From: OmniaX-Dev Date: Sun, 17 May 2026 14:36:33 +0200 Subject: [PATCH] Added new ostd::Serial class --- src/ostd/data/BaseObject.hpp | 2 +- src/ostd/io/Serial.cpp | 959 ++++------------------------------- src/ostd/io/Serial.hpp | 378 +++++++------- 3 files changed, 319 insertions(+), 1020 deletions(-) diff --git a/src/ostd/data/BaseObject.hpp b/src/ostd/data/BaseObject.hpp index 92a7c07..90bfbe0 100755 --- a/src/ostd/data/BaseObject.hpp +++ b/src/ostd/data/BaseObject.hpp @@ -27,7 +27,7 @@ namespace ostd { class OutputHandlerBase; struct Signal; - class BaseObject : public I_stringeable, public I_serializable + class BaseObject : public I_stringeable, public serial::I_serializable { public: using SignalCallback = std::function; public: diff --git a/src/ostd/io/Serial.cpp b/src/ostd/io/Serial.cpp index 08e3165..6ab46f1 100755 --- a/src/ostd/io/Serial.cpp +++ b/src/ostd/io/Serial.cpp @@ -1,21 +1,57 @@ #include "Serial.hpp" -#include "io/Memory.hpp" namespace ostd { - bool Serial::construct(u64 size, Serial::Endianness endianness, bool preInitialize, i8 initialValue) - { - m_address = 1; - return m_data.construct(size, endianness, preInitialize, initialValue); - } - - bool Serial::resetAddress(u64 newAddr) + bool Serial::StreamAccessor::resetAddress(u64 newAddr) { if (newAddr == 0) newAddr = 1; // Managed Address should never be 0, if the intent is to reset the managed address to the start of the Stream it will be set to 1 if (!isValidAddress(newAddr)) return false; m_address = newAddr; + m_addressBackupStored = false; + m_backupAddress = newAddr; + return true; + } + + u64& Serial::StreamAccessor::resolve_address(u64& addr) + { + if (addr == 0) + { + m_backupAddress = m_address; + m_addressBackupStored = true; + return m_address; + } + return addr; + } + + bool Serial::StreamAccessor::restore_address_and_return(bool passthrough) + { + if (!m_addressBackupStored || !m_addressRestoreEnabled) return passthrough; + resetAddress(m_backupAddress); + return passthrough; + } + + void Serial::StreamAccessor::clear_address_backup(void) + { + if (!m_addressRestoreEnabled) return; + m_addressBackupStored = false; + } + + + + + bool Serial::construct(u64 size, serial::Endianness endianness, bool preInitialize, i8 initialValue) + { + if (m_data.isValid()) return false; + if (!m_data.construct(size, endianness, preInitialize, initialValue)) + throw std::runtime_error("Serial::Stream::construct failed."); + write.data = m_data.data(); + read.data = m_data.data(); + write.resetAddress(); + read.resetAddress(); + write.clear_address_backup(); + read.clear_address_backup(); return true; } @@ -30,208 +66,41 @@ namespace ostd - - Serial::ReadResult Serial::Reader::int8(u64 _addr) - { - if (isInvalid()) return { 0, true }; - u64& addr = resolve_address(_addr); - if (!isValidAddress(addr, tTypeSize::INT8)) return { 0, true }; - i8 val = data[addr]; - addr += tTypeSize::INT8; - return { val, false }; - } - - Serial::ReadResult Serial::Reader::uint8(u64 _addr) - { - auto res = int8(_addr); - return { cast(res.value), res.error }; - } - - Serial::ReadResult Serial::Reader::int16(u64 _addr) - { - if (isInvalid()) return { 0, true }; - u64& addr = resolve_address(_addr); - if (!isValidAddress(addr, tTypeSize::INT16)) return { 0, true }; - i16 val = 0; - if (isLittleEndian()) - { - val = ((data[addr + 0] ) & 0x00FFU) - | ((data[addr + 1] << 8) & 0xFF00U); - } - else if (parent.isBigEndian()) - { - val = ((data[addr + 0] << 8) & 0xFF00U) - | ( data[addr + 1] & 0x00FFU); - } - else return { 0, true }; - addr += tTypeSize::INT16; - return { val, false }; - } - - Serial::ReadResult Serial::Reader::uint16(u64 _addr) - { - auto res = int16(_addr); - return { cast(res.value), res.error }; - } - - Serial::ReadResult Serial::Reader::int32(u64 _addr) - { - if (isInvalid()) return { 0, true }; - u64& addr = resolve_address(_addr); - if (!isValidAddress(addr, tTypeSize::INT32)) return { 0, true }; - i32 val = 0; - if (isLittleEndian()) - { - val = ((data[addr + 0] ) & 0x000000FF) - | ((data[addr + 1] << 8) & 0x0000FF00) - | ((data[addr + 2] << 16) & 0x00FF0000) - | ((data[addr + 3] << 24) & 0xFF000000); - } - else if (isBigEndian()) - { - val = ((data[addr + 0] << 24) & 0xFF000000U) - | ((data[addr + 1] << 16) & 0x00FF0000U) - | ((data[addr + 2] << 8) & 0x0000FF00U) - | ( data[addr + 3] & 0x000000FFU); - } - else return { 0, true }; - addr += tTypeSize::INT32; - return { val, false }; - } - - Serial::ReadResult Serial::Reader::uint32(u64 _addr) - { - auto res = int32(_addr); - return { cast(res.value), res.error }; - } - - Serial::ReadResult Serial::Reader::int64(u64 _addr) - { - if (isInvalid()) return { 0, true }; - u64& addr = resolve_address(_addr); - if (!isValidAddress(addr, tTypeSize::INT64)) return { 0, true }; - i64 val = 0; - if (isLittleEndian()) - { - val = ( data[addr + 7] & 0x00000000000000FFU) - | (( data[addr + 6] << 8) & 0x000000000000FF00U) - | (( data[addr + 5] << 16) & 0x0000000000FF0000U) - | (( data[addr + 4] << 24) & 0x00000000FF000000U) - | (((i64)data[addr + 3] << 32) & 0x000000FF00000000U) - | (((i64)data[addr + 2] << 40) & 0x0000FF0000000000U) - | (((i64)data[addr + 1] << 48) & 0x00FF000000000000U) - | (((i64)data[addr + 0] << 56) & 0xFF00000000000000U); - } - else if (isBigEndian()) - { - val = (((i64)data[addr + 0] << 56) & 0xFF00000000000000U) - | (((i64)data[addr + 1] << 48) & 0x00FF000000000000U) - | (((i64)data[addr + 2] << 40) & 0x0000FF0000000000U) - | (((i64)data[addr + 3] << 32) & 0x000000FF00000000U) - | (( data[addr + 4] << 24) & 0x00000000FF000000U) - | (( data[addr + 5] << 16) & 0x0000000000FF0000U) - | (( data[addr + 6] << 8) & 0x000000000000FF00U) - | ( data[addr + 7] & 0x00000000000000FFU); - } - else return { 0, true }; - addr += tTypeSize::INT64; - return { val, false }; - } - - Serial::ReadResult Serial::Reader::uint64(u64 _addr) - { - auto res = int64(_addr); - return { cast(res.value), res.error }; - } - - Serial::ReadResult Serial::Reader::float32(u64 _addr) - { - if (isInvalid()) return { 0, true }; - u64& addr = resolve_address(_addr); - if (!isValidAddress(addr, tTypeSize::FLOAT32)) return { 0, true }; - __float_parser fp; - if (isLittleEndian()) - { - fp.data[3] = data[addr + 0]; - fp.data[2] = data[addr + 1]; - fp.data[1] = data[addr + 2]; - fp.data[0] = data[addr + 3]; - } - else if (isBigEndian()) - { - fp.data[0] = data[addr + 0]; - fp.data[1] = data[addr + 1]; - fp.data[2] = data[addr + 2]; - fp.data[3] = data[addr + 3]; - } - else return { 0, true }; - addr += tTypeSize::FLOAT32; - return { fp.val, false }; - } - - Serial::ReadResult Serial::Reader::float64(u64 _addr) - { - if (isInvalid()) return { 0, true }; - u64& addr = resolve_address(_addr); - if (!isValidAddress(addr, tTypeSize::FLOAT64)) return { 0, true }; - __double_parser dp; - if (isLittleEndian()) - { - dp.data[7] = data[addr++]; - dp.data[6] = data[addr++]; - dp.data[5] = data[addr++]; - dp.data[4] = data[addr++]; - dp.data[3] = data[addr++]; - dp.data[2] = data[addr++]; - dp.data[1] = data[addr++]; - dp.data[0] = data[addr ]; - } - else if (isBigEndian()) - { - dp.data[0] = data[addr++]; - dp.data[1] = data[addr++]; - dp.data[2] = data[addr++]; - dp.data[3] = data[addr++]; - dp.data[4] = data[addr++]; - dp.data[5] = data[addr++]; - dp.data[6] = data[addr++]; - dp.data[7] = data[addr ]; - } - else return { 0, true }; - addr += tTypeSize::FLOAT64; - return { dp.val, false }; - } - bool Serial::Reader::stream(u64 _addr, Stream& outStream, bool sizeStored, u32 size_if_not_stored) { if (isInvalid()) return false; u64& addr = resolve_address(_addr); - if (!sizeStored && size_if_not_stored < 1) return false; + if (!sizeStored && size_if_not_stored < 1) return restore_address_and_return(false); u32 size = size_if_not_stored; if (sizeStored) { + disable_address_restore(); auto tmp = uint32(addr); - if (tmp.error) return false; + enable_address_restore(); + if (tmp.error) return restore_address_and_return(false); addr += tTypeSize::UINT32; size = tmp.value; } - Endianness endianness; + serial::Endianness endianness; { + disable_address_restore(); auto tmp = uint8(addr); - if (tmp.error) return false; + enable_address_restore(); + if (tmp.error) return restore_address_and_return(false); addr += tTypeSize::UINT8; - if (tmp.value == cast(Endianness::LittleEndian)) - endianness = Endianness::LittleEndian; - else if (tmp.value == cast(Endianness::BigEndian)) - endianness = Endianness::BigEndian; - else return false; + if (tmp.value == cast(serial::Endianness::LittleEndian)) + endianness = serial::Endianness::LittleEndian; + else if (tmp.value == cast(serial::Endianness::BigEndian)) + endianness = serial::Endianness::BigEndian; + else return restore_address_and_return(false); } - if (!isValidAddress(addr, size)) return false; + if (!isValidAddress(addr, size)) return restore_address_and_return(false); Serial::Stream _data = { size, endianness }; StreamEdit edit = _data.data(); std::copy_n(data.begin() + addr, size, edit.begin()); outStream = std::move(_data); addr += size; + clear_address_backup(); return true; } @@ -241,724 +110,120 @@ namespace ostd u64& addr = resolve_address(_addr); if (!null_terminated || sizeStored) // I want null_terminated to have the lowest priority { - if (!sizeStored && size_if_not_stored < 1) return false; + if (!sizeStored && size_if_not_stored < 1) return restore_address_and_return(false); u32 size = size_if_not_stored; if (sizeStored) { + disable_address_restore(); auto tmp = uint32(addr); - if (tmp.error) return false; + enable_address_restore(); + if (tmp.error) return restore_address_and_return(false); addr += tTypeSize::UINT32; size = tmp.value; } - if (!isValidAddress(addr, size)) return false; + if (size > 0 && !isValidAddress(addr, size)) return restore_address_and_return(false); + outString = ""; for (u64 i = addr; i < (addr + size); i++) { outString += cast(data[i]); } addr += size; + clear_address_backup(); return true; } else { String out = ""; + disable_address_restore(); auto tmp = int8(addr); - if (tmp.error) return false; + enable_address_restore(); + if (tmp.error) return restore_address_and_return(false); addr += tTypeSize::INT8; while (tmp.value != '\0') { out += cast(tmp.value); + disable_address_restore(); tmp = int8(addr); - if (tmp.error) return false; + enable_address_restore(); + if (tmp.error) return restore_address_and_return(false); addr += tTypeSize::INT8; } outString = out; + clear_address_backup(); return true; } } - bool Serial::Reader::object(I_serializable& outObject, u64 addr) + bool Serial::Reader::object(u64 _addr, serial::I_serializable& outObject) { - Serial::Stream objData(0); - if (!stream(objData, addr, true, 0)) + Serial::Stream objData; + if (!stream(_addr, objData, true, 0)) return false; return outObject.deserialize(objData); } - bool Serial::Writer::int8(u64 addr, i8 value) - { - if (!isStreamAttached()) return false; - managed_address_check(addr); - if (!isValidAddress(addr, tTypeSize::INT8)) return false; - s_openStream[addr] = value; - s_addr += tTypeSize::INT8; - return true; - } - bool Serial::Writer::uint8(u64 addr, u8 value) + bool Serial::Writer::stream(u64 _addr, const Stream& value, bool storeSize) { - return int8(addr, cast(value)); - } - - bool Serial::Writer::int16(u64 addr, i16 value) - { - if (!isStreamAttached()) return false; - managed_address_check(addr); - if (!isValidAddress(addr, tTypeSize::INT16)) return false; - if (isLittleEndian()) - { - s_openStream[addr + 0] = value & 0xFF; - s_openStream[addr + 1] = (value >> 8) & 0xFF; - } - else if (isBigEndian()) - { - s_openStream[addr + 0] = (value >> 8) & 0xFF; - s_openStream[addr + 1] = value & 0xFF; - } - else return false; - s_addr += tTypeSize::INT16; - return true; - } - - bool Serial::Writer::uint16(u64 addr, u16 value) - { - return int16(addr, cast(value)); - } - - bool Serial::Writer::int32(u64 addr, i32 value) - { - if (!isStreamAttached()) return false; - managed_address_check(addr); - if (!isValidAddress(addr, tTypeSize::INT32)) return false; - if (isLittleEndian()) - { - s_openStream[addr + 0] = value & 0xFF; - s_openStream[addr + 1] = (value >> 8) & 0xFF; - s_openStream[addr + 2] = (value >> 16) & 0xFF; - s_openStream[addr + 3] = (value >> 24) & 0xFF; - } - else if (isBigEndian()) - { - s_openStream[addr + 0] = (value >> 24) & 0xFF; - s_openStream[addr + 1] = (value >> 16) & 0xFF; - s_openStream[addr + 2] = (value >> 8) & 0xFF; - s_openStream[addr + 3] = value & 0xFF; - } - else return false; - s_addr += tTypeSize::INT32; - return true; - } - - bool Serial::Writer::uint32(u64 addr, u32 value) - { - return int32(addr, cast(value)); - } - - bool Serial::Writer::int64(u64 addr, i64 value) - { - if (!isStreamAttached()) return false; - managed_address_check(addr); - if (!isValidAddress(addr, tTypeSize::INT64)) return false; - if (isLittleEndian()) - { - s_openStream[addr + 0] = value & 0xFF; - s_openStream[addr + 1] = (value >> 8) & 0xFF; - s_openStream[addr + 2] = (value >> 16) & 0xFF; - s_openStream[addr + 3] = (value >> 24) & 0xFF; - s_openStream[addr + 4] = (value >> 32) & 0xFF; - s_openStream[addr + 5] = (value >> 40) & 0xFF; - s_openStream[addr + 6] = (value >> 48) & 0xFF; - s_openStream[addr + 7] = (value >> 56) & 0xFF; - } - else if (isBigEndian()) - { - s_openStream[addr + 0] = (value >> 56) & 0xFF; - s_openStream[addr + 1] = (value >> 48) & 0xFF; - s_openStream[addr + 2] = (value >> 40) & 0xFF; - s_openStream[addr + 3] = (value >> 32) & 0xFF; - s_openStream[addr + 4] = (value >> 24) & 0xFF; - s_openStream[addr + 5] = (value >> 16) & 0xFF; - s_openStream[addr + 6] = (value >> 8) & 0xFF; - s_openStream[addr + 7] = value & 0xFF; - } - else return false; - s_addr += tTypeSize::INT64; - return true; - } - - bool Serial::Writer::uint64(u64 addr, u64 value) - { - return int64(addr, cast(value)); - } - - bool Serial::Writer::float32(u64 addr, f32 value) - { - if (!isStreamAttached()) return false; - managed_address_check(addr); - if (!isValidAddress(addr, tTypeSize::FLOAT32)) return false; - __float_parser fp; - fp.val = value; - if (isLittleEndian()) - { - s_openStream[addr + 0] = fp.data[3]; - s_openStream[addr + 1] = fp.data[2]; - s_openStream[addr + 2] = fp.data[1]; - s_openStream[addr + 3] = fp.data[0]; - } - else if (isBigEndian()) - { - s_openStream[addr + 0] = fp.data[0]; - s_openStream[addr + 1] = fp.data[1]; - s_openStream[addr + 2] = fp.data[2]; - s_openStream[addr + 3] = fp.data[3]; - } - else return false; - s_addr += tTypeSize::FLOAT32; - return true; - } - - bool Serial::Writer::float64(u64 addr, f64 value) - { - if (!isStreamAttached()) return false; - managed_address_check(addr); - if (!isValidAddress(addr, tTypeSize::FLOAT64)) return false; - __double_parser dp; - dp.val = value; - if (isLittleEndian()) - { - s_openStream[addr++] = dp.data[7]; - s_openStream[addr++] = dp.data[6]; - s_openStream[addr++] = dp.data[5]; - s_openStream[addr++] = dp.data[4]; - s_openStream[addr++] = dp.data[3]; - s_openStream[addr++] = dp.data[2]; - s_openStream[addr++] = dp.data[1]; - s_openStream[addr ] = dp.data[0]; - } - else if (isBigEndian()) - { - s_openStream[addr++] = dp.data[0]; - s_openStream[addr++] = dp.data[1]; - s_openStream[addr++] = dp.data[2]; - s_openStream[addr++] = dp.data[3]; - s_openStream[addr++] = dp.data[4]; - s_openStream[addr++] = dp.data[5]; - s_openStream[addr++] = dp.data[6]; - s_openStream[addr ] = dp.data[7]; - } - else return false; - s_addr += tTypeSize::FLOAT64; - return true; - } - - bool Serial::Writer::stream(u64 addr, const Stream& value, bool storeSize) - { - if (!isStreamAttached()) return false; - managed_address_check(addr); + if (isInvalid()) return false; + u64& addr = resolve_address(_addr); u32 size = value.size(); - if (size < 1) return false; + if (size < 1) return restore_address_and_return(false); if (storeSize) { - if (!uint32(addr, size)) return false; + disable_address_restore(); + bool res = uint32(addr, size); + enable_address_restore(); + if (!res) return restore_address_and_return(false); addr += tTypeSize::UINT32; } - if (!isValidAddress(addr, size)) return false; + disable_address_restore(); + bool res = uint8(addr, cast(value.getEndianness())); + enable_address_restore(); + if (!res) + return restore_address_and_return(false); + addr += tTypeSize::UINT8; + if (!isValidAddress(addr, size)) return restore_address_and_return(false); StreamView view = value.data(); - for (u64 i = addr; i < addr + size; i++) - s_openStream[i] = view[i - addr]; - s_addr = addr + size; + std::copy_n(view.begin(), size, data.begin() + addr); + addr += size; + clear_address_backup(); return true; } - bool Serial::Writer::string(u64 addr, const String& value, bool storeSize, bool null_terminated) + bool Serial::Writer::string(u64 _addr, const String& value, bool storeSize, bool null_terminated) { - if (!isStreamAttached()) return false; - managed_address_check(addr); + if (isInvalid()) return false; + u64& addr = resolve_address(_addr); u32 size = value.len(); - if (size < 1) return false; if (storeSize) { null_terminated = false; - if (!uint32(addr, value.len())) return false; + disable_address_restore(); + bool res = uint32(addr, size); + enable_address_restore(); + if (!res) return restore_address_and_return(false); addr += tTypeSize::UINT32; } size += (null_terminated ? 1 : 0); - if (!isValidAddress(addr, size)) - return false; - for (u64 i = addr; i < addr + size; i++) - { - i8 c = cast(value[i - addr]); - if (null_terminated && i == addr + size - 1) - c = '\0'; - s_openStream[i] = c; - } - s_addr = addr + size; + if (size > 0 && !isValidAddress(addr, size)) + return restore_address_and_return(false); + for (u64 i = 0; i < value.len(); i++) + data[addr + i] = cast(value[i]); + if (null_terminated) + data[addr + value.len()] = '\0'; + addr += size; + clear_address_backup(); return true; } - bool Serial::Writer::object(u64 addr, const I_serializable& value) + bool Serial::Writer::object(u64 _addr, const serial::I_serializable& value) { - if (!isStreamAttached()) return false; + if (isInvalid()) return false; // Even though return stream(...) will check this again, this is here to avoid serializing for nothing, since it might be an expensive operation const Serial::Stream data = value.serialize(); if (data.size() < 1) return false; - return stream(addr, data, true); - } - - - - - - // =============================================== OLD VERSION =============================================== - namespace serial - { - bool SerialIO::init(u64 size, u8 endianness) - { - if (size < 1) return false; - for (u64 i = 0; i < size; i++) - m_data.push_back(0); - m_endianness = endianness; - return true; - } - - - bool SerialIO::r_QWord(StreamIndex addr, QWord& outVal) - { - if (!is_validAddr(addr, tTypeSize::QWORD)) return false; - if (isLittleEndian()) - { - outVal = ( m_data[addr + 7] & 0x00000000000000FFU) - | (( m_data[addr + 6] << 8) & 0x000000000000FF00U) - | (( m_data[addr + 5] << 16) & 0x0000000000FF0000U) - | (( m_data[addr + 4] << 24) & 0x00000000FF000000U) - | (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U) - | (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U) - | (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U) - | (((QWord)m_data[addr + 0] << 56) & 0xFF00000000000000U); - } - else if (isBigEndian()) - { - outVal = (((QWord)m_data[addr + 0] << 56) & 0xFF00000000000000U) - | (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U) - | (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U) - | (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U) - | (( m_data[addr + 4] << 24) & 0x00000000FF000000U) - | (( m_data[addr + 5] << 16) & 0x0000000000FF0000U) - | (( m_data[addr + 6] << 8) & 0x000000000000FF00U) - | ( m_data[addr + 7] & 0x00000000000000FFU); - } - else return false; - return true; - } - - bool SerialIO::r_DWord(StreamIndex addr, DWord& outVal) - { - if (!is_validAddr(addr, tTypeSize::DWORD)) return false; - if (isLittleEndian()) - { - outVal = ((m_data[addr + 0] ) & 0x000000FF) - | ((m_data[addr + 1] << 8) & 0x0000FF00) - | ((m_data[addr + 2] << 16) & 0x00FF0000) - | ((m_data[addr + 3] << 24) & 0xFF000000); - } - else if (isBigEndian()) - { - outVal = ((m_data[addr + 0] << 24) & 0xFF000000U) - | ((m_data[addr + 1] << 16) & 0x00FF0000U) - | ((m_data[addr + 2] << 8) & 0x0000FF00U) - | ( m_data[addr + 3] & 0x000000FFU); - } - else return false; - return true; - } - - bool SerialIO::r_Word(StreamIndex addr, Word& outVal) - { - if (!is_validAddr(addr, tTypeSize::WORD)) return false; - if (isLittleEndian()) - { - outVal = ((m_data[addr + 0] ) & 0x00FFU) - | ((m_data[addr + 1] << 8) & 0xFF00U); - } - else if (isBigEndian()) - { - outVal = ((m_data[addr + 0] << 8) & 0xFF00U) - | ( m_data[addr + 1] & 0x00FFU); - } - else return false; - return true; - } - - bool SerialIO::r_Byte(StreamIndex addr, Byte& outVal) - { - if (!is_validAddr(addr, tTypeSize::BYTE)) return false; - outVal = m_data[addr]; - return true; - } - - bool SerialIO::r_Addr(StreamIndex addr, StreamIndex& outVal) - { - if (!is_validAddr(addr, tTypeSize::ADDR)) return false; - if (isLittleEndian()) - { - outVal = ((m_data[addr + 0] ) & 0x000000FF) - | ((m_data[addr + 1] << 8) & 0x0000FF00) - | ((m_data[addr + 2] << 16) & 0x00FF0000) - | ((m_data[addr + 3] << 24) & 0xFF000000); - } - else if (isBigEndian()) - { - outVal = ((m_data[addr + 0] << 24) & 0xFF000000U) - | ((m_data[addr + 1] << 16) & 0x00FF0000U) - | ((m_data[addr + 2] << 8) & 0x0000FF00U) - | ( m_data[addr + 3] & 0x000000FFU); - } - else return false; - return true; - } - - bool SerialIO::r_Float(StreamIndex addr, f32& outVal) - { - if (!is_validAddr(addr, tTypeSize::FLOAT)) return false; - __float_parser fp; - if (isLittleEndian()) - { - fp.data[3] = m_data[addr + 0]; - fp.data[2] = m_data[addr + 1]; - fp.data[1] = m_data[addr + 2]; - fp.data[0] = m_data[addr + 3]; - } - else if (isBigEndian()) - { - fp.data[0] = m_data[addr + 0]; - fp.data[1] = m_data[addr + 1]; - fp.data[2] = m_data[addr + 2]; - fp.data[3] = m_data[addr + 3]; - } - else return false; - outVal = fp.val; - return true; - } - - bool SerialIO::r_Double(StreamIndex addr, f64& outVal) - { - if (!is_validAddr(addr, tTypeSize::DOUBLE)) return false; - __double_parser dp; - if (isLittleEndian()) - { - dp.data[7] = m_data[addr++]; - dp.data[6] = m_data[addr++]; - dp.data[5] = m_data[addr++]; - dp.data[4] = m_data[addr++]; - dp.data[3] = m_data[addr++]; - dp.data[2] = m_data[addr++]; - dp.data[1] = m_data[addr++]; - dp.data[0] = m_data[addr ]; - } - else if (isBigEndian()) - { - dp.data[0] = m_data[addr++]; - dp.data[1] = m_data[addr++]; - dp.data[2] = m_data[addr++]; - dp.data[3] = m_data[addr++]; - dp.data[4] = m_data[addr++]; - dp.data[5] = m_data[addr++]; - dp.data[6] = m_data[addr++]; - dp.data[7] = m_data[addr ]; - } - else return false; - outVal = dp.val; - return true; - } - - bool SerialIO::r_ByteStream(StreamIndex addr, ByteStream& outStream) - { - if (!is_validAddr(addr, tTypeSize::ADDR)) return false; - u32 stream_size; - if (!r_Addr(addr, stream_size)) return false; - addr += tTypeSize::ADDR; - if (!is_validAddr(addr, stream_size)) return false; - outStream.clear(); - outStream.reserve(stream_size); - for (StreamIndex j = addr; j < addr + stream_size; j++) - outStream.push_back(m_data[j]); - return true; - } - - bool SerialIO::r_ByteStream(StreamIndex addr, ByteStream& outStream, u32 size) - { - if (!is_validAddr(addr, size)) return false; - outStream.clear(); - outStream.reserve(size); - for (StreamIndex j = addr; j < addr + size; j++) - outStream.push_back(m_data[j]); - return true; - } - - bool SerialIO::r_String(StreamIndex addr, String& outString) - { - if (!is_validAddr(addr, tTypeSize::ADDR)) return false; - u32 stream_size; - if (!r_Addr(addr, stream_size)) return false; - addr += tTypeSize::ADDR; - if (!is_validAddr(addr, stream_size)) return false; - outString = ""; - for (StreamIndex j = addr; j < addr + stream_size; j++) - outString += (char)(m_data[j]); - return true; - } - - bool SerialIO::r_String(StreamIndex addr, String& outString, u32 size) - { - if (!is_validAddr(addr, size)) return false; - outString = ""; - for (StreamIndex j = addr; j < addr + size; j++) - outString += (char)(m_data[j]); - return true; - } - - bool SerialIO::r_NullTerminatedString(StreamIndex addr, String& outString) - { - outString = ""; - i8 c = 0; - if (!r_Byte(addr, c)) return false; - addr += tTypeSize::BYTE; - while (c != 0) - { - outString += (char)c; - if (!r_Byte(addr, c)) return false; - addr += tTypeSize::BYTE; - } - return true; - } - - - bool SerialIO::w_QWord(StreamIndex addr, QWord val) - { - m_statuWriting = true; - if (!is_validAddr(addr, tTypeSize::QWORD)) return false; - if (isLittleEndian()) - { - m_data[addr + 0] = val & 0xFF; - m_data[addr + 1] = (val >> 8) & 0xFF; - m_data[addr + 2] = (val >> 16) & 0xFF; - m_data[addr + 3] = (val >> 24) & 0xFF; - m_data[addr + 4] = (val >> 32) & 0xFF; - m_data[addr + 5] = (val >> 40) & 0xFF; - m_data[addr + 6] = (val >> 48) & 0xFF; - m_data[addr + 7] = (val >> 56) & 0xFF; - } - else if (isBigEndian()) - { - m_data[addr + 0] = (val >> 56) & 0xFF; - m_data[addr + 1] = (val >> 48) & 0xFF; - m_data[addr + 2] = (val >> 40) & 0xFF; - m_data[addr + 3] = (val >> 32) & 0xFF; - m_data[addr + 4] = (val >> 24) & 0xFF; - m_data[addr + 5] = (val >> 16) & 0xFF; - m_data[addr + 6] = (val >> 8) & 0xFF; - m_data[addr + 7] = val & 0xFF; - } - else return false; - return true; - } - - bool SerialIO::w_DWord(StreamIndex addr, DWord val) - { - m_statuWriting = true; - if (!is_validAddr(addr, tTypeSize::DWORD)) return false; - if (isLittleEndian()) - { - m_data[addr + 0] = val & 0xFF; - m_data[addr + 1] = (val >> 8) & 0xFF; - m_data[addr + 2] = (val >> 16) & 0xFF; - m_data[addr + 3] = (val >> 24) & 0xFF; - } - else if (isBigEndian()) - { - m_data[addr + 0] = (val >> 24) & 0xFF; - m_data[addr + 1] = (val >> 16) & 0xFF; - m_data[addr + 2] = (val >> 8) & 0xFF; - m_data[addr + 3] = val & 0xFF; - } - else return false; - return true; - } - - bool SerialIO::w_Word(StreamIndex addr, Word val) - { - m_statuWriting = true; - if (!is_validAddr(addr, tTypeSize::WORD)) return false; - if (isLittleEndian()) - { - m_data[addr + 0] = val & 0xFF; - m_data[addr + 1] = (val >> 8) & 0xFF; - } - else if (isBigEndian()) - { - m_data[addr + 0] = (val >> 8) & 0xFF; - m_data[addr + 1] = val & 0xFF; - } - else return false; - return true; - } - - bool SerialIO::w_Byte(StreamIndex addr, Byte val) - { - m_statuWriting = true; - if (!is_validAddr(addr, tTypeSize::BYTE)) return false; - m_data[addr] = val; - return true; - } - - bool SerialIO::w_Addr(StreamIndex addr, StreamIndex val) - { - m_statuWriting = true; - if (!is_validAddr(addr, tTypeSize::ADDR)) return false; - if (isLittleEndian()) - { - m_data[addr + 0] = val & 0xFF; - m_data[addr + 1] = (val >> 8) & 0xFF; - m_data[addr + 2] = (val >> 16) & 0xFF; - m_data[addr + 3] = (val >> 24) & 0xFF; - } - else if (isBigEndian()) - { - m_data[addr + 0] = (val >> 24) & 0xFF; - m_data[addr + 1] = (val >> 16) & 0xFF; - m_data[addr + 2] = (val >> 8) & 0xFF; - m_data[addr + 3] = val & 0xFF; - } - else return false; - return true; - } - - bool SerialIO::w_Float(StreamIndex addr, f32 val) - { - m_statuWriting = true; - if (!is_validAddr(addr, tTypeSize::FLOAT)) return false; - __float_parser fp; - fp.val = val; - if (isLittleEndian()) - { - m_data[addr + 0] = fp.data[3]; - m_data[addr + 1] = fp.data[2]; - m_data[addr + 2] = fp.data[1]; - m_data[addr + 3] = fp.data[0]; - } - else if (isBigEndian()) - { - m_data[addr + 0] = fp.data[0]; - m_data[addr + 1] = fp.data[1]; - m_data[addr + 2] = fp.data[2]; - m_data[addr + 3] = fp.data[3]; - } - else return false; - return true; - } - - bool SerialIO::w_Double(StreamIndex addr, f64 val) - { - m_statuWriting = true; - if (!is_validAddr(addr, tTypeSize::DOUBLE)) return false; - __double_parser dp; - dp.val = val; - if (isLittleEndian()) - { - m_data[addr++] = dp.data[7]; - m_data[addr++] = dp.data[6]; - m_data[addr++] = dp.data[5]; - m_data[addr++] = dp.data[4]; - m_data[addr++] = dp.data[3]; - m_data[addr++] = dp.data[2]; - m_data[addr++] = dp.data[1]; - m_data[addr ] = dp.data[0]; - } - else if (isBigEndian()) - { - m_data[addr++] = dp.data[0]; - m_data[addr++] = dp.data[1]; - m_data[addr++] = dp.data[2]; - m_data[addr++] = dp.data[3]; - m_data[addr++] = dp.data[4]; - m_data[addr++] = dp.data[5]; - m_data[addr++] = dp.data[6]; - m_data[addr ] = dp.data[7]; - } - else return false; - return true; - } - - bool SerialIO::w_ByteStream(StreamIndex addr, const ByteStream& stream, bool store_size) - { - m_statuWriting = true; - u32 stream_size = stream.size(); - if (store_size) - { - if (!is_validAddr(addr, tTypeSize::ADDR + stream_size)) return false; - if (!w_Addr(addr, stream_size)) return false; - addr += tTypeSize::ADDR; - } - else if (!is_validAddr(addr, stream_size)) return false; - for (StreamIndex j = addr; j < addr + stream_size; j++) - m_data[j] = stream[j - addr]; - return true; - } - - bool SerialIO::w_String(StreamIndex addr, const String& str, bool store_size, bool null_terminate) - { - m_statuWriting = true; - auto stream = Memory::stringToByteStream(str); - u32 stream_size = stream.size(); - if (store_size && !null_terminate) - { - if (!is_validAddr(addr, tTypeSize::ADDR + stream_size)) return false; - if (!w_Addr(addr, stream_size)) return false; - addr += tTypeSize::ADDR; - } - else if (!is_validAddr(addr, stream_size)) return false; - for (StreamIndex j = addr; j < addr + stream_size; j++) - m_data[j] = stream[j - addr]; - addr += str.len() * tTypeSize::BYTE; - if (null_terminate) - if (!w_Byte(addr, 0x00)) return false; - return true; - } - - - bool SerialIO::is_validAddr(StreamIndex addr, StreamIndex offset) - { - if ((addr + offset - 1) >= m_data.size()) - { - if (isAutoResizeEnabled() && m_statuWriting) - { - for (u32 i = 0; i <= m_resizeAmount; i++) - m_data.push_back(0); - m_statuWriting = false; - return true; - } - else - { - m_statuWriting = false; - return false; - } - } - m_statuWriting = false; - return true; - } - - void SerialIO::print(StreamIndex start, OutputHandlerBase& out) - { - u32 line_len = 32; - u64 power = 1; - while(power < size()) - power *= 2; - Memory::printByteStream(m_data, start, line_len, power / line_len, out); - } - - bool SerialIO::saveToFile(const String& filePath) - { - return Memory::saveByteStreamToFile(getData(), filePath); - } + return stream(_addr, data, true); } } diff --git a/src/ostd/io/Serial.hpp b/src/ostd/io/Serial.hpp index 2b37a98..d684096 100755 --- a/src/ostd/io/Serial.hpp +++ b/src/ostd/io/Serial.hpp @@ -25,11 +25,91 @@ namespace ostd { - class I_serializable; + namespace serial + { + enum class Endianness : u8 { LittleEndian = 0, BigEndian }; + + + // ============================================================ + // Byte-packing utilities + // ============================================================ + + // Map a type to its unsigned-integer "bit container" of the same size. + namespace detail + { + template struct bit_container; + template<> struct bit_container { using type = u8; }; + template<> struct bit_container { using type = u8; }; + template<> struct bit_container { using type = u16; }; + template<> struct bit_container { using type = u16; }; + template<> struct bit_container { using type = u32; }; + template<> struct bit_container { using type = u32; }; + template<> struct bit_container { using type = u64; }; + template<> struct bit_container { using type = u64; }; + template<> struct bit_container { using type = u32; }; + template<> struct bit_container { using type = u64; }; + + template + using bit_container_t = typename bit_container::type; + } + + // Pack any 1/2/4/8-byte scalar into an array of bytes. + // Works for signed and unsigned integers, and for floats. + template + std::array to_bytes(T value, Endianness endianness = Endianness::LittleEndian) + { + static_assert(std::is_trivially_copyable_v, "to_bytes: T must be trivially copyable"); + static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "to_bytes: T must be 1, 2, 4, or 8 bytes"); + + using U = detail::bit_container_t; + U u; + std::memcpy(&u, &value, sizeof(T)); // bit-cast value -> unsigned + + std::array out{}; + if (endianness == Endianness::LittleEndian) + { + for (std::size_t i = 0; i < sizeof(T); ++i) + out[i] = static_cast((u >> (i * 8)) & 0xFF); + } + else // BigEndian + { + for (std::size_t i = 0; i < sizeof(T); ++i) + out[i] = static_cast((u >> ((sizeof(T) - 1 - i) * 8)) & 0xFF); + } + return out; + } + + // Unpack bytes back into any 1/2/4/8-byte scalar. + template + T from_bytes(std::span bytes, Endianness endianness = Endianness::LittleEndian) + { + static_assert(std::is_trivially_copyable_v, "from_bytes: T must be trivially copyable"); + static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8, "from_bytes: T must be 1, 2, 4, or 8 bytes"); + + using U = detail::bit_container_t; + U u = 0; + if (endianness == Endianness::LittleEndian) + { + for (std::size_t i = 0; i < sizeof(T); ++i) + u |= static_cast(static_cast(bytes[i])) << (i * 8); + } + else // BigEndian + { + for (std::size_t i = 0; i < sizeof(T); ++i) + u |= static_cast(static_cast(bytes[i])) << ((sizeof(T) - 1 - i) * 8); + } + + T value; + std::memcpy(&value, &u, sizeof(T)); // bit-cast unsigned -> T + return value; + } + + // Forward declaration + class I_serializable; + } class Serial { public: template struct ReadResult { T value; bool error { false }; }; - public: enum class Endianness : u8 { LittleEndian = 0, BigEndian }; public: using StreamEdit = std::span; public: using StreamView = std::span; public: class Stream @@ -38,7 +118,7 @@ namespace ostd Stream(const Stream&) = delete; Stream& operator=(const Stream&) = delete; inline Stream(void) { } // Uninitialized Stream - inline Stream(u64 size, Endianness endianness = Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) { + inline Stream(u64 size, serial::Endianness endianness = serial::Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) { construct(size, endianness, preInitialize, initialValue); } inline Stream(Stream&& other) noexcept : m_data(other.m_data), m_size(other.m_size), m_endianness(other.m_endianness) { @@ -60,7 +140,7 @@ namespace ostd delete[] m_data; m_data = nullptr; } - inline bool construct(u64 size, Endianness endianness = Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) { + inline bool construct(u64 size, serial::Endianness endianness = serial::Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) { if (isValid()) return false; if (size < 1) return false; if constexpr (sizeof(size_t) < sizeof(uint64_t)) @@ -80,10 +160,10 @@ namespace ostd } inline bool isValid(void) const { return m_size > 0 && m_data != nullptr; } inline u64 size(void) const { return isValid() ? m_size : 0; } - inline bool isLittleEndian(void) const { return m_endianness == Endianness::LittleEndian; } - inline bool isBigEndian(void) const { return m_endianness == Endianness::BigEndian; } - inline Endianness getEndianness(void) const { return m_endianness; } - inline void setEndianness(Endianness endianness) { m_endianness = endianness; } + inline bool isLittleEndian(void) const { return m_endianness == serial::Endianness::LittleEndian; } + inline bool isBigEndian(void) const { return m_endianness == serial::Endianness::BigEndian; } + inline serial::Endianness getEndianness(void) const { return m_endianness; } + inline void setEndianness(serial::Endianness endianness) { m_endianness = endianness; } inline StreamEdit data() { if (isValid()) return { m_data, cast(m_size) }; @@ -98,204 +178,158 @@ namespace ostd private: i8* m_data { nullptr }; u64 m_size { 0 }; - Endianness m_endianness { Endianness::LittleEndian }; + serial::Endianness m_endianness { serial::Endianness::LittleEndian }; }; - private: struct Reader + public: struct StreamAccessor { - inline Reader(Serial& _parent) : parent(_parent) { data = parent.m_data.data(); } + public: + bool resetAddress(u64 newAddr = 1); - ReadResult int8(u64 addr); - inline ReadResult int8(void) { return int8(0); } - ReadResult uint8(u64 addr); - inline ReadResult uint8(void) { return uint8(0); } + protected: + inline StreamAccessor(Serial& _parent) : parent(_parent) { } - ReadResult int16(u64 addr); - inline ReadResult int16(void) { return int16(0); } - ReadResult uint16(u64 addr); - inline ReadResult uint16(void) { return uint16(0); } + u64& resolve_address(u64& addr); + bool restore_address_and_return(bool passthrough); + void clear_address_backup(void); + inline void disable_address_restore(void) { m_addressRestoreEnabled = false; } + inline void enable_address_restore(void) { m_addressRestoreEnabled = true; } - ReadResult int32(u64 addr); - inline ReadResult int32(void) { return int32(0); } - ReadResult uint32(u64 addr); - inline ReadResult uint32(void) { return uint32(0); } - - ReadResult int64(u64 addr); - inline ReadResult int64(void) { return int64(0); } - ReadResult uint64(u64 addr); - inline ReadResult uint64(void) { return uint64(0); } - - ReadResult float32(u64 addr); - inline ReadResult float32(void) { return float32(0); } - ReadResult float64(u64 addr); - inline ReadResult float64(void) { return float64(0); } - - bool stream(u64 addr, Stream& outStream, bool sizeStored = true, u32 size_if_not_stored = 0); - inline bool stream(Stream& outStream, bool sizeStored = true, u32 size_if_not_stored = 0) { return stream(0, outStream, sizeStored, size_if_not_stored); } - bool string(u64 addr, String& outString, bool sizeStored = true, u32 size_if_not_stored = 0, bool null_terminated = false); - inline bool string(String& outString, bool sizeStored = true, u32 size_if_not_stored = 0, bool null_terminated = false) { return string(0, outString, sizeStored, size_if_not_stored, null_terminated); } - bool object(u64 addr, I_serializable& outObject); - inline bool object(I_serializable& outObject) { return object(0, outObject); } - - private: // Convenience wrappers + // Convenience wrappers inline bool isValid(void) const { return parent.isValid(); } inline bool isInvalid(void) const { return parent.isInvalid(); } inline bool isLittleEndian(void) const { return parent.isLittleEndian(); } inline bool isBigEndian(void) const { return parent.isBigEndian(); } - inline u64& resolve_address(u64& addr) { return parent.resolve_address(addr); } - inline bool isValidAddress(u64 addr, u32 size = 1) const { return parent.isValidAddress(addr); } + inline bool isValidAddress(u64 addr, u32 size = 1) const { return parent.isValidAddress(addr, size); } - private: - Serial& parent; - StreamView data; - }; - private: struct Writer - { - inline Writer(Serial& _parent) : parent(_parent) { data = parent.m_data.data(); } - - bool int8(u64 addr, i8 value); - inline bool int8(i8 value) { return int8(0, value); } - bool uint8(u64 addr, u8 value); - inline bool uint8(u8 value) { return uint8(0, value); } - - bool int16(u64 addr, i16 value); - inline bool int16(i16 value) { return int16(0, value); } - bool uint16(u64 addr, u16 value); - inline bool uint16(u16 value) { return uint16(0, value); } - - bool int32(u64 addr, i32 value); - inline bool int32(i32 value) { return int32(0, value); } - bool uint32(u64 addr, u32 value); - inline bool uint32(u32 value) { return uint32(0, value); } - - bool int64(u64 addr, i64 value); - inline bool int64(i64 value) { return int64(0, value); } - bool uint64(u64 addr, u64 value); - inline bool uint64(u64 value) { return uint64(0, value); } - - bool float32(u64 addr, f32 value); - inline bool float32(f32 value) { return float32(0, value); } - bool float64(u64 addr, f64 value); - inline bool float64(f64 value) { return float64(0, value); } - - bool stream(u64 addr, const Stream& value, bool storeSize = true); - inline bool stream(const Stream& value, bool storeSize = true) { return stream(0, value, storeSize); } - bool string(u64 addr, const String& value, bool storeSize = true, bool null_terminated = false); // if sizeStored, null_terminated will be ignored - inline bool string(const String& value, bool storeSize = true, bool null_terminated = false) { return string(0, value, storeSize, null_terminated); } - bool object(u64 addr, const I_serializable& value); - inline bool object(const I_serializable& value) { return object(0, value); } - - private: // Convenience wrappers - inline bool isValid(void) const { return parent.isValid(); } - inline bool isInvalid(void) const { return parent.isInvalid(); } - inline bool isLittleEndian(void) const { return parent.isLittleEndian(); } - inline bool isBigEndian(void) const { return parent.isBigEndian(); } - inline u64& resolve_address(u64& addr) { return parent.resolve_address(addr); } - inline bool isValidAddress(u64 addr, u32 size = 1) const { return parent.isValidAddress(addr); } - - private: + protected: Serial& parent; StreamEdit data; + private: + u64 m_address { 1 }; + u64 m_backupAddress { 1 }; + bool m_addressBackupStored { false }; + bool m_addressRestoreEnabled { true }; + + friend class Serial; + }; + public: struct Reader : public StreamAccessor + { + inline Reader(Serial& _parent) : StreamAccessor(_parent) { } + + template + Serial::ReadResult read_scalar(u64 _addr) + { + if (isInvalid()) return { T{}, true }; + u64& addr = resolve_address(_addr); + if (!isValidAddress(addr, sizeof(T))) + return { T{}, restore_address_and_return(true) }; + T val = from_bytes(data.subspan(addr, sizeof(T)), parent.getEndianness()); + addr += sizeof(T); + clear_address_backup(); + return { val, false }; + } + + inline ReadResult int8(u64 _addr) { return read_scalar(_addr); } + inline ReadResult int8(void) { return int8(0); } + inline ReadResult uint8(u64 _addr) { return read_scalar(_addr); } + inline ReadResult uint8(void) { return uint8(0); } + inline ReadResult int16(u64 _addr) { return read_scalar(_addr); } + inline ReadResult int16(void) { return int16(0); } + inline ReadResult uint16(u64 _addr) { return read_scalar(_addr); } + inline ReadResult uint16(void) { return uint16(0); } + inline ReadResult int32(u64 _addr) { return read_scalar(_addr); } + inline ReadResult int32(void) { return int32(0); } + inline ReadResult uint32(u64 _addr) { return read_scalar(_addr); } + inline ReadResult uint32(void) { return uint32(0); } + inline ReadResult int64(u64 _addr) { return read_scalar(_addr); } + inline ReadResult int64(void) { return int64(0); } + inline ReadResult uint64(u64 _addr) { return read_scalar(_addr); } + inline ReadResult uint64(void) { return uint64(0); } + inline ReadResult float32(u64 _addr) { return read_scalar(_addr); } + inline ReadResult float32(void) { return float32(0); } + inline ReadResult float64(u64 _addr) { return read_scalar(_addr); } + inline ReadResult float64(void) { return float64(0); } + + bool stream(u64 _addr, Stream& outStream, bool sizeStored = true, u32 size_if_not_stored = 0); + inline bool stream(Stream& outStream, bool sizeStored = true, u32 size_if_not_stored = 0) { return stream(0, outStream, sizeStored, size_if_not_stored); } + bool string(u64 _addr, String& outString, bool sizeStored = true, u32 size_if_not_stored = 0, bool null_terminated = false); + inline bool string(String& outString, bool sizeStored = true, u32 size_if_not_stored = 0, bool null_terminated = false) { return string(0, outString, sizeStored, size_if_not_stored, null_terminated); } + bool object(u64 _addr, serial::I_serializable& outObject); + inline bool object(serial::I_serializable& outObject) { return object(0, outObject); } + }; + public: struct Writer : public StreamAccessor + { + inline Writer(Serial& _parent) : StreamAccessor(_parent) { } + + template + bool write_scalar(u64 _addr, T value) + { + if (isInvalid()) return false; + u64& addr = resolve_address(_addr); + if (!isValidAddress(addr, sizeof(T))) + return restore_address_and_return(false); + auto bytes = to_bytes(value, parent.getEndianness()); + std::copy(bytes.begin(), bytes.end(), data.begin() + addr); + addr += sizeof(T); + clear_address_backup(); + return true; + } + + inline bool int8(u64 _addr, i8 value) { return write_scalar (_addr, value); } + inline bool int8(i8 value) { return int8(0, value); } + inline bool uint8(u64 _addr, u8 value) { return write_scalar (_addr, value); } + inline bool uint8(u8 value) { return uint8(0, value); } + inline bool int16(u64 _addr, i16 value) { return write_scalar(_addr, value); } + inline bool int16(i16 value) { return int16(0, value); } + inline bool uint16(u64 _addr, u16 value) { return write_scalar(_addr, value); } + inline bool uint16(u16 value) { return uint16(0, value); } + inline bool int32(u64 _addr, i32 value) { return write_scalar(_addr, value); } + inline bool int32(i32 value) { return int32(0, value); } + inline bool uint32(u64 _addr, u32 value) { return write_scalar(_addr, value); } + inline bool uint32(u32 value) { return uint32(0, value); } + inline bool int64(u64 _addr, i64 value) { return write_scalar(_addr, value); } + inline bool int64(i64 value) { return int64(0, value); } + inline bool uint64(u64 _addr, u64 value) { return write_scalar(_addr, value); } + inline bool uint64(u64 value) { return uint64(0, value); } + inline bool float32(u64 _addr, f32 value) { return write_scalar(_addr, value); } + inline bool float32(f32 value) { return float32(0, value); } + inline bool float64(u64 _addr, f64 value) { return write_scalar(_addr, value); } + inline bool float64(f64 value) { return float64(0, value); } + + bool stream(u64 _addr, const Stream& value, bool storeSize = true); + inline bool stream(const Stream& value, bool storeSize = true) { return stream(0, value, storeSize); } + bool string(u64 _addr, const String& value, bool storeSize = true, bool null_terminated = false); // if sizeStored, null_terminated will be ignored + inline bool string(const String& value, bool storeSize = true, bool null_terminated = false) { return string(0, value, storeSize, null_terminated); } + bool object(u64 _addr, const serial::I_serializable& value); + inline bool object(const serial::I_serializable& value) { return object(0, value); } }; public: inline Serial(void) : read(*this), write(*this) { } - inline Serial(u64 size, Endianness endianness = Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) : read(*this), write(*this) { construct(size, endianness, preInitialize, initialValue); } - bool construct(u64 size, Endianness endianness = Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0); - bool resetAddress(u64 newAddr); + inline Serial(u64 size, serial::Endianness endianness = serial::Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0) : read(*this), write(*this) { construct(size, endianness, preInitialize, initialValue); } + bool construct(u64 size, serial::Endianness endianness = serial::Endianness::LittleEndian, bool preInitialize = false, i8 initialValue = 0); bool isValidAddress(u64 addr, u32 size = 1) const; inline bool isValid(void) const { return m_data.isValid(); } inline bool isInvalid(void) const { return !isValid(); } inline bool isLittleEndian(void) const { return m_data.isLittleEndian(); } inline bool isBigEndian(void) const { return m_data.isBigEndian(); } - inline Endianness getEndianness(void) const { return m_data.getEndianness(); } - - private: - inline u64& resolve_address(u64& addr) { if (addr == 0) return m_address; return addr; } - inline bool restore_address(void) { resetAddress(m_backupAddress); return false; } // Always returns false so it can be used as false on error in return statements + inline serial::Endianness getEndianness(void) const { return m_data.getEndianness(); } private: Stream m_data; - u64 m_address { 0 }; - u64 m_backupAddress { 0 }; - bool m_backupStored { false }; public: Writer write; Reader read; }; - class I_serializable - { - public: - virtual Serial::Stream serialize(void) const = 0; - virtual bool deserialize(const Serial::Stream& data) = 0; - }; - - - - - - // =============================================== OLD VERSION =============================================== - class OutputHandlerBase; namespace serial { - class SerialIO + class I_serializable { - public: struct tEndianness { - inline static constexpr u8 LittleEndian = 0x00; - inline static constexpr u8 BigEndian = 0x01; - }; - public: - inline SerialIO(void) { init(); } - inline SerialIO(u64 size, u8 endianness = tEndianness::BigEndian) { init(size, endianness); } - inline SerialIO(ByteStream& data, u8 endianness = tEndianness::BigEndian) { m_data = data; m_endianness = endianness; } - bool init(u64 size = SerialIO::DefaultMaxSize, u8 endianness = tEndianness::BigEndian); - bool r_QWord(StreamIndex addr, QWord& outVal); - bool r_DWord(StreamIndex addr, DWord& outVal); - bool r_Word(StreamIndex addr, Word& outVal); - bool r_Byte(StreamIndex addr, Byte& outVal); - bool r_Addr(StreamIndex addr, StreamIndex& outVal); - bool r_Float(StreamIndex addr, f32& outVal); - bool r_Double(StreamIndex addr, f64& outVal); - bool r_ByteStream(StreamIndex addr, ByteStream& outStream); - bool r_ByteStream(StreamIndex addr, ByteStream& outStream, u32 size); - bool r_String(StreamIndex addr, String& outString); - bool r_String(StreamIndex addr, String& outString, u32 size); - bool r_NullTerminatedString(StreamIndex addr, String& outString); - - bool w_QWord(StreamIndex addr, QWord val); - bool w_DWord(StreamIndex addr, DWord val); - bool w_Word(StreamIndex addr, Word val); - bool w_Byte(StreamIndex addr, Byte val); - bool w_Addr(StreamIndex addr, StreamIndex val); - bool w_Float(StreamIndex addr, f32 val); - bool w_Double(StreamIndex addr, f64 val); - bool w_ByteStream(StreamIndex addr, const ByteStream& stream, bool store_size = true); - bool w_String(StreamIndex addr, const String& str, bool store_size = false, bool null_terminate = true); - bool is_validAddr(StreamIndex addr, StreamIndex offset = 1); - inline u64 size(void) { return m_data.size(); } - inline ByteStream& getData(void) { return m_data; } - - void print(StreamIndex start, OutputHandlerBase& out); - bool saveToFile(const String& filePath); - - inline u8 getEndianness(void) const { return m_endianness; } - inline bool isLittleEndian(void) const { return m_endianness == tEndianness::LittleEndian; } - inline bool isBigEndian(void) const { return m_endianness == tEndianness::BigEndian; } - - inline bool isAutoResizeEnabled(void) const { return m_autoResize; } - inline void enableAutoResize(bool val = true, i32 resizeAmount = 1024) { m_autoResize = val; if (!val) return; m_resizeAmount = resizeAmount; } - - private: - ByteStream m_data; - u8 m_endianness { tEndianness::BigEndian }; - bool m_autoResize { true }; - i32 m_resizeAmount { 1024 }; - bool m_statuWriting { false }; - - public: - inline static constexpr u64 DefaultMaxSize = 512; + virtual Serial::Stream serialize(void) const = 0; + virtual bool deserialize(const Serial::Stream& data) = 0; }; } }