diff --git a/deps/ox/src/ox/mc/read.cpp b/deps/ox/src/ox/mc/read.cpp index 5b58fca8..56119894 100644 --- a/deps/ox/src/ox/mc/read.cpp +++ b/deps/ox/src/ox/mc/read.cpp @@ -109,6 +109,10 @@ Error MetalClawReader::field(const char*, SerStr val) noexcept { return OxError(0); } +Error MetalClawReader::fieldCString(const char *name, char **val, int len) noexcept { + return field(name, SerStr(val, len)); +} + Result MetalClawReader::arrayLength(const char*, bool pass) noexcept { if ((m_unionIdx == -1 || m_unionIdx == m_field) && m_fieldPresence.get(static_cast(m_field))) { // read the length diff --git a/deps/ox/src/ox/mc/read.hpp b/deps/ox/src/ox/mc/read.hpp index efca8215..d1595ac0 100644 --- a/deps/ox/src/ox/mc/read.hpp +++ b/deps/ox/src/ox/mc/read.hpp @@ -72,11 +72,16 @@ class MetalClawReader { template Error field(const char*, UnionView val) noexcept; + template + Error field(const char*, BasicString *val) noexcept; + template Error field(const char*, BString *val) noexcept; Error field(const char*, SerStr val) noexcept; + Error fieldCString(const char *name, char **val, int len) noexcept; + /** * Reads an array length from the current location in the buffer. * @param pass indicates that the parsing should iterate past the array length @@ -158,6 +163,38 @@ Error MetalClawReader::field(const char*, UnionView val) noexcept { return OxError(0); } +template +Error MetalClawReader::field(const char*, BasicString *val) noexcept { + if (m_unionIdx == -1 || m_unionIdx == m_field) { + if (m_fieldPresence.get(static_cast(m_field))) { + // read the length + if (m_buffIt >= m_buffLen) { + return OxError(MC_BUFFENDED); + } + std::size_t bytesRead = 0; + oxRequire(size, mc::decodeInteger(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead)); + m_buffIt += bytesRead; + const auto cap = size; + *val = BasicString(cap); + auto data = val->data(); + // read the string + if (static_cast(cap) < size) { + return OxError(MC_OUTBUFFENDED); + } + if (m_buffIt + size > m_buffLen) { + return OxError(MC_BUFFENDED); + } + memcpy(data, &m_buff[m_buffIt], size); + data[size] = 0; + m_buffIt += size; + } else { + *val = ""; + } + } + ++m_field; + return OxError(0); +} + template Error MetalClawReader::field(const char *name, BString *val) noexcept { return field(name, SerStr(val->data(), val->cap())); @@ -201,7 +238,7 @@ Error MetalClawReader::field(const char *name, T *val, std::size_t valLen) noexc if (valLen >= len) { auto reader = child(""); reader.setTypeInfo("List", static_cast(len)); - for (std::size_t i = 0; i < len; i++) { + for (std::size_t i = 0; i < len; ++i) { oxReturnError(reader.field("", &val[i])); } } else { @@ -225,15 +262,14 @@ Error MetalClawReader::field(const char*, HashMap *val) noexcept { std::size_t bytesRead = 0; oxRequire(len, mc::decodeInteger(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead)); m_buffIt += bytesRead; - // read the list auto reader = child(""); reader.setTypeInfo("List", static_cast(len)); - for (std::size_t i = 0; i < len; i++) { + for (std::size_t i = 0; i < len; ++i) { const auto keyLen = reader.stringLength(nullptr); auto wkey = ox_malloca(keyLen + 1, char, 0); auto wkeyPtr = wkey.get(); - oxReturnError(reader.field("", SerStr(&wkeyPtr, static_cast(keyLen)))); + oxReturnError(reader.fieldCString("", &wkeyPtr, static_cast(keyLen + 1))); oxReturnError(reader.field("", &val->operator[](wkey.get()))); } } @@ -257,7 +293,7 @@ Error MetalClawReader::field(const char*, Handler handler) noexcept { // read the list auto reader = child(""); reader.setTypeInfo("List", static_cast(len)); - for (std::size_t i = 0; i < len; i++) { + for (std::size_t i = 0; i < len; ++i) { T val; oxReturnError(reader.field("", &val)); oxReturnError(handler(i, &val)); diff --git a/deps/ox/src/ox/mc/test/tests.cpp b/deps/ox/src/ox/mc/test/tests.cpp index a0ec669a..605afb4c 100644 --- a/deps/ox/src/ox/mc/test/tests.cpp +++ b/deps/ox/src/ox/mc/test/tests.cpp @@ -23,7 +23,7 @@ union TestUnion { static constexpr auto Fields = 3; bool Bool; uint32_t Int = 5; - char String[32]; + char CString[32]; }; struct TestStructNest { @@ -31,7 +31,7 @@ struct TestStructNest { static constexpr auto Fields = 3; bool Bool = false; uint32_t Int = 0; - ox::BString<32> String = ""; + ox::BString<32> BString = ""; }; struct TestStruct { @@ -48,7 +48,8 @@ struct TestStruct { int32_t Int7 = 0; int32_t Int8 = 0; TestUnion Union; - ox::BString<32> String = ""; + ox::String String = ""; + ox::BString<32> BString = ""; uint32_t List[4] = {0, 0, 0, 0}; ox::HashMap Map; TestStructNest EmptyStruct; @@ -60,18 +61,15 @@ constexpr ox::Error model(T *io, TestUnion *obj) noexcept { io->template setTypeInfo(); oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Int", &obj->Int)); - oxReturnError(io->field("String", ox::SerStr(obj->String))); + oxReturnError(io->field("CString", ox::SerStr(obj->CString))); return OxError(0); } -template -constexpr ox::Error model(T *io, TestStructNest *obj) noexcept { - io->template setTypeInfo(); - oxReturnError(io->field("Bool", &obj->Bool)); - oxReturnError(io->field("Int", &obj->Int)); - oxReturnError(io->field("String", &obj->String)); - return OxError(0); -} +oxModelBegin(TestStructNest) + oxModelField(Bool) + oxModelField(Int) + oxModelField(BString) +oxModelEnd() template constexpr ox::Error model(T *io, TestStruct *obj) noexcept { @@ -88,6 +86,7 @@ constexpr ox::Error model(T *io, TestStruct *obj) noexcept { oxReturnError(io->field("Int8", &obj->Int8)); oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 1})); oxReturnError(io->field("String", &obj->String)); + oxReturnError(io->field("BString", &obj->BString)); oxReturnError(io->field("List", obj->List, 4)); oxReturnError(io->field("Map", &obj->Map)); oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct)); @@ -119,7 +118,8 @@ std::map tests = { testIn.Bool = true; testIn.Int = 42; testIn.Union.Int = 42; - testIn.String = "Test String 1"; + testIn.String = "Test String 0"; + testIn.BString = "Test String 1"; testIn.List[0] = 1; testIn.List[1] = 2; testIn.List[2] = 3; @@ -128,36 +128,37 @@ std::map tests = { testIn.Map["aoeu"] = 94; testIn.Struct.Bool = false; testIn.Struct.Int = 300; - testIn.Struct.String = "Test String 2"; + testIn.Struct.BString = "Test String 2"; oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed"); oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed"); //std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n"; - oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); - oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); - oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch"); - oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch"); - oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch"); - oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch"); - oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch"); - oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch"); - oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch"); - oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch"); - oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch"); - oxAssert(testIn.String == testOut.String, "String value mismatch"); - oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch"); - oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch"); - oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch"); - oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch"); - oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch"); - oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch"); - oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch"); - oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch"); - oxAssert(testIn.EmptyStruct.String == testOut.EmptyStruct.String, "EmptyStruct.String value mismatch"); - oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch"); - oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch"); - oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch"); + oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); + oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); + oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch"); + oxAssert(testIn.Int2 == testOut.Int2, "Int2 value mismatch"); + oxAssert(testIn.Int3 == testOut.Int3, "Int3 value mismatch"); + oxAssert(testIn.Int4 == testOut.Int4, "Int4 value mismatch"); + oxAssert(testIn.Int5 == testOut.Int5, "Int5 value mismatch"); + oxAssert(testIn.Int6 == testOut.Int6, "Int6 value mismatch"); + oxAssert(testIn.Int7 == testOut.Int7, "Int7 value mismatch"); + oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch"); + oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch"); + oxAssert(testIn.String == testOut.String, "String value mismatch"); + oxAssert(testIn.BString == testOut.BString, "BString value mismatch"); + oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch"); + oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch"); + oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch"); + oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch"); + oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch"); + oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch"); + oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch"); + oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch"); + oxAssert(testIn.EmptyStruct.BString == testOut.EmptyStruct.BString, "EmptyStruct.BString value mismatch"); + oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch"); + oxAssert(testIn.Struct.BString == testOut.Struct.BString, "Struct.BString value mismatch"); + oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch"); return OxError(0); } @@ -277,14 +278,14 @@ std::map tests = { testIn.Bool = true; testIn.Int = 42; - testIn.String = "Test String 1"; + testIn.BString = "Test String 1"; testIn.List[0] = 1; testIn.List[1] = 2; testIn.List[2] = 3; testIn.List[3] = 4; testIn.Struct.Bool = false; testIn.Struct.Int = 300; - testIn.Struct.String = "Test String 2"; + testIn.Struct.BString = "Test String 2"; oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed"); auto type = ox::buildTypeDef(&testIn); diff --git a/deps/ox/src/ox/mc/write.cpp b/deps/ox/src/ox/mc/write.cpp index b144a0bb..715c2db3 100644 --- a/deps/ox/src/ox/mc/write.cpp +++ b/deps/ox/src/ox/mc/write.cpp @@ -90,7 +90,7 @@ Error MetalClawWriter::field(const char*, SerStr val) noexcept { return OxError(0); } -std::size_t MetalClawWriter::size() noexcept { +std::size_t MetalClawWriter::size() const noexcept { return m_buffIt; } diff --git a/deps/ox/src/ox/mc/write.hpp b/deps/ox/src/ox/mc/write.hpp index a1a98e8d..029725ed 100644 --- a/deps/ox/src/ox/mc/write.hpp +++ b/deps/ox/src/ox/mc/write.hpp @@ -60,6 +60,9 @@ class MetalClawWriter { template Error field(const char*, HashMap *val) noexcept; + template + Error field(const char*, BasicString *val) noexcept; + template Error field(const char*, BString *val) noexcept; @@ -75,7 +78,7 @@ class MetalClawWriter { void setTypeInfo(const char *name = T::TypeName, int fields = countFields()) noexcept; [[nodiscard]] - std::size_t size() noexcept; + std::size_t size() const noexcept; [[nodiscard]] static constexpr auto opType() noexcept { @@ -88,6 +91,28 @@ class MetalClawWriter { }; +template +Error MetalClawWriter::field(const char*, BasicString *val) noexcept { + bool fieldSet = false; + if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) { + // write the length + const auto strLen = mc::encodeInteger(val->len()); + if (m_buffIt + strLen.length + static_cast(val->len()) < m_buffLen) { + memcpy(&m_buff[m_buffIt], strLen.data, strLen.length); + m_buffIt += strLen.length; + // write the string + memcpy(&m_buff[m_buffIt], val->c_str(), static_cast(val->len())); + m_buffIt += static_cast(val->len()); + fieldSet = true; + } else { + return OxError(MC_BUFFENDED); + } + } + oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); + ++m_field; + return OxError(0); +} + template Error MetalClawWriter::field(const char *name, BString *val) noexcept { return field(name, SerStr(val->data(), val->cap())); @@ -108,7 +133,7 @@ Error MetalClawWriter::field(const char*, T *val) noexcept { } } oxReturnError(m_fieldPresence.set(static_cast(m_field), fieldSet)); - m_field++; + ++m_field; return OxError(0); } } diff --git a/deps/ox/src/ox/model/types.hpp b/deps/ox/src/ox/model/types.hpp index 30e247d5..1ff41de0 100644 --- a/deps/ox/src/ox/model/types.hpp +++ b/deps/ox/src/ox/model/types.hpp @@ -94,9 +94,11 @@ class SerStr { constexpr char *data(std::size_t sz = 0) noexcept { if (m_tgt && sz) { - *m_tgt = new char[sz]; - m_str = *m_tgt; - m_cap = static_cast(sz); + if (!*m_tgt || sz > static_cast(m_cap)) { + *m_tgt = new char[sz]; + m_str = *m_tgt; + m_cap = static_cast(sz); + } } return m_str; }