mirror of https://github.com/AxioDL/metaforce.git
340 lines
9.5 KiB
C++
340 lines
9.5 KiB
C++
#ifndef HECL_HPP
|
|
#define HECL_HPP
|
|
|
|
#if _WIN32
|
|
char* win_realpath(const char* name, char* restrict resolved);
|
|
#else
|
|
#include <stdlib.h>
|
|
#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <functional>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <regex>
|
|
#include "../extern/blowfish/blowfish.h"
|
|
|
|
namespace HECL
|
|
{
|
|
|
|
std::string WideToUTF8(const std::wstring& src);
|
|
std::wstring UTF8ToWide(const std::string& src);
|
|
|
|
#if _WIN32 && UNICODE
|
|
typedef wchar_t SystemChar;
|
|
typedef std::wstring SystemString;
|
|
class CSystemUTF8View
|
|
{
|
|
std::string m_utf8;
|
|
public:
|
|
CSystemUTF8View(const SystemString& str)
|
|
: m_utf8(WideToUTF8(str)) {}
|
|
inline const std::string& utf8_str() {return m_utf8;}
|
|
};
|
|
class CSystemStringView
|
|
{
|
|
std::wstring m_sys;
|
|
public:
|
|
CSystemStringView(const std::string& str)
|
|
: m_sys(UTF8ToWide(str)) {}
|
|
inline const std::string& sys_str() {return m_sys;}
|
|
};
|
|
#ifndef _S
|
|
#define _S(val) L ## val
|
|
#endif
|
|
#else
|
|
typedef char SystemChar;
|
|
typedef std::string SystemString;
|
|
class CSystemUTF8View
|
|
{
|
|
const std::string& m_utf8;
|
|
public:
|
|
CSystemUTF8View(const SystemString& str)
|
|
: m_utf8(str) {}
|
|
inline const std::string& utf8_str() {return m_utf8;}
|
|
};
|
|
class CSystemStringView
|
|
{
|
|
const std::string& m_sys;
|
|
public:
|
|
CSystemStringView(const std::string& str)
|
|
: m_sys(str) {}
|
|
inline const std::string& sys_str() {return m_sys;}
|
|
};
|
|
#ifndef _S
|
|
#define _S(val) val
|
|
#endif
|
|
#endif
|
|
|
|
static inline void MakeDir(const SystemString& dir)
|
|
{
|
|
#if _WIN32
|
|
HRESULT err;
|
|
if (!CreateDirectory(dir.c_str(), NULL))
|
|
if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
|
|
throw std::error_code(err, std::system_category());
|
|
#else
|
|
if (mkdir(dir.c_str(), 0755))
|
|
if (errno != EEXIST)
|
|
throw std::error_code(errno, std::system_category());
|
|
#endif
|
|
}
|
|
|
|
static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode)
|
|
{
|
|
#if _WIN32 && UNICODE
|
|
FILE* fp = wfopen(path, mode);
|
|
#else
|
|
FILE* fp = fopen(path, mode);
|
|
#endif
|
|
if (!fp)
|
|
throw std::error_code(errno, std::system_category());
|
|
|
|
return fp;
|
|
}
|
|
|
|
typedef std::basic_regex<SystemChar> SystemRegex;
|
|
typedef std::regex_token_iterator<SystemString::const_iterator> SystemRegexTokenIterator;
|
|
typedef std::match_results<SystemString::const_iterator> SystemRegexMatch;
|
|
|
|
class ProjectRootPath;
|
|
|
|
/**
|
|
* @brief Severity of a log event
|
|
*/
|
|
enum LogType
|
|
{
|
|
LOG_INFO,
|
|
LOG_WARN,
|
|
LOG_ERROR
|
|
};
|
|
|
|
/**
|
|
* @brief Logger callback type
|
|
*/
|
|
typedef std::function<void(LogType, std::string&)> TLogger;
|
|
|
|
/**
|
|
* @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.
|
|
*/
|
|
class FourCC
|
|
{
|
|
union
|
|
{
|
|
char fcc[4];
|
|
uint32_t num;
|
|
};
|
|
public:
|
|
FourCC() /* Sentinel FourCC */
|
|
: num(0) {}
|
|
FourCC(const char* name)
|
|
: num(*(uint32_t*)name) {}
|
|
inline bool operator==(FourCC& other) {return num == other.num;}
|
|
inline bool operator!=(FourCC& other) {return num != other.num;}
|
|
inline std::string toString() {return std::string(fcc, 4);}
|
|
};
|
|
|
|
/**
|
|
* @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.
|
|
*/
|
|
class Hash
|
|
{
|
|
int64_t hash;
|
|
public:
|
|
Hash(const void* buf, size_t len)
|
|
: hash(Blowfish_hash(buf, len)) {}
|
|
Hash(const std::string& str)
|
|
: hash(Blowfish_hash(str.data(), str.size())) {}
|
|
Hash(int64_t hashin)
|
|
: hash(hashin) {}
|
|
inline bool operator==(Hash& other) {return hash == other.hash;}
|
|
inline bool operator!=(Hash& other) {return hash != other.hash;}
|
|
inline bool operator<(Hash& other) {return hash < other.hash;}
|
|
inline bool operator>(Hash& other) {return hash > other.hash;}
|
|
inline bool operator<=(Hash& other) {return hash <= other.hash;}
|
|
inline bool operator>=(Hash& other) {return hash >= other.hash;}
|
|
};
|
|
|
|
/**
|
|
* @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:
|
|
SystemString m_absPath;
|
|
const SystemChar* m_relPath = NULL;
|
|
ProjectPath() {}
|
|
bool _canonAbsPath(const SystemString& path);
|
|
public:
|
|
/**
|
|
* @brief Construct a project subpath representation
|
|
* @param rootPath previously constructed ProjectRootPath held by HECLDatabase::IProject
|
|
* @param path valid filesystem-path (relative or absolute) to subpath
|
|
*/
|
|
ProjectPath(const ProjectRootPath& rootPath, const SystemString& path);
|
|
|
|
/**
|
|
* @brief Determine if ProjectPath represents project root directory
|
|
* @return true if project root directory
|
|
*/
|
|
inline bool isRoot() {return (m_relPath == NULL);}
|
|
|
|
/**
|
|
* @brief Access fully-canonicalized absolute path
|
|
* @return Absolute path reference
|
|
*/
|
|
inline const SystemString& getAbsolutePath() {return m_absPath;}
|
|
|
|
/**
|
|
* @brief Access fully-canonicalized project-relative path
|
|
* @return Relative pointer to within absolute-path or "." for project root-directory (use isRoot to detect)
|
|
*/
|
|
inline const SystemChar* getRelativePath()
|
|
{
|
|
if (m_relPath)
|
|
return m_relPath;
|
|
return _S(".");
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
PathType getPathType();
|
|
|
|
/**
|
|
* @brief Insert glob matches into existing vector
|
|
* @param outPaths Vector to add matches to (will not erase existing contents)
|
|
*/
|
|
void getGlobResults(std::vector<SystemString>& outPaths);
|
|
};
|
|
|
|
/**
|
|
* @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:
|
|
ProjectRootPath(const SystemString& path)
|
|
{
|
|
_canonAbsPath(path);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/* Type-sensitive byte swappers */
|
|
template <typename T>
|
|
static inline T bswap16(T val)
|
|
{
|
|
#if __GNUC__
|
|
return __builtin_bswap16(val);
|
|
#elif _WIN32
|
|
return _byteswap_ushort(val);
|
|
#else
|
|
return (val = (val << 8) | ((val >> 8) & 0xFF));
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
static inline T bswap32(T val)
|
|
{
|
|
#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
|
|
}
|
|
|
|
template <typename T>
|
|
static inline T bswap64(T val)
|
|
{
|
|
#if __GNUC__
|
|
return __builtin_bswap64(val);
|
|
#elif _WIN32
|
|
return _byteswap_uint64(val);
|
|
#else
|
|
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);
|
|
#endif
|
|
}
|
|
|
|
|
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
static inline int16_t ToBig(int16_t val) {return bswap16(val);}
|
|
static inline uint16_t ToBig(uint16_t val) {return bswap16(val);}
|
|
static inline int32_t ToBig(int32_t val) {return bswap32(val);}
|
|
static inline uint32_t ToBig(uint32_t val) {return bswap32(val);}
|
|
static inline int64_t ToBig(int64_t val) {return bswap64(val);}
|
|
static inline uint64_t ToBig(uint64_t val) {return bswap64(val);}
|
|
|
|
static inline int16_t ToLittle(int16_t val) {return val;}
|
|
static inline uint16_t ToLittle(uint16_t val) {return val;}
|
|
static inline int32_t ToLittle(int32_t val) {return val;}
|
|
static inline uint32_t ToLittle(uint32_t val) {return val;}
|
|
static inline int64_t ToLittle(int64_t val) {return val;}
|
|
static inline uint64_t ToLittle(uint64_t val) {return val;}
|
|
#else
|
|
static inline int16_t ToLittle(int16_t val) {return bswap16(val);}
|
|
static inline uint16_t ToLittle(uint16_t val) {return bswap16(val);}
|
|
static inline int32_t ToLittle(int32_t val) {return bswap32(val);}
|
|
static inline uint32_t ToLittle(uint32_t val) {return bswap32(val);}
|
|
static inline int64_t ToLittle(int64_t val) {return bswap64(val);}
|
|
static inline uint64_t ToLittle(uint64_t val) {return bswap64(val);}
|
|
|
|
static inline int16_t ToBig(int16_t val) {return val;}
|
|
static inline uint16_t ToBig(uint16_t val) {return val;}
|
|
static inline int32_t ToBig(int32_t val) {return val;}
|
|
static inline uint32_t ToBig(uint32_t val) {return val;}
|
|
static inline int64_t ToBig(int64_t val) {return val;}
|
|
static inline uint64_t ToBig(uint64_t val) {return val;}
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif // HECL_HPP
|