#ifndef DNAYAML_HPP #define DNAYAML_HPP /* BIG FAT WARNING!!! * * The type-structure of this file is expected to remain consistent for 'atdna' * Any changes to the types or namespacing must be reflected in 'atdna/main.cpp' */ #include #include #include #include "DNA.hpp" #include "FileReader.hpp" namespace athena { namespace io { std::string base64_encode(const atUint8* bytes_to_encode, size_t in_len); std::unique_ptr base64_decode(const std::string& encoded_string); void HandleYAMLParserError(yaml_parser_t* parser); void HandleYAMLEmitterError(yaml_emitter_t* emitter); struct YAMLStdStringReaderState { std::string::const_iterator begin; std::string::const_iterator end; YAMLStdStringReaderState(const std::string& str) { begin = str.begin(); end = str.end(); } }; int YAMLStdStringReader(YAMLStdStringReaderState* str, unsigned char* buffer, size_t size, size_t* size_read); int YAMLStdStringWriter(std::string* str, unsigned char* buffer, size_t size); struct YAMLNode { yaml_node_type_t m_type; std::string m_scalarString; std::vector> m_seqChildren; std::vector>> m_mapChildren; YAMLNode(yaml_node_type_t type) : m_type(type) {} inline const YAMLNode* findMapChild(const char* key) const { for (const auto& item : m_mapChildren) if (!item.first.compare(key)) return item.second.get(); return nullptr; } }; template RETURNTYPE NodeToVal(const YAMLNode* node); template std::unique_ptr ValToNode(const INTYPE& val); template std::unique_ptr ValToNode(const INTYPE* val); template std::unique_ptr ValToNode(const INTYPE& val, size_t byteCount); template <> inline bool NodeToVal(const YAMLNode* node) { char firstCh = tolower(node->m_scalarString[0]); if (firstCh == 't') return true; else if (firstCh == 'f') return false; else if (isdigit(firstCh) && firstCh != 0) return true; return false; } template <> inline std::unique_ptr ValToNode(const bool& val) { YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = val?"True":"False"; return std::unique_ptr(ret); } template <> inline atInt8 NodeToVal(const YAMLNode* node) { return strtol(node->m_scalarString.c_str(), NULL, 0); } template <> inline std::unique_ptr ValToNode(const atInt8& val) { char str[32]; snprintf(str, 32, "0x%02X", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline atUint8 NodeToVal(const YAMLNode* node) { return strtoul(node->m_scalarString.c_str(), NULL, 0); } template <> inline std::unique_ptr ValToNode(const atUint8& val) { char str[32]; snprintf(str, 32, "0x%02X", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline atInt16 NodeToVal(const YAMLNode* node) { return strtol(node->m_scalarString.c_str(), NULL, 0); } template <> inline std::unique_ptr ValToNode(const atInt16& val) { char str[32]; snprintf(str, 32, "0x%04X", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline atUint16 NodeToVal(const YAMLNode* node) { return strtoul(node->m_scalarString.c_str(), NULL, 0); } template <> inline std::unique_ptr ValToNode(const atUint16& val) { char str[32]; snprintf(str, 32, "0x%04X", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline atInt32 NodeToVal(const YAMLNode* node) { return strtol(node->m_scalarString.c_str(), NULL, 0); } template <> inline std::unique_ptr ValToNode(const atInt32& val) { char str[32]; snprintf(str, 32, "0x%08X", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline atUint32 NodeToVal(const YAMLNode* node) { return strtoul(node->m_scalarString.c_str(), NULL, 0); } template <> inline std::unique_ptr ValToNode(const atUint32& val) { char str[32]; snprintf(str, 32, "0x%08X", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline atInt64 NodeToVal(const YAMLNode* node) { #if _WIN32 return _strtoi64(node->m_scalarString.c_str(), NULL, 0); #else return strtoq(node->m_scalarString.c_str(), NULL, 0); #endif } template <> inline std::unique_ptr ValToNode(const atInt64& val) { char str[32]; snprintf(str, 32, "0x%016" PRIX64, val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline atUint64 NodeToVal(const YAMLNode* node) { #if _WIN32 return _strtoui64(node->m_scalarString.c_str(), NULL, 0); #else return strtouq(node->m_scalarString.c_str(), NULL, 0); #endif } template <> inline std::unique_ptr ValToNode(const atUint64& val) { char str[32]; snprintf(str, 32, "0x%016" PRIX64, val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline float NodeToVal(const YAMLNode* node) { return strtof(node->m_scalarString.c_str(), NULL); } template <> inline std::unique_ptr ValToNode(const float& val) { char str[64]; snprintf(str, 64, "%f", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template <> inline double NodeToVal(const YAMLNode* node) { return strtod(node->m_scalarString.c_str(), NULL); } template <> inline std::unique_ptr ValToNode(const double& val) { char str[64]; snprintf(str, 64, "%f", val); YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = str; return std::unique_ptr(ret); } template inline RETURNTYPE NodeToVec(const YAMLNode* node) { RETURNTYPE retval = {}; auto it = node->m_seqChildren.begin(); for (size_t i=0; i<4 && it != node->m_seqChildren.end(); ++i, ++it) { YAMLNode* snode = it->get(); if (snode->m_type == YAML_SCALAR_NODE) { if (std::is_same::value || std::is_same::value || std::is_same::value) retval.vec[i] = NodeToVal(snode); else retval.vec[i] = NodeToVal(snode); } else retval.vec[i] = 0.0; } return retval; } template <> inline atVec2f NodeToVal(const YAMLNode* node) { return NodeToVec(node); } template <> inline std::unique_ptr ValToNode(const atVec2f& val) { YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE); ret->m_seqChildren.reserve(2); for (size_t i=0 ; i<2 ; ++i) { char str[64]; snprintf(str, 64, "%f", val.vec[i]); YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE); comp->m_scalarString = str; ret->m_seqChildren.emplace_back(comp); } return std::unique_ptr(ret); } template <> inline atVec3f NodeToVal(const YAMLNode* node) { return NodeToVec(node); } template <> inline std::unique_ptr ValToNode(const atVec3f& val) { YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE); ret->m_seqChildren.reserve(3); for (size_t i=0 ; i<3 ; ++i) { char str[64]; snprintf(str, 64, "%f", val.vec[i]); YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE); comp->m_scalarString = str; ret->m_seqChildren.emplace_back(comp); } return std::unique_ptr(ret); } template <> inline atVec4f NodeToVal(const YAMLNode* node) { return NodeToVec(node); } template <> inline std::unique_ptr ValToNode(const atVec4f& val) { YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE); ret->m_seqChildren.reserve(4); for (size_t i=0 ; i<4 ; ++i) { char str[64]; snprintf(str, 64, "%f", val.vec[i]); YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE); comp->m_scalarString = str; ret->m_seqChildren.emplace_back(comp); } return std::unique_ptr(ret); } template <> inline atVec2d NodeToVal(const YAMLNode* node) { return NodeToVec(node); } template <> inline std::unique_ptr ValToNode(const atVec2d& val) { YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE); ret->m_seqChildren.reserve(2); for (size_t i=0 ; i<2 ; ++i) { char str[64]; snprintf(str, 64, "%f", val.vec[i]); YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE); comp->m_scalarString = str; ret->m_seqChildren.emplace_back(comp); } return std::unique_ptr(ret); } template <> inline atVec3d NodeToVal(const YAMLNode* node) { return NodeToVec(node); } template <> inline std::unique_ptr ValToNode(const atVec3d& val) { YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE); ret->m_seqChildren.reserve(3); for (size_t i=0 ; i<3 ; ++i) { char str[64]; snprintf(str, 64, "%f", val.vec[i]); YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE); comp->m_scalarString = str; ret->m_seqChildren.emplace_back(comp); } return std::unique_ptr(ret); } template <> inline atVec4d NodeToVal(const YAMLNode* node) { return NodeToVec(node); } template <> inline std::unique_ptr ValToNode(const atVec4d& val) { YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE); ret->m_seqChildren.reserve(4); for (size_t i=0 ; i<4 ; ++i) { char str[64]; snprintf(str, 64, "%f", val.vec[i]); YAMLNode* comp = new YAMLNode(YAML_SCALAR_NODE); comp->m_scalarString = str; ret->m_seqChildren.emplace_back(comp); } return std::unique_ptr(ret); } template <> inline std::unique_ptr NodeToVal(const YAMLNode* node) { return base64_decode(node->m_scalarString); } template <> inline std::unique_ptr ValToNode(const std::unique_ptr& val, size_t byteCount) { YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = base64_encode(val.get(), byteCount); return std::unique_ptr(ret); } template <> inline std::string NodeToVal(const YAMLNode* node) { return node->m_scalarString; } template <> inline std::unique_ptr ValToNode(const std::string& val) { YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = val; return std::unique_ptr(ret); } template <> inline std::unique_ptr ValToNode(const char* val) { YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString = val; return std::unique_ptr(ret); } template <> inline std::wstring NodeToVal(const YAMLNode* node) { std::wstring retval; retval.reserve(node->m_scalarString.length()); const utf8proc_uint8_t* buf = reinterpret_cast(node->m_scalarString.c_str()); while (*buf) { utf8proc_int32_t wc; utf8proc_ssize_t len = utf8proc_iterate(buf, -1, &wc); if (len < 0) { atWarning("invalid UTF-8 character while decoding"); return retval; } buf += len; retval += wchar_t(wc); } return retval; } template <> inline std::unique_ptr ValToNode(const std::wstring& val) { YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); ret->m_scalarString.reserve(val.length()); for (wchar_t ch : val) { utf8proc_uint8_t mb[4]; utf8proc_ssize_t c = utf8proc_encode_char(utf8proc_int32_t(ch), mb); if (c < 0) { atWarning("invalid UTF-8 character while encoding"); return std::unique_ptr(ret); } ret->m_scalarString.append(reinterpret_cast(mb), c); } return std::unique_ptr(ret); } template <> inline std::unique_ptr ValToNode(const wchar_t* val) { std::wstring wstr(val); return ValToNode(wstr); } class YAMLDocReader { std::unique_ptr m_rootNode; std::vector m_subStack; std::vector m_seqTrackerStack; yaml_parser_t m_parser; std::unique_ptr ParseEvents(); public: YAMLDocReader() { if (!yaml_parser_initialize(&m_parser)) { HandleYAMLParserError(&m_parser); return; } } ~YAMLDocReader() { yaml_parser_delete(&m_parser); } void reset() { yaml_parser_delete(&m_parser); if (!yaml_parser_initialize(&m_parser)) HandleYAMLParserError(&m_parser); } yaml_parser_t* getParser() {return &m_parser;} bool parse() { std::unique_ptr newRoot = ParseEvents(); if (!newRoot) return false; m_rootNode = std::move(newRoot); m_subStack.clear(); m_subStack.push_back(m_rootNode.get()); m_seqTrackerStack.clear(); return true; } bool ClassTypeOperation(std::function func); bool ValidateClassType(const char* expectedType); inline const YAMLNode* getRootNode() const {return m_rootNode.get();} inline const YAMLNode* getCurNode() const {return m_subStack.empty() ? nullptr : m_subStack.back();} std::unique_ptr releaseRootNode() {return std::move(m_rootNode);} bool enterSubRecord(const char* name) { YAMLNode* curSub = m_subStack.back(); if (curSub->m_type == YAML_SEQUENCE_NODE) { int& seqIdx = m_seqTrackerStack.back(); m_subStack.push_back(curSub->m_seqChildren[seqIdx++].get()); if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE) m_seqTrackerStack.push_back(0); return true; } for (const auto& item : curSub->m_mapChildren) { if (!item.first.compare(name)) { m_subStack.push_back(item.second.get()); if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE) m_seqTrackerStack.push_back(0); return true; } } return false; } void leaveSubRecord() { if (m_subStack.size() > 1) { if (m_subStack.back()->m_type == YAML_SEQUENCE_NODE) m_seqTrackerStack.pop_back(); m_subStack.pop_back(); } } template void enumerate(const char* name, T& record) { enterSubRecord(name); record.read(*this); leaveSubRecord(); } bool enterSubVector(const char* name, size_t& countOut) { YAMLNode* curSub = m_subStack.back(); if (!name && curSub->m_type == YAML_SEQUENCE_NODE) { m_subStack.push_back(curSub); m_seqTrackerStack.push_back(0); countOut = curSub->m_seqChildren.size(); return true; } else { for (const auto& item : curSub->m_mapChildren) { if (!item.first.compare(name)) { YAMLNode* nextSub = item.second.get(); if (nextSub->m_type == YAML_SEQUENCE_NODE) { countOut = nextSub->m_seqChildren.size(); } else { atError("'%s' is not a vector field", name); countOut = 0; } m_subStack.push_back(nextSub); m_seqTrackerStack.push_back(0); return true; } } } countOut = 0; return false; } void leaveSubVector() { if (m_subStack.size() > 1) { m_subStack.pop_back(); m_seqTrackerStack.pop_back(); } } template size_t enumerate(const char* name, std::vector& vector, typename std::enable_if::value && !std::is_same::value && !std::is_same::value && !std::is_same::value>::type* = 0) { size_t countOut; enterSubVector(name, countOut); vector.clear(); vector.reserve(countOut); for (size_t i=0 ; i size_t enumerate(const char* name, std::vector& vector, typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value>::type* = 0) { size_t countOut; enterSubVector(name, countOut); vector.clear(); vector.reserve(countOut); for (size_t i=0 ; i(name)); leaveSubVector(); return countOut; } template size_t enumerate(const char* name, std::vector& vector, std::function readf) { size_t countOut; enterSubVector(name, countOut); vector.clear(); vector.reserve(countOut); for (size_t i=0 ; i RETURNTYPE readVal(const char* name) { if (m_subStack.size()) { const YAMLNode* mnode = m_subStack.back(); if (mnode->m_type == YAML_SCALAR_NODE) { return NodeToVal(mnode); } else if (mnode->m_type == YAML_SEQUENCE_NODE) { int& seqIdx = m_seqTrackerStack.back(); return NodeToVal(mnode->m_seqChildren[seqIdx++].get()); } else if (mnode->m_type == YAML_MAPPING_NODE) { for (const auto& item : mnode->m_mapChildren) { if (!item.first.compare(name)) { return NodeToVal(item.second.get()); } } } } if (name) atWarning("Unable to find field '%s'; returning 0", name); return RETURNTYPE(); } inline bool readBool(const char* name) { return readVal(name); } inline atInt8 readByte(const char* name) { return readVal(name); } inline atUint8 readUByte(const char* name) { return readVal(name); } inline atInt16 readInt16(const char* name) { return readVal(name); } inline atUint16 readUint16(const char* name) { return readVal(name); } inline atInt32 readInt32(const char* name) { return readVal(name); } inline atUint32 readUint32(const char* name) { return readVal(name); } inline atInt64 readInt64(const char* name) { return readVal(name); } inline atUint64 readUint64(const char* name) { return readVal(name); } inline float readFloat(const char* name) { return readVal(name); } inline double readDouble(const char* name) { return readVal(name); } inline atVec2f readVec2f(const char* name) { return readVal(name); } inline atVec3f readVec3f(const char* name) { return readVal(name); } inline atVec4f readVec4f(const char* name) { return readVal(name); } inline atVec2d readVec2d(const char* name) { return readVal(name); } inline atVec3d readVec3d(const char* name) { return readVal(name); } inline atVec4d readVec4d(const char* name) { return readVal(name); } inline std::unique_ptr readUBytes(const char* name) { return readVal>(name); } inline std::string readString(const char* name) { return readVal(name); } inline std::wstring readWString(const char* name) { return readVal(name); } }; class YAMLDocWriter { YAMLNode m_rootNode; std::vector m_subStack; yaml_emitter_t m_emitter; static bool RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node); public: YAMLDocWriter(const char* classType) : m_rootNode(YAML_MAPPING_NODE) { if (!yaml_emitter_initialize(&m_emitter)) { HandleYAMLEmitterError(&m_emitter); return; } yaml_emitter_set_unicode(&m_emitter, true); yaml_emitter_set_width(&m_emitter, -1); m_subStack.emplace_back(&m_rootNode); if (classType) { YAMLNode* classVal = new YAMLNode(YAML_SCALAR_NODE); classVal->m_scalarString.assign(classType); m_rootNode.m_mapChildren.emplace_back("DNAType", std::unique_ptr(classVal)); } } ~YAMLDocWriter() { yaml_emitter_delete(&m_emitter); } yaml_emitter_t* getEmitter() {return &m_emitter;} bool finish() { yaml_event_t event = {}; if (!yaml_emitter_open(&m_emitter)) goto err; event.type = YAML_DOCUMENT_START_EVENT; event.data.document_start.implicit = true; if (!yaml_emitter_emit(&m_emitter, &event)) goto err; if (!RecursiveFinish(&m_emitter, m_rootNode)) return false; event.type = YAML_DOCUMENT_END_EVENT; event.data.document_end.implicit = true; if (!yaml_emitter_emit(&m_emitter, &event)) goto err; if (!yaml_emitter_close(&m_emitter) || !yaml_emitter_flush(&m_emitter)) goto err; return true; err: HandleYAMLEmitterError(&m_emitter); return false; } inline YAMLNode* getCurNode() const {return m_subStack.empty() ? nullptr : m_subStack.back();} void enterSubRecord(const char* name) { YAMLNode* curSub = m_subStack.back(); if (curSub->m_type != YAML_MAPPING_NODE && curSub->m_type != YAML_SEQUENCE_NODE) return; YAMLNode* newNode = new YAMLNode(YAML_MAPPING_NODE); if (curSub->m_type == YAML_MAPPING_NODE) curSub->m_mapChildren.emplace_back(name?std::string(name):std::string(), std::unique_ptr(newNode)); else if (curSub->m_type == YAML_SEQUENCE_NODE) curSub->m_seqChildren.emplace_back(newNode); m_subStack.push_back(newNode); } void leaveSubRecord() { if (m_subStack.size() > 1) { YAMLNode* curSub = m_subStack.back(); /* Automatically lower to scalar or sequence if there's only one unnamed node */ if (curSub->m_mapChildren.size() == 1 && curSub->m_mapChildren[0].first.empty()) { auto& item = curSub->m_mapChildren[0]; if (item.first.empty()) { if (item.second->m_type == YAML_SCALAR_NODE) { curSub->m_type = YAML_SCALAR_NODE; curSub->m_scalarString = std::move(item.second->m_scalarString); curSub->m_mapChildren.clear(); } else if (item.second->m_type == YAML_SEQUENCE_NODE) { curSub->m_type = YAML_SEQUENCE_NODE; curSub->m_seqChildren = std::move(item.second->m_seqChildren); curSub->m_mapChildren.clear(); } } } m_subStack.pop_back(); } } template void enumerate(const char* name, T& record) { enterSubRecord(name); record.write(*this); leaveSubRecord(); } void enterSubVector(const char* name) { YAMLNode* curSub = m_subStack.back(); if (curSub->m_type != YAML_MAPPING_NODE && curSub->m_type != YAML_SEQUENCE_NODE) return; YAMLNode* newNode = new YAMLNode(YAML_SEQUENCE_NODE); if (curSub->m_type == YAML_MAPPING_NODE) curSub->m_mapChildren.emplace_back(name?std::string(name):std::string(), std::unique_ptr(newNode)); else if (curSub->m_type == YAML_SEQUENCE_NODE) curSub->m_seqChildren.emplace_back(newNode); m_subStack.push_back(newNode); } void leaveSubVector() { if (m_subStack.size() > 1) m_subStack.pop_back(); } template void enumerate(const char* name, const std::vector& vector, typename std::enable_if::value && !std::is_same::value && !std::is_same::value && !std::is_same::value && !std::is_same::value && !std::is_same::value && !std::is_same::value>::type* = 0) { enterSubVector(name); for (const T& item : vector) { enterSubRecord(nullptr); item.write(*this); leaveSubRecord(); } leaveSubVector(); } template void enumerate(const char* name, const std::vector& vector, typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value || std::is_same::value>::type* = 0) { enterSubVector(name); for (T item : vector) writeVal(nullptr, item); leaveSubVector(); } template void enumerate(const char* name, const std::vector& vector, std::function writef) { enterSubVector(name); for (const T& item : vector) { enterSubRecord(nullptr); writef(*this, item); leaveSubRecord(); } leaveSubVector(); } template void writeVal(const char* name, const INTYPE& val) { YAMLNode* curSub = m_subStack.back(); if (curSub->m_type == YAML_MAPPING_NODE) curSub->m_mapChildren.emplace_back(name?name:std::string(), std::move(ValToNode(val))); else if (curSub->m_type == YAML_SEQUENCE_NODE) curSub->m_seqChildren.emplace_back(std::move(ValToNode(val))); } template void writeVal(const char* name, const INTYPE& val, size_t byteCount) { YAMLNode* curSub = m_subStack.back(); if (curSub->m_type == YAML_MAPPING_NODE) curSub->m_mapChildren.emplace_back(name?name:std::string(), std::move(ValToNode(val, byteCount))); else if (curSub->m_type == YAML_SEQUENCE_NODE) curSub->m_seqChildren.emplace_back(std::move(ValToNode(val, byteCount))); } inline void writeBool(const char* name, const bool& val) { writeVal(name, val); } inline void writeByte(const char* name, const atInt8& val) { writeVal(name, val); } inline void writeUByte(const char* name, const atUint8& val) { writeVal(name, val); } inline void writeInt16(const char* name, const atInt16& val) { writeVal(name, val); } inline void writeUint16(const char* name, const atUint16& val) { writeVal(name, val); } inline void writeInt32(const char* name, const atInt32& val) { writeVal(name, val); } inline void writeUint32(const char* name, const atUint32& val) { writeVal(name, val); } inline void writeInt64(const char* name, const atInt64& val) { writeVal(name, val); } inline void writeUint64(const char* name, const atUint64& val) { writeVal(name, val); } inline void writeFloat(const char* name, const float& val) { writeVal(name, val); } inline void writeDouble(const char* name, const double& val) { writeVal(name, val); } inline void writeVec2f(const char* name, const atVec2f& val) { writeVal(name, val); } inline void writeVec3f(const char* name, const atVec3f& val) { writeVal(name, val); } inline void writeVec4f(const char* name, const atVec4f& val) { writeVal(name, val); } inline void writeVec2d(const char* name, const atVec2d& val) { writeVal(name, val); } inline void writeVec3d(const char* name, const atVec3d& val) { writeVal(name, val); } inline void writeVec4d(const char* name, const atVec4d& val) { writeVal(name, val); } inline void writeUBytes(const char* name, const std::unique_ptr& val, size_t byteCount) { writeVal&>(name, val, byteCount); } inline void writeString(const char* name, const std::string& val) { writeVal(name, val); } inline void writeString(const char* name, const char* val) { writeVal(name, val); } inline void writeWString(const char* name, const std::wstring& val) { writeVal(name, val); } inline void writeWString(const char* name, const wchar_t* val) { writeVal(name, val); } }; /* forward-declaration dance for recursively-derived types */ template struct BufferYaml; template struct StringYaml; template struct WStringYaml; template struct WStringAsStringYaml; template struct DNAYaml : DNA { virtual ~DNAYaml() {} using DNA::read; using DNA::write; virtual void read(YAMLDocReader& in)=0; virtual void write(YAMLDocWriter& out) const=0; static const char* DNAType() {return nullptr;} virtual const char* DNATypeV() const {return nullptr;} template using Buffer = struct athena::io::BufferYaml; template using String = struct athena::io::StringYaml; template using WString = struct athena::io::WStringYaml; template using WStringAsString = struct athena::io::WStringAsStringYaml; std::string toYAMLString() const { YAMLDocWriter docWriter(DNATypeV()); std::string res; yaml_emitter_set_output(docWriter.getEmitter(), (yaml_write_handler_t*)YAMLStdStringWriter, &res); yaml_emitter_set_unicode(docWriter.getEmitter(), true); yaml_emitter_set_width(docWriter.getEmitter(), -1); write(docWriter); if (!docWriter.finish()) return std::string(); return res; } bool fromYAMLString(const std::string& str) { YAMLStdStringReaderState reader(str); YAMLDocReader docReader; yaml_parser_set_input(docReader.getParser(), (yaml_read_handler_t*)YAMLStdStringReader, &reader); if (!docReader.parse()) return false; read(docReader); return true; } template static bool ValidateFromYAMLString(const std::string& str) { YAMLStdStringReaderState reader(str); YAMLDocReader docReader; yaml_parser_set_input(docReader.getParser(), (yaml_read_handler_t*)YAMLStdStringReader, &reader); bool retval = docReader.ValidateClassType(DNASubtype::DNAType()); return retval; } bool toYAMLFile(FILE* fout) const { YAMLDocWriter docWriter(DNATypeV()); yaml_emitter_set_output_file(docWriter.getEmitter(), fout); yaml_emitter_set_unicode(docWriter.getEmitter(), true); yaml_emitter_set_width(docWriter.getEmitter(), -1); write(docWriter); if (!docWriter.finish()) return false; return true; } bool fromYAMLFile(FILE* fin) { YAMLDocReader docReader; yaml_parser_set_input_file(docReader.getParser(), fin); if (!docReader.parse()) return false; read(docReader); return true; } template static bool ValidateFromYAMLFile(FILE* fin) { YAMLDocReader reader; long pos = ftell(fin); yaml_parser_set_input_file(reader.getParser(), fin); bool retval = reader.ValidateClassType(DNASubtype::DNAType()); fseek(fin, pos, SEEK_SET); return retval; } template static bool ValidateFromYAMLFile(athena::io::FileReader& fin) { return ValidateFromYAMLFile(fin._fileHandle()); } }; template struct BufferYaml : public DNAYaml, public std::unique_ptr { typename DNA::Delete expl; void read(IStreamReader& reader) { reset(new atUint8[sizeVar]); reader.readUBytesToBuf(get(), sizeVar); } void write(IStreamWriter& writer) const { writer.writeUBytes(get(), sizeVar); } size_t binarySize(size_t __isz) const { return __isz + sizeVar; } void read(athena::io::YAMLDocReader& reader) {*this = reader.readUBytes(nullptr);} void write(athena::io::YAMLDocWriter& writer) const {writer.writeUBytes(nullptr, *this, sizeVar);} }; template struct StringYaml : public DNAYaml, public std::string { typename DNA::Delete expl; void read(IStreamReader& reader) {this->assign(std::move(reader.readString(sizeVar)));} void write(IStreamWriter& writer) const {writer.writeString(*this, sizeVar);} size_t binarySize(size_t __isz) const {return __isz + ((sizeVar<0)?(this->size()+1):sizeVar);} void read(athena::io::YAMLDocReader& reader) {this->assign(std::move(reader.readString(nullptr)));} void write(athena::io::YAMLDocWriter& writer) const {writer.writeString(nullptr, *this);} std::string& operator=(const std::string& __str) {return this->assign(__str);} std::string& operator=(std::string&& __str) {this->swap(__str); return *this;} }; template struct WStringYaml : public DNAYaml, public std::wstring { typename DNA::Delete expl; void read(IStreamReader& reader) { reader.setEndian(VE); this->assign(std::move(reader.readWString(sizeVar))); } void write(IStreamWriter& writer) const { writer.setEndian(VE); writer.writeWString(*this, sizeVar); } size_t binarySize(size_t __isz) const {return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);} void read(athena::io::YAMLDocReader& reader) {this->assign(std::move(reader.readWString(nullptr)));} void write(athena::io::YAMLDocWriter& writer) const {writer.writeWString(nullptr, *this);} std::wstring& operator=(const std::wstring& __str) {return this->assign(__str);} std::wstring& operator=(std::wstring&& __str) {this->swap(__str); return *this;} }; template struct WStringAsStringYaml : public DNAYaml, public std::string { typename DNA::Delete expl; void read(IStreamReader& reader) {*this = reader.readWStringAsString(sizeVar);} void write(IStreamWriter& writer) const {writer.writeStringAsWString(*this, sizeVar);} size_t binarySize(size_t __isz) const {return __isz + (((sizeVar<0)?(this->size()+1):sizeVar)*2);} void read(athena::io::YAMLDocReader& reader) {this->assign(std::move(reader.readString(nullptr)));} void write(athena::io::YAMLDocWriter& writer) const {writer.writeString(nullptr, *this);} std::string& operator=(const std::string& __str) {return this->assign(__str);} std::string& operator=(std::string&& __str) {this->swap(__str); return *this;} }; /** Macro to automatically declare YAML read/write methods in subclasses */ #define DECL_YAML \ DECL_DNA \ void read(athena::io::YAMLDocReader&); \ void write(athena::io::YAMLDocWriter&) const; \ static const char* DNAType(); \ const char* DNATypeV() const {return DNAType();} \ /** Macro to automatically declare YAML read/write methods with client-code's definition */ #define DECL_EXPLICIT_YAML \ void read(athena::io::YAMLDocReader&); \ void write(athena::io::YAMLDocWriter&) const; \ static const char* DNAType(); \ const char* DNATypeV() const {return DNAType();} \ } } #endif // DNAYAML_HPP