From 4252bd6e39dd1e3cc50e8e5f18ae4bd02b7520ba Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 15 Jul 2015 16:03:38 -1000 Subject: [PATCH] added AngelScript; work on extractor --- hecl/.gitmodules | 3 ++ hecl/CMakeLists.txt | 8 ++- hecl/driver/CMakeLists.txt | 5 +- hecl/driver/main.cpp | 22 +++++--- hecl/extern/AngelScript | 1 + hecl/extern/Athena | 2 +- hecl/extern/CMakeLists.txt | 2 +- hecl/extern/LogVisor | 2 +- hecl/extern/RetroCommon | 2 +- hecl/include/HECL/Database.hpp | 92 ++++++++++++++++++++++++++++++++ hecl/include/HECL/HECL.hpp | 28 ++++++++-- hecl/lib/Database/ASEngine.cpp | 21 ++++++++ hecl/lib/Database/ASInit.cpp | 24 +++++++++ hecl/lib/Database/CMakeLists.txt | 8 ++- hecl/lib/ProjectPath.cpp | 40 ++++++++++---- 15 files changed, 227 insertions(+), 33 deletions(-) create mode 160000 hecl/extern/AngelScript create mode 100644 hecl/lib/Database/ASEngine.cpp create mode 100644 hecl/lib/Database/ASInit.cpp diff --git a/hecl/.gitmodules b/hecl/.gitmodules index 3a94f75e1..bf48c3af1 100644 --- a/hecl/.gitmodules +++ b/hecl/.gitmodules @@ -10,3 +10,6 @@ [submodule "extern/LogVisor"] path = extern/LogVisor url = https://github.com/RetroView/LogVisor.git +[submodule "extern/AngelScript"] + path = extern/AngelScript + url = https://github.com/RetroView/AngelScript.git diff --git a/hecl/CMakeLists.txt b/hecl/CMakeLists.txt index cf63a0716..df116f9f4 100644 --- a/hecl/CMakeLists.txt +++ b/hecl/CMakeLists.txt @@ -1,8 +1,12 @@ cmake_minimum_required(VERSION 3.0) project(hecl) -set(HECL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE PATH "HECL include dir" FORCE) +set(HECL_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) +set(ATHENA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/Athena/include) +set(LOG_VISOR_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/LogVisor/include) +set(ANGELSCRIPT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/AngelScript/angelscript/include) +add_definitions(-DAS_USE_NAMESPACE=1) add_subdirectory(extern) -include_directories(include ${LOG_VISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR}) +include_directories(include ${LOG_VISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${ANGELSCRIPT_INCLUDE_DIR}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") add_subdirectory(lib) add_subdirectory(blender) diff --git a/hecl/driver/CMakeLists.txt b/hecl/driver/CMakeLists.txt index 828c6f96a..40df3f8ab 100644 --- a/hecl/driver/CMakeLists.txt +++ b/hecl/driver/CMakeLists.txt @@ -20,7 +20,6 @@ list(APPEND DATA_SPEC_LIBS DNAMP3) target_link_libraries(hecl - HECLDatabase - "-Wl,-whole-archive" ${DATA_SPEC_LIBS} "-Wl,-no-whole-archive" - HECL AthenaCore NOD LogVisor blowfish z lzo2 pthread + "-Wl,-whole-archive" HECLDatabaseInit ${DATA_SPEC_LIBS} "-Wl,-no-whole-archive" + HECLDatabase HECL AthenaCore AngelScript NOD LogVisor blowfish z lzo2 ) diff --git a/hecl/driver/main.cpp b/hecl/driver/main.cpp index cf4ad0622..2e4de0380 100644 --- a/hecl/driver/main.cpp +++ b/hecl/driver/main.cpp @@ -206,10 +206,15 @@ int main(int argc, const char** argv) else LogModule.report(LogVisor::FatalError, _S("unrecognized tool '%s'"), toolName.c_str()); } - catch (std::exception&) + catch (std::exception& ex) { - LogModule.report(LogVisor::Error, _S("Unable to construct HECL tool '%s'"), - toolName.c_str()); +#if HECL_UCS2 + LogModule.report(LogVisor::Error, _S("Unable to construct HECL tool '%s': %S"), + toolName.c_str(), ex.what()); +#else + LogModule.report(LogVisor::Error, _S("Unable to construct HECL tool '%s': %s"), + toolName.c_str(), ex.what()); +#endif return -1; } @@ -223,10 +228,15 @@ int main(int argc, const char** argv) { retval = tool->run(); } - catch (std::exception&) + catch (std::exception& ex) { - LogModule.report(LogVisor::Error, _S("Error running HECL tool '%s'"), - toolName.c_str()); +#if HECL_UCS2 + LogModule.report(LogVisor::Error, _S("Error running HECL tool '%s': %S"), + toolName.c_str(), ex.what()); +#else + LogModule.report(LogVisor::Error, _S("Error running HECL tool '%s': %s"), + toolName.c_str(), ex.what()); +#endif return -1; } diff --git a/hecl/extern/AngelScript b/hecl/extern/AngelScript new file mode 160000 index 000000000..0a8e531a6 --- /dev/null +++ b/hecl/extern/AngelScript @@ -0,0 +1 @@ +Subproject commit 0a8e531a63fad935ca3ce68e2122715320417668 diff --git a/hecl/extern/Athena b/hecl/extern/Athena index 87306a18d..7442d618e 160000 --- a/hecl/extern/Athena +++ b/hecl/extern/Athena @@ -1 +1 @@ -Subproject commit 87306a18d87c136930bd3252775303ad7bff77ec +Subproject commit 7442d618e7f82acdc8f986baca040033c1f411f9 diff --git a/hecl/extern/CMakeLists.txt b/hecl/extern/CMakeLists.txt index c7e741504..81fe9a6d6 100644 --- a/hecl/extern/CMakeLists.txt +++ b/hecl/extern/CMakeLists.txt @@ -1,6 +1,6 @@ -set(ATHENA_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Athena/include CACHE PATH "Athena include dir" FORCE) add_subdirectory(libpng) add_subdirectory(blowfish) add_subdirectory(LogVisor) +add_subdirectory(AngelScript) add_subdirectory(Athena) add_subdirectory(RetroCommon) diff --git a/hecl/extern/LogVisor b/hecl/extern/LogVisor index 462971b13..c2bfffa6c 160000 --- a/hecl/extern/LogVisor +++ b/hecl/extern/LogVisor @@ -1 +1 @@ -Subproject commit 462971b134432330b30b60898d8c8b5c758bacb7 +Subproject commit c2bfffa6cf1d07986fecaf7dde42acb29fe1f6e6 diff --git a/hecl/extern/RetroCommon b/hecl/extern/RetroCommon index a4d1fdbcf..94a6707dd 160000 --- a/hecl/extern/RetroCommon +++ b/hecl/extern/RetroCommon @@ -1 +1 @@ -Subproject commit a4d1fdbcfa2ea1331ae1c8d9a1e96822e1dce52e +Subproject commit 94a6707dd32e6aed988c7606c6c28836a398ad6d diff --git a/hecl/include/HECL/Database.hpp b/hecl/include/HECL/Database.hpp index d003c673d..b7b6bb79b 100644 --- a/hecl/include/HECL/Database.hpp +++ b/hecl/include/HECL/Database.hpp @@ -13,7 +13,9 @@ #include #include #include +#include +#include #include #include @@ -25,6 +27,94 @@ namespace Database { class Project; +extern AngelScript::asIScriptEngine* asENGINE; +void InitASEngine(); + +template +class ASType +{ + static void Constructor(ASCLASS* self) + { + new(self) ASCLASS(); + } + static void Destructor(ASCLASS* self) + { + self->~ASCLASS(); + } + const char* m_name; + int m_typeid; +public: + ASType(const char* namesp, const char* name) : m_name(name) + { + InitASEngine(); + assert(asENGINE->SetDefaultNamespace(namesp) >= 0); + assert((m_typeid = asENGINE->RegisterObjectType(name, sizeof(ASCLASS), AngelScript::asOBJ_VALUE)) >= 0); + assert(asENGINE->RegisterObjectBehaviour(name, AngelScript::asBEHAVE_CONSTRUCT, "void f()", + AngelScript::asFUNCTION(Constructor), + AngelScript::asCALL_CDECL_OBJLAST) >= 0); + assert(asENGINE->RegisterObjectBehaviour(name, AngelScript::asBEHAVE_DESTRUCT, "void f()", + AngelScript::asFUNCTION(Destructor), + AngelScript::asCALL_CDECL_OBJLAST) >= 0); + } + inline const char* getName() const {return m_name;} + inline int getTypeID() const {return m_typeid;} +}; + +template +class ASListType +{ + struct ASListInst + { + std::vector m_items; + ASListInst(void* list) + { + AngelScript::asUINT count = *(AngelScript::asUINT*)list; + ASELEMCLASS* items = (ASELEMCLASS*)((char*)list + 4); + m_items.reserve(count); + for (AngelScript::asUINT i=0 ; i~ASListInst(); + } + const char* m_name; + const char* m_elemName; + int m_typeid; +public: + ASListType(const char* namesp, const char* name, const char* elemName) : m_name(name), m_elemName(elemName) + { + InitASEngine(); + assert(asENGINE->SetDefaultNamespace(namesp) >= 0); + assert((m_typeid = asENGINE->RegisterObjectType(name, sizeof(ASListInst), AngelScript::asOBJ_VALUE)) >= 0); + assert(asENGINE->RegisterObjectBehaviour(name, AngelScript::asBEHAVE_LIST_CONSTRUCT, + ("void f(int &in) {repeat " + std::string(elemName) + "}").c_str(), + AngelScript::asFUNCTION(ListConstructor), + AngelScript::asCALL_CDECL_OBJLAST) >= 0); + assert(asENGINE->RegisterObjectBehaviour(name, AngelScript::asBEHAVE_DESTRUCT, "void f()", + AngelScript::asFUNCTION(ListDestructor), + AngelScript::asCALL_CDECL_OBJLAST) >= 0); + } + inline const char* getName() const {return m_name;} + inline const char* getElemName() const {return m_elemName;} + inline int getTypeID() const {return m_typeid;} + inline std::vector& vectorCast(void* addr) const + {return static_cast(addr)->m_items;} + inline const std::vector& vectorCast(const void* addr) const + {return static_cast(addr)->m_items;} +}; + +struct ASStringType : ASType +{ + ASStringType(); +}; +extern ASStringType asSTRINGTYPE; + extern LogVisor::LogModule LogModule; /** @@ -62,6 +152,8 @@ public: class IDataSpec { public: + virtual ~IDataSpec() {} + /** * @brief Extract Pass Info * diff --git a/hecl/include/HECL/HECL.hpp b/hecl/include/HECL/HECL.hpp index f0a3fd0d4..e72ded018 100644 --- a/hecl/include/HECL/HECL.hpp +++ b/hecl/include/HECL/HECL.hpp @@ -178,6 +178,18 @@ static inline void FPrintf(FILE* fp, const SystemChar* format, ...) va_end(va); } +static inline void SNPrintf(SystemChar* str, size_t maxlen, const SystemChar* format, ...) +{ + va_list va; + va_start(va, format); +#if HECL_UCS2 + vsnwprintf(str, maxlen, format, va); +#else + vsnprintf(str, maxlen, format, va); +#endif + va_end(va); +} + #define FORMAT_BUF_SZ 1024 static inline SystemString SysFormat(const SystemChar* format, ...) @@ -314,14 +326,15 @@ protected: const char* m_utf8RelPath; #endif ProjectPath() {} - bool _canonAbsPath(const SystemString& path); + bool _canonAbsPath(const SystemString& path, bool& needsMake); + inline void _makeDir() const {MakeDir(getAbsolutePath());} public: /** - * @brief Construct a project subpath representation - * @param rootPath previously constructed ProjectRootPath held by HECLDatabase::IProject + * @brief Construct a project subpath representation within another subpath + * @param parentPath previously constructed ProjectPath which ultimately connects to a ProjectRootPath * @param path valid filesystem-path (relative or absolute) to subpath */ - ProjectPath(const ProjectRootPath& rootPath, const SystemString& path); + ProjectPath(const ProjectPath& parentPath, const SystemString& path); /** * @brief Determine if ProjectPath represents project root directory @@ -422,7 +435,12 @@ class ProjectRootPath : public ProjectPath { public: ProjectRootPath(const SystemString& path) - {_canonAbsPath(path);} + { + bool needsMake = false; + _canonAbsPath(path, needsMake); + if (needsMake) + _makeDir(); + } }; /** diff --git a/hecl/lib/Database/ASEngine.cpp b/hecl/lib/Database/ASEngine.cpp new file mode 100644 index 000000000..f10aa1f3b --- /dev/null +++ b/hecl/lib/Database/ASEngine.cpp @@ -0,0 +1,21 @@ +#include "HECL/Database.hpp" + +namespace HECL +{ +namespace Database +{ + +/* Centralized AngelScript engine */ +AngelScript::asIScriptEngine* asENGINE = nullptr; + +static bool InitEntered = false; +void InitASEngine() +{ + if (InitEntered) + return; + InitEntered = true; + assert(asENGINE = AngelScript::asCreateScriptEngine(ANGELSCRIPT_VERSION)); +} + +} +} diff --git a/hecl/lib/Database/ASInit.cpp b/hecl/lib/Database/ASInit.cpp new file mode 100644 index 000000000..8adea267e --- /dev/null +++ b/hecl/lib/Database/ASInit.cpp @@ -0,0 +1,24 @@ +#include "HECL/Database.hpp" + +namespace HECL +{ +namespace Database +{ + +static std::string StringFactory(unsigned int byteLength, const char *s) +{ + return std::string(s, byteLength); +} + +ASStringType asSTRINGTYPE; +ASStringType::ASStringType() : ASType("", "string") +{ + assert(asENGINE->RegisterStringFactory("string", + AngelScript::asFUNCTION(StringFactory), + AngelScript::asCALL_CDECL) >= 0); +} + +} +} + + diff --git a/hecl/lib/Database/CMakeLists.txt b/hecl/lib/Database/CMakeLists.txt index d1555adbd..a2525c074 100644 --- a/hecl/lib/Database/CMakeLists.txt +++ b/hecl/lib/Database/CMakeLists.txt @@ -1,3 +1,7 @@ +add_library(HECLDatabaseInit + Registry.cpp + ASInit.cpp) add_library(HECLDatabase - Project.cpp - Registry.cpp) + ASEngine.cpp + Project.cpp) + diff --git a/hecl/lib/ProjectPath.cpp b/hecl/lib/ProjectPath.cpp index 6655f55d6..427519f8f 100644 --- a/hecl/lib/ProjectPath.cpp +++ b/hecl/lib/ProjectPath.cpp @@ -15,39 +15,54 @@ static const SystemRegex regGLOB(_S("\\*"), SystemRegex::ECMAScript|SystemRegex: static const SystemRegex regPATHCOMP(_S("/([^/]+)"), SystemRegex::ECMAScript|SystemRegex::optimize); static const SystemRegex regDRIVELETTER(_S("^([^/]*)/"), SystemRegex::ECMAScript|SystemRegex::optimize); -bool ProjectPath::_canonAbsPath(const SystemString& path) +inline bool isAbsolute(const SystemString& path) +{ + if (path.size() && path[0] == '/') + return true; + return false; +} + +bool ProjectPath::_canonAbsPath(const SystemString& path, bool& needsMake) { #if _WIN32 #else SystemChar resolvedPath[PATH_MAX]; if (!realpath(path.c_str(), resolvedPath)) { - throw std::invalid_argument("Unable to resolve '" + SystemUTF8View(path).utf8_str() + + if (errno != ENOENT) + { + throw std::system_error(errno, std::system_category(), + "Unable to resolve '" + SystemUTF8View(path).utf8_str() + "' as a canonicalized path"); - return false; + return false; + } + else + needsMake = true; } m_absPath = resolvedPath; #endif return true; } -ProjectPath::ProjectPath(const ProjectRootPath& rootPath, const SystemString& path) +ProjectPath::ProjectPath(const ProjectPath& parentPath, const SystemString& path) { - _canonAbsPath(path); - if (m_absPath.size() < ((ProjectPath&)rootPath).m_absPath.size() || - m_absPath.compare(0, ((ProjectPath&)rootPath).m_absPath.size(), - ((ProjectPath&)rootPath).m_absPath)) + bool needsMake = false; + if (!_canonAbsPath(parentPath.getRelativePath() + '/' + path, needsMake)) + return; + if (m_absPath.size() < parentPath.m_absPath.size() || + m_absPath.compare(0, parentPath.m_absPath.size(), + parentPath.m_absPath)) { throw std::invalid_argument("'" + SystemUTF8View(m_absPath).utf8_str() + "' is not a subpath of '" + - SystemUTF8View(((ProjectPath&)rootPath).m_absPath).utf8_str() + "'"); + SystemUTF8View(parentPath.m_absPath).utf8_str() + "'"); return; } - if (m_absPath.size() == ((ProjectPath&)rootPath).m_absPath.size()) + if (m_absPath.size() == parentPath.m_absPath.size()) { /* Copies of the project root are permitted */ return; } - SystemString::iterator beginit = m_absPath.begin() + ((ProjectPath&)rootPath).m_absPath.size(); + SystemString::iterator beginit = m_absPath.begin() + parentPath.m_absPath.size(); if (*beginit == _S('/')) ++beginit; m_relPath = SystemString(beginit, m_absPath.end()); @@ -57,6 +72,9 @@ ProjectPath::ProjectPath(const ProjectRootPath& rootPath, const SystemString& pa m_utf8AbsPath = WideToUTF8(m_absPath); m_utf8RelPath = m_utf8AbsPath.c_str() + ((ProjectPath&)rootPath).m_utf8AbsPath.size(); #endif + + if (needsMake) + _makeDir(); } ProjectPath::PathType ProjectPath::getPathType() const