From fe1a489820973b5dca4ba598e2e2daa77cbffdcf Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Mon, 24 Aug 2015 17:42:24 -1000 Subject: [PATCH] made stream classes STL-customizable with a traits class --- CMakeLists.txt | 4 - atdna/main.cpp | 8 +- include/Athena/DNA.hpp | 80 +- include/Athena/DNAYaml.hpp | 1194 +++++++++++++++++++----------- include/Athena/FileReader.hpp | 212 +++++- include/Athena/FileWriter.hpp | 136 +++- include/Athena/Global.hpp | 7 + include/Athena/IStreamReader.hpp | 74 +- include/Athena/IStreamWriter.hpp | 112 ++- include/Athena/MemoryReader.hpp | 196 ++++- include/Athena/MemoryWriter.hpp | 303 +++++++- src/Athena/DNAYaml.cpp | 326 +------- src/Athena/FileInfo.cpp | 2 +- src/Athena/FileReader.cpp | 195 ----- src/Athena/FileWriter.cpp | 124 ---- src/Athena/MemoryReader.cpp | 196 ----- src/Athena/MemoryWriter.cpp | 315 -------- src/LZ77/LZType10.cpp | 2 +- src/LZ77/LZType11.cpp | 2 +- 19 files changed, 1705 insertions(+), 1783 deletions(-) delete mode 100644 src/Athena/FileReader.cpp delete mode 100644 src/Athena/FileWriter.cpp delete mode 100644 src/Athena/MemoryReader.cpp delete mode 100644 src/Athena/MemoryWriter.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 22ab505..349e3d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,10 +32,6 @@ endif() add_library(AthenaCore src/Athena/Utility.cpp - src/Athena/FileReader.cpp - src/Athena/FileWriter.cpp - src/Athena/MemoryReader.cpp - src/Athena/MemoryWriter.cpp src/Athena/Global.cpp src/Athena/Checksums.cpp src/Athena/Compression.cpp diff --git a/atdna/main.cpp b/atdna/main.cpp index 4f401a6..a6c5d40 100644 --- a/atdna/main.cpp +++ b/atdna/main.cpp @@ -563,9 +563,9 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor for (int p=0 ; p<2 ; ++p) { if (p) - fileOut << "void " << decl->getQualifiedNameAsString() << "::write(Athena::io::IStreamWriter& " ATHENA_DNA_WRITER ") const\n{\n"; + fileOut << "void " << decl->getQualifiedNameAsString() << "::write(IStreamWriter& " ATHENA_DNA_WRITER ") const\n{\n"; else - fileOut << "void " << decl->getQualifiedNameAsString() << "::read(Athena::io::IStreamReader& " ATHENA_DNA_READER ")\n{\n"; + fileOut << "void " << decl->getQualifiedNameAsString() << "::read(IStreamReader& " ATHENA_DNA_READER ")\n{\n"; if (baseDNA.size()) { @@ -1338,9 +1338,9 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor for (int p=0 ; p<2 ; ++p) { if (p) - fileOut << "void " << decl->getQualifiedNameAsString() << "::toYAML(Athena::io::YAMLDocWriter& " ATHENA_YAML_WRITER ") const\n{\n"; + fileOut << "void " << decl->getQualifiedNameAsString() << "::toYAML(YAMLDocWriter& " ATHENA_YAML_WRITER ") const\n{\n"; else - fileOut << "void " << decl->getQualifiedNameAsString() << "::fromYAML(Athena::io::YAMLDocReader& " ATHENA_YAML_READER ")\n{\n"; + fileOut << "void " << decl->getQualifiedNameAsString() << "::fromYAML(YAMLDocReader& " ATHENA_YAML_READER ")\n{\n"; if (baseDNA.size()) { diff --git a/include/Athena/DNA.hpp b/include/Athena/DNA.hpp index 5383b99..7d2d976 100644 --- a/include/Athena/DNA.hpp +++ b/include/Athena/DNA.hpp @@ -20,16 +20,16 @@ namespace io /* forward-declaration dance for recursively-derived types */ -template +template struct Buffer; -template +template struct String; -template +template struct WString; -template +template struct WStringAsString; /** @@ -40,9 +40,17 @@ struct WStringAsString; * with all read/write calls necessary to marshal the DNA structure to/from * a streamed medium */ -template +template struct DNA { + using IStreamReader = IStreamReader; + using IStreamWriter = IStreamWriter; + using StlTraits = STLTRAITS; + + using StlString = typename STLTRAITS::String; + using StlWString = typename STLTRAITS::WString; + template using StlVector = typename STLTRAITS::template Vector; + virtual void read(IStreamReader&)=0; virtual void write(IStreamWriter&) const=0; @@ -50,19 +58,19 @@ struct DNA using Value = T; template - using Vector = std::vector; + using Vector = typename STLTRAITS::template Vector; template - using Buffer = struct Athena::io::Buffer; + using Buffer = struct Athena::io::Buffer; template - using String = struct Athena::io::String; + using String = struct Athena::io::String; template - using WString = struct Athena::io::WString; + using WString = struct Athena::io::WString; template - using WStringAsString = struct Athena::io::WStringAsString; + using WStringAsString = struct Athena::io::WStringAsString; template struct Seek {}; @@ -73,78 +81,78 @@ struct DNA struct Delete {}; }; -template -struct Buffer : public DNA, public std::unique_ptr +template +struct Buffer : public DNA, public std::unique_ptr { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNA::IStreamReader& reader) { reset(new atUint8[sizeVar]); reader.readUBytesToBuf(get(), sizeVar); } - inline void write(IStreamWriter& writer) const + inline void write(typename DNA::IStreamWriter& writer) const { writer.writeUBytes(get(), sizeVar); } }; -template -struct String : public DNA, public std::string +template +struct String : public DNA, public STLTRAITS::String { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNA::IStreamReader& reader) {this->assign(std::move(reader.readString(sizeVar)));} - inline void write(IStreamWriter& writer) const + inline void write(typename DNA::IStreamWriter& writer) const {writer.writeString(*this, sizeVar);} - inline std::string& operator=(const std::string& __str) + inline typename STLTRAITS::String& operator=(const typename STLTRAITS::String& __str) {return this->assign(__str);} - inline std::string& operator=(std::string&& __str) + inline typename STLTRAITS::String& operator=(typename STLTRAITS::String&& __str) {this->swap(__str); return *this;} }; -template -struct WString : public DNA, public std::wstring +template +struct WString : public DNA, public STLTRAITS::WString { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNA::IStreamReader& reader) { reader.setEndian(VE); this->assign(std::move(reader.readWString(sizeVar))); } - inline void write(IStreamWriter& writer) const + inline void write(typename DNA::IStreamWriter& writer) const { writer.setEndian(VE); writer.writeWString(*this, sizeVar); } - inline std::wstring& operator=(const std::wstring& __str) + inline typename STLTRAITS::WString& operator=(const typename STLTRAITS::WString& __str) {return this->assign(__str);} - inline std::wstring& operator=(std::wstring&& __str) + inline typename STLTRAITS::WString& operator=(typename STLTRAITS::WString&& __str) {this->swap(__str); return *this;} }; -template -struct WStringAsString : public DNA, public std::string +template +struct WStringAsString : public DNA, public STLTRAITS::String { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNA::IStreamReader& reader) {*this = reader.readWStringAsString(sizeVar);} - inline void write(IStreamWriter& writer) const + inline void write(typename DNA::IStreamWriter& writer) const {writer.writeStringAsWString(*this, sizeVar);} - inline std::string& operator=(const std::string& __str) + inline typename STLTRAITS::String& operator=(const typename STLTRAITS::String& __str) {return this->assign(__str);} - inline std::string& operator=(std::string&& __str) + inline typename STLTRAITS::String& operator=(typename STLTRAITS::String&& __str) {this->swap(__str); return *this;} }; /** Macro to automatically declare read/write methods in subclasses */ #define DECL_DNA \ - void read(Athena::io::IStreamReader&); \ - void write(Athena::io::IStreamWriter&) const; \ + void read(IStreamReader&); \ + void write(IStreamWriter&) const; \ /** Macro to automatically declare read/write methods and prevent outputting implementation */ #define DECL_EXPLICIT_DNA \ - void read(Athena::io::IStreamReader&); \ - void write(Athena::io::IStreamWriter&) const; \ + void read(IStreamReader&); \ + void write(IStreamWriter&) const; \ Delete __dna_delete; /** Macro to supply count variable to atdna and mute it for other compilers */ diff --git a/include/Athena/DNAYaml.hpp b/include/Athena/DNAYaml.hpp index 4afe113..540157d 100644 --- a/include/Athena/DNAYaml.hpp +++ b/include/Athena/DNAYaml.hpp @@ -7,8 +7,6 @@ * Any changes to the types or namespacing must be reflected in 'atdna/main.cpp' */ -#include -#include #include #include #include "DNA.hpp" @@ -18,32 +16,154 @@ 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); +extern const char* AT_BASE64_CHARS; + +static inline bool at_is_base64(unsigned char c) +{ + return (isalnum(c) || (c == '+') || (c == '/')); +} + +template +typename STLTRAITS::String base64_encode(const atUint8* bytes_to_encode, size_t in_len) +{ + typename STLTRAITS::String ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + ret.reserve(in_len * 4 / 3); + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += AT_BASE64_CHARS[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += AT_BASE64_CHARS[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + +template +std::unique_ptr base64_decode(const typename STLTRAITS::String& encoded_string) +{ + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::unique_ptr ret(new atUint8[in_len * 3 / 4]); + atUint8* retBuf = ret.get(); + + while (in_len-- && ( encoded_string[in_] != '=') && at_is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = reinterpret_cast(strchr(AT_BASE64_CHARS, char_array_4[i]) - char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + *retBuf++ = char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = reinterpret_cast(strchr(AT_BASE64_CHARS, char_array_4[j]) - char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) *retBuf++ = char_array_3[j]; + } + + return ret; +} void HandleYAMLParserError(yaml_parser_t* parser); void HandleYAMLEmitterError(yaml_emitter_t* emitter); +template struct YAMLStdStringReaderState { - std::string::const_iterator begin; - std::string::const_iterator end; - YAMLStdStringReaderState(const std::string& str) + typename STLTRAITS::String::const_iterator begin; + typename STLTRAITS::String::const_iterator end; + YAMLStdStringReaderState(const typename STLTRAITS::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); +template +int YAMLStdStringReader(YAMLStdStringReaderState* reader, + unsigned char* buffer, size_t size, size_t* size_read) +{ + size_t diff = reader->end - reader->begin; + if (!diff) + { + *size_read = 0; + } + else if (diff < size) + { + memcpy(buffer, &*reader->begin, diff); + *size_read = diff; + } + else + { + memcpy(buffer, &*reader->begin, size); + *size_read = size; + } + return 1; +} + +template +int YAMLStdStringWriter(typename STLTRAITS::String* str, unsigned char *buffer, size_t size) +{ + str->append((char*)buffer, size); + return 1; +} + +template struct YAMLNode { yaml_node_type_t m_type; - std::string m_scalarString; - std::vector> m_seqChildren; - std::vector>> m_mapChildren; + typename STLTRAITS::String m_scalarString; + typename STLTRAITS::template Vector> m_seqChildren; + typename STLTRAITS::template Vector>> m_mapChildren; YAMLNode(yaml_node_type_t type) : m_type(type) {} inline const YAMLNode* findMapChild(const char* key) const { @@ -54,359 +174,529 @@ struct YAMLNode } }; -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) +template +static inline void InsertNode(typename STLTRAITS::template Vector*>& nodeStack, + std::unique_ptr>& mapKey, + std::unique_ptr>& retVal, + std::unique_ptr>&& newNode) { - 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%016llX", 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%016llX", 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) + if (nodeStack.empty()) { - YAMLNode* snode = it->get(); - if (snode->m_type == YAML_SCALAR_NODE) - retval.vec[i] = NodeToVal(snode); + retVal = std::move(newNode); + return; + } + YAMLNode* parent = nodeStack.back(); + if (parent->m_type == YAML_SEQUENCE_NODE) + { + parent->m_seqChildren.emplace_back(std::move(newNode)); + } + else if (parent->m_type == YAML_MAPPING_NODE) + { + if (!mapKey) + mapKey = std::move(newNode); else - retval.vec[i] = 0.0; + { + parent->m_mapChildren.emplace_back(std::move(mapKey->m_scalarString), std::move(newNode)); + mapKey.reset(nullptr); + } } - return retval; } -template <> -inline atVec2f NodeToVal(const YAMLNode* node) +static inline bool EmitKeyScalar(yaml_emitter_t* doc, const char* val) { - return NodeToVec(node); + yaml_event_t event; + if (!yaml_scalar_event_initialize(&event, nullptr, nullptr, (yaml_char_t*)val, + strlen(val), true, true, YAML_PLAIN_SCALAR_STYLE)) + return false; + return yaml_emitter_emit(doc, &event); } -template <> -inline std::unique_ptr ValToNode(const atVec2f& val) +template +static inline yaml_scalar_style_t ScalarStyle(const YAMLNode& node) { - YAMLNode* ret = new YAMLNode(YAML_SEQUENCE_NODE); - ret->m_seqChildren.reserve(2); - for (size_t i=0 ; i<2 ; ++i) + for (const auto& ch : node.m_scalarString) + if (ch == '\n') + return YAML_LITERAL_SCALAR_STYLE; + return YAML_ANY_SCALAR_STYLE; +} + +template +static inline yaml_sequence_style_t SequenceStyle(const YAMLNode& node) +{ + size_t count = 0; + for (const auto& item : node.m_seqChildren) + { + if (item->m_type != YAML_SCALAR_NODE) + return YAML_BLOCK_SEQUENCE_STYLE; + size_t strLen = item->m_scalarString.size(); + size_t thisCount = strLen / 10; + if (!thisCount) + thisCount = 1; + count += thisCount; + } + return (count > 6) ? YAML_BLOCK_SEQUENCE_STYLE : YAML_FLOW_SEQUENCE_STYLE; +} + +template +static inline yaml_mapping_style_t MappingStyle(const YAMLNode& node) +{ + size_t count = 0; + for (const auto& item : node.m_mapChildren) + { + if (item.second->m_type != YAML_SCALAR_NODE) + return YAML_BLOCK_MAPPING_STYLE; + size_t strLen = item.second->m_scalarString.size(); + size_t thisCount = strLen / 10; + if (!thisCount) + thisCount = 1; + count += thisCount; + } + return (count > 6) ? YAML_BLOCK_MAPPING_STYLE : YAML_FLOW_MAPPING_STYLE; +} + +template +struct YAMLTranslate +{ + template + static std::unique_ptr> ValToNode(const INTYPE& val); + template + static std::unique_ptr> ValToNode(const INTYPE* val); + template + static std::unique_ptr> ValToNode(const INTYPE& val, size_t byteCount); + + template + static bool NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + 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; + } + + static 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 + static atInt8 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtol(node->m_scalarString.c_str(), NULL, 0); + } + + static 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 + static atUint8 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtoul(node->m_scalarString.c_str(), NULL, 0); + } + + static 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 + static atInt16 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtol(node->m_scalarString.c_str(), NULL, 0); + } + + static 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 + static atUint16 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtoul(node->m_scalarString.c_str(), NULL, 0); + } + + static 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 + static atInt32 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtol(node->m_scalarString.c_str(), NULL, 0); + } + + static 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 + static atUint32 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtoul(node->m_scalarString.c_str(), NULL, 0); + } + + static 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 + static atInt64 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { +#if _WIN32 + return _strtoi64(node->m_scalarString.c_str(), NULL, 0); +#else + return strtoq(node->m_scalarString.c_str(), NULL, 0); +#endif + } + + static std::unique_ptr> ValToNode(const atInt64& val) + { + char str[32]; + snprintf(str, 32, "0x%016llX", val); + YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); + ret->m_scalarString = str; + return std::unique_ptr>(ret); + } + + template + static atUint64 NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { +#if _WIN32 + return _strtoui64(node->m_scalarString.c_str(), NULL, 0); +#else + return strtouq(node->m_scalarString.c_str(), NULL, 0); +#endif + } + + static std::unique_ptr> ValToNode(const atUint64& val) + { + char str[32]; + snprintf(str, 32, "0x%016llX", val); + YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); + ret->m_scalarString = str; + return std::unique_ptr>(ret); + } + + template + static float NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtof(node->m_scalarString.c_str(), NULL); + } + + static std::unique_ptr> ValToNode(const float& val) { 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); + snprintf(str, 64, "%f", val); + YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); + ret->m_scalarString = str; + return std::unique_ptr>(ret); } - return std::unique_ptr(ret); -} -template <> -inline atVec3f NodeToVal(const YAMLNode* node) -{ - return NodeToVec(node); -} + template + static double NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return strtod(node->m_scalarString.c_str(), NULL); + } -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) + static std::unique_ptr> ValToNode(const double& val) { 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); + snprintf(str, 64, "%f", val); + YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); + ret->m_scalarString = str; + return std::unique_ptr>(ret); } - 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) + template + static RETURNTYPE NodeToVec(const YAMLNode* node) { - 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); + 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) + retval.vec[i] = NodeToVal(snode); + else + retval.vec[i] = 0.0; + } + return retval; } - return std::unique_ptr(ret); -} -template <> -inline std::unique_ptr NodeToVal(const YAMLNode* node) -{ - return base64_decode(node->m_scalarString); -} + template + static atVec2f NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return NodeToVec(node); + } -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); -} + static 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 std::string NodeToVal(const YAMLNode* node) -{ - return node->m_scalarString; -} + template + static atVec3f NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return NodeToVec(node); + } -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); -} + static 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 std::unique_ptr ValToNode(const char* val) -{ - YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); - ret->m_scalarString = val; - return std::unique_ptr(ret); -} + template + static atVec4f NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return NodeToVec(node); + } -template <> -inline std::wstring NodeToVal(const YAMLNode* node) -{ - std::wstring_convert> conv; - return conv.from_bytes(node->m_scalarString); -} + static 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 std::unique_ptr ValToNode(const std::wstring& val) -{ - std::wstring_convert> conv; - YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); - ret->m_scalarString = conv.to_bytes(val); - return std::unique_ptr(ret); -} + template + static std::unique_ptr NodeToVal(const YAMLNode* node, + typename std::enable_if, RETURNTYPE>::value>::type* = 0) + { + return base64_decode(node->m_scalarString); + } -template <> -inline std::unique_ptr ValToNode(const wchar_t* val) -{ - std::wstring wstr(val); - return ValToNode(wstr); -} + static 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 + static typename STLTRAITS::String NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + return node->m_scalarString; + } + + static std::unique_ptr> ValToNode(const typename STLTRAITS::String& val) + { + YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); + ret->m_scalarString = val; + return std::unique_ptr>(ret); + } + + static std::unique_ptr> ValToNode(const char* val) + { + YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); + ret->m_scalarString = val; + return std::unique_ptr>(ret); + } + + template + static typename STLTRAITS::WString NodeToVal(const YAMLNode* node, + typename std::enable_if::value>::type* = 0) + { + typename STLTRAITS::WString retval; + retval.reserve(node->m_scalarString.length()); + const char* buf = node->m_scalarString.c_str(); + while (*buf) + { + wchar_t wc; + buf += std::mbtowc(&wc, buf, MB_CUR_MAX); + retval += wc; + } + return retval; + } + + static std::unique_ptr> ValToNode(const typename STLTRAITS::WString& val) + { + YAMLNode* ret = new YAMLNode(YAML_SCALAR_NODE); + ret->m_scalarString.reserve(val.length()); + for (wchar_t ch : val) + { + char mb[4]; + int c = std::wctomb(mb, ch); + ret->m_scalarString.append(mb, c); + } + return std::unique_ptr>(ret); + } + + static std::unique_ptr> ValToNode(const wchar_t* val) + { + std::wstring wstr(val); + return ValToNode(wstr); + } + +}; + +template class YAMLDocReader { - std::unique_ptr m_rootNode; - std::vector m_subStack; - std::vector m_seqTrackerStack; - static std::unique_ptr ParseEvents(yaml_parser_t* doc); + std::unique_ptr> m_rootNode; + typename STLTRAITS::template Vector*> m_subStack; + typename STLTRAITS::template Vector m_seqTrackerStack; + static std::unique_ptr> ParseEvents(yaml_parser_t* doc) + { + yaml_event_t event; + if (!yaml_parser_parse(doc, &event)) + { + HandleYAMLParserError(doc); + return std::unique_ptr>(); + } + + typename STLTRAITS::template Vector*> nodeStack; + std::unique_ptr> mapKey; + std::unique_ptr> retVal; + int result; + for (result = yaml_parser_parse(doc, &event); + event.type != YAML_STREAM_END_EVENT; + result = yaml_parser_parse(doc, &event)) + { + if (!result) + { + HandleYAMLParserError(doc); + return std::unique_ptr>(); + } + switch (event.type) + { + case YAML_SCALAR_EVENT: + { + if (nodeStack.empty()) + { + atWarning("YAML parser stack empty; skipping scalar node"); + break; + } + std::unique_ptr> newScalar(new YAMLNode(YAML_SCALAR_NODE)); + newScalar->m_scalarString.assign((char*)event.data.scalar.value, event.data.scalar.length); + if (nodeStack.empty()) + retVal = std::move(newScalar); + else + InsertNode(nodeStack, mapKey, retVal, std::move(newScalar)); + break; + } + case YAML_SEQUENCE_START_EVENT: + { + YAMLNode* newSeq = new YAMLNode(YAML_SEQUENCE_NODE); + InsertNode(nodeStack, mapKey, retVal, std::unique_ptr>(newSeq)); + nodeStack.emplace_back(newSeq); + break; + } + case YAML_SEQUENCE_END_EVENT: + { + nodeStack.pop_back(); + break; + } + case YAML_MAPPING_START_EVENT: + { + YAMLNode* newMap = new YAMLNode(YAML_MAPPING_NODE); + InsertNode(nodeStack, mapKey, retVal, std::unique_ptr>(newMap)); + nodeStack.emplace_back(newMap); + break; + } + case YAML_MAPPING_END_EVENT: + { + nodeStack.pop_back(); + break; + } + case YAML_DOCUMENT_END_EVENT: + { + yaml_event_delete(&event); + return retVal; + } + default: + break; + } + yaml_event_delete(&event); + } + return std::unique_ptr>(); + } public: - inline const YAMLNode* getRootNode() const {return m_rootNode.get();} + using StlTraits = STLTRAITS; + + inline const YAMLNode* getRootNode() const {return m_rootNode.get();} bool read(yaml_parser_t* doc) { - std::unique_ptr newRoot = ParseEvents(doc); + std::unique_ptr> newRoot = ParseEvents(doc); if (!newRoot) return false; m_rootNode = std::move(newRoot); @@ -418,7 +708,7 @@ public: void enterSubRecord(const char* name) { - YAMLNode* curSub = m_subStack.back(); + YAMLNode* curSub = m_subStack.back(); if (curSub->m_type == YAML_SEQUENCE_NODE) { int& seqIdx = m_seqTrackerStack.back(); @@ -451,12 +741,12 @@ public: void enterSubVector(const char* name) { - YAMLNode* curSub = m_subStack.back(); + YAMLNode* curSub = m_subStack.back(); for (const auto& item : curSub->m_mapChildren) { if (!item.first.compare(name)) { - YAMLNode* nextSub = item.second.get(); + YAMLNode* nextSub = item.second.get(); m_subStack.push_back(nextSub); m_seqTrackerStack.push_back(0); break; @@ -474,7 +764,7 @@ public: } template - void enumerate(const char* name, std::vector& vector, size_t count, + void enumerate(const char* name, typename STLTRAITS::template Vector& vector, size_t count, typename std::enable_if::value && !std::is_same::value && !std::is_same::value && @@ -494,7 +784,7 @@ public: } template - void enumerate(const char* name, std::vector& vector, size_t count, + void enumerate(const char* name, typename STLTRAITS::template Vector& vector, size_t count, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -509,8 +799,8 @@ public: } template - void enumerate(const char* name, std::vector& vector, size_t count, - std::function readf) + void enumerate(const char* name, typename STLTRAITS::template Vector& vector, size_t count, + std::function&, T&)> readf) { vector.clear(); vector.reserve(count); @@ -530,15 +820,15 @@ public: { if (m_subStack.size()) { - const YAMLNode* mnode = m_subStack.back(); + const YAMLNode* mnode = m_subStack.back(); if (mnode->m_type == YAML_SCALAR_NODE) { - return NodeToVal(mnode); + return YAMLTranslate::template NodeToVal(mnode); } else if (mnode->m_type == YAML_SEQUENCE_NODE) { int& seqIdx = m_seqTrackerStack.back(); - return NodeToVal(mnode->m_seqChildren[seqIdx++].get()); + return YAMLTranslate::template NodeToVal(mnode->m_seqChildren[seqIdx++].get()); } else if (mnode->m_type == YAML_MAPPING_NODE) { @@ -546,7 +836,7 @@ public: { if (!item.first.compare(name)) { - return NodeToVal(item.second.get()); + return YAMLTranslate::template NodeToVal(item.second.get()); } } } @@ -630,24 +920,73 @@ public: return readVal>(name); } - inline std::string readString(const char* name) + inline typename STLTRAITS::String readString(const char* name) { - return readVal(name); + return readVal(name); } - inline std::wstring readWString(const char* name) + inline typename STLTRAITS::WString readWString(const char* name) { - return readVal(name); + return readVal(name); } }; +template class YAMLDocWriter { - YAMLNode m_rootNode; - std::vector m_subStack; - static bool RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node); + YAMLNode m_rootNode; + typename STLTRAITS::template Vector*> m_subStack; + static bool RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node) + { + yaml_event_t event; + if (node.m_type == YAML_SCALAR_NODE) + { + if (!yaml_scalar_event_initialize(&event, nullptr, nullptr, (yaml_char_t*)node.m_scalarString.c_str(), + node.m_scalarString.length(), true, true, ScalarStyle(node)) || + !yaml_emitter_emit(doc, &event)) + goto err; + } + else if (node.m_type == YAML_SEQUENCE_NODE) + { + if (!yaml_sequence_start_event_initialize(&event, nullptr, nullptr, 1, SequenceStyle(node)) || + !yaml_emitter_emit(doc, &event)) + goto err; + for (const auto& item : node.m_seqChildren) + { + if (!RecursiveFinish(doc, *item)) + goto err; + } + if (!yaml_sequence_end_event_initialize(&event) || + !yaml_emitter_emit(doc, &event)) + goto err; + } + else if (node.m_type == YAML_MAPPING_NODE) + { + if (!yaml_mapping_start_event_initialize(&event, nullptr, nullptr, true, MappingStyle(node)) || + !yaml_emitter_emit(doc, &event)) + goto err; + for (const auto& item : node.m_mapChildren) + { + if (!EmitKeyScalar(doc, item.first.c_str())) + goto err; + if (!RecursiveFinish(doc, *item.second)) + goto err; + } + event.type = YAML_MAPPING_END_EVENT; + if (!yaml_mapping_end_event_initialize(&event) || + !yaml_emitter_emit(doc, &event)) + goto err; + + } + return true; + err: + HandleYAMLEmitterError(doc); + return false; + } public: + using StlTraits = STLTRAITS; + YAMLDocWriter() : m_rootNode(YAML_MAPPING_NODE) { m_subStack.emplace_back(&m_rootNode); @@ -655,13 +994,14 @@ public: void enterSubRecord(const char* name) { - YAMLNode* curSub = m_subStack.back(); + 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); + 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)); + curSub->m_mapChildren.emplace_back(name?typename STLTRAITS::String(name):typename STLTRAITS::String(), + std::unique_ptr>(newNode)); else if (curSub->m_type == YAML_SEQUENCE_NODE) curSub->m_seqChildren.emplace_back(newNode); m_subStack.push_back(newNode); @@ -671,7 +1011,7 @@ public: { if (m_subStack.size() > 1) { - YAMLNode* curSub = m_subStack.back(); + YAMLNode* curSub = m_subStack.back(); /* Automatically lower to scalar if there's only one unnamed node */ if (curSub->m_mapChildren.size() == 1 && curSub->m_mapChildren[0].first.empty()) @@ -698,13 +1038,14 @@ public: void enterSubVector(const char* name) { - YAMLNode* curSub = m_subStack.back(); + 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); + 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)); + curSub->m_mapChildren.emplace_back(name?typename STLTRAITS::String(name):typename STLTRAITS::String(), + std::unique_ptr>(newNode)); else if (curSub->m_type == YAML_SEQUENCE_NODE) curSub->m_seqChildren.emplace_back(newNode); m_subStack.push_back(newNode); @@ -717,7 +1058,7 @@ public: } template - void enumerate(const char* name, const std::vector& vector, + void enumerate(const char* name, const typename STLTRAITS::template Vector& vector, typename std::enable_if::value && !std::is_same::value && !std::is_same::value && @@ -734,7 +1075,7 @@ public: } template - void enumerate(const char* name, const std::vector& vector, + void enumerate(const char* name, const typename STLTRAITS::template Vector& vector, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -747,7 +1088,7 @@ public: } template - void enumerate(const char* name, const std::vector& vector, + void enumerate(const char* name, const typename STLTRAITS::template Vector& vector, std::function writef) { enterSubVector(name); @@ -781,21 +1122,23 @@ public: template void writeVal(const char* name, INTYPE val) { - YAMLNode* curSub = m_subStack.back(); + 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))); + curSub->m_mapChildren.emplace_back(name?name:typename STLTRAITS::String(), + std::move(YAMLTranslate::ValToNode(val))); else if (curSub->m_type == YAML_SEQUENCE_NODE) - curSub->m_seqChildren.emplace_back(std::move(ValToNode(val))); + curSub->m_seqChildren.emplace_back(std::move(YAMLTranslate::ValToNode(val))); } template void writeVal(const char* name, INTYPE val, size_t byteCount) { - YAMLNode* curSub = m_subStack.back(); + 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))); + curSub->m_mapChildren.emplace_back(name?name:typename STLTRAITS::String(), + std::move(YAMLTranslate::ValToNode(val, byteCount))); else if (curSub->m_type == YAML_SEQUENCE_NODE) - curSub->m_seqChildren.emplace_back(std::move(ValToNode(val, byteCount))); + curSub->m_seqChildren.emplace_back(std::move(YAMLTranslate::ValToNode(val, byteCount))); } inline void writeBool(const char* name, const bool& val) @@ -873,9 +1216,9 @@ public: writeVal&>(name, val, byteCount); } - inline void writeString(const char* name, const std::string& val) + inline void writeString(const char* name, const typename STLTRAITS::String& val) { - writeVal(name, val); + writeVal(name, val); } inline void writeString(const char* name, const char* val) @@ -883,9 +1226,9 @@ public: writeVal(name, val); } - inline void writeWString(const char* name, const std::wstring& val) + inline void writeWString(const char* name, const typename STLTRAITS::WString& val) { - writeVal(name, val); + writeVal(name, val); } inline void writeWString(const char* name, const wchar_t* val) @@ -896,47 +1239,52 @@ public: /* forward-declaration dance for recursively-derived types */ -template +template struct BufferYaml; -template +template struct StringYaml; -template +template struct WStringYaml; -template +template struct WStringAsStringYaml; -template -struct DNAYaml : DNA +template +struct DNAYaml : DNA { + using YAMLDocReader = YAMLDocReader; + using YAMLDocWriter = YAMLDocWriter; + using YAMLNode = YAMLNode; + using YAMLTranslate = YAMLTranslate; + virtual void toYAML(YAMLDocWriter& out) const=0; virtual void fromYAML(YAMLDocReader& in)=0; template - using Buffer = struct Athena::io::BufferYaml; + using Buffer = struct Athena::io::BufferYaml; template - using String = struct Athena::io::StringYaml; + using String = struct Athena::io::StringYaml; template - using WString = struct Athena::io::WStringYaml; + using WString = struct Athena::io::WStringYaml; template - using WStringAsString = struct Athena::io::WStringAsStringYaml; + using WStringAsString = struct Athena::io::WStringAsStringYaml; - std::string toYAMLString() const + typename STLTRAITS::String toYAMLString() const { yaml_emitter_t emitter; if (!yaml_emitter_initialize(&emitter)) { HandleYAMLEmitterError(&emitter); - return std::string(); + return typename STLTRAITS::String(); } - std::string res; - yaml_emitter_set_output(&emitter, (yaml_write_handler_t*)YAMLStdStringWriter, &res); + typename STLTRAITS::String res; + yaml_emitter_set_output(&emitter, (yaml_write_handler_t*)YAMLStdStringWriter, &res); yaml_emitter_set_unicode(&emitter, true); yaml_emitter_set_width(&emitter, -1); @@ -944,7 +1292,7 @@ struct DNAYaml : DNA { HandleYAMLEmitterError(&emitter); yaml_emitter_delete(&emitter); - return std::string(); + return typename STLTRAITS::String(); } { YAMLDocWriter docWriter; @@ -952,7 +1300,7 @@ struct DNAYaml : DNA if (!docWriter.finish(&emitter)) { yaml_emitter_delete(&emitter); - return std::string(); + return typename STLTRAITS::String(); } } if (!yaml_emitter_close(&emitter) || @@ -960,14 +1308,14 @@ struct DNAYaml : DNA { HandleYAMLEmitterError(&emitter); yaml_emitter_delete(&emitter); - return std::string(); + return typename STLTRAITS::String(); } yaml_emitter_delete(&emitter); return res; } - bool fromYAMLString(const std::string& str) + bool fromYAMLString(const typename STLTRAITS::String& str) { yaml_parser_t parser; if (!yaml_parser_initialize(&parser)) @@ -976,8 +1324,8 @@ struct DNAYaml : DNA return false; } - YAMLStdStringReaderState reader(str); - yaml_parser_set_input(&parser, (yaml_read_handler_t*)YAMLStdStringReader, &reader); + YAMLStdStringReaderState reader(str); + yaml_parser_set_input(&parser, (yaml_read_handler_t*)YAMLStdStringReader, &reader); YAMLDocReader docReader; if (!docReader.read(&parser)) @@ -1053,95 +1401,95 @@ struct DNAYaml : DNA } }; -template -struct BufferYaml : public DNAYaml, public std::unique_ptr +template +struct BufferYaml : public DNAYaml, public std::unique_ptr { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNAYaml::IStreamReader& reader) { reset(new atUint8[sizeVar]); reader.readUBytesToBuf(get(), sizeVar); } - inline void write(IStreamWriter& writer) const + inline void write(typename DNAYaml::IStreamWriter& writer) const { writer.writeUBytes(get(), sizeVar); } - inline void fromYAML(Athena::io::YAMLDocReader& reader) + inline void fromYAML(YAMLDocReader& reader) {*this = reader.readUBytes(nullptr);} - inline void toYAML(Athena::io::YAMLDocWriter& writer) const + inline void toYAML(YAMLDocWriter& writer) const {writer.writeUBytes(nullptr, *this, sizeVar);} }; -template -struct StringYaml : public DNAYaml, public std::string +template +struct StringYaml : public DNAYaml, public STLTRAITS::String { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNAYaml::IStreamReader& reader) {this->assign(std::move(reader.readString(sizeVar)));} - inline void write(IStreamWriter& writer) const + inline void write(typename DNAYaml::IStreamWriter& writer) const {writer.writeString(*this, sizeVar);} - inline void fromYAML(Athena::io::YAMLDocReader& reader) + inline void fromYAML(YAMLDocReader& reader) {this->assign(std::move(reader.readString(nullptr)));} - inline void toYAML(Athena::io::YAMLDocWriter& writer) const + inline void toYAML(YAMLDocWriter& writer) const {writer.writeString(nullptr, *this);} - inline std::string& operator=(const std::string& __str) + inline typename STLTRAITS::String& operator=(const typename STLTRAITS::String& __str) {return this->assign(__str);} - inline std::string& operator=(std::string&& __str) + inline typename STLTRAITS::String& operator=(typename STLTRAITS::String&& __str) {this->swap(__str); return *this;} }; -template -struct WStringYaml : public DNAYaml, public std::wstring +template +struct WStringYaml : public DNAYaml, public STLTRAITS::WString { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNAYaml::IStreamReader& reader) { reader.setEndian(VE); this->assign(std::move(reader.readWString(sizeVar))); } - inline void write(IStreamWriter& writer) const + inline void write(typename DNAYaml::IStreamWriter& writer) const { writer.setEndian(VE); writer.writeWString(*this, sizeVar); } - inline void fromYAML(Athena::io::YAMLDocReader& reader) + inline void fromYAML(YAMLDocReader& reader) {this->assign(std::move(reader.readWString(nullptr)));} - inline void toYAML(Athena::io::YAMLDocWriter& writer) const + inline void toYAML(YAMLDocWriter& writer) const {writer.writeWString(nullptr, *this);} - inline std::wstring& operator=(const std::wstring& __str) + inline typename STLTRAITS::WSTRING& operator=(const typename STLTRAITS::WSTRING& __str) {return this->assign(__str);} - inline std::wstring& operator=(std::wstring&& __str) + inline typename STLTRAITS::WSTRING& operator=(typename STLTRAITS::WSTRING&& __str) {this->swap(__str); return *this;} }; -template -struct WStringAsStringYaml : public DNAYaml, public std::string +template +struct WStringAsStringYaml : public DNAYaml, public STLTRAITS::String { typename DNA::Delete expl; - inline void read(IStreamReader& reader) + inline void read(typename DNAYaml::IStreamReader& reader) {*this = reader.readWStringAsString(sizeVar);} - inline void write(IStreamWriter& writer) const + inline void write(typename DNAYaml::IStreamWriter& writer) const {writer.writeStringAsWString(*this, sizeVar);} - inline void fromYAML(Athena::io::YAMLDocReader& reader) + inline void fromYAML(YAMLDocReader& reader) {this->assign(std::move(reader.readString(nullptr)));} - inline void toYAML(Athena::io::YAMLDocWriter& writer) const + inline void toYAML(YAMLDocWriter& writer) const {writer.writeString(nullptr, *this);} - inline std::string& operator=(const std::string& __str) + inline typename STLTRAITS::String& operator=(const typename STLTRAITS::String& __str) {return this->assign(__str);} - inline std::string& operator=(std::string&& __str) + inline typename STLTRAITS::String& operator=(typename STLTRAITS::String&& __str) {this->swap(__str); return *this;} }; /** Macro to automatically declare YAML read/write methods in subclasses */ #define DECL_YAML \ DECL_DNA \ - void fromYAML(Athena::io::YAMLDocReader&); \ - void toYAML(Athena::io::YAMLDocWriter&) const; \ + void fromYAML(YAMLDocReader&); \ + void toYAML(YAMLDocWriter&) const; \ /** Macro to automatically declare YAML read/write methods with client-code's definition */ #define DECL_EXPLICIT_YAML \ - void fromYAML(Athena::io::YAMLDocReader&); \ - void toYAML(Athena::io::YAMLDocWriter&) const; \ + void fromYAML(YAMLDocReader&); \ + void toYAML(YAMLDocWriter&) const; \ } } diff --git a/include/Athena/FileReader.hpp b/include/Athena/FileReader.hpp index 461c1c2..c306a84 100644 --- a/include/Athena/FileReader.hpp +++ b/include/Athena/FileReader.hpp @@ -6,36 +6,210 @@ #include #include "Athena/IStreamReader.hpp" +#if _WIN32 +#include "win32_largefilewrapper.h" +#elif __APPLE__ +#include "osx_largefilewrapper.h" +#endif + namespace Athena { namespace io { -class FileReader : public IStreamReader +template +class FileReader : public IStreamReader { public: - FileReader(const std::string& filename, atInt32 cacheSize = (32 * 1024)); -#if _WIN32 - FileReader(const std::wstring& filename, atInt32 cacheSize = (32 * 1024)); -#endif - virtual ~FileReader(); - inline const std::string& filename() const + inline const typename STLTRAITS::String& filename() const {return m_filename;} - void open(); - void close(); - inline bool isOpen() const - {return m_fileHandle != NULL;} - bool save(); - void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); - atUint64 position() const; - atUint64 length() const; - atUint64 readUBytesToBuf(void* buf, atUint64 len); + FileReader(const typename STLTRAITS::String& filename, atInt32 cacheSize = (32 * 1024)) + : m_filename(filename), + m_fileHandle(nullptr), + m_cacheData(nullptr), + m_offset(0) + { + open(); + setCacheSize(cacheSize); + } + + #if _WIN32 + FileReader::FileReader(const typename STLTRAITS::WString& filename, atInt32 cacheSize = (32 * 1024)) + : m_wfilename(filename), + m_fileHandle(nullptr), + m_cacheData(nullptr), + m_offset(0) + { + open(); + setCacheSize(cacheSize); + } + #endif + + virtual ~FileReader() + { + if (isOpen()) + close(); + } + + void open() + { + #if _WIN32 + if (m_wfilename.size()) + m_fileHandle = _wfopen(m_wfilename.c_str(), L"rb"); + else + m_fileHandle = fopen(m_filename.c_str(), "rb"); + #else + m_fileHandle = fopen(m_filename.c_str(), "rb"); + #endif + + if (!m_fileHandle) + { + atError("File not found '%s'", m_filename.c_str()); + IStream::setError(); + return; + } + + // ensure we're at the beginning of the file + rewind(m_fileHandle); + } + + void close() + { + if (!m_fileHandle) + { + atError("Cannot close an unopened stream"); + IStream::setError(); + return; + } + + fclose(m_fileHandle); + m_fileHandle = NULL; + return; + } + + inline bool isOpen() const {return m_fileHandle != NULL;} + + void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current) + { + // check block position + if (m_blockSize > 0) + { + atUint64 oldOff = m_offset; + switch(origin) + { + case SeekOrigin::Begin: + m_offset = pos; + break; + case SeekOrigin::Current: + m_offset += pos; + break; + case SeekOrigin::End: + m_offset = length() - pos; + break; + } + if (m_offset > length()) + { + oldOff = m_offset; + atError("Unable to seek in file"); + return; + } + + size_t block = m_offset / m_blockSize; + if (block != m_curBlock) + { + fseeko64(m_fileHandle, block * m_blockSize, SEEK_SET); + fread(m_cacheData.get(), 1, m_blockSize, m_fileHandle); + m_curBlock = (atInt32)block; + } + } + else if (fseeko64(m_fileHandle, pos, (int)origin) != 0) + atError("Unable to seek in file"); + } + + atUint64 position() const + { + if (!isOpen()) + { + atError("File not open"); + return 0; + } + + if (m_blockSize > 0) + return m_offset; + else + return ftello64(m_fileHandle); + } + + atUint64 length() const + { + if (!isOpen()) + { + atError("File not open"); + return 0; + } + + return utility::fileSize(m_filename); + } + + atUint64 readUBytesToBuf(void* buf, atUint64 len) + { + if (!isOpen()) + { + atError("File not open for reading"); + IStream::setError(); + return 0; + } + + if (m_blockSize <= 0) + return fread(buf, 1, len, m_fileHandle); + else + { + size_t block = m_offset / m_blockSize; + atUint64 cacheOffset = m_offset % m_blockSize; + atUint64 cacheSize; + atUint64 rem = len; + atUint8* dst = (atUint8*)buf; + + while (rem) + { + if (block != m_curBlock) + { + fseeko64(m_fileHandle, block * m_blockSize, SEEK_SET); + fread(m_cacheData.get(), 1, m_blockSize, m_fileHandle); + m_curBlock = (atInt32)block; + } + + cacheSize = rem; + if (cacheSize + cacheOffset > m_blockSize) + cacheSize = m_blockSize - cacheOffset; + + memcpy(dst, m_cacheData.get() + cacheOffset, cacheSize); + dst += cacheSize; + rem -= cacheSize; + cacheOffset = 0; + ++block; + } + m_offset += len; + return dst - (atUint8*)buf; + } + } + + void setCacheSize(const atInt32 blockSize) + { + m_blockSize = blockSize; + + if (m_blockSize > length()) + m_blockSize = (atInt32)length(); + + m_curBlock = -1; + if (m_blockSize > 0) + m_cacheData.reset(new atUint8[m_blockSize]); + } - void setCacheSize(const atInt32 blockSize); protected: - std::string m_filename; + typename STLTRAITS::String m_filename; #if _WIN32 - std::wstring m_wfilename; + typename STLTRAITS::WString m_wfilename; #endif FILE* m_fileHandle; std::unique_ptr m_cacheData; diff --git a/include/Athena/FileWriter.hpp b/include/Athena/FileWriter.hpp index e09c2fb..838c011 100644 --- a/include/Athena/FileWriter.hpp +++ b/include/Athena/FileWriter.hpp @@ -4,32 +4,136 @@ #include "Athena/IStreamWriter.hpp" #include +#if _WIN32 +#include "win32_largefilewrapper.h" +#elif __APPLE__ +#include "osx_largefilewrapper.h" +#endif + namespace Athena { namespace io { -class FileWriter : public IStreamWriter +template +class FileWriter : public IStreamWriter { public: - FileWriter(const std::string& filename, bool overwrite = true); -#if _WIN32 - FileWriter(const std::wstring& filename, bool overwrite = true); -#endif - virtual ~FileWriter(); + inline bool isOpen() const {return m_fileHandle != NULL;} - void open(bool overwrite = true); - void close(); - inline bool isOpen() const - {return m_fileHandle != NULL;} - void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); - atUint64 position() const; - atUint64 length() const; - void writeUBytes(const atUint8* data, atUint64 len); + FileWriter(const std::string& filename, bool overwrite = true) + : m_filename(filename), + m_fileHandle(NULL), + m_bytePosition(0) + { + open(overwrite); + } + + #if _WIN32 + FileWriter(const std::wstring& filename, bool overwrite = true) + : m_wfilename(filename), + m_fileHandle(NULL), + m_bytePosition(0) + { + open(overwrite); + } + #endif + + virtual ~FileWriter() + { + if (isOpen()) + close(); + } + + void open(bool overwrite = true) + { + #if _WIN32 + if (m_wfilename.size()) + { + if (overwrite) + m_fileHandle = _wfopen(m_wfilename.c_str(), L"w+b"); + else + m_fileHandle = _wfopen(m_wfilename.c_str(), L"r+b"); + } + else + { + if (overwrite) + m_fileHandle = fopen(m_filename.c_str(), "w+b"); + else + m_fileHandle = fopen(m_filename.c_str(), "r+b"); + } + #else + if (overwrite) + m_fileHandle = fopen(m_filename.c_str(), "w+b"); + else + m_fileHandle = fopen(m_filename.c_str(), "r+b"); + #endif + + + + if (!m_fileHandle) + { + atError("Unable to open file '%s'", m_filename.c_str()); + IStream::setError(); + return; + } + + // ensure we're at the beginning of the file + rewind(m_fileHandle); + } + + void close() + { + if (!m_fileHandle) + { + atError("Cannot close an unopened stream"); + IStream::setError(); + return; + } + + fclose(m_fileHandle); + m_fileHandle = NULL; + return; + } + + void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current) + { + if (fseeko64(m_fileHandle, pos, (int)origin) != 0) + { + atError("Unable to seek in file"); + IStream::setError(); + } + } + + atUint64 position() const + { + return ftello64(m_fileHandle); + } + + atUint64 length() const + { + return utility::fileSize(m_filename); + } + + void writeUBytes(const atUint8* data, atUint64 len) + { + if (!isOpen()) + { + atError("File not open for writing"); + IStream::setError(); + return; + } + + if (fwrite(data, 1, len, m_fileHandle) != len) + { + atError("Unable to write to stream"); + IStream::setError(); + } + } private: - std::string m_filename; + typename STLTRAITS::String m_filename; #if _WIN32 - std::wstring m_wfilename; + typename STLTRAITS::WString m_wfilename; #endif FILE* m_fileHandle; atUint8 m_currentByte; diff --git a/include/Athena/Global.hpp b/include/Athena/Global.hpp index 1d4a942..f81afff 100644 --- a/include/Athena/Global.hpp +++ b/include/Athena/Global.hpp @@ -60,6 +60,13 @@ typedef struct stat64 stat64_t; namespace Athena { +struct StlTraits +{ + template using Vector = std::vector; + using String = std::string; + using WString = std::wstring; +}; + namespace error { enum Level diff --git a/include/Athena/IStreamReader.hpp b/include/Athena/IStreamReader.hpp index 8203fad..a43fa28 100644 --- a/include/Athena/IStreamReader.hpp +++ b/include/Athena/IStreamReader.hpp @@ -1,8 +1,7 @@ #ifndef ISTREAMREADER_HPP #define ISTREAMREADER_HPP -#include -#include +#include #include #include "IStream.hpp" @@ -10,6 +9,7 @@ namespace Athena { namespace io { +template class IStreamReader : public IStream { public: @@ -589,9 +589,9 @@ public: * \return std::string The value at the current address * \throw IOException when address is out of range */ - inline std::string readWStringAsString(atInt32 fixedLen = -1) + inline typename STLTRAITS::String readWStringAsString(atInt32 fixedLen = -1) { - std::wstring tmp; + typename STLTRAITS::String retval; atUint16 chr = readUint16(); atInt32 i; @@ -603,20 +603,21 @@ public: if (!chr) break; - tmp.push_back(chr); + char mb[4]; + int c = std::wctomb(mb, chr); + retval.append(mb, c); chr = readUint16(); } if (fixedLen >= 0 && i < fixedLen) seek(fixedLen - i); - std::wstring_convert> conv; - return conv.to_bytes(tmp); + return retval; } - inline std::string readWStringAsStringLittle(atInt32 fixedLen = -1) + inline typename STLTRAITS::String readWStringAsStringLittle(atInt32 fixedLen = -1) { - std::wstring tmp; + typename STLTRAITS::String retval; atUint16 chr = readUint16Little(); atInt32 i; @@ -628,20 +629,21 @@ public: if (!chr) break; - tmp.push_back(chr); + char mb[4]; + int c = std::wctomb(mb, chr); + retval.append(mb, c); chr = readUint16Little(); } if (fixedLen >= 0 && i < fixedLen) seek(fixedLen - i); - std::wstring_convert> conv; - return conv.to_bytes(tmp); + return retval; } - inline std::string readWStringAsStringBig(atInt32 fixedLen = -1) + inline typename STLTRAITS::String readWStringAsStringBig(atInt32 fixedLen = -1) { - std::wstring tmp; + typename STLTRAITS::String retval; atUint16 chr = readUint16Big(); atInt32 i; @@ -653,15 +655,16 @@ public: if (!chr) break; - tmp.push_back(chr); + char mb[4]; + int c = std::wctomb(mb, chr); + retval.append(mb, c); chr = readUint16Big(); } if (fixedLen >= 0 && i < fixedLen) seek(fixedLen - i); - std::wstring_convert> conv; - return conv.to_bytes(tmp); + return retval; } /*! \brief Reads a string and advances the position in the file @@ -670,9 +673,9 @@ public: * \return std::string The value at the current address * \throw IOException when address is out of range */ - inline std::string readString(atInt32 fixedLen = -1) + inline typename STLTRAITS::String readString(atInt32 fixedLen = -1) { - std::string ret; + typename STLTRAITS::String ret; atUint8 chr = readByte(); atInt32 i; @@ -692,18 +695,18 @@ public: return ret; } template - inline std::string readVal(typename std::enable_if::value>::type* = 0) + inline typename STLTRAITS::String readVal(typename std::enable_if::value>::type* = 0) {return readString();} /*! \brief Reads a wstring and advances the position in the file * * \param fixedLen If non-negative, this is a fixed-length string read - * \return std::wstring The value at the current address + * \return The value at the current address * \throw IOException when address is out of range */ - inline std::wstring readWString(atInt32 fixedLen = -1) + inline typename STLTRAITS::WString readWString(atInt32 fixedLen = -1) { - std::wstring ret; + typename STLTRAITS::WString ret; atUint16 chr = readUint16(); atInt32 i; @@ -723,12 +726,12 @@ public: return ret; } template - inline std::wstring readVal(typename std::enable_if::value>::type* = 0) + inline typename STLTRAITS::WString readVal(typename std::enable_if::value>::type* = 0) {return readWString();} - inline std::wstring readWStringLittle(atInt32 fixedLen = -1) + inline typename STLTRAITS::WString readWStringLittle(atInt32 fixedLen = -1) { - std::wstring ret; + typename STLTRAITS::WString ret; atUint16 chr = readUint16Little(); atInt32 i; @@ -748,12 +751,12 @@ public: return ret; } template - inline std::wstring readValLittle(typename std::enable_if::value>::type* = 0) + inline typename STLTRAITS::WString readValLittle(typename std::enable_if::value>::type* = 0) {return readWStringLittle();} - inline std::wstring readWStringBig(atInt32 fixedLen = -1) + inline typename STLTRAITS::WString readWStringBig(atInt32 fixedLen = -1) { - std::wstring ret; + typename STLTRAITS::WString ret; atUint16 chr = readUint16Big(); atInt32 i; @@ -773,11 +776,11 @@ public: return ret; } template - inline std::wstring readValBig(typename std::enable_if::value>::type* = 0) + inline typename STLTRAITS::WString readValBig(typename std::enable_if::value>::type* = 0) {return readWStringBig();} template - void enumerate(std::vector& vector, size_t count, + void enumerate(typename STLTRAITS::template Vector& vector, size_t count, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -790,7 +793,7 @@ public: } template - void enumerateLittle(std::vector& vector, size_t count, + void enumerateLittle(typename STLTRAITS::template Vector& vector, size_t count, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -803,7 +806,7 @@ public: } template - void enumerateBig(std::vector& vector, size_t count, + void enumerateBig(typename STLTRAITS::template Vector& vector, size_t count, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -816,7 +819,7 @@ public: } template - void enumerate(std::vector& vector, size_t count, + void enumerate(typename STLTRAITS::template Vector& vector, size_t count, typename std::enable_if::value && !std::is_same::value && !std::is_same::value && @@ -832,7 +835,8 @@ public: } template - void enumerate(std::vector& vector, size_t count, std::function readf) + void enumerate(typename STLTRAITS::template Vector& vector, + size_t count, std::function readf) { vector.clear(); vector.reserve(count); diff --git a/include/Athena/IStreamWriter.hpp b/include/Athena/IStreamWriter.hpp index bdda703..e5318cb 100644 --- a/include/Athena/IStreamWriter.hpp +++ b/include/Athena/IStreamWriter.hpp @@ -9,6 +9,7 @@ namespace Athena { namespace io { +template class IStreamWriter : public IStream { public: @@ -436,116 +437,107 @@ public: * \param str The string to write to the buffer * \param fixedLen If not -1, the number of characters to zero-fill string to */ - inline void writeStringAsWString(const std::string& str, atInt32 fixedLen = -1) + inline void writeStringAsWString(const typename STLTRAITS::String& str, atInt32 fixedLen = -1) { - std::string tmpStr = "\xEF\xBB\xBF" + str; - - std::wstring_convert> conv; - std::wstring tmp = conv.from_bytes(tmpStr); + typename STLTRAITS::String tmpStr = "\xEF\xBB\xBF" + str; + const char* buf = tmpStr.c_str(); if (fixedLen < 0) { - for (atUint16 chr : tmp) + while (*buf) { - if (chr != 0xFEFF) - writeUint16(chr); + wchar_t wc; + buf += std::mbtowc(&wc, buf, MB_CUR_MAX); + if (wc != 0xFEFF) + writeUint16(wc); } writeUint16(0); } else { - auto it = tmp.begin(); for (atInt32 i=0 ; i> conv; - std::wstring tmp = conv.from_bytes(tmpStr); + typename STLTRAITS::String tmpStr = "\xEF\xBB\xBF" + str; + const char* buf = tmpStr.c_str(); if (fixedLen < 0) { - for (atUint16 chr : tmp) + while (*buf) { - if (chr != 0xFEFF) - writeUint16Little(chr); + wchar_t wc; + buf += std::mbtowc(&wc, buf, MB_CUR_MAX); + if (wc != 0xFEFF) + writeUint16Little(wc); } writeUint16Little(0); } else { - auto it = tmp.begin(); for (atInt32 i=0 ; i> conv; - std::wstring tmp = conv.from_bytes(tmpStr); + typename STLTRAITS::String tmpStr = "\xEF\xBB\xBF" + str; + const char* buf = tmpStr.c_str(); if (fixedLen < 0) { - for (atUint16 chr : tmp) + while (*buf) { - if (chr != 0xFEFF) - writeUint16Big(chr); + wchar_t wc; + buf += std::mbtowc(&wc, buf, MB_CUR_MAX); + if (wc != 0xFEFF) + writeUint16Big(wc); } writeUint16Big(0); } else { - auto it = tmp.begin(); for (atInt32 i=0 ; i - void enumerate(const std::vector& vector, + void enumerate(const typename STLTRAITS::template Vector& vector, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -695,7 +687,7 @@ public: } template - void enumerateLittle(const std::vector& vector, + void enumerateLittle(const typename STLTRAITS::template Vector& vector, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -706,7 +698,7 @@ public: } template - void enumerateBig(const std::vector& vector, + void enumerateBig(const typename STLTRAITS::template Vector& vector, typename std::enable_if::value || std::is_same::value || std::is_same::value || @@ -717,7 +709,7 @@ public: } template - void enumerate(const std::vector& vector, + void enumerate(const typename STLTRAITS::template Vector& vector, typename std::enable_if::value && !std::is_same::value && !std::is_same::value && diff --git a/include/Athena/MemoryReader.hpp b/include/Athena/MemoryReader.hpp index 6b87d18..66dd151 100644 --- a/include/Athena/MemoryReader.hpp +++ b/include/Athena/MemoryReader.hpp @@ -18,10 +18,16 @@ namespace io * this allows for fast, flexible code as well as the ability to quickly modify data * \sa Stream */ -class MemoryReader : public IStreamReader +template +class MemoryReader : public IStreamReader { + using base = IStreamReader; public: - virtual ~MemoryReader(); + virtual ~MemoryReader() + { + if (m_owns) + delete[] m_data; + } /*! \brief This constructor references an existing buffer to read from. * @@ -29,28 +35,82 @@ public: * \param length The length of the existing buffer * \param takeOwnership Memory will be freed with the reader if set */ - MemoryReader(const atUint8* data, atUint64 length, bool takeOwnership=false); + MemoryReader(const atUint8* data, atUint64 length, bool takeOwnership=false) + : m_data(data), + m_length(length), + m_position(0), + m_owns(takeOwnership) + { + if (!data) + { + atError("data cannot be NULL"); + IStream::setError(); + return; + } + + if (length == 0) + { + atError("length cannot be 0"); + IStream::setError(); + return; + } + } /*! \brief Sets the buffers position relative to the specified position.
* It seeks relative to the current position by default. * \param position where in the buffer to seek * \param origin The Origin to seek \sa SeekOrigin */ - void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); + void seek(atInt64 position, SeekOrigin origin = SeekOrigin::Current) + { + switch (origin) + { + case SeekOrigin::Begin: + if ((position < 0 || (atInt64)position > (atInt64)m_length)) + { + atError("Position %0.8X outside stream bounds ", position); + IStream::setError(); + return; + } + + m_position = position; + break; + + case SeekOrigin::Current: + if ((((atInt64)m_position + position) < 0 || (m_position + position) > m_length)) + { + atError("Position %0.8X outside stream bounds ", position); + IStream::setError(); + return; + } + + m_position += position; + break; + + case SeekOrigin::End: + if ((((atInt64)m_length - position < 0) || (m_length - position) > m_length)) + { + atError("Position %0.8X outside stream bounds ", position); + IStream::setError(); + return; + } + + m_position = m_length - position; + break; + } + } /*! \brief Returns the current position in the stream. * * \return Int64 The current position in the stream. */ - inline atUint64 position() const - {return m_position;} + inline atUint64 position() const {return m_position;} /*! \brief Returns whether or not the stream is at the end. * * \return bool True if at end; False otherwise. */ - inline atUint64 length() const - {return m_length;} + inline atUint64 length() const {return m_length;} /*! \brief Sets the buffer to the given one, deleting the current one.
@@ -63,7 +123,15 @@ public: * \param takeOwnership Memory will be freed with the reader if set * \throw IOException */ - void setData(const atUint8* data, atUint64 length, bool takeOwnership=false); + void setData(const atUint8* data, atUint64 length, bool takeOwnership=false) + { + if (m_owns && m_data) + delete[] m_data; + m_data = (atUint8*)data; + m_length = length; + m_position = 0; + m_owns = takeOwnership; + } /*! \brief Returns a copy of the current buffer.
@@ -73,14 +141,32 @@ public: * as Stream now owns the address, this is done to keep memory usage down. * \return Uint8* The copy of the buffer. */ - atUint8* data() const; + atUint8* data() const + { + atUint8* ret = new atUint8[m_length]; + memset(ret, 0, m_length); + memcpy(ret, m_data, m_length); + return ret; + } /*! \brief Reads a specified number of bytes to user-allocated buffer * \param buf User-allocated buffer pointer - * \param len Length to read + * \param length Length to read * \return Number of bytes read */ - atUint64 readUBytesToBuf(void* buf, atUint64 len); + atUint64 readUBytesToBuf(void* buf, atUint64 length) + { + if (m_position + length > m_length) + { + atError("Position %0.8X outside stream bounds ", m_position); + IStream::setError(); + return 0; + } + + memcpy(buf, (const atUint8*)(m_data + m_position), length); + m_position += length; + return length; + } protected: const atUint8* m_data; @@ -89,29 +175,105 @@ protected: bool m_owns; }; -class MemoryCopyReader : public MemoryReader +template +class MemoryCopyReader : public MemoryReader { + using base = MemoryReader; public: /*! \brief This constructor copies an existing buffer to read from. * * \param data The existing buffer * \param length The length of the existing buffer */ - MemoryCopyReader(const atUint8* data, atUint64 length); + MemoryCopyReader(const atUint8* data, atUint64 length) + : base(data, length, false) + { + if (!data) + { + atError("data cannot be NULL"); + IStream::setError(); + return; + } + + if (length == 0) + { + atError("length cannot be 0"); + IStream::setError(); + return; + } + + m_dataCopy.reset(new atUint8[base::m_length]); + base::m_data = m_dataCopy.get(); + memcpy(m_dataCopy.get(), data, base::m_length); + } /*! \brief This constructor creates an instance from a file on disk. * * \param filename The file to create the stream from */ MemoryCopyReader(const std::string& filename) - : MemoryReader(NULL, 0), + : base(NULL, 0), m_filepath(filename) {loadData();} - void setData(const atUint8* data, atUint64 length); + void setData(const atUint8* data, atUint64 length) + { + m_dataCopy.reset(new atUint8[length]); + base::m_data = m_dataCopy.get(); + memcpy(m_dataCopy.get(), data, length); + base::m_length = length; + base::m_position = 0; + } protected: - void loadData(); + void loadData() + { + FILE* in; + atUint64 length; + in = fopen(m_filepath.c_str(), "rb"); + + if (!in) + { + atError("Unable to open file '%s'", m_filepath.c_str()); + IStream::setError(); + return; + } + + rewind(in); + + length = utility::fileSize(m_filepath); + m_dataCopy.reset(new atUint8[length]); + base::m_data = m_dataCopy.get(); + + atUint64 done = 0; + atUint64 blocksize = BLOCKSZ; + + do + { + if (blocksize > length - done) + blocksize = length - done; + + atInt64 ret = fread(m_dataCopy.get() + done, 1, blocksize, in); + + if (ret < 0) + { + atError("Error reading data from disk"); + IStream::setError(); + return; + } + else if (ret == 0) + break; + + done += ret; + + + } + while (done < length); + + fclose(in); + base::m_length = length; + base::m_position = 0; + } std::unique_ptr m_dataCopy; std::string m_filepath; //!< Path to the target file }; diff --git a/include/Athena/MemoryWriter.hpp b/include/Athena/MemoryWriter.hpp index 836341c..5404b76 100644 --- a/include/Athena/MemoryWriter.hpp +++ b/include/Athena/MemoryWriter.hpp @@ -19,7 +19,8 @@ namespace io * this allows for fast, flexible code as well as the ability to quickly modify data * \sa Stream */ -class MemoryWriter : public IStreamWriter +template +class MemoryWriter : public IStreamWriter { public: @@ -28,14 +29,90 @@ public: * \param data The existing buffer * \param length The length of the existing buffer */ - explicit MemoryWriter(atUint8* data, atUint64 length); + explicit MemoryWriter(atUint8* data, atUint64 length) + : m_data((atUint8*)data), + m_length(length), + m_position(0) + { + if (!data) + { + atError("data cannot be NULL"); + IStream::setError(); + return; + } + + if (length == 0) + { + atError("length cannot be 0"); + IStream::setError(); + return; + } + } /*! \brief Sets the buffers position relative to the specified position.
* It seeks relative to the current position by default. * \param position where in the buffer to seek * \param origin The Origin to seek \sa SeekOrigin */ - void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); + void seek(atInt64 position, SeekOrigin origin = SeekOrigin::Current) + { + switch (origin) + { + case SeekOrigin::Begin: + if (position < 0) + { + atError("Position outside stream bounds"); + IStream::setError(); + return; + } + + if ((atUint64)position > m_length) + { + atError("data exceeds available buffer space"); + IStream::setError(); + return; + } + + m_position = position; + break; + + case SeekOrigin::Current: + if ((((atInt64)m_position + position) < 0)) + { + atError("Position outside stream bounds"); + IStream::setError(); + return; + } + + if (m_position + position > m_length) + { + atError("data exceeds available buffer space"); + IStream::setError(); + return; + } + + m_position += position; + break; + + case SeekOrigin::End: + if (((atInt64)m_length - position) < 0) + { + atError("Position outside stream bounds"); + IStream::setError(); + return; + } + + if ((atUint64)position > m_length) + { + atError("data exceeds available buffer space"); + IStream::setError(); + return; + } + + m_position = m_length - position; + break; + } + } /*! \brief Returns the current position in the stream. @@ -63,7 +140,12 @@ public: * \param length The length of the new buffer. * \throw IOException */ - void setData(atUint8* data, atUint64 length); + void setData(atUint8* data, atUint64 length) + { + m_data = (atUint8*)data; + m_length = length; + m_position = 0; + } /*! \brief Returns a copy of the current buffer.
@@ -73,7 +155,13 @@ public: * as Stream now owns the address, this is done to keep memory usage down. * \return Uint8* The copy of the buffer. */ - atUint8* data() const; + atUint8* data() const + { + atUint8* ret = new atUint8[m_length]; + memset(ret, 0, m_length); + memcpy(ret, m_data, m_length); + return ret; + } /*! \brief Sets the target file * @@ -93,7 +181,52 @@ public: * * \param filename If not empty, the filename to save to */ - void save(const std::string& filename = ""); + void save(const std::string& filename = "") + { + if (filename.empty() && m_filepath.empty()) + { + atError("No file specified, cannot save."); + IStream::setError(); + return; + } + + if (!filename.empty()) + m_filepath = filename; + + FILE* out = fopen(m_filepath.c_str(), "wb"); + + if (!out) + { + atError("Unable to open file '%s'", m_filepath.c_str()); + IStream::setError(); + return; + } + + atUint64 done = 0; + atUint64 blocksize = BLOCKSZ; + + do + { + if (blocksize > m_length - done) + blocksize = m_length - done; + + atInt64 ret = fwrite(m_data + done, 1, blocksize, out); + + if (ret < 0) + { + atError("Error writing data to disk"); + IStream::setError(); + return; + } + else if (ret == 0) + break; + + done += blocksize; + } + while (done < m_length); + + fclose(out); + } /*! \brief Writes the given buffer with the specified length, buffers can be bigger than the length * however it's undefined behavior to try and write a buffer which is smaller than the given length. @@ -101,7 +234,26 @@ public: * \param data The buffer to write * \param length The amount to write */ - void writeUBytes(const atUint8* data, atUint64 len); + void writeUBytes(const atUint8* data, atUint64 length) + { + if (!data) + { + atError("data cannnot be NULL"); + IStream::setError(); + return; + } + + if (m_position + length > m_length) + { + atError("data length exceeds available buffer space"); + IStream::setError(); + return; + } + + memcpy((atInt8*)(m_data + m_position), data, length); + + m_position += length; + } protected: MemoryWriter() {} @@ -111,8 +263,10 @@ protected: std::string m_filepath; //!< Path to the target file }; -class MemoryCopyWriter : public MemoryWriter +template +class MemoryCopyWriter : public MemoryWriter { + using base = MemoryWriter; public: /*! \brief This constructor copies an existing buffer to write to. @@ -120,20 +274,100 @@ public: * \param data The existing buffer * \param length The length of the existing buffer */ - explicit MemoryCopyWriter(atUint8* data=nullptr, atUint64 length=0x10); + explicit MemoryCopyWriter(atUint8* data=nullptr, atUint64 length=0x10) + { + base::m_data = data; + base::m_length = length; + base::m_position = 0; + + if (length == 0) + { + atError("length cannot be 0"); + IStream::setError(); + return; + } + + base::m_dataCopy.reset(new atUint8[length]); + base::m_data = m_dataCopy.get(); + if (data) + memcpy(base::m_data, data, length); + } /*! \brief This constructor creates an instance from a file on disk. * * \param filename The file to create the stream from */ - MemoryCopyWriter(const std::string& filename); + MemoryCopyWriter(const std::string& filename) + : base(NULL, 0) + { + base::m_filepath = filename; + base::m_length = 0x10; + base::m_position = 0; + m_dataCopy.reset(new atUint8[base::m_length]); + base::m_data = m_dataCopy.get(); + + if (!base::m_data) + { + atError("Could not allocate memory!"); + IStream::setError(); + return; + } + + memset(base::m_data, 0, base::m_length); + } /*! \brief Sets the buffers position relative to the specified position.
* It seeks relative to the current position by default. * \param position where in the buffer to seek * \param origin The Origin to seek \sa SeekOrigin */ - void seek(atInt64 pos, SeekOrigin origin = SeekOrigin::Current); + void seek(atInt64 position, SeekOrigin origin = SeekOrigin::Current) + { + switch (origin) + { + case SeekOrigin::Begin: + if (position < 0) + { + atError("Position outside stream bounds"); + IStream::setError(); + return; + } + + if ((atUint64)position > base::m_length) + resize(position); + + base::m_position = position; + break; + + case SeekOrigin::Current: + if ((((atInt64)base::m_position + position) < 0)) + { + atError("Position outside stream bounds"); + IStream::setError(); + return; + } + + if (base::m_position + position > base::m_length) + resize(base::m_position + position); + + base::m_position += position; + break; + + case SeekOrigin::End: + if (((atInt64)base::m_length - position) < 0) + { + atError("Position outside stream bounds"); + IStream::setError(); + return; + } + + if ((atUint64)position > base::m_length) + resize(position); + + base::m_position = base::m_length - position; + break; + } + } /*! \brief Sets the buffer to the given one, deleting the current one.
* BEWARE: As this deletes the current buffer it WILL cause a loss of data @@ -144,7 +378,14 @@ public: * \param length The length of the new buffer. * \throw IOException */ - void setData(const atUint8* data, atUint64 length); + void setData(const atUint8* data, atUint64 length) + { + m_dataCopy.reset(new atUint8[length]); + base::m_data = m_dataCopy.get(); + memcpy(base::m_data, data, length); + base::m_length = length; + base::m_position = 0; + } /*! \brief Writes the given buffer with the specified length, buffers can be bigger than the length * however it's undefined behavior to try and write a buffer which is smaller than the given length. @@ -152,12 +393,46 @@ public: * \param data The buffer to write * \param length The amount to write */ - void writeUBytes(const atUint8* data, atUint64 len); + void writeUBytes(const atUint8* data, atUint64 length) + { + if (!data) + { + atError("data cannnot be NULL"); + IStream::setError(); + return; + } + + if (base::m_position + length > base::m_length) + resize(base::m_position + length); + + memcpy((atInt8*)(base::m_data + base::m_position), data, length); + + base::m_position += length; + } protected: std::unique_ptr m_dataCopy; private: - void resize(atUint64 newSize); + void resize(atUint64 newSize) + { + if (newSize < base::m_length) + { + atError("New size cannot be less to the old size."); + return; + } + + // Allocate and copy new buffer + atUint8* newArray = new atUint8[newSize]; + memset(newArray, 0, newSize); + + if (m_dataCopy) + memcpy(newArray, m_dataCopy.get(), base::m_length); + m_dataCopy.reset(newArray); + + // Swap the pointer and size out for the new ones. + base::m_data = newArray; + base::m_length = newSize; + } }; } diff --git a/src/Athena/DNAYaml.cpp b/src/Athena/DNAYaml.cpp index 8aa25f0..a5a5f3e 100644 --- a/src/Athena/DNAYaml.cpp +++ b/src/Athena/DNAYaml.cpp @@ -39,330 +39,12 @@ void HandleYAMLEmitterError(yaml_emitter_t* emitter) atError("YAML error: %s: %s", ErrorString(emitter->error), emitter->problem?emitter->problem:""); } -int YAMLStdStringReader(YAMLStdStringReaderState* reader, - unsigned char* buffer, size_t size, size_t* size_read) -{ - size_t diff = reader->end - reader->begin; - if (!diff) - { - *size_read = 0; - } - else if (diff < size) - { - memcpy(buffer, &*reader->begin, diff); - *size_read = diff; - } - else - { - memcpy(buffer, &*reader->begin, size); - *size_read = size; - } - return 1; -} - -int YAMLStdStringWriter(std::string* str, unsigned char *buffer, size_t size) -{ - str->append((char*)buffer, size); - return 1; -} - -static inline void InsertNode(std::vector& nodeStack, - std::unique_ptr& mapKey, - std::unique_ptr& retVal, - std::unique_ptr&& newNode) -{ - if (nodeStack.empty()) - { - retVal = std::move(newNode); - return; - } - YAMLNode* parent = nodeStack.back(); - if (parent->m_type == YAML_SEQUENCE_NODE) - { - parent->m_seqChildren.emplace_back(std::move(newNode)); - } - else if (parent->m_type == YAML_MAPPING_NODE) - { - if (!mapKey) - mapKey = std::move(newNode); - else - { - parent->m_mapChildren.emplace_back(std::move(mapKey->m_scalarString), std::move(newNode)); - mapKey.reset(nullptr); - } - } -} - -std::unique_ptr YAMLDocReader::ParseEvents(yaml_parser_t* doc) -{ - yaml_event_t event; - if (!yaml_parser_parse(doc, &event)) - { - HandleYAMLParserError(doc); - return std::unique_ptr(); - } - - std::vector nodeStack; - std::unique_ptr mapKey; - std::unique_ptr retVal; - int result; - for (result = yaml_parser_parse(doc, &event); - event.type != YAML_STREAM_END_EVENT; - result = yaml_parser_parse(doc, &event)) - { - if (!result) - { - HandleYAMLParserError(doc); - return std::unique_ptr(); - } - switch (event.type) - { - case YAML_SCALAR_EVENT: - { - if (nodeStack.empty()) - { - atWarning("YAML parser stack empty; skipping scalar node"); - break; - } - std::unique_ptr newScalar(new YAMLNode(YAML_SCALAR_NODE)); - newScalar->m_scalarString.assign((char*)event.data.scalar.value, event.data.scalar.length); - if (nodeStack.empty()) - retVal = std::move(newScalar); - else - InsertNode(nodeStack, mapKey, retVal, std::move(newScalar)); - break; - } - case YAML_SEQUENCE_START_EVENT: - { - YAMLNode* newSeq = new YAMLNode(YAML_SEQUENCE_NODE); - InsertNode(nodeStack, mapKey, retVal, std::unique_ptr(newSeq)); - nodeStack.emplace_back(newSeq); - break; - } - case YAML_SEQUENCE_END_EVENT: - { - nodeStack.pop_back(); - break; - } - case YAML_MAPPING_START_EVENT: - { - YAMLNode* newMap = new YAMLNode(YAML_MAPPING_NODE); - InsertNode(nodeStack, mapKey, retVal, std::unique_ptr(newMap)); - nodeStack.emplace_back(newMap); - break; - } - case YAML_MAPPING_END_EVENT: - { - nodeStack.pop_back(); - break; - } - case YAML_DOCUMENT_END_EVENT: - { - yaml_event_delete(&event); - return retVal; - } - default: - break; - } - yaml_event_delete(&event); - } - return std::unique_ptr(); -} - -static inline bool EmitKeyScalar(yaml_emitter_t* doc, const char* val) -{ - yaml_event_t event; - if (!yaml_scalar_event_initialize(&event, nullptr, nullptr, (yaml_char_t*)val, - strlen(val), true, true, YAML_PLAIN_SCALAR_STYLE)) - return false; - return yaml_emitter_emit(doc, &event); -} - -static inline yaml_scalar_style_t ScalarStyle(const YAMLNode& node) -{ - for (const auto& ch : node.m_scalarString) - if (ch == '\n') - return YAML_LITERAL_SCALAR_STYLE; - return YAML_ANY_SCALAR_STYLE; -} - -static inline yaml_sequence_style_t SequenceStyle(const YAMLNode& node) -{ - size_t count = 0; - for (const auto& item : node.m_seqChildren) - { - if (item->m_type != YAML_SCALAR_NODE) - return YAML_BLOCK_SEQUENCE_STYLE; - size_t strLen = item->m_scalarString.size(); - size_t thisCount = strLen / 10; - if (!thisCount) - thisCount = 1; - count += thisCount; - } - return (count > 6) ? YAML_BLOCK_SEQUENCE_STYLE : YAML_FLOW_SEQUENCE_STYLE; -} - -static inline yaml_mapping_style_t MappingStyle(const YAMLNode& node) -{ - size_t count = 0; - for (const auto& item : node.m_mapChildren) - { - if (item.second->m_type != YAML_SCALAR_NODE) - return YAML_BLOCK_MAPPING_STYLE; - size_t strLen = item.second->m_scalarString.size(); - size_t thisCount = strLen / 10; - if (!thisCount) - thisCount = 1; - count += thisCount; - } - return (count > 6) ? YAML_BLOCK_MAPPING_STYLE : YAML_FLOW_MAPPING_STYLE; -} - -bool YAMLDocWriter::RecursiveFinish(yaml_emitter_t* doc, const YAMLNode& node) -{ - yaml_event_t event; - if (node.m_type == YAML_SCALAR_NODE) - { - if (!yaml_scalar_event_initialize(&event, nullptr, nullptr, (yaml_char_t*)node.m_scalarString.c_str(), - node.m_scalarString.length(), true, true, ScalarStyle(node)) || - !yaml_emitter_emit(doc, &event)) - goto err; - } - else if (node.m_type == YAML_SEQUENCE_NODE) - { - if (!yaml_sequence_start_event_initialize(&event, nullptr, nullptr, 1, SequenceStyle(node)) || - !yaml_emitter_emit(doc, &event)) - goto err; - for (const auto& item : node.m_seqChildren) - { - if (!RecursiveFinish(doc, *item)) - goto err; - } - if (!yaml_sequence_end_event_initialize(&event) || - !yaml_emitter_emit(doc, &event)) - goto err; - } - else if (node.m_type == YAML_MAPPING_NODE) - { - if (!yaml_mapping_start_event_initialize(&event, nullptr, nullptr, true, MappingStyle(node)) || - !yaml_emitter_emit(doc, &event)) - goto err; - for (const auto& item : node.m_mapChildren) - { - if (!EmitKeyScalar(doc, item.first.c_str())) - goto err; - if (!RecursiveFinish(doc, *item.second)) - goto err; - } - event.type = YAML_MAPPING_END_EVENT; - if (!yaml_mapping_end_event_initialize(&event) || - !yaml_emitter_emit(doc, &event)) - goto err; - - } - return true; -err: - HandleYAMLEmitterError(doc); - return false; -} - -static const std::string base64_chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; +const char* AT_BASE64_CHARS = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; -static inline bool is_base64(unsigned char c) -{ - return (isalnum(c) || (c == '+') || (c == '/')); -} - -std::string base64_encode(const atUint8* bytes_to_encode, size_t in_len) -{ - std::string ret; - int i = 0; - int j = 0; - unsigned char char_array_3[3]; - unsigned char char_array_4[4]; - ret.reserve(in_len * 4 / 3); - - while (in_len--) { - char_array_3[i++] = *(bytes_to_encode++); - if (i == 3) { - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for(i = 0; (i <4) ; i++) - ret += base64_chars[char_array_4[i]]; - i = 0; - } - } - - if (i) - { - for(j = i; j < 3; j++) - char_array_3[j] = '\0'; - - char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; - char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); - char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); - char_array_4[3] = char_array_3[2] & 0x3f; - - for (j = 0; (j < i + 1); j++) - ret += base64_chars[char_array_4[j]]; - - while((i++ < 3)) - ret += '='; - - } - - return ret; - -} -std::unique_ptr base64_decode(const std::string& encoded_string) -{ - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::unique_ptr ret(new atUint8[in_len * 3 / 4]); - atUint8* retBuf = ret.get(); - - while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++] = encoded_string[in_]; in_++; - if (i ==4) { - for (i = 0; i <4; i++) - char_array_4[i] = base64_chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; (i < 3); i++) - *retBuf++ = char_array_3[i]; - i = 0; - } - } - - if (i) { - for (j = i; j <4; j++) - char_array_4[j] = 0; - - for (j = 0; j <4; j++) - char_array_4[j] = base64_chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (j = 0; (j < i - 1); j++) *retBuf++ = char_array_3[j]; - } - - return ret; -} } } diff --git a/src/Athena/FileInfo.cpp b/src/Athena/FileInfo.cpp index 10999ed..227ad73 100644 --- a/src/Athena/FileInfo.cpp +++ b/src/Athena/FileInfo.cpp @@ -117,7 +117,7 @@ bool FileInfo::touch() const #if defined(__GNUC__) && !(defined(HW_DOL) || defined(HW_RVL) || defined(GEKKO)) stat64_t st; if (stat64(m_path.c_str(), &st) < 0) { - (void)Athena::io::FileWriter(m_path); + (void)Athena::io::FileWriter<>(m_path); return true; } if (utimes(m_path.c_str(), NULL) < 0) { diff --git a/src/Athena/FileReader.cpp b/src/Athena/FileReader.cpp deleted file mode 100644 index f517f3a..0000000 --- a/src/Athena/FileReader.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "Athena/FileReader.hpp" - -#if _WIN32 -#include "win32_largefilewrapper.h" -#elif __APPLE__ -#include "osx_largefilewrapper.h" -#endif - -namespace Athena -{ -namespace io -{ -FileReader::FileReader(const std::string& filename, atInt32 cacheSize) - : m_filename(filename), - m_fileHandle(nullptr), - m_cacheData(nullptr), - m_offset(0) -{ - open(); - setCacheSize(cacheSize); -} - -#if _WIN32 -FileReader::FileReader(const std::wstring& filename, atInt32 cacheSize) - : m_wfilename(filename), - m_fileHandle(nullptr), - m_cacheData(nullptr), - m_offset(0) -{ - open(); - setCacheSize(cacheSize); -} -#endif - -FileReader::~FileReader() -{ - if (isOpen()) - close(); -} - -void FileReader::open() -{ -#if _WIN32 - if (m_wfilename.size()) - m_fileHandle = _wfopen(m_wfilename.c_str(), L"rb"); - else - m_fileHandle = fopen(m_filename.c_str(), "rb"); -#else - m_fileHandle = fopen(m_filename.c_str(), "rb"); -#endif - - if (!m_fileHandle) - { - atError("File not found '%s'", m_filename.c_str()); - setError(); - return; - } - - // ensure we're at the beginning of the file - rewind(m_fileHandle); -} - -void FileReader::close() -{ - if (!m_fileHandle) - { - atError("Cannot close an unopened stream"); - setError(); - return; - } - - fclose(m_fileHandle); - m_fileHandle = NULL; - return; -} - -void FileReader::seek(atInt64 pos, SeekOrigin origin) -{ - // check block position - if (m_blockSize > 0) - { - atUint64 oldOff = m_offset; - switch(origin) - { - case SeekOrigin::Begin: - m_offset = pos; - break; - case SeekOrigin::Current: - m_offset += pos; - break; - case SeekOrigin::End: - m_offset = length() - pos; - break; - } - if (m_offset > length()) - { - oldOff = m_offset; - atError("Unable to seek in file"); - return; - } - - size_t block = m_offset / m_blockSize; - if (block != m_curBlock) - { - fseeko64(m_fileHandle, block * m_blockSize, SEEK_SET); - fread(m_cacheData.get(), 1, m_blockSize, m_fileHandle); - m_curBlock = (atInt32)block; - } - } - else if (fseeko64(m_fileHandle, pos, (int)origin) != 0) - atError("Unable to seek in file"); -} - -atUint64 FileReader::position() const -{ - if (!isOpen()) - { - atError("File not open"); - return 0; - } - - if (m_blockSize > 0) - return m_offset; - else - return ftello64(m_fileHandle); -} - -atUint64 FileReader::length() const -{ - if (!isOpen()) - { - atError("File not open"); - return 0; - } - - return utility::fileSize(m_filename); -} - -atUint64 FileReader::readUBytesToBuf(void* buf, atUint64 len) -{ - if (!isOpen()) - { - atError("File not open for reading"); - setError(); - return 0; - } - - if (m_blockSize <= 0) - return fread(buf, 1, len, m_fileHandle); - else - { - size_t block = m_offset / m_blockSize; - atUint64 cacheOffset = m_offset % m_blockSize; - atUint64 cacheSize; - atUint64 rem = len; - atUint8* dst = (atUint8*)buf; - - while (rem) - { - if (block != m_curBlock) - { - fseeko64(m_fileHandle, block * m_blockSize, SEEK_SET); - fread(m_cacheData.get(), 1, m_blockSize, m_fileHandle); - m_curBlock = (atInt32)block; - } - - cacheSize = rem; - if (cacheSize + cacheOffset > m_blockSize) - cacheSize = m_blockSize - cacheOffset; - - memcpy(dst, m_cacheData.get() + cacheOffset, cacheSize); - dst += cacheSize; - rem -= cacheSize; - cacheOffset = 0; - ++block; - } - m_offset += len; - return dst - (atUint8*)buf; - } -} - -void FileReader::setCacheSize(const atInt32 blockSize) -{ - m_blockSize = blockSize; - - if (m_blockSize > length()) - m_blockSize = (atInt32)length(); - - m_curBlock = -1; - if (m_blockSize > 0) - m_cacheData.reset(new atUint8[m_blockSize]); -} - -} // io -} // Athena diff --git a/src/Athena/FileWriter.cpp b/src/Athena/FileWriter.cpp deleted file mode 100644 index 7376d47..0000000 --- a/src/Athena/FileWriter.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "Athena/FileWriter.hpp" - -#if _WIN32 -#include "win32_largefilewrapper.h" -#elif __APPLE__ -#include "osx_largefilewrapper.h" -#endif - -namespace Athena -{ -namespace io -{ -FileWriter::FileWriter(const std::string& filename, bool overwrite) - : m_filename(filename), - m_fileHandle(NULL), - m_bytePosition(0) -{ - open(overwrite); -} - -#if _WIN32 -FileWriter::FileWriter(const std::wstring& filename, bool overwrite) - : m_wfilename(filename), - m_fileHandle(NULL), - m_bytePosition(0) -{ - open(overwrite); -} -#endif - -FileWriter::~FileWriter() -{ - if (isOpen()) - close(); -} - -void FileWriter::open(bool overwrite) -{ -#if _WIN32 - if (m_wfilename.size()) - { - if (overwrite) - m_fileHandle = _wfopen(m_wfilename.c_str(), L"w+b"); - else - m_fileHandle = _wfopen(m_wfilename.c_str(), L"r+b"); - } - else - { - if (overwrite) - m_fileHandle = fopen(m_filename.c_str(), "w+b"); - else - m_fileHandle = fopen(m_filename.c_str(), "r+b"); - } -#else - if (overwrite) - m_fileHandle = fopen(m_filename.c_str(), "w+b"); - else - m_fileHandle = fopen(m_filename.c_str(), "r+b"); -#endif - - - - if (!m_fileHandle) - { - atError("Unable to open file '%s'", m_filename.c_str()); - setError(); - return; - } - - // ensure we're at the beginning of the file - rewind(m_fileHandle); -} - -void FileWriter::close() -{ - if (!m_fileHandle) - { - atError("Cannot close an unopened stream"); - setError(); - return; - } - - fclose(m_fileHandle); - m_fileHandle = NULL; - return; -} - -void FileWriter::seek(atInt64 pos, SeekOrigin origin) -{ - if (fseeko64(m_fileHandle, pos, (int)origin) != 0) - { - atError("Unable to seek in file"); - setError(); - } -} - -atUint64 FileWriter::position() const -{ - return ftello64(m_fileHandle); -} - -atUint64 FileWriter::length() const -{ - return utility::fileSize(m_filename); -} - -void FileWriter::writeUBytes(const atUint8* data, atUint64 len) -{ - if (!isOpen()) - { - atError("File not open for writing"); - setError(); - return; - } - - if (fwrite(data, 1, len, m_fileHandle) != len) - { - atError("Unable to write to stream"); - setError(); - } -} - -} -} // Athena diff --git a/src/Athena/MemoryReader.cpp b/src/Athena/MemoryReader.cpp deleted file mode 100644 index 6cb9ad6..0000000 --- a/src/Athena/MemoryReader.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "Athena/MemoryReader.hpp" - -#include -#include -#include -#include -#include - -#ifdef HW_RVL -#include -#endif // HW_RVL - -namespace Athena -{ -namespace io -{ -MemoryReader::MemoryReader(const atUint8* data, atUint64 length, bool takeOwnership) - : m_data(data), - m_length(length), - m_position(0), - m_owns(takeOwnership) -{ - if (!data) - { - atError("data cannot be NULL"); - setError(); - return; - } - - if (length == 0) - { - atError("length cannot be 0"); - setError(); - return; - } -} - -MemoryReader::~MemoryReader() -{ - if (m_owns) - delete[] m_data; -} - -MemoryCopyReader::MemoryCopyReader(const atUint8* data, atUint64 length) - : MemoryReader(data, length, false) -{ - if (!data) - { - atError("data cannot be NULL"); - setError(); - return; - } - - if (length == 0) - { - atError("length cannot be 0"); - setError(); - return; - } - - m_dataCopy.reset(new atUint8[m_length]); - m_data = m_dataCopy.get(); - memcpy(m_dataCopy.get(), data, m_length); -} - -void MemoryReader::seek(atInt64 position, SeekOrigin origin) -{ - switch (origin) - { - case SeekOrigin::Begin: - if ((position < 0 || (atInt64)position > (atInt64)m_length)) - { - atError("Position %0.8X outside stream bounds ", position); - setError(); - return; - } - - m_position = position; - break; - - case SeekOrigin::Current: - if ((((atInt64)m_position + position) < 0 || (m_position + position) > m_length)) - { - atError("Position %0.8X outside stream bounds ", position); - setError(); - return; - } - - m_position += position; - break; - - case SeekOrigin::End: - if ((((atInt64)m_length - position < 0) || (m_length - position) > m_length)) - { - atError("Position %0.8X outside stream bounds ", position); - setError(); - return; - } - - m_position = m_length - position; - break; - } -} - -void MemoryReader::setData(const atUint8* data, atUint64 length, bool takeOwnership) -{ - if (m_owns && m_data) - delete[] m_data; - m_data = (atUint8*)data; - m_length = length; - m_position = 0; - m_owns = takeOwnership; -} - -void MemoryCopyReader::setData(const atUint8* data, atUint64 length) -{ - m_dataCopy.reset(new atUint8[length]); - m_data = m_dataCopy.get(); - memcpy(m_dataCopy.get(), data, length); - m_length = length; - m_position = 0; -} - -atUint8* MemoryReader::data() const -{ - atUint8* ret = new atUint8[m_length]; - memset(ret, 0, m_length); - memcpy(ret, m_data, m_length); - return ret; -} - -atUint64 MemoryReader::readUBytesToBuf(void* buf, atUint64 length) -{ - if (m_position + length > m_length) - { - atError("Position %0.8X outside stream bounds ", m_position); - setError(); - return 0; - } - - memcpy(buf, (const atUint8*)(m_data + m_position), length); - m_position += length; - return length; -} - -void MemoryCopyReader::loadData() -{ - FILE* in; - atUint64 length; - in = fopen(m_filepath.c_str(), "rb"); - - if (!in) - { - atError("Unable to open file '%s'", m_filepath.c_str()); - setError(); - return; - } - - rewind(in); - - length = utility::fileSize(m_filepath); - m_dataCopy.reset(new atUint8[length]); - m_data = m_dataCopy.get(); - - atUint64 done = 0; - atUint64 blocksize = BLOCKSZ; - - do - { - if (blocksize > length - done) - blocksize = length - done; - - atInt64 ret = fread(m_dataCopy.get() + done, 1, blocksize, in); - - if (ret < 0) - { - atError("Error reading data from disk"); - setError(); - return; - } - else if (ret == 0) - break; - - done += ret; - - - } - while (done < length); - - fclose(in); - m_length = length; - m_position = 0; -} - -} -} diff --git a/src/Athena/MemoryWriter.cpp b/src/Athena/MemoryWriter.cpp deleted file mode 100644 index 8fec07f..0000000 --- a/src/Athena/MemoryWriter.cpp +++ /dev/null @@ -1,315 +0,0 @@ -#include "Athena/MemoryWriter.hpp" - -#include -#include -#include -#include - -#ifdef HW_RVL -#include -#endif // HW_RVL - -namespace Athena -{ -namespace io -{ - -MemoryWriter::MemoryWriter(atUint8* data, atUint64 length) - : m_data((atUint8*)data), - m_length(length), - m_position(0) -{ - if (!data) - { - atError("data cannot be NULL"); - setError(); - return; - } - - if (length == 0) - { - atError("length cannot be 0"); - setError(); - return; - } -} - -MemoryCopyWriter::MemoryCopyWriter(atUint8* data, atUint64 length) -{ - m_data = data; - m_length = length; - m_position = 0; - - if (length == 0) - { - atError("length cannot be 0"); - setError(); - return; - } - - m_dataCopy.reset(new atUint8[length]); - m_data = m_dataCopy.get(); - if (data) - memcpy(m_data, data, length); -} - -MemoryCopyWriter::MemoryCopyWriter(const std::string& filename) - : MemoryWriter(NULL, 0) -{ - m_filepath = filename; - m_length = 0x10; - m_position = 0; - m_dataCopy.reset(new atUint8[m_length]); - m_data = m_dataCopy.get(); - - if (!m_data) - { - atError("Could not allocate memory!"); - setError(); - return; - } - - memset(m_data, 0, m_length); -} - -void MemoryWriter::seek(atInt64 position, SeekOrigin origin) -{ - switch (origin) - { - case SeekOrigin::Begin: - if (position < 0) - { - atError("Position outside stream bounds"); - setError(); - return; - } - - if ((atUint64)position > m_length) - { - atError("data exceeds available buffer space"); - setError(); - return; - } - - m_position = position; - break; - - case SeekOrigin::Current: - if ((((atInt64)m_position + position) < 0)) - { - atError("Position outside stream bounds"); - setError(); - return; - } - - if (m_position + position > m_length) - { - atError("data exceeds available buffer space"); - setError(); - return; - } - - m_position += position; - break; - - case SeekOrigin::End: - if (((atInt64)m_length - position) < 0) - { - atError("Position outside stream bounds"); - setError(); - return; - } - - if ((atUint64)position > m_length) - { - atError("data exceeds available buffer space"); - setError(); - return; - } - - m_position = m_length - position; - break; - } -} - -void MemoryCopyWriter::seek(atInt64 position, SeekOrigin origin) -{ - switch (origin) - { - case SeekOrigin::Begin: - if (position < 0) - { - atError("Position outside stream bounds"); - setError(); - return; - } - - if ((atUint64)position > m_length) - resize(position); - - m_position = position; - break; - - case SeekOrigin::Current: - if ((((atInt64)m_position + position) < 0)) - { - atError("Position outside stream bounds"); - setError(); - return; - } - - if (m_position + position > m_length) - resize(m_position + position); - - m_position += position; - break; - - case SeekOrigin::End: - if (((atInt64)m_length - position) < 0) - { - atError("Position outside stream bounds"); - setError(); - return; - } - - if ((atUint64)position > m_length) - resize(position); - - m_position = m_length - position; - break; - } -} - -void MemoryWriter::setData(atUint8* data, atUint64 length) -{ - m_data = (atUint8*)data; - m_length = length; - m_position = 0; -} - -void MemoryCopyWriter::setData(const atUint8* data, atUint64 length) -{ - m_dataCopy.reset(new atUint8[length]); - m_data = m_dataCopy.get(); - memcpy(m_data, data, length); - m_length = length; - m_position = 0; -} - -atUint8* MemoryWriter::data() const -{ - atUint8* ret = new atUint8[m_length]; - memset(ret, 0, m_length); - memcpy(ret, m_data, m_length); - return ret; -} - - -void MemoryWriter::save(const std::string& filename) -{ - if (filename.empty() && m_filepath.empty()) - { - atError("No file specified, cannot save."); - setError(); - return; - } - - if (!filename.empty()) - m_filepath = filename; - - FILE* out = fopen(m_filepath.c_str(), "wb"); - - if (!out) - { - atError("Unable to open file '%s'", m_filepath.c_str()); - setError(); - return; - } - - atUint64 done = 0; - atUint64 blocksize = BLOCKSZ; - - do - { - if (blocksize > m_length - done) - blocksize = m_length - done; - - atInt64 ret = fwrite(m_data + done, 1, blocksize, out); - - if (ret < 0) - { - atError("Error writing data to disk"); - setError(); - return; - } - else if (ret == 0) - break; - - done += blocksize; - } - while (done < m_length); - - fclose(out); -} - -void MemoryWriter::writeUBytes(const atUint8* data, atUint64 length) -{ - if (!data) - { - atError("data cannnot be NULL"); - setError(); - return; - } - - if (m_position + length > m_length) - { - atError("data length exceeds available buffer space"); - setError(); - return; - } - - memcpy((atInt8*)(m_data + m_position), data, length); - - m_position += length; -} - -void MemoryCopyWriter::writeUBytes(const atUint8* data, atUint64 length) -{ - if (!data) - { - atError("data cannnot be NULL"); - setError(); - return; - } - - if (m_position + length > m_length) - resize(m_position + length); - - memcpy((atInt8*)(m_data + m_position), data, length); - - m_position += length; -} - -void MemoryCopyWriter::resize(atUint64 newSize) -{ - if (newSize < m_length) - { - atError("New size cannot be less to the old size."); - return; - } - - // Allocate and copy new buffer - atUint8* newArray = new atUint8[newSize]; - memset(newArray, 0, newSize); - - if (m_dataCopy) - memcpy(newArray, m_dataCopy.get(), m_length); - m_dataCopy.reset(newArray); - - // Swap the pointer and size out for the new ones. - m_data = newArray; - m_length = newSize; -} - -} // io -} // Athena diff --git a/src/LZ77/LZType10.cpp b/src/LZ77/LZType10.cpp index 8b2d694..83b5a8a 100644 --- a/src/LZ77/LZType10.cpp +++ b/src/LZ77/LZType10.cpp @@ -16,7 +16,7 @@ atUint32 LZType10::compress(const atUint8* src, atUint8** dstBuf, atUint32 srcLe atUint32 encodeSize = (srcLength << 8) | (0x10); encodeSize = Athena::utility::LittleUint32(encodeSize); //File size needs to be written as little endian always - Athena::io::MemoryCopyWriter outbuf("tmp"); + Athena::io::MemoryCopyWriter<> outbuf("tmp"); outbuf.writeUint32(encodeSize); atUint8* ptrStart = (atUint8*)src; diff --git a/src/LZ77/LZType11.cpp b/src/LZ77/LZType11.cpp index 0c7a9e0..bdbf98b 100644 --- a/src/LZ77/LZType11.cpp +++ b/src/LZ77/LZType11.cpp @@ -13,7 +13,7 @@ LZType11::LZType11(atInt32 minimumOffset, atInt32 slidingWindow, atInt32 minimum atUint32 LZType11::compress(const atUint8* src, atUint8** dst, atUint32 srcLength) { - Athena::io::MemoryCopyWriter outbuff("tmp"); + Athena::io::MemoryCopyWriter<> outbuff("tmp"); if (srcLength > 0xFFFFFF) // If length is greater than 24 bits or 16 Megs {