hecl
High-Level Extensible Combiner Language and Resource Database
HECL.hpp
1 #ifndef HECL_HPP
2 #define HECL_HPP
3 
4 #if _WIN32
5 char* win_realpath(const char* name, char* restrict resolved);
6 #else
7 #include <stdlib.h>
8 #include <sys/param.h>
9 #include <sys/stat.h>
10 #include <dirent.h>
11 #include <fcntl.h>
12 #endif
13 
14 #include <time.h>
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <functional>
18 #include <stdexcept>
19 #include <string>
20 #include <algorithm>
21 #include <regex>
22 #include "../extern/blowfish/blowfish.h"
23 
24 namespace HECL
25 {
26 
27 #if _WIN32 && UNICODE
28 #define HECL_UCS2 1
29 #endif
30 
31 std::string WideToUTF8(const std::wstring& src);
32 std::wstring UTF8ToWide(const std::string& src);
33 
34 #if HECL_UCS2
35 typedef wchar_t SystemChar;
36 typedef std::wstring SystemString;
37 static inline void ToLower(SystemString& str)
38 {std::transform(str.begin(), str.end(), str.begin(), towlower);}
39 static inline void ToUpper(SystemString& str)
40 {std::transform(str.begin(), str.end(), str.begin(), towupper);}
41 class SystemUTF8View
42 {
43  std::string m_utf8;
44 public:
45  SystemUTF8View(const SystemString& str)
46  : m_utf8(WideToUTF8(str)) {}
47  inline const std::string& utf8_str() {return m_utf8;}
48 };
49 class SystemStringView
50 {
51  std::wstring m_sys;
52 public:
53  SystemStringView(const std::string& str)
54  : m_sys(UTF8ToWide(str)) {}
55  inline const std::wstring& sys_str() {return m_sys;}
56 };
57 #ifndef _S
58 #define _S(val) L ## val
59 #endif
60 #else
61 typedef char SystemChar;
62 typedef std::string SystemString;
63 static inline void ToLower(SystemString& str)
64 {std::transform(str.begin(), str.end(), str.begin(), tolower);}
65 static inline void ToUpper(SystemString& str)
66 {std::transform(str.begin(), str.end(), str.begin(), toupper);}
68 {
69  const std::string& m_utf8;
70 public:
71  SystemUTF8View(const SystemString& str)
72  : m_utf8(str) {}
73  inline const std::string& utf8_str() {return m_utf8;}
74 };
76 {
77  const std::string& m_sys;
78 public:
79  SystemStringView(const std::string& str)
80  : m_sys(str) {}
81  inline const std::string& sys_str() {return m_sys;}
82 };
83 #ifndef _S
84 #define _S(val) val
85 #endif
86 #endif
87 
88 class Exception : public std::exception
89 {
90  SystemString m_what;
91 #if HECL_UCS2
92  std::string m_utf8what;
93 #endif
94 public:
95  Exception(const SystemString& what) noexcept
96  : m_what(what)
97  {
98 #if HECL_UCS2
99  m_utf8what = WideToUTF8(what);
100 #endif
101  }
102  const char* what() const noexcept
103  {
104 #if HECL_UCS2
105  return m_utf8what.c_str();
106 #else
107  return m_what.c_str();
108 #endif
109  }
110  inline const SystemChar* swhat() const noexcept {return m_what.c_str();}
111 };
112 
113 static inline void MakeDir(const SystemString& dir)
114 {
115 #if _WIN32
116  HRESULT err;
117  if (!CreateDirectory(dir.c_str(), NULL))
118  if ((err = GetLastError()) != ERROR_ALREADY_EXISTS)
119  throw std::error_code(err, std::system_category());
120 #else
121  if (mkdir(dir.c_str(), 0755))
122  if (errno != EEXIST)
123  throw std::error_code(errno, std::system_category());
124 #endif
125 }
126 
127 static inline SystemChar* Getcwd(SystemChar* buf, int maxlen)
128 {
129 #if HECL_UCS2
130  return wgetcwd(buf, maxlen);
131 #else
132  return getcwd(buf, maxlen);
133 #endif
134 }
135 
136 enum FileLockType
137 {
138  LNONE = 0,
139  LREAD,
140  LWRITE
141 };
142 static inline FILE* Fopen(const SystemChar* path, const SystemChar* mode, FileLockType lock=LNONE)
143 {
144 #if HECL_UCS2
145  FILE* fp = wfopen(path, mode);
146 #else
147  FILE* fp = fopen(path, mode);
148 #endif
149  if (!fp)
150  throw std::error_code(errno, std::system_category());
151 
152  if (lock)
153  {
154 #if _WIN32
155  HANDLE fhandle = (HANDLE)fileno(fp);
156  OVERLAPPED ov = {};
157  LockFileEx(fhandle, (lock == LWRITE) ? LOCKFILE_EXCLUSIVE_LOCK : 0, 0, 0, 1, &ov);
158 #else
159  struct flock lk =
160  {
161  (short)((lock == LREAD) ? F_RDLCK : F_WRLCK),
162  SEEK_SET, 0, 0, 0
163  };
164  fcntl(fileno(fp), F_SETLK, &lk);
165 #endif
166  }
167 
168  return fp;
169 }
170 
171 static inline int Stat(const SystemChar* path, struct stat* statOut)
172 {
173 #if HECL_UCS2
174  return wstat(path, statOut);
175 #else
176  return stat(path, statOut);
177 #endif
178 }
179 
180 static inline void Printf(const SystemChar* format, ...)
181 {
182  va_list va;
183  va_start(va, format);
184 #if HECL_UCS2
185  vwprintf(format, va);
186 #else
187  vprintf(format, va);
188 #endif
189  va_end(va);
190 }
191 
192 static inline void FPrintf(FILE* fp, const SystemChar* format, ...)
193 {
194  va_list va;
195  va_start(va, format);
196 #if HECL_UCS2
197  vfwprintf(fp, format, va);
198 #else
199  vfprintf(fp, format, va);
200 #endif
201  va_end(va);
202 }
203 
204 typedef std::basic_regex<SystemChar> SystemRegex;
205 typedef std::regex_token_iterator<SystemString::const_iterator> SystemRegexTokenIterator;
206 typedef std::match_results<SystemString::const_iterator> SystemRegexMatch;
207 
208 class ProjectRootPath;
209 
213 enum LogType
214 {
215  LOG_INFO,
216  LOG_WARN,
217  LOG_ERROR
218 };
219 
223 typedef std::function<void(LogType, std::string&)> FLogger;
224 
232 class FourCC final
233 {
234  union
235  {
236  char fcc[4];
237  uint32_t num;
238  };
239 public:
240  FourCC() /* Sentinel FourCC */
241  : num(0) {}
242  FourCC(const char* name)
243  : num(*(uint32_t*)name) {}
244  inline bool operator==(const FourCC& other) const {return num == other.num;}
245  inline bool operator!=(const FourCC& other) const {return num != other.num;}
246  inline bool operator==(const char* other) const {return num == *(uint32_t*)other;}
247  inline bool operator!=(const char* other) const {return num != *(uint32_t*)other;}
248  inline std::string toString() const {return std::string(fcc, 4);}
249 };
250 
257 class Hash final
258 {
259  int64_t hash;
260 public:
261  Hash(const void* buf, size_t len)
262  : hash(Blowfish_hash(buf, len)) {}
263  Hash(const std::string& str)
264  : hash(Blowfish_hash(str.data(), str.size())) {}
265  Hash(int64_t hashin)
266  : hash(hashin) {}
267  Hash(const Hash& other) {hash = other.hash;}
268  inline Hash& operator=(const Hash& other) {hash = other.hash; return *this;}
269  inline bool operator==(const Hash& other) const {return hash == other.hash;}
270  inline bool operator!=(const Hash& other) const {return hash != other.hash;}
271  inline bool operator<(const Hash& other) const {return hash < other.hash;}
272  inline bool operator>(const Hash& other) const {return hash > other.hash;}
273  inline bool operator<=(const Hash& other) const {return hash <= other.hash;}
274  inline bool operator>=(const Hash& other) const {return hash >= other.hash;}
275 };
276 
280 class Time final
281 {
282  time_t ts;
283 public:
284  Time() : ts(time(NULL)) {}
285  Time(time_t ti) : ts(ti) {}
286  Time(const Time& other) {ts = other.ts;}
287  inline time_t getTs() const {return ts;}
288  inline Time& operator=(const Time& other) {ts = other.ts; return *this;}
289  inline bool operator==(const Time& other) const {return ts == other.ts;}
290  inline bool operator!=(const Time& other) const {return ts != other.ts;}
291  inline bool operator<(const Time& other) const {return ts < other.ts;}
292  inline bool operator>(const Time& other) const {return ts > other.ts;}
293  inline bool operator<=(const Time& other) const {return ts <= other.ts;}
294  inline bool operator>=(const Time& other) const {return ts >= other.ts;}
295 };
296 
311 {
312 protected:
313  SystemString m_absPath;
314  SystemString m_relPath;
315  size_t m_hash = 0;
316 #if HECL_UCS2
317  std::string m_utf8AbsPath;
318  const char* m_utf8RelPath;
319 #endif
320  ProjectPath() {}
321  bool _canonAbsPath(const SystemString& path);
322 public:
328  ProjectPath(const ProjectRootPath& rootPath, const SystemString& path);
329 
334  inline bool isRoot() const {return m_relPath.empty();}
335 
340  inline const SystemString& getAbsolutePath() const {return m_absPath;}
341 
346  inline const SystemString& getRelativePath() const
347  {
348  if (m_relPath.size())
349  return m_relPath;
350  static const SystemString dot = _S(".");
351  return dot;
352  }
353 
358  inline const std::string& getAbsolutePathUTF8() const
359  {
360 #if HECL_UCS2
361  return m_utf8AbsPath;
362 #else
363  return m_absPath;
364 #endif
365  }
366 
367  inline const std::string& getRelativePathUTF8() const
368  {
369 #if HECL_UCS2
370  return m_utf8RelPath;
371 #else
372  return m_relPath;
373 #endif
374  }
375 
379  enum PathType
380  {
385  };
386 
391  PathType getPathType() const;
392 
401  Time getModtime() const;
402 
407  void getGlobResults(std::vector<SystemString>& outPaths) const;
408 
413  inline size_t hash() const {return m_hash;}
414  inline bool operator==(const ProjectPath& other) const {return m_hash == other.m_hash;}
415  inline bool operator!=(const ProjectPath& other) const {return m_hash != other.m_hash;}
416 
417 };
418 
426 {
427 public:
428  ProjectRootPath(const SystemString& path)
429  {_canonAbsPath(path);}
430 };
431 
437 ProjectRootPath* SearchForProject(const SystemString& path);
438 
439 
440 /* Type-sensitive byte swappers */
441 template <typename T>
442 static inline T bswap16(T val)
443 {
444 #if __GNUC__
445  return __builtin_bswap16(val);
446 #elif _WIN32
447  return _byteswap_ushort(val);
448 #else
449  return (val = (val << 8) | ((val >> 8) & 0xFF));
450 #endif
451 }
452 
453 template <typename T>
454 static inline T bswap32(T val)
455 {
456 #if __GNUC__
457  return __builtin_bswap32(val);
458 #elif _WIN32
459  return _byteswap_ulong(val);
460 #else
461  val = (val & 0x0000FFFF) << 16 | (val & 0xFFFF0000) >> 16;
462  val = (val & 0x00FF00FF) << 8 | (val & 0xFF00FF00) >> 8;
463  return val;
464 #endif
465 }
466 
467 template <typename T>
468 static inline T bswap64(T val)
469 {
470 #if __GNUC__
471  return __builtin_bswap64(val);
472 #elif _WIN32
473  return _byteswap_uint64(val);
474 #else
475  return ((val & 0xFF00000000000000ULL) >> 56) |
476  ((val & 0x00FF000000000000ULL) >> 40) |
477  ((val & 0x0000FF0000000000ULL) >> 24) |
478  ((val & 0x000000FF00000000ULL) >> 8) |
479  ((val & 0x00000000FF000000ULL) << 8) |
480  ((val & 0x0000000000FF0000ULL) << 24) |
481  ((val & 0x000000000000FF00ULL) << 40) |
482  ((val & 0x00000000000000FFULL) << 56);
483 #endif
484 }
485 
486 
487 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
488 static inline int16_t ToBig(int16_t val) {return bswap16(val);}
489 static inline uint16_t ToBig(uint16_t val) {return bswap16(val);}
490 static inline int32_t ToBig(int32_t val) {return bswap32(val);}
491 static inline uint32_t ToBig(uint32_t val) {return bswap32(val);}
492 static inline int64_t ToBig(int64_t val) {return bswap64(val);}
493 static inline uint64_t ToBig(uint64_t val) {return bswap64(val);}
494 
495 static inline int16_t ToLittle(int16_t val) {return val;}
496 static inline uint16_t ToLittle(uint16_t val) {return val;}
497 static inline int32_t ToLittle(int32_t val) {return val;}
498 static inline uint32_t ToLittle(uint32_t val) {return val;}
499 static inline int64_t ToLittle(int64_t val) {return val;}
500 static inline uint64_t ToLittle(uint64_t val) {return val;}
501 #else
502 static inline int16_t ToLittle(int16_t val) {return bswap16(val);}
503 static inline uint16_t ToLittle(uint16_t val) {return bswap16(val);}
504 static inline int32_t ToLittle(int32_t val) {return bswap32(val);}
505 static inline uint32_t ToLittle(uint32_t val) {return bswap32(val);}
506 static inline int64_t ToLittle(int64_t val) {return bswap64(val);}
507 static inline uint64_t ToLittle(uint64_t val) {return bswap64(val);}
508 
509 static inline int16_t ToBig(int16_t val) {return val;}
510 static inline uint16_t ToBig(uint16_t val) {return val;}
511 static inline int32_t ToBig(int32_t val) {return val;}
512 static inline uint32_t ToBig(uint32_t val) {return val;}
513 static inline int64_t ToBig(int64_t val) {return val;}
514 static inline uint64_t ToBig(uint64_t val) {return val;}
515 #endif
516 
517 }
518 
519 namespace std
520 {
521 template <> struct hash<HECL::ProjectPath>
522 {
523  size_t operator()(const HECL::ProjectPath& val) const noexcept
524  {return val.hash();}
525 };
526 }
527 
528 #endif // HECL_HPP
Time getModtime() const
Get time of last modification with special behaviors for directories and glob-paths.
Definition: HECL.hpp:384
STL namespace.
bool isRoot() const
Determine if ProjectPath represents project root directory.
Definition: HECL.hpp:334
Definition: HECL.hpp:383
FourCC representation used within HECL's database.
Definition: HECL.hpp:232
Definition: HECL.hpp:381
Definition: HECL.hpp:382
const std::string & getAbsolutePathUTF8() const
Access fully-canonicalized absolute path in UTF-8.
Definition: HECL.hpp:358
Timestamp representation used for comparing modtimes of cooked resources.
Definition: HECL.hpp:280
const SystemString & getRelativePath() const
Access fully-canonicalized project-relative path.
Definition: HECL.hpp:346
size_t hash() const
C++11 compatible runtime hash (NOT USED IN PACKAGES!!)
Definition: HECL.hpp:413
Special ProjectRootPath subclass for opening HECLDatabase::IProject instances.
Definition: HECL.hpp:425
Definition: HECL.hpp:75
Definition: HECL.hpp:67
Definition: HECL.hpp:88
PathType
Type of path.
Definition: HECL.hpp:379
Definition: HECL.hpp:24
const SystemString & getAbsolutePath() const
Access fully-canonicalized absolute path.
Definition: HECL.hpp:340
PathType getPathType() const
Get type of path based on syntax and filesystem queries.
void getGlobResults(std::vector< SystemString > &outPaths) const
Insert glob matches into existing vector.
Canonicalized project path representation using POSIX conventions.
Definition: HECL.hpp:310
Hash representation used for all storable and comparable objects.
Definition: HECL.hpp:257