#ifndef HECL_HPP #define HECL_HPP #if _WIN32 char* win_realpath(const char* name, char* restrict resolved); #else #include #include #include #include #endif #include #include #include #include #include #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 SystemRegex; typedef std::regex_token_iterator SystemRegexTokenIterator; typedef std::match_results SystemRegexMatch; class ProjectRootPath; /** * @brief Severity of a log event */ enum LogType { LOG_INFO, LOG_WARN, LOG_ERROR }; /** * @brief Logger callback type */ typedef std::function 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& 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 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 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 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