diff --git a/hecl/CMakeLists.txt b/hecl/CMakeLists.txt index 28339935d..6c0b22dfe 100644 --- a/hecl/CMakeLists.txt +++ b/hecl/CMakeLists.txt @@ -1,5 +1,10 @@ cmake_minimum_required(VERSION 3.0) project(hecl) +if(WIN32) +add_definitions(-DUNICODE=1 -D_UNICODE=1 -D_CRT_SECURE_NO_WARNINGS=1 /wd4267 /wd4244) +else() +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-multichar") +endif() 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) @@ -9,7 +14,6 @@ set(SQUISH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/extern/libSquish) add_definitions(-DAS_USE_NAMESPACE=1) add_subdirectory(extern) 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) add_subdirectory(driver) diff --git a/hecl/DataSpecRegistry.hpp b/hecl/DataSpecRegistry.hpp new file mode 100644 index 000000000..e8e3ab270 --- /dev/null +++ b/hecl/DataSpecRegistry.hpp @@ -0,0 +1,25 @@ +#include "HECL/Database.hpp" + +namespace HECL +{ +namespace Database +{ +/* Centralized registry for DataSpec lookup */ +std::vector DATA_SPEC_REGISTRY; +} +} + +/* RetroCommon specs */ +namespace Retro +{ + extern HECL::Database::DataSpecEntry SpecEntMP1; + extern HECL::Database::DataSpecEntry SpecEntMP2; + extern HECL::Database::DataSpecEntry SpecEntMP3; +} + +extern "C" void HECLDataSpecs() +{ + HECL::Printf(Retro::SpecEntMP1.m_name); + HECL::Printf(Retro::SpecEntMP2.m_name); + HECL::Printf(Retro::SpecEntMP3.m_name); +} diff --git a/hecl/blender/BlenderConnection.cpp b/hecl/blender/BlenderConnection.cpp index 348c46e8a..08938c20c 100644 --- a/hecl/blender/BlenderConnection.cpp +++ b/hecl/blender/BlenderConnection.cpp @@ -5,19 +5,23 @@ #include #include +#include +#include #include "BlenderConnection.hpp" +static LogVisor::LogModule Log("BlenderConnection"); + #ifdef __APPLE__ #define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender" #elif _WIN32 -#define DEFAULT_BLENDER_BIN "%ProgramFiles%\\Blender Foundation\\Blender\\blender.exe" +#define DEFAULT_BLENDER_BIN _S("%ProgramFiles%\\Blender Foundation\\Blender\\blender.exe") #else #define DEFAULT_BLENDER_BIN "blender" #endif #define TEMP_SHELLSCRIPT "/home/jacko/hecl/blender/blendershell.py" -size_t CBlenderConnection::_readLine(char* buf, size_t bufSz) +size_t BlenderConnection::_readLine(char* buf, size_t bufSz) { size_t readBytes = 0; while (true) @@ -28,9 +32,15 @@ size_t CBlenderConnection::_readLine(char* buf, size_t bufSz) *(buf-1) = '\0'; return bufSz - 1; } +#if _WIN32 + DWORD ret = 0; + if (!ReadFile(m_readpipe[0], buf, 1, &ret, NULL)) + goto err; +#else ssize_t ret = read(m_readpipe[0], buf, 1); if (ret < 0) goto err; +#endif else if (ret == 1) { if (*buf == '\n') @@ -52,8 +62,15 @@ err: return 0; } -size_t CBlenderConnection::_writeLine(const char* buf) +size_t BlenderConnection::_writeLine(const char* buf) { +#if _WIN32 + DWORD ret = 0; + if (!WriteFile(m_writepipe[1], buf, strlen(buf), &ret, NULL)) + goto err; + if (!WriteFile(m_writepipe[1], "\n", 1, NULL, NULL)) + goto err; +#else ssize_t ret, nlerr; ret = write(m_writepipe[1], buf, strlen(buf)); if (ret < 0) @@ -61,43 +78,125 @@ size_t CBlenderConnection::_writeLine(const char* buf) nlerr = write(m_writepipe[1], "\n", 1); if (nlerr < 0) goto err; +#endif return (size_t)ret; err: throw std::error_code(errno, std::system_category()); } -size_t CBlenderConnection::_readBuf(char* buf, size_t len) +size_t BlenderConnection::_readBuf(char* buf, size_t len) { +#if _WIN32 + DWORD ret = 0; + if (!ReadFile(m_readpipe[0], buf, len, &ret, NULL)) + goto err; +#else ssize_t ret = read(m_readpipe[0], buf, len); if (ret < 0) - throw std::error_code(errno, std::system_category()); + goto err; +#endif return ret; +err: + throw std::error_code(errno, std::system_category()); + return 0; } -size_t CBlenderConnection::_writeBuf(const char* buf, size_t len) +size_t BlenderConnection::_writeBuf(const char* buf, size_t len) { +#if _WIN32 + DWORD ret = 0; + if (!WriteFile(m_writepipe[1], buf, len, &ret, NULL)) + goto err; +#else ssize_t ret = write(m_writepipe[1], buf, len); if (ret < 0) - throw std::error_code(errno, std::system_category()); + goto err; +#endif return ret; +err: + throw std::error_code(errno, std::system_category()); + return 0; } -void CBlenderConnection::_closePipe() +void BlenderConnection::_closePipe() { +#if _WIN32 + CloseHandle(m_readpipe[0]); + CloseHandle(m_writepipe[1]); +#else close(m_readpipe[0]); close(m_writepipe[1]); +#endif } -CBlenderConnection::CBlenderConnection(bool silenceBlender) +BlenderConnection::BlenderConnection(bool silenceBlender) { /* Construct communication pipes */ +#if _WIN32 + SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; + CreatePipe(&m_readpipe[0], &m_readpipe[1], &sattrs, 0); + CreatePipe(&m_writepipe[0], &m_writepipe[1], &sattrs, 0); +#else pipe(m_readpipe); pipe(m_writepipe); +#endif /* User-specified blender path */ +#if _WIN32 + wchar_t BLENDER_BIN_BUF[2048]; + wchar_t* blenderBin = _wgetenv(L"BLENDER_BIN"); +#else char* blenderBin = getenv("BLENDER_BIN"); +#endif /* Child process of blender */ +#if _WIN32 + if (!blenderBin) + { + /* Environment not set; use registry */ + HKEY blenderKey; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\BlenderFoundation", 0, KEY_READ, &blenderKey) == ERROR_SUCCESS) + { + DWORD bufSz = sizeof(BLENDER_BIN_BUF); + if (RegGetValueW(blenderKey, NULL, L"Install_Dir", REG_SZ, NULL, BLENDER_BIN_BUF, &bufSz) == ERROR_SUCCESS) + { + wcscat_s(BLENDER_BIN_BUF, 2048, L"\\blender.exe"); + blenderBin = BLENDER_BIN_BUF; + } + RegCloseKey(blenderKey); + } + } + if (!blenderBin) + { + Log.report(LogVisor::FatalError, "unable to find blender"); + return; + } + + wchar_t cmdLine[2048]; + _snwprintf(cmdLine, 2048, L" --background -P shellscript.py -- %08X %08X", + (uint32_t)m_writepipe[0], (uint32_t)m_readpipe[1]); + + STARTUPINFO sinfo = {sizeof(STARTUPINFO)}; + HANDLE nulHandle = NULL; + if (silenceBlender) + { + nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sattrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + sinfo.hStdError = nulHandle; + sinfo.hStdOutput = nulHandle; + sinfo.dwFlags = STARTF_USESTDHANDLES; + } + + PROCESS_INFORMATION pinfo; + if (!CreateProcessW(blenderBin, cmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sinfo, &pinfo)) + Log.report(LogVisor::FatalError, "unable to launch blender"); + + CloseHandle(m_writepipe[1]); + CloseHandle(m_readpipe[0]); + + if (nulHandle) + CloseHandle(nulHandle); + +#else pid_t pid = fork(); if (!pid) { @@ -149,6 +248,7 @@ CBlenderConnection::CBlenderConnection(bool silenceBlender) close(m_writepipe[0]); close(m_readpipe[1]); m_blenderProc = pid; +#endif /* Handle first response */ char lineBuf[256]; @@ -156,40 +256,38 @@ CBlenderConnection::CBlenderConnection(bool silenceBlender) if (!strcmp(lineBuf, "NOLAUNCH")) { _closePipe(); - throw std::runtime_error("Unable to launch blender"); + Log.report(LogVisor::FatalError, "Unable to launch blender"); } else if (!strcmp(lineBuf, "NOBLENDER")) { _closePipe(); if (blenderBin) - throw std::runtime_error("Unable to find blender at '" + - std::string(blenderBin) + "' or '" + - std::string(DEFAULT_BLENDER_BIN) + "'"); + Log.report(LogVisor::FatalError, _S("Unable to find blender at '%s' or '%s'"), + blenderBin, DEFAULT_BLENDER_BIN); else - throw std::runtime_error("Unable to find blender at '" + - std::string(DEFAULT_BLENDER_BIN) + "'"); + Log.report(LogVisor::FatalError, _S("Unable to find blender at '%s'"), + DEFAULT_BLENDER_BIN); } else if (!strcmp(lineBuf, "NOADDON")) { _closePipe(); - throw std::runtime_error("HECL addon not installed within blender"); + Log.report(LogVisor::FatalError, "HECL addon not installed within blender"); } else if (strcmp(lineBuf, "READY")) { _closePipe(); - throw std::runtime_error("read '" + std::string(lineBuf) + - "' from blender; expected 'READY'"); + Log.report(LogVisor::FatalError, "read '%s' from blender; expected 'READY'", lineBuf); } _writeLine("ACK"); } -CBlenderConnection::~CBlenderConnection() +BlenderConnection::~BlenderConnection() { _closePipe(); } -bool CBlenderConnection::openBlend(const std::string& path) +bool BlenderConnection::openBlend(const std::string& path) { _writeLine(("OPEN" + path).c_str()); char lineBuf[256]; @@ -202,7 +300,7 @@ bool CBlenderConnection::openBlend(const std::string& path) return false; } -bool CBlenderConnection::cookBlend(std::function bufGetter, +bool BlenderConnection::cookBlend(std::function bufGetter, const std::string& expectedType, const std::string& platform, bool bigEndian) @@ -238,7 +336,7 @@ bool CBlenderConnection::cookBlend(std::function bufGetter, return false; } -void CBlenderConnection::quitBlender() +void BlenderConnection::quitBlender() { _writeLine("QUIT"); char lineBuf[256]; diff --git a/hecl/blender/BlenderConnection.hpp b/hecl/blender/BlenderConnection.hpp index 9e8049a02..e68d07cb6 100644 --- a/hecl/blender/BlenderConnection.hpp +++ b/hecl/blender/BlenderConnection.hpp @@ -1,5 +1,5 @@ -#ifndef CBLENDERCONNECTION_HPP -#define CBLENDERCONNECTION_HPP +#ifndef BLENDERCONNECTION_HPP +#define BLENDERCONNECTION_HPP #if _WIN32 #define _WIN32_LEAN_AND_MEAN 1 @@ -8,15 +8,16 @@ #include #endif +#include #include #include -class CBlenderConnection +class BlenderConnection { #if _WIN32 HANDLE m_blenderProc; - HANDLE m_readpipe; - HANDLE m_writepipe; + HANDLE m_readpipe[2]; + HANDLE m_writepipe[2]; #else pid_t m_blenderProc; int m_readpipe[2]; @@ -29,8 +30,8 @@ class CBlenderConnection size_t _writeBuf(const char* buf, size_t len); void _closePipe(); public: - CBlenderConnection(bool silenceBlender=false); - ~CBlenderConnection(); + BlenderConnection(bool silenceBlender=false); + ~BlenderConnection(); bool openBlend(const std::string& path); enum CookPlatform @@ -45,4 +46,4 @@ public: void quitBlender(); }; -#endif // CBLENDERCONNECTION_HPP +#endif // BLENDERCONNECTION_HPP diff --git a/hecl/driver/CMakeLists.txt b/hecl/driver/CMakeLists.txt index 005203da9..df14dc614 100644 --- a/hecl/driver/CMakeLists.txt +++ b/hecl/driver/CMakeLists.txt @@ -1,3 +1,7 @@ +if(WIN32) +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /INCLUDE:HECLDataSpecs") +endif() + add_executable(hecl main.cpp ToolBase.hpp ToolPackage.hpp @@ -19,7 +23,12 @@ list(APPEND DATA_SPEC_LIBS DNAMP2 DNAMP3) +if(NOT WIN32) +set(WHOLE_START "-Wl,-whole-archive") +set(WHOLE_END "-Wl,-no-whole-archive") +endif() + target_link_libraries(hecl - "-Wl,-whole-archive" HECLDatabaseInit ${DATA_SPEC_LIBS} "-Wl,-no-whole-archive" - HECLDatabase HECL AthenaCore AngelScript NOD LogVisor png squish blowfish z lzo2 + ${WHOLE_START} HECLDatabaseInit ${DATA_SPEC_LIBS} ${WHOLE_END} + HECLDatabase HECLCommon AthenaCore AngelScript NOD LogVisor png squish blowfish z lzo2 ) diff --git a/hecl/driver/ToolAdd.hpp b/hecl/driver/ToolAdd.hpp index b7c297c53..4d11935ec 100644 --- a/hecl/driver/ToolAdd.hpp +++ b/hecl/driver/ToolAdd.hpp @@ -26,15 +26,15 @@ public: help.secHead(_S("DESCRIPTION")); help.beginWrap(); - help.wrap(_S("This command stages a file or glob-pattern of files within the project database " - "for inclusion in the ")); + help.wrap(_S("This command stages a file or glob-pattern of files within the project database ") + _S("for inclusion in the ")); help.wrapBold(_S("hecl cook")); - help.wrap(_S(" process.\n\n" - "Files added in this manner automatically become 'explicit' database " - "objects. 'Explicit objects' will not be removed in housekeeping tasks automatically " - "performed by HECL's library functions, unless the user (re)moves the file " - "using the filesystem.\n\n" - "For details on explicit vs. implicit objects, view the ")); + help.wrap(_S(" process.\n\n") + _S("Files added in this manner automatically become 'explicit' database ") + _S("objects. 'Explicit objects' will not be removed in housekeeping tasks automatically ") + _S("performed by HECL's library functions, unless the user (re)moves the file ") + _S("using the filesystem.\n\n") + _S("For details on explicit vs. implicit objects, view the ")); help.wrapBold(_S("hecl cook")); help.wrap(_S(" documentation.\n")); help.endWrap(); @@ -42,8 +42,8 @@ public: help.secHead(_S("OPTIONS")); help.optionHead(_S("..."), _S("input file(s)")); help.beginWrap(); - help.wrap(_S("Working file(s) containing production data to be cooked by HECL. " - "Glob-strings may be specified (e.g. ")); + help.wrap(_S("Working file(s) containing production data to be cooked by HECL. ") + _S("Glob-strings may be specified (e.g. ")); help.wrapBold(_S("*.blend")); help.wrap(_S(") to automatically add all matching files to the database.\n")); help.endWrap(); diff --git a/hecl/driver/ToolBase.hpp b/hecl/driver/ToolBase.hpp index c11af5ca9..edd510336 100644 --- a/hecl/driver/ToolBase.hpp +++ b/hecl/driver/ToolBase.hpp @@ -4,9 +4,12 @@ #include #include #include -#include #include +#ifndef _WIN32 +#include +#endif + #include "HECL/Database.hpp" #include "LogVisor/LogVisor.hpp" @@ -151,26 +154,38 @@ public: void printBold(const HECL::SystemChar* str) { +#if _WIN32 + HECL::FPrintf(m_sout, _S("%s"), str); +#else if (XTERM_COLOR) HECL::FPrintf(m_sout, _S("" BOLD "%s" NORMAL ""), str); else HECL::FPrintf(m_sout, _S("%s"), str); +#endif } void secHead(const HECL::SystemChar* headName) { +#if _WIN32 + HECL::FPrintf(m_sout, _S("%s\n"), headName); +#else if (XTERM_COLOR) HECL::FPrintf(m_sout, _S("" BOLD "%s" NORMAL "\n"), headName); else HECL::FPrintf(m_sout, _S("%s\n"), headName); +#endif } void optionHead(const HECL::SystemChar* flag, const HECL::SystemChar* synopsis) { +#if _WIN32 + HECL::FPrintf(m_sout, _S("%s (%s)\n"), flag, synopsis); +#else if (XTERM_COLOR) HECL::FPrintf(m_sout, _S("" BOLD "%s" NORMAL " (%s)\n"), flag, synopsis); else HECL::FPrintf(m_sout, _S("%s (%s)\n"), flag, synopsis); +#endif } void beginWrap() @@ -185,11 +200,15 @@ public: void wrapBold(const HECL::SystemChar* str) { +#if _WIN32 + m_wrapBuffer += str; +#else if (XTERM_COLOR) m_wrapBuffer += _S("" BOLD ""); m_wrapBuffer += str; if (XTERM_COLOR) m_wrapBuffer += _S("" NORMAL ""); +#endif } void endWrap() diff --git a/hecl/driver/ToolClean.hpp b/hecl/driver/ToolClean.hpp index 74c6265f9..7f166d0ac 100644 --- a/hecl/driver/ToolClean.hpp +++ b/hecl/driver/ToolClean.hpp @@ -30,19 +30,19 @@ public: help.secHead(_S("DESCRIPTION")); help.beginWrap(); - help.wrap(_S("This command performs an immediate deletion of cooked objects cached " - "within the project database. It may operate on a subset of objects or the " - "entire project.\n")); + help.wrap(_S("This command performs an immediate deletion of cooked objects cached ") + _S("within the project database. It may operate on a subset of objects or the ") + _S("entire project.\n")); help.endWrap(); help.secHead(_S("OPTIONS")); help.optionHead(_S("..."), _S("clean path(s)")); help.beginWrap(); - help.wrap(_S("When one or more paths are specified in the command, the clean process will " - "restrict object deletion to only the working file(s) specified. If ")); + help.wrap(_S("When one or more paths are specified in the command, the clean process will ") + _S("restrict object deletion to only the working file(s) specified. If ")); help.wrapBold(_S("-r")); - help.wrap(_S(" is also specifed, directories may be provided as well. If no path(s) specified, " - "the entire project is cleaned.\n")); + help.wrap(_S(" is also specifed, directories may be provided as well. If no path(s) specified, ") + _S("the entire project is cleaned.\n")); help.endWrap(); help.optionHead(_S("-r"), _S("recursion")); @@ -52,10 +52,10 @@ public: help.optionHead(_S("-i"), _S("follow implicit links")); help.beginWrap(); - help.wrap(_S("Enables implicit object traversal and cleaning. This is only useful if one or more paths " - "are specified. For objects supporting implicit-gathering, this will query those " - "objects for their current implicit links and ensure the linked-objects are cleaned " - "as well.\n")); + help.wrap(_S("Enables implicit object traversal and cleaning. This is only useful if one or more paths ") + _S("are specified. For objects supporting implicit-gathering, this will query those ") + _S("objects for their current implicit links and ensure the linked-objects are cleaned ") + _S("as well.\n")); help.endWrap(); } diff --git a/hecl/driver/ToolCook.hpp b/hecl/driver/ToolCook.hpp index 0ba637a68..8b5fdffd5 100644 --- a/hecl/driver/ToolCook.hpp +++ b/hecl/driver/ToolCook.hpp @@ -30,10 +30,10 @@ public: help.secHead(_S("DESCRIPTION")); help.beginWrap(); - help.wrap(_S("This command initiates a cooking pass on the project database. Cooking " - "is analogous to compiling in software development. The resulting object buffers " - "are cached within the project database. HECL performs the following " - "tasks for each object during the cook process:\n\n")); + help.wrap(_S("This command initiates a cooking pass on the project database. Cooking ") + _S("is analogous to compiling in software development. The resulting object buffers ") + _S("are cached within the project database. HECL performs the following ") + _S("tasks for each object during the cook process:\n\n")); help.wrapBold(_S("- Object Gather: ")); help.wrap(_S("Files added with ")); help.wrapBold(_S("hecl add")); @@ -43,13 +43,13 @@ public: help.wrapBold(_S(".png")); help.wrap(_S(" images). If the dependent files are unable to be found, the cook process aborts.\n\n")); help.wrapBold(_S("- Modtime Comparison: ")); - help.wrap(_S("Files that have previously finished a cook pass are inspected for their time of " - "last modification. If the file hasn't changed since its previous cook-pass, the " - "process is skipped. If the file has been moved or deleted, the object is automatically " - "removed from the project database.\n\n")); + help.wrap(_S("Files that have previously finished a cook pass are inspected for their time of ") + _S("last modification. If the file hasn't changed since its previous cook-pass, the ") + _S("process is skipped. If the file has been moved or deleted, the object is automatically ") + _S("removed from the project database.\n\n")); help.wrapBold(_S("- Cook: ")); - help.wrap(_S("A type-specific procedure compiles the file's contents into an efficient format " - "for use by the runtime. A data-buffer is provided to HECL.\n\n")); + help.wrap(_S("A type-specific procedure compiles the file's contents into an efficient format ") + _S("for use by the runtime. A data-buffer is provided to HECL.\n\n")); help.wrapBold(_S("- Hash and Compress: ")); help.wrap(_S("The data-buffer is hashed and compressed before being cached in the object database.\n\n")); help.endWrap(); @@ -57,11 +57,11 @@ public: help.secHead(_S("OPTIONS")); help.optionHead(_S("..."), _S("input file(s)")); help.beginWrap(); - help.wrap(_S("Specifies working file(s) containing production data to be cooked by HECL. " - "Glob-strings may be specified (e.g. ")); + help.wrap(_S("Specifies working file(s) containing production data to be cooked by HECL. ") + _S("Glob-strings may be specified (e.g. ")); help.wrapBold(_S("*.blend")); - help.wrap(_S(") to automatically cook all matching current-directory files in the project database. " - "If no path specified, all files in the project database are cooked.\n")); + help.wrap(_S(") to automatically cook all matching current-directory files in the project database. ") + _S("If no path specified, all files in the project database are cooked.\n")); help.endWrap(); help.optionHead(_S("-r"), _S("recursion")); diff --git a/hecl/driver/ToolExtract.hpp b/hecl/driver/ToolExtract.hpp index 69187158e..9e237f77a 100644 --- a/hecl/driver/ToolExtract.hpp +++ b/hecl/driver/ToolExtract.hpp @@ -13,6 +13,8 @@ class ToolExtract final : public ToolBase std::unique_ptr m_instance; SpecExtractPass(const HECL::Database::DataSpecEntry* entry, HECL::Database::IDataSpec* instance) : m_entry(entry), m_instance(instance) {} + SpecExtractPass(const SpecExtractPass& other) = delete; + SpecExtractPass(SpecExtractPass&& other) = default; }; std::vector m_specPasses; std::vector m_reps; @@ -60,16 +62,16 @@ public: help.secHead(_S("DESCRIPTION")); help.beginWrap(); - help.wrap(_S("This command recursively extracts all or part of a dataspec-supported " - "package format. Each object is decoded to a working format and added to the project.\n\n")); + help.wrap(_S("This command recursively extracts all or part of a dataspec-supported ") + _S("package format. Each object is decoded to a working format and added to the project.\n\n")); help.endWrap(); help.secHead(_S("OPTIONS")); help.optionHead(_S("[/...]"), _S("input file")); help.beginWrap(); - help.wrap(_S("Specifies the package file or disc image to source data from. " - "An optional subnode specifies a named hierarchical-node specific " - "to the game architecture (levels/areas).")); + help.wrap(_S("Specifies the package file or disc image to source data from. ") + _S("An optional subnode specifies a named hierarchical-node specific ") + _S("to the game architecture (levels/areas).")); help.endWrap(); } @@ -79,10 +81,14 @@ public: { for (int l=0 ; lm_name); +#else if (XTERM_COLOR) - HECL::Printf(_S("" MAGENTA BOLD "Using DataSpec %s:" NORMAL "\n"), ds.m_entry->m_name.c_str()); + HECL::Printf(_S("" MAGENTA BOLD "Using DataSpec %s:" NORMAL "\n"), ds.m_entry->m_name); else - HECL::Printf(_S("Using DataSpec %s:\n"), ds.m_entry->m_name.c_str()); + HECL::Printf(_S("Using DataSpec %s:\n"), ds.m_entry->m_name); +#endif int lineIdx = 0; ds.m_instance->doExtract(*m_info.project, m_einfo, [&lineIdx](const HECL::SystemChar* message, int lidx, float factor) { +#ifndef _WIN32 if (XTERM_COLOR) HECL::Printf(_S("" HIDE_CURSOR "")); +#endif if (lidx > lineIdx) { @@ -161,6 +185,7 @@ public: HECL::Printf(_S(" ")); } +#ifndef _WIN32 if (XTERM_COLOR) { size_t blocks = half - 7; @@ -175,6 +200,7 @@ public: } else { +#endif size_t blocks = half - 7; size_t filled = blocks * factor; size_t rem = blocks - filled; @@ -184,11 +210,15 @@ public: for (int b=0 ; b-._...................................|.......`=~-, \n" - ".....`=~-,__......`,................................. \n" - "...................`=~-,,.,........................... \n" - ".........................`:,,..........................`\n" - "...........................`=-,...............,%%`>--==`` \n" - ".................................._.........._,-%%...` \n" - "...................................,\n")); + help.printBold( + _S("................................___________ \n") + _S("...........................,.-'\"...........``~., \n") + _S("........................,.-\".......................\"-., \n") + _S("....................,/..................................\":, \n") + _S("..................,?........................................, \n") + _S("................/...........................................,}\n") + _S("............../........................................,:`^`..}\n") + _S("............./.......................................,:\"...../\n") + _S("............?.....__..................................:`...../\n") + _S(".........../__.(...\"~-,_...........................,:`....../\n") + _S("........../(_....\"~,_....\"~,_.....................,:`...._/ \n") + _S("..........{.._$;_....\"=,_.....\"-,_......,.-~-,},.~\";/....} \n") + _S("...........((...*~_......\"=-._...\";,,./`........../\"..../ \n") + _S("...,,,___.`~,......\"~.,....................`......}....../ \n") + _S("............(....`=-,,...`.........................(...;_,,-\" \n") + _S("............/.`~,......`-.................................../ \n") + _S(".............`~.*-,.....................................|,./...,__ \n") + _S(",,_..........}.>-._...................................|.......`=~-, \n") + _S(".....`=~-,__......`,................................. \n") + _S("...................`=~-,,.,........................... \n") + _S(".........................`:,,..........................`\n") + _S("...........................`=-,...............,%%`>--==`` \n") + _S(".................................._.........._,-%%...` \n") + _S("...................................,\n")); } static void ShowHelp(const HECL::SystemString& toolName) diff --git a/hecl/driver/ToolInit.hpp b/hecl/driver/ToolInit.hpp index a343925c6..2c8ef31e5 100644 --- a/hecl/driver/ToolInit.hpp +++ b/hecl/driver/ToolInit.hpp @@ -11,7 +11,7 @@ public: ToolInit(const ToolPassInfo& info) : ToolBase(info) { - struct stat theStat; + HECL::Sstat theStat; const HECL::SystemString* dir; if (info.args.size()) dir = &info.args[0]; @@ -50,7 +50,7 @@ public: } catch (std::exception& e) { - LogModule.report(LogVisor::Error, "unable to init project"); + LogModule.report(LogVisor::Error, "unable to init project: %s", e.what()); return -1; } LogModule.report(LogVisor::Info, _S("initialized project at '%s/.hecl'"), m_dir->c_str()); @@ -73,8 +73,8 @@ public: help.beginWrap(); help.wrap(_S("Creates a ")); help.wrapBold(_S(".hecl")); - help.wrap(_S(" directory within the selected directory with an initialized database index. " - "This constitutes an empty HECL project, ready for making stuff!!\n")); + help.wrap(_S(" directory within the selected directory with an initialized database index. ") + _S("This constitutes an empty HECL project, ready for making stuff!!\n")); help.endWrap(); help.secHead(_S("OPTIONS")); diff --git a/hecl/driver/ToolPackage.hpp b/hecl/driver/ToolPackage.hpp index 31d1b7dd2..1ceec3cbc 100644 --- a/hecl/driver/ToolPackage.hpp +++ b/hecl/driver/ToolPackage.hpp @@ -24,8 +24,8 @@ public: { help.secHead(_S("NAME")); help.beginWrap(); - help.wrap(_S("hecl-pack\n" - "hecl-package - Package objects within the project database\n")); + help.wrap(_S("hecl-pack\n") + _S("hecl-package - Package objects within the project database\n")); help.endWrap(); help.secHead(_S("SYNOPSIS")); @@ -35,29 +35,29 @@ public: help.secHead(_S("DESCRIPTION")); help.beginWrap(); - help.wrap(_S("This command initiates a packaging pass on the project database. Packaging " - "is analogous to linking in software development. All objects necessary to " - "generate a complete package are gathered, grouped, and indexed within an .hlpk file.\n")); + help.wrap(_S("This command initiates a packaging pass on the project database. Packaging ") + _S("is analogous to linking in software development. All objects necessary to ") + _S("generate a complete package are gathered, grouped, and indexed within an .hlpk file.\n")); help.endWrap(); help.secHead(_S("OPTIONS")); help.optionHead(_S(""), _S("input directory")); help.beginWrap(); - help.wrap(_S("Specifies a project subdirectory to root the resulting package from. " - "If any dependent-files fall outside this subdirectory, they will implicitly " - "be gathered and packaged.\n")); + help.wrap(_S("Specifies a project subdirectory to root the resulting package from. ") + _S("If any dependent-files fall outside this subdirectory, they will implicitly ") + _S("be gathered and packaged.\n")); help.endWrap(); help.optionHead(_S("-o "), _S("output package file")); help.beginWrap(); - help.wrap(_S("Specifies a target path to write the package. If not specified, the package " - "is written into /out//.hlpk\n")); + help.wrap(_S("Specifies a target path to write the package. If not specified, the package ") + _S("is written into /out//.hlpk\n")); help.endWrap(); help.optionHead(_S("-a"), _S("auto cook")); help.beginWrap(); - help.wrap(_S("Any referenced objects that haven't already been cooked are automatically cooked as " - "part of the packaging process. If this flag is omitted, the packaging process will abort.\n")); + help.wrap(_S("Any referenced objects that haven't already been cooked are automatically cooked as ") + _S("part of the packaging process. If this flag is omitted, the packaging process will abort.\n")); help.endWrap(); } diff --git a/hecl/driver/ToolRemove.hpp b/hecl/driver/ToolRemove.hpp index 80d9dd415..f8db8d795 100644 --- a/hecl/driver/ToolRemove.hpp +++ b/hecl/driver/ToolRemove.hpp @@ -31,16 +31,16 @@ public: help.secHead(_S("DESCRIPTION")); help.beginWrap(); - help.wrap(_S("This command removes a file, directory, or glob-pattern of files from the project database. " - "Once a file is removed, any cooked cache objects are deleted automatically. ")); + help.wrap(_S("This command removes a file, directory, or glob-pattern of files from the project database. ") + _S("Once a file is removed, any cooked cache objects are deleted automatically. ")); help.wrapBold(_S("The working file itself is not deleted from the filesystem.\n")); help.endWrap(); help.secHead(_S("OPTIONS")); help.optionHead(_S("..."), _S("input file(s)")); help.beginWrap(); - help.wrap(_S("Working file(s) to be removed from the project database. " - "Glob-strings may be specified (e.g. ")); + help.wrap(_S("Working file(s) to be removed from the project database. ") + _S("Glob-strings may be specified (e.g. ")); help.wrapBold(_S("*.blend")); help.wrap(_S(") to automatically remove all matching files from the database.\n")); help.endWrap(); diff --git a/hecl/driver/ToolSpec.hpp b/hecl/driver/ToolSpec.hpp index 760b4f558..09cd25000 100644 --- a/hecl/driver/ToolSpec.hpp +++ b/hecl/driver/ToolSpec.hpp @@ -48,7 +48,7 @@ public: bool found = false; for (auto& spec : specs) { - if (!spec.spec.m_name.compare(*it)) + if (!it->compare(spec.spec.m_name)) { found = true; break; @@ -75,9 +75,9 @@ public: help.secHead(_S("DESCRIPTION")); help.beginWrap(); - help.wrap(_S("This command configures the HECL project with the user's preferred target DataSpecs.\n\n" - "Providing enable/disable argument will bulk-set the enable status of the provided spec(s)" - "list. If enable/disable is not provided, a list of supported DataSpecs is printed.\n\n")); + help.wrap(_S("This command configures the HECL project with the user's preferred target DataSpecs.\n\n") + _S("Providing enable/disable argument will bulk-set the enable status of the provided spec(s)") + _S("list. If enable/disable is not provided, a list of supported DataSpecs is printed.\n\n")); help.endWrap(); help.secHead(_S("OPTIONS")); @@ -95,11 +95,15 @@ public: { for (const HECL::Database::DataSpecEntry* spec : HECL::Database::DATA_SPEC_REGISTRY) { +#if _WIN32 + HECL::Printf(_S("%s\n %s\n"), spec->m_name, spec->m_desc); +#else if (XTERM_COLOR) - HECL::Printf(_S("" BOLD CYAN "%s" NORMAL "\n"), spec->m_name.c_str()); + HECL::Printf(_S("" BOLD CYAN "%s" NORMAL "\n"), spec->m_name); else - HECL::Printf(_S("%s\n"), spec->m_name.c_str()); - HECL::Printf(_S(" %s\n"), spec->m_desc.c_str()); + HECL::Printf(_S("%s\n"), spec->m_name); + HECL::Printf(_S(" %s\n"), spec->m_desc); +#endif } return 0; } @@ -109,10 +113,16 @@ public: { for (auto& spec : specs) { +#if _WIN32 + HECL::Printf(_S("%s"), spec.spec.m_name); + if (spec.active) + HECL::Printf(_S(" [ENABLED]")); + HECL::Printf(_S("\n %s\n"), spec.spec.m_desc); +#else if (XTERM_COLOR) - HECL::Printf(_S("" BOLD CYAN "%s" NORMAL ""), spec.spec.m_name.c_str()); + HECL::Printf(_S("" BOLD CYAN "%s" NORMAL ""), spec.spec.m_name); else - HECL::Printf(_S("%s"), spec.spec.m_name.c_str()); + HECL::Printf(_S("%s"), spec.spec.m_name); if (spec.active) { if (XTERM_COLOR) @@ -120,7 +130,8 @@ public: else HECL::Printf(_S(" [ENABLED]")); } - HECL::Printf(_S("\n %s\n"), spec.spec.m_desc.c_str()); + HECL::Printf(_S("\n %s\n"), spec.spec.m_desc); +#endif } return 0; } @@ -134,7 +145,7 @@ public: HECL::ToLower(itName); for (auto& spec : specs) { - if (!spec.spec.m_name.compare(itName)) + if (!itName.compare(spec.spec.m_name)) { opSpecs.push_back(spec.spec.m_name); break; diff --git a/hecl/driver/main.cpp b/hecl/driver/main.cpp index 2e4de0380..b85888c8b 100644 --- a/hecl/driver/main.cpp +++ b/hecl/driver/main.cpp @@ -1,7 +1,10 @@ +#if _WIN32 +#define WIN_PAUSE 1 +#endif + #include #include #include -#include #include #include #include @@ -22,6 +25,8 @@ LogVisor::LogModule LogModule("HECLDriver"); #include "ToolPackage.hpp" #include "ToolHelp.hpp" +#include "../DataSpecRegistry.hpp" + bool XTERM_COLOR = false; @@ -35,10 +40,14 @@ bool XTERM_COLOR = false; /* Main usage message */ static void printHelp(const HECL::SystemChar* pname) { +#if _WIN32 + HECL::Printf(_S("HECL")); +#else if (XTERM_COLOR) HECL::Printf(_S("" BOLD "HECL" NORMAL "")); else HECL::Printf(_S("HECL")); +#endif #if HECL_GIT HECL::Printf(_S(" Commit " HECL_GIT_S " " HECL_BRANCH_S "\nUsage: %s init|add|remove|group|cook|clean|package|help\n"), pname); #elif HECL_VER @@ -61,6 +70,7 @@ int wmain(int argc, const wchar_t** argv) int main(int argc, const char** argv) #endif { + //dummy(); /* Xterm check */ const char* term = getenv("TERM"); if (term && !strncmp(term, "xterm", 5)) @@ -75,19 +85,25 @@ int main(int argc, const char** argv) if (argc == 1) { printHelp(argv[0]); +#if WIN_PAUSE + system("PAUSE"); +#endif return 0; } else if (argc == 0) { printHelp(_S("hecl")); +#if WIN_PAUSE + system("PAUSE"); +#endif return 0; } /* Assemble common tool pass info */ ToolPassInfo info; info.pname = argv[0]; - HECL::SystemChar cwdbuf[MAXPATHLEN]; - if (HECL::Getcwd(cwdbuf, MAXPATHLEN)) + HECL::SystemChar cwdbuf[1024]; + if (HECL::Getcwd(cwdbuf, 1024)) info.cwd = cwdbuf; /* Concatenate args */ @@ -173,6 +189,9 @@ int main(int argc, const char** argv) LogModule.report(LogVisor::Error, _S("Unable to open discovered project at '%s'"), rootPath->getAbsolutePath().c_str()); +#if WIN_PAUSE + system("PAUSE"); +#endif return -1; } } @@ -214,6 +233,9 @@ int main(int argc, const char** argv) #else LogModule.report(LogVisor::Error, _S("Unable to construct HECL tool '%s': %s"), toolName.c_str(), ex.what()); +#endif +#if WIN_PAUSE + system("PAUSE"); #endif return -1; } @@ -236,10 +258,16 @@ int main(int argc, const char** argv) #else LogModule.report(LogVisor::Error, _S("Error running HECL tool '%s': %s"), toolName.c_str(), ex.what()); +#endif +#if WIN_PAUSE + system("PAUSE"); #endif return -1; } +#if WIN_PAUSE + system("PAUSE"); +#endif return retval; } diff --git a/hecl/extern/Athena b/hecl/extern/Athena index 6405bffdd..5d3dcb57a 160000 --- a/hecl/extern/Athena +++ b/hecl/extern/Athena @@ -1 +1 @@ -Subproject commit 6405bffdd20d9b4c5e61a9600c69ca7bde5bc582 +Subproject commit 5d3dcb57ad44fc270f87a7c554490ca2d5a263ef diff --git a/hecl/extern/CMakeLists.txt b/hecl/extern/CMakeLists.txt index ee467e361..7299e3d51 100644 --- a/hecl/extern/CMakeLists.txt +++ b/hecl/extern/CMakeLists.txt @@ -3,5 +3,5 @@ add_subdirectory(libSquish) add_subdirectory(blowfish) add_subdirectory(LogVisor) add_subdirectory(AngelScript) -add_subdirectory(Athena) -add_subdirectory(RetroCommon) +add_subdirectory(Athena EXCLUDE_FROM_ALL) +add_subdirectory(RetroCommon EXCLUDE_FROM_ALL) diff --git a/hecl/extern/LogVisor b/hecl/extern/LogVisor index c2bfffa6c..085920205 160000 --- a/hecl/extern/LogVisor +++ b/hecl/extern/LogVisor @@ -1 +1 @@ -Subproject commit c2bfffa6cf1d07986fecaf7dde42acb29fe1f6e6 +Subproject commit 085920205b71a0a5a9bf710de5794cc136051b2d diff --git a/hecl/extern/RetroCommon b/hecl/extern/RetroCommon index a4d6e32e4..5deacef56 160000 --- a/hecl/extern/RetroCommon +++ b/hecl/extern/RetroCommon @@ -1 +1 @@ -Subproject commit a4d6e32e4848b2b33c9e95104b7259d24067b0b9 +Subproject commit 5deacef567cd295e78cbbabfde944a8e0b3a2272 diff --git a/hecl/extern/blowfish/blowfish.c b/hecl/extern/blowfish/blowfish.c index 3852f5298..6738e0015 100644 --- a/hecl/extern/blowfish/blowfish.c +++ b/hecl/extern/blowfish/blowfish.c @@ -94,14 +94,14 @@ void Blowfish_decipher(uint32_t *xl, uint32_t *xr) *xr = Xr; } -int64_t Blowfish_hash(const void* buf, size_t len) +int64_t Blowfish_hash(const uint8_t* buf, size_t len) { unsigned i,j; union { uint32_t h32[2]; int64_t h64; - } hash = {}; + } hash = {0,0}; for (i=0 ; iDiscard();} ASUniqueModule(ASUniqueModule&& other) = default; - ASUniqueModule(ASUniqueModule& other) = delete; + ASUniqueModule(const ASUniqueModule& other) = delete; ASUniqueModule& operator=(ASUniqueModule&& other) = default; - ASUniqueModule& operator=(ASUniqueModule& other) = delete; + ASUniqueModule& operator=(const ASUniqueModule& other) = delete; inline operator AngelScript::asIScriptModule&() {return *m_mod;} inline operator bool() {return m_mod != nullptr;} static ASUniqueModule CreateFromCode(const char* module, const char* code) @@ -218,10 +218,10 @@ public: typedef std::function FExtractProgress; - virtual bool canExtract(Project& project, const ExtractPassInfo& info, std::vector& reps) - {(void)project;(void)info;LogModule.report(LogVisor::Error, "not implemented");return false;} - virtual void doExtract(Project& project, const ExtractPassInfo& info, FExtractProgress progress) - {(void)project;(void)info;(void)progress;} + virtual bool canExtract(Project&, const ExtractPassInfo& info, std::vector& reps) + {(void)info;LogModule.report(LogVisor::Error, "not implemented");return false;} + virtual void doExtract(Project&, const ExtractPassInfo& info, FExtractProgress progress) + {(void)info;(void)progress;} /** * @brief Cook Task Info @@ -234,11 +234,11 @@ public: ProjectPath path; ProjectPath cookedPath; }; - virtual bool canCook(const Project& project, const CookTaskInfo& info, + virtual bool canCook(const Project&, const CookTaskInfo& info, SystemString& reasonNo) - {(void)project;(void)info;reasonNo=_S("not implemented");return false;} - virtual void doCook(const Project& project, const CookTaskInfo& info) - {(void)project;(void)info;} + {(void)info;reasonNo=_S("not implemented");return false;} + virtual void doCook(const Project&, const CookTaskInfo& info) + {(void)info;} /** * @brief Package Pass Info @@ -253,14 +253,14 @@ public: ProjectPath subpath; ProjectPath outpath; }; - virtual bool canPackage(const Project& project, const PackagePassInfo& info, + virtual bool canPackage(const Project&, const PackagePassInfo& info, SystemString& reasonNo) - {(void)project;(void)info;reasonNo=_S("not implemented");return false;} - virtual void gatherDependencies(const Project& project, const PackagePassInfo& info, + {(void)info;reasonNo=_S("not implemented");return false;} + virtual void gatherDependencies(const Project&, const PackagePassInfo& info, std::unordered_set& implicitsOut) - {(void)project;(void)info;(void)implicitsOut;} - virtual void doPackage(const Project& project, const PackagePassInfo& info) - {(void)project;(void)info;} + {(void)info;(void)implicitsOut;} + virtual void doPackage(const Project&, const PackagePassInfo& info) + {(void)info;} }; /** @@ -282,11 +282,11 @@ extern std::vector DATA_SPEC_REGISTRY; */ struct DataSpecEntry { - SystemString m_name; - SystemString m_desc; + const SystemChar* m_name; + const SystemChar* m_desc; std::function m_factory; - DataSpecEntry(SystemString&& name, SystemString&& desc, + DataSpecEntry(const SystemChar* name, const SystemChar* desc, std::function&& factory) : m_name(std::move(name)), m_desc(std::move(desc)), m_factory(std::move(factory)) { @@ -469,7 +469,7 @@ public: for (const ProjectDataSpec& sp : m_compiledSpecs) if (&sp.spec == &spec) return sp.cookedPath; - LogModule.report(LogVisor::FatalError, "Unable to find spec '%s'", spec.m_name.c_str()); + LogModule.report(LogVisor::FatalError, "Unable to find spec '%s'", spec.m_name); return m_cookedRoot; } diff --git a/hecl/include/HECL/HECL.hpp b/hecl/include/HECL/HECL.hpp index 29327f4ec..7b1bd07a8 100644 --- a/hecl/include/HECL/HECL.hpp +++ b/hecl/include/HECL/HECL.hpp @@ -10,6 +10,12 @@ #include #include #include +#else +#define _WIN32_LEAN_AND_MEAN 1 +#include +#include +#include "winsupport.h" +#define snprintf _snprintf #endif #include @@ -24,6 +30,10 @@ #include #include "../extern/blowfish/blowfish.h" +/* Handy MIN/MAX macros */ +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + namespace HECL { @@ -73,6 +83,7 @@ inline std::wstring operator+(const wchar_t* lhs, const SystemStringView& rhs) { #ifndef _S #define _S(val) L ## val #endif +typedef struct _stat Sstat; #else typedef char SystemChar; static inline size_t StrLen(const SystemChar* str) {return strlen(str);} @@ -110,6 +121,7 @@ inline std::string operator+(const char* lhs, const SystemStringView& rhs) {retu #ifndef _S #define _S(val) val #endif +typedef struct stat Sstat; #endif static inline void MakeDir(const SystemString& dir) @@ -129,7 +141,7 @@ static inline void MakeDir(const SystemString& dir) static inline SystemChar* Getcwd(SystemChar* buf, int maxlen) { #if HECL_UCS2 - return wgetcwd(buf, maxlen); + return _wgetcwd(buf, maxlen); #else return getcwd(buf, maxlen); #endif @@ -144,7 +156,7 @@ enum FileLockType static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock=LNONE) { #if HECL_UCS2 - FILE* fp = wfopen(path, mode); + FILE* fp = _wfopen(path, mode); #else FILE* fp = fopen(path, mode); #endif @@ -154,9 +166,8 @@ static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLo if (lock) { #if _WIN32 - HANDLE fhandle = (HANDLE)fileno(fp); OVERLAPPED ov = {}; - LockFileEx(fhandle, (lock == LWRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov); + LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == LWRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov); #else if (flock(fileno(fp), ((lock == LWRITE) ? LOCK_EX : LOCK_SH) | LOCK_NB)) throw std::error_code(errno, std::system_category()); @@ -166,10 +177,10 @@ static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLo return fp; } -static inline int Stat(const SystemChar* path, struct stat* statOut) +static inline int Stat(const SystemChar* path, Sstat* statOut) { #if HECL_UCS2 - return wstat(path, statOut); + return _wstat(path, statOut); #else return stat(path, statOut); #endif @@ -204,7 +215,7 @@ static inline void SNPrintf(SystemChar* str, size_t maxlen, const SystemChar* fo va_list va; va_start(va, format); #if HECL_UCS2 - vsnwprintf(str, maxlen, format, va); + _vsnwprintf(str, maxlen, format, va); #else vsnprintf(str, maxlen, format, va); #endif @@ -243,7 +254,7 @@ static inline int ConsoleWidth() #if _WIN32 CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info); - m_lineWidth = info.dwSize.X; + retval = info.dwSize.X; #else struct winsize w; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) @@ -304,9 +315,11 @@ class Hash final int64_t hash; public: Hash(const void* buf, size_t len) - : hash(Blowfish_hash(buf, len)) {} + : hash(Blowfish_hash((uint8_t*)buf, len)) {} Hash(const std::string& str) - : hash(Blowfish_hash(str.data(), str.size())) {} + : hash(Blowfish_hash((uint8_t*)str.data(), str.size())) {} + Hash(const std::wstring& str) + : hash(Blowfish_hash((uint8_t*)str.data(), str.size()*2)) {} Hash(int64_t hashin) : hash(hashin) {} Hash(const Hash& other) {hash = other.hash;} @@ -362,14 +375,14 @@ protected: Hash m_hash = 0; #if HECL_UCS2 std::string m_utf8AbsPath; - const char* m_utf8RelPath; + std::string m_utf8RelPath; #endif ProjectPath(const SystemString& projRoot) - : m_projRoot(projRoot), m_absPath(projRoot), m_relPath("."), m_hash(m_relPath) + : m_projRoot(projRoot), m_absPath(projRoot), m_relPath(_S(".")), m_hash(m_relPath) { #if HECL_UCS2 m_utf8AbsPath = WideToUTF8(m_absPath); - m_utf8RelPath = m_utf8AbsPath.c_str() + ((ProjectPath&)rootPath).m_utf8AbsPath.size(); + m_utf8RelPath = "."; #endif } public: @@ -380,6 +393,10 @@ public: */ ProjectPath(const ProjectPath& parentPath, const SystemString& path); +#if HECL_UCS2 + ProjectPath(const ProjectPath& parentPath, const std::string& path); +#endif + /** * @brief Determine if ProjectPath represents project root directory * @return true if project root directory @@ -577,16 +594,22 @@ static inline uint64_t SBig(uint64_t val) {return val;} } +#if _MSC_VER +#define NOEXCEPT +#else +#define NOEXCEPT noexcept +#endif + namespace std { template <> struct hash { - inline size_t operator()(const HECL::FourCC& val) const noexcept + inline size_t operator()(const HECL::FourCC& val) const NOEXCEPT {return val.toUint32();} }; template <> struct hash { - inline size_t operator()(const HECL::ProjectPath& val) const noexcept + inline size_t operator()(const HECL::ProjectPath& val) const NOEXCEPT {return val.hash();} }; } diff --git a/hecl/include/HECL/winsupport.h b/hecl/include/HECL/winsupport.h new file mode 100644 index 000000000..043ac6043 --- /dev/null +++ b/hecl/include/HECL/winsupport.h @@ -0,0 +1,14 @@ +#ifndef _HECL_WINSUPPORT_H_ +#define _HECL_WINSUPPORT_H_ + +#if __cplusplus +extern "C" { +#endif + +void* memmem(const void *haystack, size_t hlen, const void *needle, size_t nlen); + +#if __cplusplus +} +#endif + +#endif // _HECL_WINSUPPORT_H_ diff --git a/hecl/lib/CMakeLists.txt b/hecl/lib/CMakeLists.txt index 1898af543..412be8f52 100644 --- a/hecl/lib/CMakeLists.txt +++ b/hecl/lib/CMakeLists.txt @@ -3,7 +3,11 @@ add_subdirectory(Database) add_subdirectory(Frontend) add_subdirectory(Runtime) -add_library(HECL +if(WIN32) +list(APPEND PLAT_SRCS winsupport.c ../include/HECL/winsupport.h) +endif() + +add_library(HECLCommon HECL.cpp ProjectPath.cpp WideStringConvert.cpp @@ -11,5 +15,6 @@ add_library(HECL ../include/HECL/Backend.hpp ../include/HECL/Frontend.hpp ../include/HECL/Database.hpp - ../include/HECL/Runtime.hpp) + ../include/HECL/Runtime.hpp + ${PLAT_SRCS}) diff --git a/hecl/lib/Database/CMakeLists.txt b/hecl/lib/Database/CMakeLists.txt index a2525c074..751ee4814 100644 --- a/hecl/lib/Database/CMakeLists.txt +++ b/hecl/lib/Database/CMakeLists.txt @@ -1,5 +1,4 @@ add_library(HECLDatabaseInit - Registry.cpp ASInit.cpp) add_library(HECLDatabase ASEngine.cpp diff --git a/hecl/lib/Database/Project.cpp b/hecl/lib/Database/Project.cpp index 9b7a59a3a..f8f2da7ae 100644 --- a/hecl/lib/Database/Project.cpp +++ b/hecl/lib/Database/Project.cpp @@ -174,12 +174,20 @@ bool Project::ConfigFile::unlockAndCommit() m_lockedFile = NULL; if (fail) { +#if HECL_UCS2 + _wunlink(newPath.c_str()); +#else unlink(newPath.c_str()); +#endif return false; } else { +#if HECL_UCS2 + _wrename(newPath.c_str(), m_filepath.c_str()); +#else rename(newPath.c_str(), m_filepath.c_str()); +#endif return true; } } @@ -197,7 +205,7 @@ Project::Project(const ProjectRootPath& rootPath) m_groups(*this, _S("groups")) { /* Stat for existing project directory (must already exist) */ - struct stat myStat; + Sstat myStat; if (HECL::Stat(m_rootPath.getAbsolutePath().c_str(), &myStat)) throw std::error_code(errno, std::system_category()); @@ -293,7 +301,7 @@ void Project::rescanDataSpecs() for (const DataSpecEntry* spec : DATA_SPEC_REGISTRY) { SystemUTF8View specUTF8(spec->m_name); - m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, spec->m_name + ".spec"), + m_compiledSpecs.push_back({*spec, ProjectPath(m_cookedRoot, HECL::SystemString(spec->m_name) + _S(".spec")), m_specs.checkForLine(specUTF8) ? true : false}); } m_specs.unlockAndDiscard(); @@ -303,7 +311,10 @@ bool Project::enableDataSpecs(const std::vector& specs) { m_specs.lockAndRead(); for (const SystemString& spec : specs) - m_specs.addLine(spec); + { + SystemUTF8View specView(spec); + m_specs.addLine(specView); + } bool result = m_specs.unlockAndCommit(); rescanDataSpecs(); return result; @@ -313,16 +324,20 @@ bool Project::disableDataSpecs(const std::vector& specs) { m_specs.lockAndRead(); for (const SystemString& spec : specs) - m_specs.removeLine(spec); + { + SystemUTF8View specView(spec); + m_specs.removeLine(specView); + } bool result = m_specs.unlockAndCommit(); rescanDataSpecs(); return result; } bool Project::cookPath(const ProjectPath& path, - std::function feedbackCb, + std::function feedbackCb, bool recursive) { + return false; } void Project::interruptCook() @@ -331,10 +346,12 @@ void Project::interruptCook() bool Project::cleanPath(const ProjectPath& path, bool recursive) { + return false; } PackageDepsgraph Project::buildPackageDepsgraph(const ProjectPath& path) { + return PackageDepsgraph(); } } diff --git a/hecl/lib/Database/Registry.cpp b/hecl/lib/Database/Registry.cpp deleted file mode 100644 index cb1a705e9..000000000 --- a/hecl/lib/Database/Registry.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "HECL/Database.hpp" - -namespace HECL -{ -namespace Database -{ - -/* Centralized registry for DataSpec lookup */ -std::vector DATA_SPEC_REGISTRY; - -} -} diff --git a/hecl/lib/ProjectPath.cpp b/hecl/lib/ProjectPath.cpp index 2c10f6826..f20de98db 100644 --- a/hecl/lib/ProjectPath.cpp +++ b/hecl/lib/ProjectPath.cpp @@ -54,41 +54,51 @@ static SystemString canonRelPath(const SystemString& path) } return retval; } - return "."; + return _S("."); } ProjectPath::ProjectPath(const ProjectPath& parentPath, const SystemString& path) : m_projRoot(parentPath.m_projRoot) { - m_relPath = canonRelPath(parentPath.m_relPath + '/' + path); - m_absPath = parentPath.m_projRoot + '/' + m_relPath; + m_relPath = canonRelPath(parentPath.m_relPath + _S('/') + path); + m_absPath = parentPath.m_projRoot + _S('/') + m_relPath; m_hash = Hash(m_relPath); #if HECL_UCS2 m_utf8AbsPath = WideToUTF8(m_absPath); - m_utf8RelPath = m_utf8AbsPath.c_str() + ((ProjectPath&)rootPath).m_utf8AbsPath.size(); + m_utf8RelPath = WideToUTF8(m_relPath); #endif } +#if HECL_UCS2 +ProjectPath::ProjectPath(const ProjectPath& parentPath, const std::string& path) +: m_projRoot(parentPath.m_projRoot) +{ + std::wstring wpath = UTF8ToWide(path); + m_relPath = canonRelPath(parentPath.m_relPath + _S('/') + wpath); + m_absPath = parentPath.m_projRoot + _S('/') + m_relPath; + m_hash = Hash(m_relPath); + m_utf8AbsPath = WideToUTF8(m_absPath); + m_utf8RelPath = WideToUTF8(m_relPath); +} +#endif + ProjectPath::PathType ProjectPath::getPathType() const { if (std::regex_search(m_absPath, regGLOB)) return PT_GLOB; -#if _WIN32 -#else - struct stat theStat; - if (stat(m_absPath.c_str(), &theStat)) + Sstat theStat; + if (HECL::Stat(m_absPath.c_str(), &theStat)) return PT_NONE; if (S_ISDIR(theStat.st_mode)) return PT_DIRECTORY; if (S_ISREG(theStat.st_mode)) return PT_FILE; return PT_NONE; -#endif } Time ProjectPath::getModtime() const { - struct stat theStat; + Sstat theStat; time_t latestTime = 0; if (std::regex_search(m_absPath, regGLOB)) { @@ -189,7 +199,7 @@ static void _recursiveGlob(std::vector& outPaths, void ProjectPath::getGlobResults(std::vector& outPaths) const { #if _WIN32 - TSystemPath itStr; + SystemString itStr; SystemRegexMatch letterMatch; if (m_absPath.compare(0, 2, _S("//"))) itStr = _S("\\\\"); @@ -214,7 +224,7 @@ std::unique_ptr SearchForProject(const SystemString& path) { SystemString testPath(begin, end); SystemString testIndexPath = testPath + _S("/.hecl/beacon"); - struct stat theStat; + Sstat theStat; if (!HECL::Stat(testIndexPath.c_str(), &theStat)) { if (S_ISREG(theStat.st_mode)) @@ -236,7 +246,8 @@ std::unique_ptr SearchForProject(const SystemString& path) while (begin != end && *(end-1) != _S('/') && *(end-1) != _S('\\')) --end; - --end; + if (begin != end) + --end; } return std::unique_ptr(); } diff --git a/hecl/lib/Runtime/HECLRuntime.cpp b/hecl/lib/Runtime/HECLRuntime.cpp index 15ce100ad..a4c05ccae 100644 --- a/hecl/lib/Runtime/HECLRuntime.cpp +++ b/hecl/lib/Runtime/HECLRuntime.cpp @@ -15,11 +15,13 @@ Runtime::~Runtime() std::shared_ptr Runtime::loadSync(const Hash& pathHash) { + return std::shared_ptr(); } std::shared_ptr Runtime::loadAsync(const Hash& pathHash, SGroupLoadStatus* statusOut) { + return std::shared_ptr(); } } diff --git a/hecl/lib/winsupport.c b/hecl/lib/winsupport.c new file mode 100644 index 000000000..ddb933bbc --- /dev/null +++ b/hecl/lib/winsupport.c @@ -0,0 +1,34 @@ +#include +#include +#include + +/* +* The memmem() function finds the start of the first occurrence of the +* substring 'needle' of length 'nlen' in the memory area 'haystack' of +* length 'hlen'. +* +* The return value is a pointer to the beginning of the sub-string, or +* NULL if the substring is not found. +*/ +void *memmem(const uint8_t *haystack, size_t hlen, const void *needle, size_t nlen) +{ + int needle_first; + const uint8_t *p = haystack; + size_t plen = hlen; + + if (!nlen) + return NULL; + + needle_first = *(unsigned char *)needle; + + while (plen >= nlen && (p = memchr(p, needle_first, plen - nlen + 1))) + { + if (!memcmp(p, needle, nlen)) + return (void *)p; + + p++; + plen = hlen - (p - haystack); + } + + return NULL; +}