diff --git a/PKGBUILD b/PKGBUILD index 6b9924a..9d0d16b 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -1,7 +1,7 @@ # PKGBUILD for libAthena _pkgname=libathena pkgname=$_pkgname-git -pkgver=1.1.0.40.g687a7ee +pkgver=1.1.0.43.g490c6d5 pkgrel=1 pkgdesc="Basic cross platform IO library" arch=('i686' 'x86_64') diff --git a/atdna/PKGBUILD b/atdna/PKGBUILD index 613e9db..2223727 100644 --- a/atdna/PKGBUILD +++ b/atdna/PKGBUILD @@ -1,7 +1,7 @@ # PKGBUILD for atdna _pkgname=atdna pkgname=$_pkgname-git -pkgver=1.1.0.37.g3dfb001 +pkgver=1.1.0.43.g490c6d5 pkgrel=1 pkgdesc="Companion DNA utility for libAthena" arch=('i686' 'x86_64') diff --git a/atdna/main.cpp b/atdna/main.cpp index 125b103..af200cf 100644 --- a/atdna/main.cpp +++ b/atdna/main.cpp @@ -44,11 +44,50 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor clang::ASTContext& context; llvm::raw_fd_ostream& fileOut; + bool isDNARecord(const clang::CXXRecordDecl* record, std::string& baseDNA) + { + for (const clang::CXXBaseSpecifier& base : record->bases()) + { + const clang::QualType qtp = base.getType().getCanonicalType(); + if (!qtp.getAsString().compare(0, sizeof(ATHENA_DNA_BASETYPE)-1, ATHENA_DNA_BASETYPE)) + return true; + } + for (const clang::CXXBaseSpecifier& base : record->bases()) + { + clang::QualType qtp = base.getType().getCanonicalType(); + const clang::Type* tp = qtp.getTypePtrOrNull(); + if (tp) + { + const clang::CXXRecordDecl* rDecl = tp->getAsCXXRecordDecl(); + if (rDecl) + { + if (isDNARecord(rDecl, baseDNA)) + { + bool hasRead = false; + bool hasWrite = false; + for (const clang::CXXMethodDecl* method : rDecl->methods()) + { + std::string compName = method->getNameAsString(); + if (!compName.compare("read")) + hasRead = true; + else if (!compName.compare("write")) + hasWrite = true; + } + if (hasRead && hasWrite) + baseDNA = rDecl->getNameAsString(); + return true; + } + } + } + } + return false; + } + std::string GetOpString(const clang::Type* theType, unsigned width, const std::string& fieldName, bool writerPass, - bool& isDNAType) + bool& isDNATypeOut) { - isDNAType = false; + isDNATypeOut = false; if (writerPass) { if (theType->isBuiltinType()) @@ -56,36 +95,36 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor const clang::BuiltinType* bType = (clang::BuiltinType*)theType; if (bType->isBooleanType()) { - return "writer.writeBool(" + fieldName + ");"; + return "__dna_writer.writeBool(" + fieldName + ");"; } else if (bType->isUnsignedInteger()) { if (width == 8) - return "writer.writeUByte(" + fieldName + ");"; + return "__dna_writer.writeUByte(" + fieldName + ");"; else if (width == 16) - return "writer.writeUint16(" + fieldName + ");"; + return "__dna_writer.writeUint16(" + fieldName + ");"; else if (width == 32) - return "writer.writeUint32(" + fieldName + ");"; + return "__dna_writer.writeUint32(" + fieldName + ");"; else if (width == 64) - return "writer.writeUint64(" + fieldName + ");"; + return "__dna_writer.writeUint64(" + fieldName + ");"; } else if (bType->isSignedInteger()) { if (width == 8) - return "writer.writeByte(" + fieldName + ");"; + return "__dna_writer.writeByte(" + fieldName + ");"; else if (width == 16) - return "writer.writeInt16(" + fieldName + ");"; + return "__dna_writer.writeInt16(" + fieldName + ");"; else if (width == 32) - return "writer.writeInt32(" + fieldName + ");"; + return "__dna_writer.writeInt32(" + fieldName + ");"; else if (width == 64) - return "writer.writeInt64(" + fieldName + ");"; + return "__dna_writer.writeInt64(" + fieldName + ");"; } else if (bType->isFloatingPoint()) { if (width == 32) - return "writer.writeFloat(" + fieldName + ");"; + return "__dna_writer.writeFloat(" + fieldName + ");"; else if (width == 64) - return "writer.writeDouble(" + fieldName + ");"; + return "__dna_writer.writeDouble(" + fieldName + ");"; } } else if (theType->isRecordType()) @@ -103,18 +142,18 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor context.getTypeInfo(eType).Width != 32) continue; if (vType->getNumElements() == 3) - return "writer.writeVec3f(" + fieldName + ");"; + return "__dna_writer.writeVec3f(" + fieldName + ");"; else if (vType->getNumElements() == 4) - return "writer.writeVec4f(" + fieldName + ");"; + return "__dna_writer.writeVec4f(" + fieldName + ");"; } } } - for (const clang::CXXBaseSpecifier& base : rDecl->bases()) - if (!base.getType().getCanonicalType().getAsString().compare(0, sizeof(ATHENA_DNA_BASETYPE)-1, ATHENA_DNA_BASETYPE)) - { - isDNAType = true; - return "write(writer);"; - } + std::string baseDNA; + if (isDNARecord(rDecl, baseDNA)) + { + isDNATypeOut = true; + return "write(__dna_writer);"; + } } } else @@ -124,36 +163,36 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor const clang::BuiltinType* bType = (clang::BuiltinType*)theType; if (bType->isBooleanType()) { - return "reader.readBool()"; + return "__dna_reader.readBool()"; } else if (bType->isUnsignedInteger()) { if (width == 8) - return "reader.readUByte()"; + return "__dna_reader.readUByte()"; else if (width == 16) - return "reader.readUint16()"; + return "__dna_reader.readUint16()"; else if (width == 32) - return "reader.readUint32()"; + return "__dna_reader.readUint32()"; else if (width == 64) - return "reader.readUint64()"; + return "__dna_reader.readUint64()"; } else if (bType->isSignedInteger()) { if (width == 8) - return "reader.readByte()"; + return "__dna_reader.readByte()"; else if (width == 16) - return "reader.readInt16()"; + return "__dna_reader.readInt16()"; else if (width == 32) - return "reader.readInt32()"; + return "__dna_reader.readInt32()"; else if (width == 64) - return "reader.readInt64()"; + return "__dna_reader.readInt64()"; } else if (bType->isFloatingPoint()) { if (width == 32) - return "reader.readFloat()"; + return "__dna_reader.readFloat()"; else if (width == 64) - return "reader.readDouble()"; + return "__dna_reader.readDouble()"; } } else if (theType->isRecordType()) @@ -171,18 +210,18 @@ class ATDNAEmitVisitor : public clang::RecursiveASTVisitor context.getTypeInfo(eType).Width != 32) continue; if (vType->getNumElements() == 3) - return "reader.readVec3f()"; + return "__dna_reader.readVec3f()"; else if (vType->getNumElements() == 4) - return "reader.readVec4f()"; + return "__dna_reader.readVec4f()"; } } } - for (const clang::CXXBaseSpecifier& base : rDecl->bases()) - if (!base.getType().getCanonicalType().getAsString().compare(0, sizeof(ATHENA_DNA_BASETYPE)-1, ATHENA_DNA_BASETYPE)) - { - isDNAType = true; - return "read(reader);"; - } + std::string baseDNA; + if (isDNARecord(rDecl, baseDNA)) + { + isDNATypeOut = true; + return "read(__dna_reader);"; + } } } return std::string(); @@ -202,30 +241,61 @@ public: return true; /* First ensure this inherits from struct Athena::io::DNA */ - bool foundDNA = false; - for (const clang::CXXBaseSpecifier& base : decl->bases()) + std::string baseDNA; + if (!isDNARecord(decl, baseDNA)) + return true; + + /* Make sure there aren't namespace conflicts or Delete meta type */ + for (const clang::FieldDecl* field : decl->fields()) { - clang::QualType canonType = base.getType().getCanonicalType(); - if (!canonType.getAsString().compare(0, sizeof(ATHENA_DNA_BASETYPE)-1, ATHENA_DNA_BASETYPE)) + if (!field->getNameAsString().compare("__dna_reader") || + !field->getNameAsString().compare("__dna_writer")) { - foundDNA = true; - break; + clang::DiagnosticBuilder diag = context.getDiagnostics().Report(field->getLocStart(), AthenaError); + diag.AddString("Field may not be named '__dna_reader' or '__dna_writer'"); + diag.AddSourceRange(clang::CharSourceRange(field->getSourceRange(), true)); + return true; + } + clang::QualType qualType = field->getType().getCanonicalType(); + const clang::Type* regType = qualType.getTypePtrOrNull(); + if (regType) + { + const clang::CXXRecordDecl* rDecl = regType->getAsCXXRecordDecl(); + if (rDecl) + { + if (!rDecl->getNameAsString().compare("Delete")) + { + const clang::CXXRecordDecl* rParentDecl = llvm::dyn_cast_or_null(rDecl->getParent()); + if (rParentDecl) + { + std::string parentCheck = rParentDecl->getTypeForDecl()->getCanonicalTypeInternal().getAsString(); + if (!parentCheck.compare(0, sizeof(ATHENA_DNA_BASETYPE)-1, ATHENA_DNA_BASETYPE)) + return true; + } + } + } } } - if (!foundDNA) - return true; /* Two passes - read then write */ for (int p=0 ; p<2 ; ++p) { if (p) - fileOut << "void " << decl->getQualifiedNameAsString() << "::write(Athena::io::IStreamWriter& writer) const\n{\n"; + fileOut << "void " << decl->getQualifiedNameAsString() << "::write(Athena::io::IStreamWriter& __dna_writer) const\n{\n"; else - fileOut << "void " << decl->getQualifiedNameAsString() << "::read(Athena::io::IStreamReader& reader)\n{\n"; + fileOut << "void " << decl->getQualifiedNameAsString() << "::read(Athena::io::IStreamReader& __dna_reader)\n{\n"; int currentEndian = -1; - for (const clang::FieldDecl* field : decl->fields()) + if (baseDNA.size()) { + if (p) + fileOut << " " << baseDNA << "::write(__dna_writer);\n"; + else + fileOut << " " << baseDNA << "::read(__dna_reader);\n"; + } + + for (const clang::FieldDecl* field : decl->fields()) + { clang::QualType qualType = field->getType(); clang::TypeInfo regTypeInfo = context.getTypeInfo(qualType); const clang::Type* regType = qualType.getTypePtrOrNull(); @@ -355,9 +425,9 @@ public: if (currentEndian != endianVal) { if (endianVal == 0) - fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n"); + fileOut << (p ? " __dna_writer.setEndian(Athena::LittleEndian);\n" : " __dna_reader.setEndian(Athena::LittleEndian);\n"); else if (endianVal == 1) - fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n"); + fileOut << (p ? " __dna_writer.setEndian(Athena::BigEndian);\n" : " __dna_reader.setEndian(Athena::BigEndian);\n"); currentEndian = endianVal; } @@ -494,9 +564,9 @@ public: if (currentEndian != endianVal) { if (endianVal == 0) - fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n"); + fileOut << (p ? " __dna_writer.setEndian(Athena::LittleEndian);\n" : " __dna_reader.setEndian(Athena::LittleEndian);\n"); else if (endianVal == 1) - fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n"); + fileOut << (p ? " __dna_writer.setEndian(Athena::BigEndian);\n" : " __dna_reader.setEndian(Athena::BigEndian);\n"); currentEndian = endianVal; } @@ -570,11 +640,11 @@ public: if (!p) { fileOut << " " << fieldName << ".reset(new atUint8[" << sizeExprStr << "]);\n"; - fileOut << " reader.readUBytesToBuf(" << fieldName << ".get(), " << sizeExprStr << ");\n"; + fileOut << " __dna_reader.readUBytesToBuf(" << fieldName << ".get(), " << sizeExprStr << ");\n"; } else { - fileOut << " writer.writeUBytes(" << fieldName << ".get(), " << sizeExprStr << ");\n"; + fileOut << " __dna_writer.writeUBytes(" << fieldName << ".get(), " << sizeExprStr << ");\n"; } } else if (!tsDecl->getNameAsString().compare("String")) @@ -607,10 +677,10 @@ public: fileOut << " /* " << fieldName << " */\n"; if (!p) - fileOut << " " << fieldName << " = reader.readString(" << sizeExprStr << ");\n"; + fileOut << " " << fieldName << " = __dna_reader.readString(" << sizeExprStr << ");\n"; else { - fileOut << " writer.writeString(" << fieldName; + fileOut << " __dna_writer.writeString(" << fieldName; if (sizeExprStr.size()) fileOut << ", " << sizeExprStr; fileOut << ");\n"; @@ -714,18 +784,18 @@ public: if (currentEndian != endianVal) { if (endianVal == 0) - fileOut << (p ? " writer.setEndian(Athena::LittleEndian);\n" : " reader.setEndian(Athena::LittleEndian);\n"); + fileOut << (p ? " __dna_writer.setEndian(Athena::LittleEndian);\n" : " __dna_reader.setEndian(Athena::LittleEndian);\n"); else if (endianVal == 1) - fileOut << (p ? " writer.setEndian(Athena::BigEndian);\n" : " reader.setEndian(Athena::BigEndian);\n"); + fileOut << (p ? " __dna_writer.setEndian(Athena::BigEndian);\n" : " __dna_reader.setEndian(Athena::BigEndian);\n"); currentEndian = endianVal; } fileOut << " /* " << fieldName << " */\n"; if (!p) - fileOut << " " << fieldName << " = reader.readWString(" << sizeExprStr << ");\n"; + fileOut << " " << fieldName << " = __dna_reader.readWString(" << sizeExprStr << ");\n"; else { - fileOut << " writer.writeWString(" << fieldName; + fileOut << " __dna_writer.writeWString(" << fieldName; if (sizeExprStr.size()) fileOut << ", " << sizeExprStr; fileOut << ");\n"; @@ -761,10 +831,10 @@ public: fileOut << " /* " << fieldName << " */\n"; if (!p) - fileOut << " " << fieldName << " = reader.readUnicode(" << sizeExprStr << ");\n"; + fileOut << " " << fieldName << " = __dna_reader.readUnicode(" << sizeExprStr << ");\n"; else { - fileOut << " writer.writeUnicode(" << fieldName; + fileOut << " __dna_writer.writeUnicode(" << fieldName; if (sizeExprStr.size()) fileOut << ", " << sizeExprStr; fileOut << ");\n"; @@ -849,23 +919,23 @@ public: if (directionVal == 0) { if (!p) - fileOut << " reader.seek(" << offsetExprStr << ", Athena::Begin);\n"; + fileOut << " __dna_reader.seek(" << offsetExprStr << ", Athena::Begin);\n"; else - fileOut << " writer.seek(" << offsetExprStr << ", Athena::Begin);\n"; + fileOut << " __dna_writer.seek(" << offsetExprStr << ", Athena::Begin);\n"; } else if (directionVal == 1) { if (!p) - fileOut << " reader.seek(" << offsetExprStr << ", Athena::Current);\n"; + fileOut << " __dna_reader.seek(" << offsetExprStr << ", Athena::Current);\n"; else - fileOut << " writer.seek(" << offsetExprStr << ", Athena::Current);\n"; + fileOut << " __dna_writer.seek(" << offsetExprStr << ", Athena::Current);\n"; } else if (directionVal == 2) { if (!p) - fileOut << " reader.seek(" << offsetExprStr << ", Athena::End);\n"; + fileOut << " __dna_reader.seek(" << offsetExprStr << ", Athena::End);\n"; else - fileOut << " writer.seek(" << offsetExprStr << ", Athena::End);\n"; + fileOut << " __dna_writer.seek(" << offsetExprStr << ", Athena::End);\n"; } } @@ -901,23 +971,23 @@ public: if (alignVal == 32) { if (!p) - fileOut << " reader.seekAlign32();\n"; + fileOut << " __dna_reader.seekAlign32();\n"; else - fileOut << " writer.seekAlign32();\n"; + fileOut << " __dna_writer.seekAlign32();\n"; } else if (align.isPowerOf2()) { if (!p) - fileOut << " reader.seek((reader.position() + " << alignVal-1 << ") & ~" << alignVal-1 << ", Athena::Begin);\n"; + fileOut << " __dna_reader.seek((__dna_reader.position() + " << alignVal-1 << ") & ~" << alignVal-1 << ", Athena::Begin);\n"; else - fileOut << " writer.seek((writer.position() + " << alignVal-1 << ") & ~" << alignVal-1 << ", Athena::Begin);\n"; + fileOut << " __dna_writer.seek((__dna_writer.position() + " << alignVal-1 << ") & ~" << alignVal-1 << ", Athena::Begin);\n"; } else { if (!p) - fileOut << " reader.seek((reader.position() + " << alignVal-1 << ") / " << alignVal << " * " << alignVal << ", Athena::Begin);\n"; + fileOut << " __dna_reader.seek((__dna_reader.position() + " << alignVal-1 << ") / " << alignVal << " * " << alignVal << ", Athena::Begin);\n"; else - fileOut << " writer.seek((writer.position() + " << alignVal-1 << ") / " << alignVal << " * " << alignVal << ", Athena::Begin);\n"; + fileOut << " __dna_writer.seek((__dna_writer.position() + " << alignVal-1 << ") / " << alignVal << " * " << alignVal << ", Athena::Begin);\n"; } } } @@ -927,19 +997,13 @@ public: else if (regType->getTypeClass() == clang::Type::Record) { const clang::CXXRecordDecl* cxxRDecl = regType->getAsCXXRecordDecl(); - if (cxxRDecl) + std::string baseDNA; + if (cxxRDecl && isDNARecord(cxxRDecl, baseDNA)) { - for (const clang::CXXBaseSpecifier& base : cxxRDecl->bases()) - { - clang::QualType canonType = base.getType().getCanonicalType(); - if (!canonType.getAsString().compare(0, sizeof(ATHENA_DNA_BASETYPE)-1, ATHENA_DNA_BASETYPE)) - { - fileOut << " /* " << fieldName << " */\n"; - fileOut << " " << fieldName << (p ? ".write(writer);\n" : ".read(reader);\n"); - currentEndian = -1; - break; - } - } + fileOut << " /* " << fieldName << " */\n"; + fileOut << " " << fieldName << (p ? ".write(__dna_writer);\n" : ".read(__dna_reader);\n"); + currentEndian = -1; + break; } } diff --git a/atdna/test.hpp b/atdna/test.hpp index 6df4abd..beeeae9 100644 --- a/atdna/test.hpp +++ b/atdna/test.hpp @@ -1,15 +1,30 @@ #include using namespace Athena; +typedef io::DNA BigDNA; -struct ANCSSubFile : public io::DNA +struct TESTSubFile : public BigDNA { DECL_DNA Value sub1; Value sub2; }; -struct ANCSFile : public io::DNA +struct TESTSubClassFile : public TESTSubFile +{ + DECL_DNA + Value sub3; + Value sub4; +}; + +struct TESTSubSubClassFile : public TESTSubClassFile +{ + DECL_DNA + Value sub5; + Value sub6; +}; + +struct TESTFile : public BigDNA { DECL_DNA Value varBool; @@ -18,27 +33,34 @@ struct ANCSFile : public io::DNA Value vec3; Value vec4; - struct ANCSNestedSubFile : public io::DNA + struct TESTNestedSubFile : public BigDNA { DECL_DNA Value nestSub1; Value nestSub2; - } nestedSubFile; + } nestedSubFile; - ANCSSubFile subFile; + TESTSubFile subFile; Align<4> align; + struct TESTExplicitSubFile : public BigDNA + { + DECL_EXPLICIT_DNA + Value explSub1; + Value explSub2; + } explSubFile; + Value arrCount[2]; - Vector array; + Vector array; Seek<21, Current> seek; Value arrCount2; - Vector array2; + Vector array2; Value bufSz; - Buffer buf; + Buffer buf; String<32> str; WString<64> wstr; diff --git a/include/Athena/DNA.hpp b/include/Athena/DNA.hpp index 12dea27..daf0bc7 100644 --- a/include/Athena/DNA.hpp +++ b/include/Athena/DNA.hpp @@ -53,6 +53,8 @@ struct DNA template struct Align {}; + struct Delete {}; + virtual void read(IStreamReader&)=0; virtual void write(IStreamWriter&) const=0; }; @@ -62,6 +64,12 @@ struct DNA void read(Athena::io::IStreamReader&); \ void write(Athena::io::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; \ + Delete __dna_delete; + /** Macro to supply count variable to atdna and mute it for other compilers */ #ifdef __clang__ #define DNA_COUNT(cnt) sizeof(cnt)