2015-05-20 05:22:32 +00:00
|
|
|
#ifndef HECL_HPP
|
|
|
|
#define HECL_HPP
|
|
|
|
|
2015-07-18 04:35:01 +00:00
|
|
|
#ifndef _WIN32
|
2015-05-27 09:09:05 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/stat.h>
|
2015-06-11 09:41:10 +00:00
|
|
|
#include <sys/file.h>
|
2015-07-20 23:27:22 +00:00
|
|
|
#include <sys/ioctl.h>
|
2015-05-27 09:09:05 +00:00
|
|
|
#include <dirent.h>
|
2015-06-10 23:34:14 +00:00
|
|
|
#include <fcntl.h>
|
2015-07-01 23:53:05 +00:00
|
|
|
#include <unistd.h>
|
2015-07-22 19:14:50 +00:00
|
|
|
#else
|
2015-08-31 03:36:24 +00:00
|
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
|
|
#define WIN32_LEAN_AND_MEAN 1
|
|
|
|
#endif
|
2015-07-22 19:14:50 +00:00
|
|
|
#include <Windows.h>
|
|
|
|
#include <wchar.h>
|
2015-08-31 03:36:24 +00:00
|
|
|
#include "winsupport.hpp"
|
2015-05-27 09:09:05 +00:00
|
|
|
#endif
|
|
|
|
|
2015-08-31 19:47:59 +00:00
|
|
|
#include <inttypes.h>
|
2015-06-10 23:34:14 +00:00
|
|
|
#include <time.h>
|
2015-06-10 02:40:03 +00:00
|
|
|
#include <stdarg.h>
|
2015-06-09 22:19:59 +00:00
|
|
|
#include <stdio.h>
|
2015-05-20 05:22:32 +00:00
|
|
|
#include <functional>
|
2015-05-27 09:09:05 +00:00
|
|
|
#include <string>
|
2015-06-11 04:55:06 +00:00
|
|
|
#include <algorithm>
|
2015-05-27 09:09:05 +00:00
|
|
|
#include <regex>
|
2015-07-06 01:35:08 +00:00
|
|
|
#include <LogVisor/LogVisor.hpp>
|
|
|
|
#include <Athena/DNA.hpp>
|
2015-05-27 09:09:05 +00:00
|
|
|
#include "../extern/blowfish/blowfish.h"
|
2015-05-20 05:22:32 +00:00
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
/* Handy MIN/MAX macros */
|
2015-08-31 03:36:24 +00:00
|
|
|
#ifndef MAX
|
2015-07-22 19:14:50 +00:00
|
|
|
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
|
|
|
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
2015-08-31 03:36:24 +00:00
|
|
|
#endif
|
2015-07-22 19:14:50 +00:00
|
|
|
|
2015-05-20 05:22:32 +00:00
|
|
|
namespace HECL
|
|
|
|
{
|
|
|
|
|
2015-08-06 19:10:12 +00:00
|
|
|
extern unsigned VerbosityLevel;
|
2015-07-06 01:35:08 +00:00
|
|
|
extern LogVisor::LogModule LogModule;
|
|
|
|
|
2015-06-10 02:40:03 +00:00
|
|
|
#if _WIN32 && UNICODE
|
|
|
|
#define HECL_UCS2 1
|
|
|
|
#endif
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
std::string WideToUTF8(const std::wstring& src);
|
|
|
|
std::wstring UTF8ToWide(const std::string& src);
|
|
|
|
|
2015-06-10 02:40:03 +00:00
|
|
|
#if HECL_UCS2
|
2015-06-09 22:19:59 +00:00
|
|
|
typedef wchar_t SystemChar;
|
2015-07-20 23:27:22 +00:00
|
|
|
static inline size_t StrLen(const SystemChar* str) {return wcslen(str);}
|
2015-06-09 22:19:59 +00:00
|
|
|
typedef std::wstring SystemString;
|
2015-06-11 04:55:06 +00:00
|
|
|
static inline void ToLower(SystemString& str)
|
|
|
|
{std::transform(str.begin(), str.end(), str.begin(), towlower);}
|
|
|
|
static inline void ToUpper(SystemString& str)
|
|
|
|
{std::transform(str.begin(), str.end(), str.begin(), towupper);}
|
2015-06-10 02:40:03 +00:00
|
|
|
class SystemUTF8View
|
2015-06-09 22:19:59 +00:00
|
|
|
{
|
|
|
|
std::string m_utf8;
|
|
|
|
public:
|
2015-06-10 02:40:03 +00:00
|
|
|
SystemUTF8View(const SystemString& str)
|
2015-06-09 22:19:59 +00:00
|
|
|
: m_utf8(WideToUTF8(str)) {}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline operator const std::string&() const {return m_utf8;}
|
2015-07-20 23:27:22 +00:00
|
|
|
inline const std::string& str() const {return m_utf8;}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::string operator+(const std::string& other) const {return m_utf8 + other;}
|
|
|
|
inline std::string operator+(const char* other) const {return m_utf8 + other;}
|
2015-06-09 22:19:59 +00:00
|
|
|
};
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::string operator+(const std::string& lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
|
|
|
inline std::string operator+(const char* lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
2015-06-10 02:40:03 +00:00
|
|
|
class SystemStringView
|
2015-06-09 22:19:59 +00:00
|
|
|
{
|
|
|
|
std::wstring m_sys;
|
|
|
|
public:
|
2015-06-10 02:40:03 +00:00
|
|
|
SystemStringView(const std::string& str)
|
2015-06-09 22:19:59 +00:00
|
|
|
: m_sys(UTF8ToWide(str)) {}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline operator const std::wstring&() const {return m_sys;}
|
2015-07-20 23:27:22 +00:00
|
|
|
inline const std::wstring& sys_str() const {return m_sys;}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::wstring operator+(const std::wstring& other) const {return m_sys + other;}
|
|
|
|
inline std::wstring operator+(const wchar_t* other) const {return m_sys + other;}
|
2015-06-09 22:19:59 +00:00
|
|
|
};
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::wstring operator+(const std::wstring& lhs, const SystemStringView& rhs) {return lhs + std::wstring(rhs);}
|
|
|
|
inline std::wstring operator+(const wchar_t* lhs, const SystemStringView& rhs) {return lhs + std::wstring(rhs);}
|
2015-06-09 22:19:59 +00:00
|
|
|
#ifndef _S
|
|
|
|
#define _S(val) L ## val
|
|
|
|
#endif
|
2015-07-22 19:14:50 +00:00
|
|
|
typedef struct _stat Sstat;
|
2015-06-09 22:19:59 +00:00
|
|
|
#else
|
|
|
|
typedef char SystemChar;
|
2015-07-20 23:27:22 +00:00
|
|
|
static inline size_t StrLen(const SystemChar* str) {return strlen(str);}
|
2015-06-09 22:19:59 +00:00
|
|
|
typedef std::string SystemString;
|
2015-06-11 04:55:06 +00:00
|
|
|
static inline void ToLower(SystemString& str)
|
|
|
|
{std::transform(str.begin(), str.end(), str.begin(), tolower);}
|
|
|
|
static inline void ToUpper(SystemString& str)
|
|
|
|
{std::transform(str.begin(), str.end(), str.begin(), toupper);}
|
2015-06-10 02:40:03 +00:00
|
|
|
class SystemUTF8View
|
2015-06-09 22:19:59 +00:00
|
|
|
{
|
|
|
|
const std::string& m_utf8;
|
|
|
|
public:
|
2015-06-10 02:40:03 +00:00
|
|
|
SystemUTF8View(const SystemString& str)
|
2015-06-09 22:19:59 +00:00
|
|
|
: m_utf8(str) {}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline operator const std::string&() const {return m_utf8;}
|
2015-07-20 23:27:22 +00:00
|
|
|
inline const std::string& str() const {return m_utf8;}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::string operator+(const std::string& other) const {return std::string(m_utf8) + other;}
|
|
|
|
inline std::string operator+(const char* other) const {return std::string(m_utf8) + other;}
|
2015-06-09 22:19:59 +00:00
|
|
|
};
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::string operator+(const std::string& lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
|
|
|
inline std::string operator+(const char* lhs, const SystemUTF8View& rhs) {return lhs + std::string(rhs);}
|
2015-06-10 02:40:03 +00:00
|
|
|
class SystemStringView
|
2015-06-09 22:19:59 +00:00
|
|
|
{
|
|
|
|
const std::string& m_sys;
|
|
|
|
public:
|
2015-06-10 02:40:03 +00:00
|
|
|
SystemStringView(const std::string& str)
|
2015-06-09 22:19:59 +00:00
|
|
|
: m_sys(str) {}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline operator const std::string&() const {return m_sys;}
|
2015-07-20 23:27:22 +00:00
|
|
|
inline const std::string& sys_str() const {return m_sys;}
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::string operator+(const std::string& other) const {return m_sys + other;}
|
|
|
|
inline std::string operator+(const char* other) const {return m_sys + other;}
|
2015-06-09 22:19:59 +00:00
|
|
|
};
|
2015-07-18 04:35:01 +00:00
|
|
|
inline std::string operator+(const std::string& lhs, const SystemStringView& rhs) {return lhs + std::string(rhs);}
|
|
|
|
inline std::string operator+(const char* lhs, const SystemStringView& rhs) {return lhs + std::string(rhs);}
|
2015-06-09 22:19:59 +00:00
|
|
|
#ifndef _S
|
|
|
|
#define _S(val) val
|
|
|
|
#endif
|
2015-07-22 19:14:50 +00:00
|
|
|
typedef struct stat Sstat;
|
2015-06-09 22:19:59 +00:00
|
|
|
#endif
|
|
|
|
|
2015-08-05 01:54:35 +00:00
|
|
|
void SanitizePath(std::string& path);
|
|
|
|
void SanitizePath(std::wstring& path);
|
|
|
|
|
2015-08-05 22:59:59 +00:00
|
|
|
static inline void Unlink(const SystemChar* file)
|
|
|
|
{
|
|
|
|
#if _WIN32
|
|
|
|
_wunlink(file);
|
|
|
|
#else
|
|
|
|
unlink(file);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
static inline void MakeDir(const char* dir)
|
2015-06-09 22:19:59 +00:00
|
|
|
{
|
2015-05-27 09:09:05 +00:00
|
|
|
#if _WIN32
|
2015-06-09 22:19:59 +00:00
|
|
|
HRESULT err;
|
2015-08-31 03:36:24 +00:00
|
|
|
if (!CreateDirectoryA(dir, NULL))
|
2015-06-09 22:19:59 +00:00
|
|
|
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
2015-07-28 23:54:54 +00:00
|
|
|
LogModule.report(LogVisor::FatalError, _S("MakeDir(%s)"), dir);
|
2015-05-27 09:09:05 +00:00
|
|
|
#else
|
2015-07-28 23:54:54 +00:00
|
|
|
if (mkdir(dir, 0755))
|
2015-06-09 22:19:59 +00:00
|
|
|
if (errno != EEXIST)
|
2015-07-28 23:54:54 +00:00
|
|
|
LogModule.report(LogVisor::FatalError, "MakeDir(%s): %s", dir, strerror(errno));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-08-31 03:36:24 +00:00
|
|
|
#if _WIN32
|
|
|
|
static inline void MakeDir(const wchar_t* dir)
|
|
|
|
{
|
|
|
|
HRESULT err;
|
|
|
|
if (!CreateDirectoryW(dir, NULL))
|
|
|
|
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
|
|
|
LogModule.report(LogVisor::FatalError, _S("MakeDir(%s)"), dir);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-07-28 23:54:54 +00:00
|
|
|
static inline void MakeLink(const SystemChar* target, const SystemChar* linkPath)
|
|
|
|
{
|
|
|
|
#if _WIN32
|
2015-08-31 03:36:24 +00:00
|
|
|
HRESULT res = CreateShellLink(target, linkPath, _S("HECL Link")); /* :(( */
|
|
|
|
if (!SUCCEEDED(res))
|
|
|
|
{
|
|
|
|
LPWSTR messageBuffer = nullptr;
|
|
|
|
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL); /* :((( */
|
|
|
|
LogModule.report(LogVisor::FatalError, _S("MakeLink(%s, %s): %s"), target, linkPath, messageBuffer);
|
|
|
|
}
|
2015-07-28 23:54:54 +00:00
|
|
|
#else
|
2015-08-31 03:36:24 +00:00
|
|
|
if (symlink(target, linkPath)) /* :) */
|
2015-07-28 23:54:54 +00:00
|
|
|
if (errno != EEXIST)
|
|
|
|
LogModule.report(LogVisor::FatalError, "MakeLink(%s, %s): %s", target, linkPath, strerror(errno));
|
2015-05-27 09:09:05 +00:00
|
|
|
#endif
|
2015-06-09 22:19:59 +00:00
|
|
|
}
|
|
|
|
|
2015-06-10 02:40:03 +00:00
|
|
|
static inline SystemChar* Getcwd(SystemChar* buf, int maxlen)
|
|
|
|
{
|
|
|
|
#if HECL_UCS2
|
2015-07-22 19:14:50 +00:00
|
|
|
return _wgetcwd(buf, maxlen);
|
2015-06-10 02:40:03 +00:00
|
|
|
#else
|
|
|
|
return getcwd(buf, maxlen);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-06-10 23:34:14 +00:00
|
|
|
enum FileLockType
|
|
|
|
{
|
|
|
|
LNONE = 0,
|
|
|
|
LREAD,
|
|
|
|
LWRITE
|
|
|
|
};
|
|
|
|
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock=LNONE)
|
2015-06-09 22:19:59 +00:00
|
|
|
{
|
2015-06-10 02:40:03 +00:00
|
|
|
#if HECL_UCS2
|
2015-07-22 19:14:50 +00:00
|
|
|
FILE* fp = _wfopen(path, mode);
|
2015-09-01 00:26:35 +00:00
|
|
|
if (!fp)
|
|
|
|
LogModule.report(LogVisor::FatalError, L"fopen %s: %s", path, _wcserror(errno));
|
2015-06-09 22:19:59 +00:00
|
|
|
#else
|
|
|
|
FILE* fp = fopen(path, mode);
|
|
|
|
if (!fp)
|
2015-07-26 02:52:02 +00:00
|
|
|
LogModule.report(LogVisor::FatalError, "fopen %s: %s", path, strerror(errno));
|
2015-09-01 00:26:35 +00:00
|
|
|
#endif
|
2015-06-09 22:19:59 +00:00
|
|
|
|
2015-06-10 23:34:14 +00:00
|
|
|
if (lock)
|
|
|
|
{
|
|
|
|
#if _WIN32
|
|
|
|
OVERLAPPED ov = {};
|
2015-07-22 19:14:50 +00:00
|
|
|
LockFileEx((HANDLE)(uintptr_t)_fileno(fp), (lock == LWRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov);
|
2015-06-10 23:34:14 +00:00
|
|
|
#else
|
2015-06-11 09:41:10 +00:00
|
|
|
if (flock(fileno(fp), ((lock == LWRITE) ? LOCK_EX : LOCK_SH) | LOCK_NB))
|
2015-07-26 02:52:02 +00:00
|
|
|
LogModule.report(LogVisor::FatalError, "flock %s: %s", path, strerror(errno));
|
2015-06-10 23:34:14 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
static inline int Stat(const SystemChar* path, Sstat* statOut)
|
2015-06-10 02:40:03 +00:00
|
|
|
{
|
|
|
|
#if HECL_UCS2
|
2015-07-22 19:14:50 +00:00
|
|
|
return _wstat(path, statOut);
|
2015-06-10 02:40:03 +00:00
|
|
|
#else
|
|
|
|
return stat(path, statOut);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void Printf(const SystemChar* format, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
#if HECL_UCS2
|
|
|
|
vwprintf(format, va);
|
|
|
|
#else
|
|
|
|
vprintf(format, va);
|
|
|
|
#endif
|
|
|
|
va_end(va);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void FPrintf(FILE* fp, const SystemChar* format, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
#if HECL_UCS2
|
|
|
|
vfwprintf(fp, format, va);
|
|
|
|
#else
|
|
|
|
vfprintf(fp, format, va);
|
|
|
|
#endif
|
|
|
|
va_end(va);
|
|
|
|
}
|
|
|
|
|
2015-07-16 02:03:38 +00:00
|
|
|
static inline void SNPrintf(SystemChar* str, size_t maxlen, const SystemChar* format, ...)
|
|
|
|
{
|
|
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
#if HECL_UCS2
|
2015-07-22 19:14:50 +00:00
|
|
|
_vsnwprintf(str, maxlen, format, va);
|
2015-07-16 02:03:38 +00:00
|
|
|
#else
|
|
|
|
vsnprintf(str, maxlen, format, va);
|
|
|
|
#endif
|
|
|
|
va_end(va);
|
|
|
|
}
|
|
|
|
|
2015-06-24 20:56:52 +00:00
|
|
|
#define FORMAT_BUF_SZ 1024
|
|
|
|
|
|
|
|
static inline SystemString SysFormat(const SystemChar* format, ...)
|
|
|
|
{
|
|
|
|
SystemChar resultBuf[FORMAT_BUF_SZ];
|
|
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
#if HECL_UCS2
|
|
|
|
int printSz = vswprintf(resultBuf, FORMAT_BUF_SZ, format, va);
|
|
|
|
#else
|
|
|
|
int printSz = vsnprintf(resultBuf, FORMAT_BUF_SZ, format, va);
|
|
|
|
#endif
|
|
|
|
va_end(va);
|
|
|
|
return SystemString(resultBuf, printSz);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline std::string Format(const char* format, ...)
|
|
|
|
{
|
|
|
|
char resultBuf[FORMAT_BUF_SZ];
|
|
|
|
va_list va;
|
|
|
|
va_start(va, format);
|
|
|
|
int printSz = vsnprintf(resultBuf, FORMAT_BUF_SZ, format, va);
|
|
|
|
va_end(va);
|
|
|
|
return std::string(resultBuf, printSz);
|
|
|
|
}
|
|
|
|
|
2015-07-20 23:27:22 +00:00
|
|
|
static inline int ConsoleWidth()
|
|
|
|
{
|
|
|
|
int retval = 80;
|
|
|
|
#if _WIN32
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO info;
|
|
|
|
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
|
2015-07-22 19:14:50 +00:00
|
|
|
retval = info.dwSize.X;
|
2015-07-20 23:27:22 +00:00
|
|
|
#else
|
|
|
|
struct winsize w;
|
|
|
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1)
|
|
|
|
retval = w.ws_col;
|
|
|
|
#endif
|
|
|
|
if (retval < 10)
|
|
|
|
return 10;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
typedef std::basic_regex<SystemChar> SystemRegex;
|
|
|
|
typedef std::regex_token_iterator<SystemString::const_iterator> SystemRegexTokenIterator;
|
|
|
|
typedef std::match_results<SystemString::const_iterator> SystemRegexMatch;
|
2015-05-27 09:09:05 +00:00
|
|
|
|
|
|
|
class ProjectRootPath;
|
2015-05-20 05:22:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief FourCC representation used within HECL's database
|
|
|
|
*
|
|
|
|
* FourCCs are efficient, mnemonic four-char-sequences used to represent types
|
|
|
|
* while fitting comfortably in a 32-bit word. HECL uses a four-char array
|
|
|
|
* to remain endian-independent.
|
2015-07-06 01:35:08 +00:00
|
|
|
*
|
|
|
|
* This class also functions as a read/write Athena DNA type,
|
|
|
|
* for easy initialization of FourCCs in DNA data records.
|
2015-05-20 05:22:32 +00:00
|
|
|
*/
|
2015-07-11 22:42:40 +00:00
|
|
|
class FourCC
|
2015-05-20 05:22:32 +00:00
|
|
|
{
|
2015-07-11 22:42:40 +00:00
|
|
|
protected:
|
2015-05-20 05:22:32 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
char fcc[4];
|
|
|
|
uint32_t num;
|
|
|
|
};
|
|
|
|
public:
|
2015-05-21 02:33:05 +00:00
|
|
|
FourCC() /* Sentinel FourCC */
|
|
|
|
: num(0) {}
|
2015-07-13 06:30:20 +00:00
|
|
|
FourCC(const FourCC& other)
|
|
|
|
{num = other.num;}
|
2015-05-20 05:22:32 +00:00
|
|
|
FourCC(const char* name)
|
|
|
|
: num(*(uint32_t*)name) {}
|
2015-08-10 02:04:56 +00:00
|
|
|
FourCC(uint32_t n)
|
|
|
|
: num(n) {}
|
2015-06-11 04:55:06 +00:00
|
|
|
inline bool operator==(const FourCC& other) const {return num == other.num;}
|
|
|
|
inline bool operator!=(const FourCC& other) const {return num != other.num;}
|
|
|
|
inline bool operator==(const char* other) const {return num == *(uint32_t*)other;}
|
|
|
|
inline bool operator!=(const char* other) const {return num != *(uint32_t*)other;}
|
2015-08-10 02:04:56 +00:00
|
|
|
inline bool operator==(uint32_t other) const {return num == other;}
|
|
|
|
inline bool operator!=(uint32_t other) const {return num != other;}
|
2015-06-11 04:55:06 +00:00
|
|
|
inline std::string toString() const {return std::string(fcc, 4);}
|
2015-07-13 06:30:20 +00:00
|
|
|
inline uint32_t toUint32() const {return num;}
|
2015-08-10 02:04:56 +00:00
|
|
|
inline operator uint32_t() const {return num;}
|
2015-05-20 05:22:32 +00:00
|
|
|
};
|
2015-08-10 20:54:09 +00:00
|
|
|
#define FOURCC(chars) FourCC(SBIG(chars))
|
2015-05-20 05:22:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Hash representation used for all storable and comparable objects
|
|
|
|
*
|
|
|
|
* Hashes are used within HECL to avoid redundant storage of objects;
|
|
|
|
* providing a rapid mechanism to compare for equality.
|
|
|
|
*/
|
2015-06-10 23:34:14 +00:00
|
|
|
class Hash final
|
2015-05-20 05:22:32 +00:00
|
|
|
{
|
|
|
|
int64_t hash;
|
|
|
|
public:
|
2015-06-09 22:19:59 +00:00
|
|
|
Hash(const void* buf, size_t len)
|
2015-07-22 19:14:50 +00:00
|
|
|
: hash(Blowfish_hash((uint8_t*)buf, len)) {}
|
2015-06-09 22:19:59 +00:00
|
|
|
Hash(const std::string& str)
|
2015-07-22 19:14:50 +00:00
|
|
|
: hash(Blowfish_hash((uint8_t*)str.data(), str.size())) {}
|
|
|
|
Hash(const std::wstring& str)
|
|
|
|
: hash(Blowfish_hash((uint8_t*)str.data(), str.size()*2)) {}
|
2015-06-09 22:19:59 +00:00
|
|
|
Hash(int64_t hashin)
|
2015-05-21 02:33:05 +00:00
|
|
|
: hash(hashin) {}
|
2015-06-10 23:34:14 +00:00
|
|
|
Hash(const Hash& other) {hash = other.hash;}
|
2015-06-12 09:08:49 +00:00
|
|
|
inline size_t val() const {return hash;}
|
2015-06-10 23:34:14 +00:00
|
|
|
inline Hash& operator=(const Hash& other) {hash = other.hash; return *this;}
|
|
|
|
inline bool operator==(const Hash& other) const {return hash == other.hash;}
|
|
|
|
inline bool operator!=(const Hash& other) const {return hash != other.hash;}
|
|
|
|
inline bool operator<(const Hash& other) const {return hash < other.hash;}
|
|
|
|
inline bool operator>(const Hash& other) const {return hash > other.hash;}
|
|
|
|
inline bool operator<=(const Hash& other) const {return hash <= other.hash;}
|
|
|
|
inline bool operator>=(const Hash& other) const {return hash >= other.hash;}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Timestamp representation used for comparing modtimes of cooked resources
|
|
|
|
*/
|
|
|
|
class Time final
|
|
|
|
{
|
2015-06-11 04:55:06 +00:00
|
|
|
time_t ts;
|
2015-06-10 23:34:14 +00:00
|
|
|
public:
|
|
|
|
Time() : ts(time(NULL)) {}
|
2015-06-11 04:55:06 +00:00
|
|
|
Time(time_t ti) : ts(ti) {}
|
2015-06-10 23:34:14 +00:00
|
|
|
Time(const Time& other) {ts = other.ts;}
|
2015-06-11 04:55:06 +00:00
|
|
|
inline time_t getTs() const {return ts;}
|
2015-06-10 23:34:14 +00:00
|
|
|
inline Time& operator=(const Time& other) {ts = other.ts; return *this;}
|
|
|
|
inline bool operator==(const Time& other) const {return ts == other.ts;}
|
|
|
|
inline bool operator!=(const Time& other) const {return ts != other.ts;}
|
|
|
|
inline bool operator<(const Time& other) const {return ts < other.ts;}
|
|
|
|
inline bool operator>(const Time& other) const {return ts > other.ts;}
|
|
|
|
inline bool operator<=(const Time& other) const {return ts <= other.ts;}
|
|
|
|
inline bool operator>=(const Time& other) const {return ts >= other.ts;}
|
2015-05-20 05:22:32 +00:00
|
|
|
};
|
|
|
|
|
2015-05-27 09:09:05 +00:00
|
|
|
/**
|
|
|
|
* @brief Canonicalized project path representation using POSIX conventions
|
|
|
|
*
|
|
|
|
* HECL uses POSIX-style paths (with '/' separator) and directory tokens
|
|
|
|
* ('.','..') to resolve files within a project. The database internally
|
|
|
|
* uses this representation to track working files.
|
|
|
|
*
|
|
|
|
* This class provides a convenient way to resolve paths relative to the
|
|
|
|
* project root. Part of this representation involves resolving symbolic
|
|
|
|
* links to regular file/directory paths and determining its type.
|
|
|
|
*
|
|
|
|
* NOTE THAT PROJECT PATHS ARE TREATED AS CASE SENSITIVE!!
|
|
|
|
*/
|
|
|
|
class ProjectPath
|
|
|
|
{
|
|
|
|
protected:
|
2015-07-18 04:35:01 +00:00
|
|
|
SystemString m_projRoot;
|
2015-06-09 22:19:59 +00:00
|
|
|
SystemString m_absPath;
|
2015-06-11 04:55:06 +00:00
|
|
|
SystemString m_relPath;
|
2015-06-12 09:08:49 +00:00
|
|
|
Hash m_hash = 0;
|
2015-06-10 02:40:03 +00:00
|
|
|
#if HECL_UCS2
|
|
|
|
std::string m_utf8AbsPath;
|
2015-07-22 19:14:50 +00:00
|
|
|
std::string m_utf8RelPath;
|
2015-06-10 02:40:03 +00:00
|
|
|
#endif
|
2015-07-18 04:35:01 +00:00
|
|
|
ProjectPath(const SystemString& projRoot)
|
2015-08-05 23:19:28 +00:00
|
|
|
: m_projRoot(projRoot), m_absPath(projRoot), m_relPath(_S("."))
|
2015-07-18 04:35:01 +00:00
|
|
|
{
|
2015-08-05 01:54:35 +00:00
|
|
|
SanitizePath(m_projRoot);
|
|
|
|
SanitizePath(m_relPath);
|
|
|
|
SanitizePath(m_absPath);
|
|
|
|
m_hash = Hash(m_relPath);
|
2015-07-18 04:35:01 +00:00
|
|
|
#if HECL_UCS2
|
|
|
|
m_utf8AbsPath = WideToUTF8(m_absPath);
|
2015-07-22 19:14:50 +00:00
|
|
|
m_utf8RelPath = ".";
|
2015-07-18 04:35:01 +00:00
|
|
|
#endif
|
|
|
|
}
|
2015-05-27 09:09:05 +00:00
|
|
|
public:
|
2015-07-28 23:54:54 +00:00
|
|
|
/**
|
|
|
|
* @brief Empty constructor
|
|
|
|
*
|
|
|
|
* Used to preallocate ProjectPath for later population using assign()
|
|
|
|
*/
|
|
|
|
ProjectPath() {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Tests for non-empty project path
|
|
|
|
*/
|
|
|
|
operator bool() const {return m_absPath.size() != 0;}
|
|
|
|
|
2015-05-27 09:09:05 +00:00
|
|
|
/**
|
2015-07-16 02:03:38 +00:00
|
|
|
* @brief Construct a project subpath representation within another subpath
|
|
|
|
* @param parentPath previously constructed ProjectPath which ultimately connects to a ProjectRootPath
|
2015-05-27 09:09:05 +00:00
|
|
|
* @param path valid filesystem-path (relative or absolute) to subpath
|
|
|
|
*/
|
2015-08-05 23:19:28 +00:00
|
|
|
ProjectPath(const ProjectPath& parentPath, const SystemString& path) {assign(parentPath, path);}
|
|
|
|
void assign(const ProjectPath& parentPath, const SystemString& path);
|
2015-06-09 22:19:59 +00:00
|
|
|
|
2015-08-05 23:19:28 +00:00
|
|
|
#if HECL_UCS2
|
2015-07-28 23:54:54 +00:00
|
|
|
ProjectPath(const ProjectPath& parentPath, const std::string& path) {assign(parentPath, path);}
|
|
|
|
void assign(const ProjectPath& parentPath, const std::string& path);
|
2015-07-22 19:14:50 +00:00
|
|
|
#endif
|
|
|
|
|
2015-05-27 09:09:05 +00:00
|
|
|
/**
|
|
|
|
* @brief Determine if ProjectPath represents project root directory
|
|
|
|
* @return true if project root directory
|
|
|
|
*/
|
2015-06-11 04:55:06 +00:00
|
|
|
inline bool isRoot() const {return m_relPath.empty();}
|
2015-05-27 09:09:05 +00:00
|
|
|
|
2015-08-14 03:03:00 +00:00
|
|
|
/**
|
|
|
|
* @brief Return new ProjectPath with extension added
|
|
|
|
* @param ext file extension to add
|
|
|
|
* @return new path with extension
|
|
|
|
*/
|
|
|
|
inline ProjectPath getWithExtension(const SystemChar* ext) const
|
|
|
|
{
|
|
|
|
ProjectPath pp(*this);
|
|
|
|
pp.m_relPath += ext;
|
|
|
|
pp.m_absPath += ext;
|
|
|
|
return pp;
|
|
|
|
}
|
|
|
|
|
2015-05-27 09:09:05 +00:00
|
|
|
/**
|
|
|
|
* @brief Access fully-canonicalized absolute path
|
|
|
|
* @return Absolute path reference
|
|
|
|
*/
|
2015-06-10 02:40:03 +00:00
|
|
|
inline const SystemString& getAbsolutePath() const {return m_absPath;}
|
2015-05-27 09:09:05 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Access fully-canonicalized project-relative path
|
|
|
|
* @return Relative pointer to within absolute-path or "." for project root-directory (use isRoot to detect)
|
|
|
|
*/
|
2015-06-11 04:55:06 +00:00
|
|
|
inline const SystemString& getRelativePath() const
|
2015-05-27 09:09:05 +00:00
|
|
|
{
|
2015-06-11 04:55:06 +00:00
|
|
|
if (m_relPath.size())
|
2015-05-27 09:09:05 +00:00
|
|
|
return m_relPath;
|
2015-06-11 04:55:06 +00:00
|
|
|
static const SystemString dot = _S(".");
|
|
|
|
return dot;
|
2015-05-27 09:09:05 +00:00
|
|
|
}
|
|
|
|
|
2015-06-10 02:40:03 +00:00
|
|
|
/**
|
|
|
|
* @brief Access fully-canonicalized absolute path in UTF-8
|
|
|
|
* @return Absolute path reference
|
|
|
|
*/
|
|
|
|
inline const std::string& getAbsolutePathUTF8() const
|
|
|
|
{
|
|
|
|
#if HECL_UCS2
|
|
|
|
return m_utf8AbsPath;
|
|
|
|
#else
|
|
|
|
return m_absPath;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-06-11 04:55:06 +00:00
|
|
|
inline const std::string& getRelativePathUTF8() const
|
2015-06-10 02:40:03 +00:00
|
|
|
{
|
|
|
|
#if HECL_UCS2
|
|
|
|
return m_utf8RelPath;
|
|
|
|
#else
|
|
|
|
return m_relPath;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-05-27 09:09:05 +00:00
|
|
|
/**
|
|
|
|
* @brief Type of path
|
|
|
|
*/
|
|
|
|
enum PathType
|
|
|
|
{
|
|
|
|
PT_NONE, /**< If path doesn't reference a valid filesystem entity, this is returned */
|
|
|
|
PT_FILE, /**< Singular file path (confirmed with filesystem) */
|
|
|
|
PT_DIRECTORY, /**< Singular directory path (confirmed with filesystem) */
|
|
|
|
PT_GLOB /**< Glob-path (whenever one or more '*' occurs in syntax) */
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get type of path based on syntax and filesystem queries
|
|
|
|
* @return Type of path
|
|
|
|
*/
|
2015-06-10 02:40:03 +00:00
|
|
|
PathType getPathType() const;
|
2015-05-27 09:09:05 +00:00
|
|
|
|
2015-06-10 23:34:14 +00:00
|
|
|
/**
|
|
|
|
* @brief Get time of last modification with special behaviors for directories and glob-paths
|
|
|
|
* @return Time object representing entity's time of last modification
|
|
|
|
*
|
|
|
|
* Regular files simply return their modtime as queried from the OS
|
|
|
|
* Directories return the latest modtime of all first-level regular files
|
|
|
|
* Glob-paths return the latest modtime of all matched regular files
|
|
|
|
*/
|
|
|
|
Time getModtime() const;
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
/**
|
|
|
|
* @brief Insert glob matches into existing vector
|
|
|
|
* @param outPaths Vector to add matches to (will not erase existing contents)
|
|
|
|
*/
|
2015-06-10 02:40:03 +00:00
|
|
|
void getGlobResults(std::vector<SystemString>& outPaths) const;
|
2015-06-10 23:34:14 +00:00
|
|
|
|
2015-08-04 21:37:12 +00:00
|
|
|
/**
|
|
|
|
* @brief Count how many directory levels deep in project path is
|
|
|
|
* @return Level Count
|
|
|
|
*/
|
|
|
|
inline size_t levelCount() const
|
|
|
|
{
|
|
|
|
size_t count = 0;
|
|
|
|
for (SystemChar ch : m_relPath)
|
|
|
|
if (ch == _S('/') || ch == _S('\\'))
|
|
|
|
++count;
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2015-07-28 23:54:54 +00:00
|
|
|
/**
|
|
|
|
* @brief Create directory at path
|
|
|
|
*
|
|
|
|
* Fatal log report is issued if directory is not able to be created or doesn't already exist.
|
|
|
|
* If directory already exists, no action taken.
|
|
|
|
*/
|
|
|
|
inline void makeDir() const {MakeDir(m_absPath.c_str());}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Create relative symbolic link at calling path targeting another path
|
|
|
|
* @param target Path to target
|
|
|
|
*/
|
|
|
|
inline void makeLinkTo(const ProjectPath& target) const
|
|
|
|
{
|
|
|
|
SystemString relTarget;
|
|
|
|
for (SystemChar ch : m_relPath)
|
|
|
|
if (ch == _S('/') || ch == _S('\\'))
|
|
|
|
relTarget += _S("../");
|
|
|
|
relTarget += target.m_relPath;
|
|
|
|
MakeLink(relTarget.c_str(), m_absPath.c_str());
|
|
|
|
}
|
2015-06-10 23:34:14 +00:00
|
|
|
/**
|
2015-06-12 09:08:49 +00:00
|
|
|
* @brief HECL-specific blowfish hash
|
|
|
|
* @return unique hash value
|
2015-06-10 23:34:14 +00:00
|
|
|
*/
|
2015-06-12 09:08:49 +00:00
|
|
|
inline size_t hash() const {return m_hash.val();}
|
2015-06-10 23:34:14 +00:00
|
|
|
inline bool operator==(const ProjectPath& other) const {return m_hash == other.m_hash;}
|
|
|
|
inline bool operator!=(const ProjectPath& other) const {return m_hash != other.m_hash;}
|
|
|
|
|
2015-05-27 09:09:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Special ProjectRootPath subclass for opening HECLDatabase::IProject instances
|
|
|
|
*
|
|
|
|
* Constructing a ProjectPath requires supplying a ProjectRootPath to consistently
|
|
|
|
* resolve canonicalized relative paths.
|
|
|
|
*/
|
|
|
|
class ProjectRootPath : public ProjectPath
|
|
|
|
{
|
|
|
|
public:
|
2015-06-09 22:19:59 +00:00
|
|
|
ProjectRootPath(const SystemString& path)
|
2015-07-18 04:35:01 +00:00
|
|
|
: ProjectPath(path) {}
|
2015-05-27 09:09:05 +00:00
|
|
|
};
|
|
|
|
|
2015-06-11 04:55:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Search from within provided directory for the project root
|
|
|
|
* @param path absolute or relative file path to search from
|
|
|
|
* @return Newly-constructed root path or NULL if not found
|
|
|
|
*/
|
2015-06-12 04:02:23 +00:00
|
|
|
std::unique_ptr<ProjectRootPath> SearchForProject(const SystemString& path);
|
2015-05-27 09:09:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* Type-sensitive byte swappers */
|
2015-06-09 22:19:59 +00:00
|
|
|
template <typename T>
|
|
|
|
static inline T bswap16(T val)
|
2015-05-22 08:21:44 +00:00
|
|
|
{
|
|
|
|
#if __GNUC__
|
|
|
|
return __builtin_bswap16(val);
|
|
|
|
#elif _WIN32
|
|
|
|
return _byteswap_ushort(val);
|
|
|
|
#else
|
|
|
|
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
template <typename T>
|
|
|
|
static inline T bswap32(T val)
|
2015-05-22 08:21:44 +00:00
|
|
|
{
|
|
|
|
#if __GNUC__
|
|
|
|
return __builtin_bswap32(val);
|
|
|
|
#elif _WIN32
|
|
|
|
return _byteswap_ulong(val);
|
|
|
|
#else
|
|
|
|
val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
|
|
|
|
val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
|
|
|
|
return val;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-06-09 22:19:59 +00:00
|
|
|
template <typename T>
|
|
|
|
static inline T bswap64(T val)
|
2015-05-22 08:21:44 +00:00
|
|
|
{
|
|
|
|
#if __GNUC__
|
|
|
|
return __builtin_bswap64(val);
|
|
|
|
#elif _WIN32
|
|
|
|
return _byteswap_uint64(val);
|
|
|
|
#else
|
2015-06-09 22:19:59 +00:00
|
|
|
return ((val & 0xFF00000000000000ULL) >> 56) |
|
|
|
|
((val & 0x00FF000000000000ULL) >> 40) |
|
|
|
|
((val & 0x0000FF0000000000ULL) >> 24) |
|
|
|
|
((val & 0x000000FF00000000ULL) >> 8) |
|
|
|
|
((val & 0x00000000FF000000ULL) << 8) |
|
|
|
|
((val & 0x0000000000FF0000ULL) << 24) |
|
|
|
|
((val & 0x000000000000FF00ULL) << 40) |
|
|
|
|
((val & 0x00000000000000FFULL) << 56);
|
2015-05-22 08:21:44 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-27 09:09:05 +00:00
|
|
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
2015-06-12 04:02:23 +00:00
|
|
|
static inline int16_t SBig(int16_t val) {return bswap16(val);}
|
|
|
|
static inline uint16_t SBig(uint16_t val) {return bswap16(val);}
|
|
|
|
static inline int32_t SBig(int32_t val) {return bswap32(val);}
|
|
|
|
static inline uint32_t SBig(uint32_t val) {return bswap32(val);}
|
|
|
|
static inline int64_t SBig(int64_t val) {return bswap64(val);}
|
|
|
|
static inline uint64_t SBig(uint64_t val) {return bswap64(val);}
|
2015-07-19 20:52:22 +00:00
|
|
|
#define SBIG(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \
|
|
|
|
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
|
2015-06-12 04:02:23 +00:00
|
|
|
|
|
|
|
static inline int16_t SLittle(int16_t val) {return val;}
|
|
|
|
static inline uint16_t SLittle(uint16_t val) {return val;}
|
|
|
|
static inline int32_t SLittle(int32_t val) {return val;}
|
|
|
|
static inline uint32_t SLittle(uint32_t val) {return val;}
|
|
|
|
static inline int64_t SLittle(int64_t val) {return val;}
|
|
|
|
static inline uint64_t SLittle(uint64_t val) {return val;}
|
2015-07-19 20:52:22 +00:00
|
|
|
#define SLITTLE(q) (q)
|
2015-05-27 09:09:05 +00:00
|
|
|
#else
|
2015-06-12 04:02:23 +00:00
|
|
|
static inline int16_t SLittle(int16_t val) {return bswap16(val);}
|
|
|
|
static inline uint16_t SLittle(uint16_t val) {return bswap16(val);}
|
|
|
|
static inline int32_t SLittle(int32_t val) {return bswap32(val);}
|
|
|
|
static inline uint32_t SLittle(uint32_t val) {return bswap32(val);}
|
|
|
|
static inline int64_t SLittle(int64_t val) {return bswap64(val);}
|
|
|
|
static inline uint64_t SLittle(uint64_t val) {return bswap64(val);}
|
2015-07-19 20:52:22 +00:00
|
|
|
#define SLITTLE(q) ( ( (q) & 0x000000FF ) << 24 | ( (q) & 0x0000FF00 ) << 8 \
|
|
|
|
| ( (q) & 0x00FF0000 ) >> 8 | ( (q) & 0xFF000000 ) >> 24 )
|
2015-06-12 04:02:23 +00:00
|
|
|
|
|
|
|
static inline int16_t SBig(int16_t val) {return val;}
|
|
|
|
static inline uint16_t SBig(uint16_t val) {return val;}
|
|
|
|
static inline int32_t SBig(int32_t val) {return val;}
|
|
|
|
static inline uint32_t SBig(uint32_t val) {return val;}
|
|
|
|
static inline int64_t SBig(int64_t val) {return val;}
|
|
|
|
static inline uint64_t SBig(uint64_t val) {return val;}
|
2015-07-19 20:52:22 +00:00
|
|
|
#define SBIG(q) (q)
|
2015-05-27 09:09:05 +00:00
|
|
|
#endif
|
|
|
|
|
2015-05-20 05:22:32 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 19:14:50 +00:00
|
|
|
#if _MSC_VER
|
|
|
|
#define NOEXCEPT
|
|
|
|
#else
|
|
|
|
#define NOEXCEPT noexcept
|
|
|
|
#endif
|
|
|
|
|
2015-06-10 23:34:14 +00:00
|
|
|
namespace std
|
|
|
|
{
|
2015-07-13 06:30:20 +00:00
|
|
|
template <> struct hash<HECL::FourCC>
|
|
|
|
{
|
2015-07-22 19:14:50 +00:00
|
|
|
inline size_t operator()(const HECL::FourCC& val) const NOEXCEPT
|
2015-07-13 06:30:20 +00:00
|
|
|
{return val.toUint32();}
|
|
|
|
};
|
2015-06-10 23:34:14 +00:00
|
|
|
template <> struct hash<HECL::ProjectPath>
|
|
|
|
{
|
2015-07-22 19:14:50 +00:00
|
|
|
inline size_t operator()(const HECL::ProjectPath& val) const NOEXCEPT
|
2015-06-10 23:34:14 +00:00
|
|
|
{return val.hash();}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-05-20 05:22:32 +00:00
|
|
|
#endif // HECL_HPP
|