mirror of
https://github.com/thunderbrewhq/bc.git
synced 2025-12-12 01:52:30 +00:00
refactor(bc): improve consistency (across platforms esp.) and readability of string conversion
This commit is contained in:
parent
5d96890167
commit
99f6576a12
35 changed files with 1106 additions and 624 deletions
|
|
@ -1,25 +1,18 @@
|
|||
file(GLOB BC_SOURCES
|
||||
"*.cpp"
|
||||
"memory/*.cpp"
|
||||
"lock/*.cpp"
|
||||
"os/*.cpp"
|
||||
"string/*.cpp"
|
||||
"file/*.cpp"
|
||||
"file/path/*.cpp"
|
||||
"time/*.cpp"
|
||||
"lock/*.cpp"
|
||||
"memory/*.cpp"
|
||||
"os/*.cpp"
|
||||
"os/file/*.cpp"
|
||||
"system/*.cpp"
|
||||
"system/file/*.cpp"
|
||||
"system/file/posix/*.cpp"
|
||||
"system/file/win/*.cpp"
|
||||
"time/*.cpp"
|
||||
)
|
||||
|
||||
if(DEFINED WHOA_SYSTEM_WIN)
|
||||
file(GLOB BC_FILE_SYSTEM_SOURCES "system/file/win/*.cpp")
|
||||
endif()
|
||||
|
||||
if(DEFINED WHOA_SYSTEM_LINUX OR WHOA_SYSTEM_MAC)
|
||||
file(GLOB BC_FILE_SYSTEM_SOURCES "system/file/posix/*.cpp")
|
||||
endif()
|
||||
|
||||
list(APPEND BC_SOURCES ${BC_FILE_SYSTEM_SOURCES})
|
||||
|
||||
add_library(bc STATIC
|
||||
${BC_SOURCES}
|
||||
)
|
||||
|
|
|
|||
281
bc/String.cpp
281
bc/String.cpp
|
|
@ -1,281 +0,0 @@
|
|||
#include "bc/String.hpp"
|
||||
#include "bc/Debug.hpp"
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
int32_t Append(char* buf, const char* appended, size_t cap) {
|
||||
const char* dx = nullptr;
|
||||
int bytesAppended = 0;
|
||||
char* outBytes = nullptr;
|
||||
char* ceiling = nullptr;
|
||||
char inByte = '\0';
|
||||
|
||||
if (!cap || !buf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ceiling = buf + (cap - 1);
|
||||
|
||||
if (buf > ceiling) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inByte = *buf;
|
||||
outBytes = buf;
|
||||
|
||||
while (inByte != '\0') {
|
||||
outBytes = outBytes + 1;
|
||||
if (ceiling < outBytes) {
|
||||
return outBytes - buf;
|
||||
}
|
||||
inByte = *outBytes;
|
||||
}
|
||||
|
||||
if ((outBytes <= ceiling) && appended != nullptr) {
|
||||
if (outBytes < ceiling) {
|
||||
inByte = *appended;
|
||||
|
||||
while (inByte != '\0') {
|
||||
*outBytes = inByte;
|
||||
outBytes = outBytes + 1;
|
||||
if (ceiling <= outBytes) {
|
||||
break;
|
||||
}
|
||||
appended = appended + 1;
|
||||
inByte = *appended;
|
||||
}
|
||||
}
|
||||
*outBytes = '\0';
|
||||
}
|
||||
|
||||
return int32_t(reinterpret_cast<uintptr_t>(outBytes) - reinterpret_cast<uintptr_t>(buf));
|
||||
}
|
||||
|
||||
int32_t Copy(char* dst, const char* src, size_t len) {
|
||||
if (!len || !dst) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
*dst = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* v3 = dst + len - 1;
|
||||
|
||||
char v4;
|
||||
const char* v5;
|
||||
char* v6;
|
||||
|
||||
int32_t result;
|
||||
|
||||
if (dst < v3 && (v4 = *src, v5 = src, v6 = dst, *src)) {
|
||||
do {
|
||||
*v6++ = v4;
|
||||
|
||||
if (v3 <= v6) {
|
||||
break;
|
||||
}
|
||||
|
||||
v4 = (v5++)[1];
|
||||
} while (v4);
|
||||
|
||||
result = v6 - dst;
|
||||
} else {
|
||||
v6 = dst;
|
||||
result = 0;
|
||||
}
|
||||
|
||||
*v6 = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Find first occurence of char ch within string str
|
||||
// returns ptr to first occurence, or null if it is not found
|
||||
char* Find(char* str, char ch, size_t len) {
|
||||
// Check if the string is null or empty.
|
||||
if (str == nullptr || len == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ptr = str;
|
||||
auto end = str + len;
|
||||
|
||||
// Loop through the string, looking for the character.
|
||||
while (ptr < end) {
|
||||
if (*ptr == '\0' && ch != '\0') {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (*ptr == ch) {
|
||||
// Return the address of the first occurrence.
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// Increment the pointer.
|
||||
ptr++;
|
||||
}
|
||||
|
||||
// The character was not found.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* FindFilename(const char* str) {
|
||||
char ch = 0;
|
||||
const char* result = nullptr;
|
||||
auto ptr = str;
|
||||
|
||||
if (str == nullptr) {
|
||||
return "";
|
||||
}
|
||||
|
||||
do {
|
||||
do {
|
||||
result = ptr;
|
||||
ch = *str;
|
||||
str = str + 1;
|
||||
ptr = str;
|
||||
} while (ch == '/');
|
||||
} while ((ch == '\\') || (ptr = result, ch != '\0'));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Format a string into char* dest, not exceeding uint32_t length.
|
||||
void Format(char* dst, size_t capacity, const char* format, ...) {
|
||||
if (!dst || capacity == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!format && capacity >= 1) {
|
||||
*dst = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
auto formatNative = format;
|
||||
|
||||
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
|
||||
constexpr size_t translatedSize = 2048;
|
||||
|
||||
// POSIX formatting convention requires %ll for 64-bit printing
|
||||
// Search-and-replace all instances of %I64 with %ll
|
||||
char translated[translatedSize] = {0};
|
||||
|
||||
Translate(format, translated, translatedSize, "%I64", "%ll");
|
||||
|
||||
formatNative = translated;
|
||||
#endif
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
vsnprintf(dst, capacity, formatNative, args);
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
uint32_t Length(const char* str) {
|
||||
if (str) {
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t MemCompare(void* p1, void *p2, size_t len) {
|
||||
return memcmp(p1, p2, len);
|
||||
}
|
||||
|
||||
void MemCopy(void* dst, const void* src, size_t len) {
|
||||
memmove(dst, src, len);
|
||||
}
|
||||
|
||||
void MemFill(void* dst, uint32_t len, uint8_t fill) {
|
||||
memset(dst, fill, len);
|
||||
}
|
||||
|
||||
void Translate(const char* src, char* dest, size_t destSize, const char* pattern, const char* replacement) {
|
||||
if (dest == nullptr || pattern == nullptr || replacement == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == nullptr) {
|
||||
src = dest;
|
||||
}
|
||||
|
||||
// Cap-1 because we need to always affix a null character.
|
||||
auto destCeiling = dest + destSize - 1;
|
||||
auto srcCeiling = src + Length(src) + 1;
|
||||
|
||||
auto patternLen = Length(pattern);
|
||||
auto replacementLen = Length(replacement);
|
||||
|
||||
// Current read pointer
|
||||
auto srcPtr = src;
|
||||
// Current write pointer
|
||||
auto destPtr = dest;
|
||||
|
||||
// Process string byte by byte
|
||||
// Until dest ceiling is reached
|
||||
while (destPtr < destCeiling && srcPtr < srcCeiling) {
|
||||
auto byte = *srcPtr;
|
||||
|
||||
if (byte == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
// If this byte is found at the start of pattern
|
||||
if (byte == *pattern) {
|
||||
// Calculate size of replacement bytes to copy
|
||||
// Read size must not read outside of bounds
|
||||
size_t copySize = replacementLen;
|
||||
if ((destPtr + copySize) >= destCeiling) {
|
||||
copySize = destCeiling - destPtr;
|
||||
}
|
||||
|
||||
// Look for the rest of the pattern
|
||||
auto substring = strstr(srcPtr, pattern);
|
||||
// If the read pointer is indeed pointing to an instance of the pattern,
|
||||
if (substring == srcPtr) {
|
||||
// Copy replacement data instead of original pattern.
|
||||
MemCopy(destPtr, replacement, copySize);
|
||||
destPtr += replacementLen;
|
||||
srcPtr += patternLen;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// copy a single byte
|
||||
*destPtr = *srcPtr;
|
||||
srcPtr++;
|
||||
destPtr++;
|
||||
}
|
||||
|
||||
*destPtr = '\0';
|
||||
}
|
||||
|
||||
void VFormat(char* dst, size_t capacity, const char* format, va_list args) {
|
||||
char buffer[0x800] = {0};
|
||||
|
||||
auto formatNative = format;
|
||||
|
||||
#if !defined(WHOA_SYSTEM_WIN)
|
||||
Translate(format, buffer, 0x800, "%I64", "%ll");
|
||||
formatNative = buffer;
|
||||
#endif
|
||||
|
||||
if (format == nullptr) {
|
||||
if (capacity != 0) {
|
||||
*dst = '\0';
|
||||
}
|
||||
} else {
|
||||
vsnprintf(dst, capacity, formatNative, args);
|
||||
dst[capacity - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
|
@ -1,66 +1,16 @@
|
|||
#ifndef BC_STRING_HPP
|
||||
#define BC_STRING_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
#define BC_FILE_SYSTEM_PATH_SEPARATOR '\\'
|
||||
#else
|
||||
#define BC_FILE_SYSTEM_PATH_SEPARATOR '/'
|
||||
#endif
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
// Types
|
||||
|
||||
template<size_t Cap>
|
||||
class QuickFormat {
|
||||
public:
|
||||
char buffer[Cap];
|
||||
|
||||
QuickFormat(const char* format, ...);
|
||||
const char* Str();
|
||||
};
|
||||
|
||||
// Functions
|
||||
int32_t Append(char* dst, const char* src, size_t cap);
|
||||
|
||||
int32_t Copy(char* dst, const char* src, size_t len);
|
||||
|
||||
char* Find(char* str, char ch, size_t len);
|
||||
|
||||
const char* FindFilename(const char* str);
|
||||
|
||||
void Format(char* dest, size_t capacity, const char* format, ...);
|
||||
|
||||
uint32_t Length(const char* str);
|
||||
|
||||
void MemFill(void* dst, uint32_t len, uint8_t fill);
|
||||
|
||||
void MemCopy(void* dst, const void* src, size_t len);
|
||||
|
||||
int32_t MemCompare(void* p1, void *p2, size_t len);
|
||||
|
||||
void Translate(const char* src, char* dest, size_t destSize, const char* pattern, const char* replacement);
|
||||
|
||||
void VFormat(char* dst, size_t capacity, const char* format, va_list args);
|
||||
|
||||
template <size_t Cap>
|
||||
QuickFormat<Cap>::QuickFormat(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
VFormat(this->buffer, Cap, format, args);
|
||||
}
|
||||
|
||||
template <size_t Cap>
|
||||
const char* QuickFormat<Cap>::Str() {
|
||||
return static_cast<const char*>(this->buffer);
|
||||
}
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
#include "bc/string/Append.hpp"
|
||||
#include "bc/string/Copy.hpp"
|
||||
#include "bc/string/Defines.hpp"
|
||||
#include "bc/string/Find.hpp"
|
||||
#include "bc/string/Format.hpp"
|
||||
#include "bc/string/Length.hpp"
|
||||
#include "bc/string/Memory.hpp"
|
||||
#include "bc/string/Path.hpp"
|
||||
#include "bc/string/QuickFormat.hpp"
|
||||
#include "bc/string/QuickNativePath.hpp"
|
||||
#include "bc/string/Translate.hpp"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
239
bc/Unicode.cpp
Normal file
239
bc/Unicode.cpp
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
#include "bc/Unicode.hpp"
|
||||
#include "bc/Debug.hpp"
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace Unicode {
|
||||
|
||||
static const uint32_t offsetsFromUTF8[] = {
|
||||
0x0,
|
||||
0x0,
|
||||
0x3080,
|
||||
0xE2080,
|
||||
0x3C82080,
|
||||
0xFA082080,
|
||||
0x82082080
|
||||
};
|
||||
|
||||
static const uint32_t firstByteMark[] = {
|
||||
0x0,
|
||||
0x0,
|
||||
0xC0,
|
||||
0xE0,
|
||||
0xF0,
|
||||
0xF8,
|
||||
0xFC
|
||||
};
|
||||
|
||||
static const uint8_t bytesFromUTF8[] = {
|
||||
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
|
||||
0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06
|
||||
};
|
||||
|
||||
int32_t ConvertUTF16to8(uint8_t* dst, uint32_t dstmaxchars, const uint16_t* src, uint32_t srcmaxchars, uint32_t* dstchars, uint32_t* srcchars) {
|
||||
auto srcend = srcmaxchars & 0x80000000 ? reinterpret_cast<uint16_t*>(0xFFFFFFFF) : &src[srcmaxchars];
|
||||
auto dstend = &dst[dstmaxchars];
|
||||
auto dststart = dst;
|
||||
auto srcstart = src;
|
||||
|
||||
int32_t result;
|
||||
|
||||
while (src < srcend) {
|
||||
uint32_t widechars = 1;
|
||||
auto grapheme = static_cast<uint32_t>(src[0]);
|
||||
if (0xD7FF < grapheme && grapheme < 0xDC00) {
|
||||
if (src + 1 >= srcend) {
|
||||
goto fail;
|
||||
}
|
||||
auto char2 = static_cast<uint32_t>(src[1]);
|
||||
if (0xDBFF < char2 && char2 < 0xE000) {
|
||||
grapheme = ((grapheme - 0xD7F7) * 1024) + char2;
|
||||
widechars = 2;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t chars;
|
||||
|
||||
if (grapheme < 0x80) {
|
||||
chars = 1;
|
||||
if (grapheme == 0) {
|
||||
if (dst < dstend) {
|
||||
*dst++ = '\0';
|
||||
result = 0;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
} else if (grapheme < 0x800) {
|
||||
chars = 2;
|
||||
} else if (grapheme < 0x10000) {
|
||||
chars = 3;
|
||||
} else if (grapheme < 0x200000) {
|
||||
chars = 4;
|
||||
} else if (grapheme < 0x4000000) {
|
||||
chars = 5;
|
||||
} else if (grapheme > 0x7FFFFFFF) {
|
||||
grapheme = 0xFFFD;
|
||||
chars = 2;
|
||||
} else {
|
||||
chars = 6;
|
||||
}
|
||||
|
||||
result = chars;
|
||||
|
||||
dst += chars;
|
||||
|
||||
if (dst > dstend) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (chars) {
|
||||
case 6:
|
||||
*--dst = (grapheme & 0x3F) | 0x80;
|
||||
grapheme >>= 6;
|
||||
case 5:
|
||||
*--dst = (grapheme & 0x3F) | 0x80;
|
||||
grapheme >>= 6;
|
||||
case 4:
|
||||
*--dst = (grapheme & 0x3F) | 0x80;
|
||||
grapheme >>= 6;
|
||||
case 3:
|
||||
*--dst = (grapheme & 0x3F) | 0x80;
|
||||
grapheme >>= 6;
|
||||
case 2:
|
||||
*--dst = (grapheme & 0x3F) | 0x80;
|
||||
grapheme >>= 6;
|
||||
case 1:
|
||||
*--dst = grapheme | firstByteMark[chars];
|
||||
}
|
||||
|
||||
src += widechars;
|
||||
dst += chars;
|
||||
}
|
||||
|
||||
fail:
|
||||
result = -1;
|
||||
|
||||
done:
|
||||
if (srcchars) {
|
||||
*srcchars = src - srcstart;
|
||||
}
|
||||
|
||||
if (dstchars) {
|
||||
*dstchars = dst - dststart;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t ConvertUTF8to16(uint16_t* dst, uint32_t dstmaxchars, const uint8_t* src, uint32_t srcmaxchars, uint32_t* dstchars, uint32_t* srcchars) {
|
||||
auto srcend = srcmaxchars & 0x80000000 ? std::numeric_limits<const uint8_t*>::max() : src + srcmaxchars;
|
||||
auto dstend = dst + dstmaxchars;
|
||||
auto dststart = dst;
|
||||
auto srcstart = src;
|
||||
|
||||
int32_t result = 0;
|
||||
|
||||
while (src < srcend) {
|
||||
auto bytes = bytesFromUTF8[*src];
|
||||
if ((src + bytes) > srcend) {
|
||||
result = -bytes;
|
||||
goto done;
|
||||
}
|
||||
|
||||
uint32_t grapheme = 0;
|
||||
|
||||
switch (bytes) {
|
||||
case 6:
|
||||
grapheme = *src++ << 6;
|
||||
case 5:
|
||||
grapheme = (grapheme + *src++) << 6;
|
||||
case 4:
|
||||
grapheme = (grapheme + *src++) << 6;
|
||||
case 3:
|
||||
grapheme = (grapheme + *src++) << 6;
|
||||
case 2:
|
||||
grapheme = (grapheme + *src++) << 6;
|
||||
case 1:
|
||||
grapheme = (grapheme + *src++) - offsetsFromUTF8[bytes];
|
||||
}
|
||||
|
||||
if (dst >= dstend) {
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (grapheme < 0x10000) {
|
||||
*dst++ = static_cast<uint16_t>(grapheme);
|
||||
if (grapheme == 0x0) {
|
||||
goto done;
|
||||
}
|
||||
} else if (grapheme < 0x110000) {
|
||||
if (dst >= dstend) {
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
auto v16 = grapheme - 0x10000;
|
||||
*dst++ = static_cast<uint16_t>(v16 >> 10) - 0x2800;
|
||||
*dst++ = static_cast<uint16_t>(v16 & 0x3FF) - 0x2400;
|
||||
} else {
|
||||
*dst++ = 0xFFFD;
|
||||
}
|
||||
}
|
||||
|
||||
result = -1;
|
||||
|
||||
done:
|
||||
if (srcchars) {
|
||||
*srcchars = src - srcstart;
|
||||
}
|
||||
|
||||
if (dstchars) {
|
||||
*dstchars = dst - dststart;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t ConvertUTF8to16Len(const uint8_t* src, uint32_t srcmaxchars, uint32_t* srcchars) {
|
||||
// TODO
|
||||
BLIZZARD_ASSERT(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t GetCodepointFromUTF8(const uint8_t** c) {
|
||||
// TODO
|
||||
BLIZZARD_ASSERT(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace Unicode
|
||||
} // namespace Blizzard
|
||||
20
bc/Unicode.hpp
Normal file
20
bc/Unicode.hpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef BC_UNICODE_HPP
|
||||
#define BC_UNICODE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace Unicode {
|
||||
|
||||
int32_t ConvertUTF16to8(uint8_t* dst, uint32_t dstmaxchars, const uint16_t* src, uint32_t srcmaxchars, uint32_t* dstchars, uint32_t* srchars);
|
||||
|
||||
int32_t ConvertUTF8to16(uint16_t* dst, uint32_t dstmaxchars, const uint8_t* src, uint32_t srcmaxchars, uint32_t* dstchars, uint32_t* srcchars);
|
||||
|
||||
int32_t ConvertUTF8to16Len(const uint8_t* src, uint32_t srcmaxchars, uint32_t* srcchars);
|
||||
|
||||
int32_t GetCodepointFromUTF8(const uint8_t** c);
|
||||
|
||||
} // namespace Unicode
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
#include "bc/os/CommandLine.hpp"
|
||||
#include "bc/Debug.hpp"
|
||||
#include "bc/string/Append.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
|
|
@ -10,10 +9,66 @@
|
|||
|
||||
// Variables
|
||||
|
||||
char commandline[1024] = {0};
|
||||
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
|
||||
char commandline[65535];
|
||||
#endif
|
||||
|
||||
// Functions
|
||||
|
||||
// CUSTOM: appends a command-line argument to the buffer,
|
||||
void append_commandline(char* buffer, int32_t buffersize, const char* argument) {
|
||||
bool escape = false;
|
||||
if (*buffer) {
|
||||
Blizzard::String::Append(buffer, " ", buffersize);
|
||||
|
||||
auto a = argument;
|
||||
while (*a++) {
|
||||
if (*a == ' ' || *a == '"') {
|
||||
escape = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// first argument is always quoted
|
||||
escape = true;
|
||||
}
|
||||
|
||||
if (escape) {
|
||||
auto a = argument;
|
||||
|
||||
auto dst = buffer;
|
||||
auto dstend = buffer + buffersize - 1;
|
||||
while (dst < dstend && *dst) {
|
||||
dst++;
|
||||
}
|
||||
|
||||
if (dst < dstend) {
|
||||
*dst++ = '"';
|
||||
}
|
||||
|
||||
while (dst < dstend && *a) {
|
||||
if (*a == '"') {
|
||||
if (dst+1 == dstend) {
|
||||
break;
|
||||
}
|
||||
*dst++ = '\\';
|
||||
*dst++ = '"';
|
||||
} else {
|
||||
*dst++ = *a;
|
||||
}
|
||||
a++;
|
||||
}
|
||||
|
||||
if (dst < dstend) {
|
||||
*dst++ = '"';
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
} else {
|
||||
Blizzard::String::Append(buffer, argument, buffersize);
|
||||
}
|
||||
}
|
||||
|
||||
const char* OsGetCommandLine() {
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
return GetCommandLine();
|
||||
|
|
@ -24,40 +79,11 @@ const char* OsGetCommandLine() {
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string QuoteArgument(std::string argument) {
|
||||
std::string result = "";
|
||||
|
||||
result += "\"";
|
||||
result += argument;
|
||||
result += "\"";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string CheckArgument(std::string argument) {
|
||||
for (size_t i = 0; i < argument.length(); i++) {
|
||||
switch (argument.at(i)) {
|
||||
case '\"':
|
||||
case ' ':
|
||||
return QuoteArgument(argument);
|
||||
}
|
||||
}
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
void OsSetCommandLine(int32_t argc, char** argv) {
|
||||
int32_t i = 0;
|
||||
std::string result = "";
|
||||
|
||||
void OsSetCommandLine(int argc, char* argv[]) {
|
||||
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
|
||||
int i = 0;
|
||||
while (i < argc) {
|
||||
if (i > 0) {
|
||||
result += " ";
|
||||
}
|
||||
|
||||
result += CheckArgument(argv[i]);
|
||||
i++;
|
||||
append_commandline(commandline, sizeof(commandline), argv[i]);
|
||||
}
|
||||
|
||||
strncpy(commandline, result.c_str(), sizeof(commandline));
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
#ifndef BC_OS_COMMAND_LINE_HPP
|
||||
#define BC_OS_COMMAND_LINE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
const char* OsGetCommandLine();
|
||||
|
||||
void OsSetCommandLine(int32_t argc, char** argv);
|
||||
void OsSetCommandLine(int argc, char* argv[]);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
166
bc/os/File.cpp
166
bc/os/File.cpp
|
|
@ -1,166 +0,0 @@
|
|||
#include "bc/os/File.hpp"
|
||||
#include "bc/file/Defines.hpp"
|
||||
#include "bc/file/File.hpp"
|
||||
#include "bc/Debug.hpp"
|
||||
|
||||
HOSFILE OsCreateFile(const char* fileName, uint32_t desiredAccess, uint32_t shareMode, uint32_t createDisposition, uint32_t flagsAndAttributes, uint32_t extendedFileType) {
|
||||
// Ensure sanity
|
||||
BLIZZARD_VALIDATE(fileName, "invalid filename", HOSFILE_INVALID);
|
||||
BLIZZARD_VALIDATE(desiredAccess != 0, "invalid desired access", HOSFILE_INVALID);
|
||||
BLIZZARD_VALIDATE(createDisposition <= OS_TRUNCATE_EXISTING, "invalid create disposition", HOSFILE_INVALID);
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
||||
// Read/write flags
|
||||
if (desiredAccess & OS_GENERIC_READ) {
|
||||
flags |= BC_FILE_OPEN_READ;
|
||||
}
|
||||
if (desiredAccess & OS_GENERIC_WRITE) {
|
||||
flags |= BC_FILE_OPEN_WRITE;
|
||||
}
|
||||
|
||||
// Allow other users to access the file in read and/or write mode
|
||||
if (shareMode & OS_FILE_SHARE_READ) {
|
||||
flags |= BC_FILE_OPEN_SHARE_READ;
|
||||
}
|
||||
if (shareMode & OS_FILE_SHARE_WRITE) {
|
||||
flags |= BC_FILE_OPEN_SHARE_WRITE;
|
||||
}
|
||||
|
||||
// Convert createDisposition into BC flags
|
||||
switch (createDisposition) {
|
||||
case OS_CREATE_NEW:
|
||||
// flags |= 0xC00;
|
||||
flags |= BC_FILE_OPEN_CREATE | BC_FILE_OPEN_MUST_NOT_EXIST;
|
||||
break;
|
||||
case OS_CREATE_ALWAYS:
|
||||
// flags |= 0x400;
|
||||
flags |= BC_FILE_OPEN_CREATE;
|
||||
break;
|
||||
case OS_OPEN_EXISTING:
|
||||
// flags |= 0x1000
|
||||
flags |= BC_FILE_OPEN_MUST_EXIST;
|
||||
break;
|
||||
case OS_OPEN_ALWAYS:
|
||||
// flags |= 0x200;
|
||||
flags |= BC_FILE_OPEN_ALWAYS;
|
||||
break;
|
||||
case OS_TRUNCATE_EXISTING:
|
||||
// flags |= 0x100;
|
||||
flags |= BC_FILE_OPEN_TRUNCATE;
|
||||
break;
|
||||
}
|
||||
|
||||
// Open file
|
||||
Blizzard::File::StreamRecord* stream;
|
||||
bool success = Blizzard::File::Open(fileName, flags, stream);
|
||||
if (!success) {
|
||||
return HOSFILE_INVALID;
|
||||
}
|
||||
|
||||
// Set attributes
|
||||
OsSetFileAttributes(fileName, flagsAndAttributes);
|
||||
return stream;
|
||||
}
|
||||
|
||||
int32_t OsSetFileAttributes(const char* fileName, uint32_t attributes) {
|
||||
BLIZZARD_ASSERT(fileName);
|
||||
|
||||
// Translate OS file attribute bits into BlizzardCore attribute bits.
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (attributes & OS_FILE_ATTRIBUTE_READONLY) {
|
||||
// flags |= 1;
|
||||
flags |= BC_FILE_ATTRIBUTE_READONLY;
|
||||
}
|
||||
if (attributes & OS_FILE_ATTRIBUTE_HIDDEN) {
|
||||
// flags |= 2;
|
||||
flags |= BC_FILE_ATTRIBUTE_HIDDEN;
|
||||
}
|
||||
if (attributes & OS_FILE_ATTRIBUTE_SYSTEM) {
|
||||
// flags |= 4
|
||||
flags |= BC_FILE_ATTRIBUTE_SYSTEM;
|
||||
}
|
||||
if (attributes & OS_FILE_ATTRIBUTE_ARCHIVE) {
|
||||
// flags |= 8;
|
||||
flags |= BC_FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
if (attributes & OS_FILE_ATTRIBUTE_TEMPORARY) {
|
||||
// flags |= 0x10;
|
||||
flags |= BC_FILE_ATTRIBUTE_TEMPORARY;
|
||||
}
|
||||
if (attributes & OS_FILE_ATTRIBUTE_NORMAL) {
|
||||
// flags |= 0x20;
|
||||
flags |= BC_FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
if (attributes & OS_FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// flags |= 0x40;
|
||||
flags |= BC_FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
return Blizzard::File::SetAttributes(fileName, flags);
|
||||
}
|
||||
|
||||
uint64_t OsGetFileSize(HOSFILE fileHandle) {
|
||||
auto info = Blizzard::File::GetFileInfo(reinterpret_cast<Blizzard::File::StreamRecord*>(fileHandle));
|
||||
return info->size;
|
||||
}
|
||||
|
||||
int32_t OsReadFile(HOSFILE fileHandle, void* buffer, size_t bytesToRead, size_t* bytesRead) {
|
||||
BLIZZARD_ASSERT(buffer);
|
||||
BLIZZARD_ASSERT(bytesToRead);
|
||||
|
||||
return Blizzard::File::Read(fileHandle, buffer, bytesToRead, bytesRead);
|
||||
}
|
||||
|
||||
int32_t OsWriteFile(HOSFILE fileHandle, void* buffer, size_t bytesToWrite, size_t* bytesWritten) {
|
||||
if (buffer != nullptr && bytesToWrite != 0) {
|
||||
return Blizzard::File::Write(fileHandle, buffer, bytesToWrite, bytesWritten);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t OsSetFilePointer(HOSFILE fileHandle, int64_t distanceToMove, uint32_t moveMethod) {
|
||||
BLIZZARD_ASSERT(moveMethod <= 2);
|
||||
|
||||
int64_t position;
|
||||
|
||||
if (moveMethod != 0 && !Blizzard::File::GetPos(fileHandle, position)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t seeks[3] = {
|
||||
BC_FILE_SEEK_START,
|
||||
BC_FILE_SEEK_CURRENT,
|
||||
BC_FILE_SEEK_END
|
||||
};
|
||||
|
||||
if (!Blizzard::File::SetPos(fileHandle, position, seeks[moveMethod])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return position + distanceToMove;
|
||||
}
|
||||
|
||||
void OsCloseFile(HOSFILE fileHandle) {
|
||||
Blizzard::File::Close(static_cast<Blizzard::File::StreamRecord*>(fileHandle));
|
||||
}
|
||||
|
||||
int32_t OsSetCurrentDirectory(const char* pathName) {
|
||||
BLIZZARD_ASSERT(pathName);
|
||||
|
||||
return Blizzard::File::SetWorkingDirectory(pathName);
|
||||
}
|
||||
|
||||
int32_t OsGetCurrentDirectory(size_t pathLen, char* pathName) {
|
||||
BLIZZARD_ASSERT(pathName);
|
||||
|
||||
return Blizzard::File::GetWorkingDirectory(pathName, pathLen);
|
||||
}
|
||||
|
||||
int32_t OsCreateDirectory(const char* pathName, int32_t recursive) {
|
||||
BLIZZARD_ASSERT(pathName);
|
||||
|
||||
return Blizzard::File::CreateDirectory(pathName, recursive == 1);
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
#include "bc/os/Path.hpp"
|
||||
#include "bc/String.hpp"
|
||||
#include "bc/file/Path.hpp"
|
||||
|
||||
// Win32
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
|
|
@ -12,54 +11,54 @@
|
|||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
// procfs
|
||||
#if defined(WHOA_SYSTEM_LINUX)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Get the full path of the currently running .exe/ELF/Mach-O executable
|
||||
void OsGetExeName(char* buffer, size_t chars) {
|
||||
void OsGetExeName(char* buffer, uint32_t buffersize) {
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
// Win32
|
||||
GetModuleFileName(nullptr, buffer, chars);
|
||||
::GetModuleFileName(nullptr, buffer, buffersize);
|
||||
#endif
|
||||
|
||||
#if defined(WHOA_SYSTEM_MAC)
|
||||
// Darwin
|
||||
char path[1024] = {0};
|
||||
uint32_t bufsize = 1024;
|
||||
_NSGetExecutablePath(path, &bufsize);
|
||||
char executablepathbuffer[4096];
|
||||
uint32_t executablepathbuffersize = sizeof(executablepathbuffer);
|
||||
::_NSGetExecutablePath(executable, &executablepathbuffersize);
|
||||
|
||||
char actualPath[1024] = {0};
|
||||
realpath(path, actualPath);
|
||||
char realpathbuffer[4096];
|
||||
::realpath(executablepathbuffer, realpathbuffer);
|
||||
|
||||
Blizzard::File::Path::MakeBackslashPath(actualPath, buffer, chars);
|
||||
Blizzard::String::Copy(buffer, realpathbuffer, buffersize);
|
||||
#endif
|
||||
|
||||
#if defined(WHOA_SYSTEM_LINUX)
|
||||
// procfs
|
||||
char actualPath[4096] = {0};
|
||||
readlink("/proc/self/exe", actualPath, chars);
|
||||
Blizzard::File::Path::MakeBackslashPath(actualPath, buffer, chars);
|
||||
if (::readlink("/proc/self/exe", buffer, buffersize) == -1) {
|
||||
*buffer = '\0';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void OsPathStripFilename(char* path) {
|
||||
auto length = Blizzard::String::Length(path);
|
||||
|
||||
char* head = &path[length-1];
|
||||
|
||||
while ((head != (path-1)) && (*head != '\0')) {
|
||||
if (*head == '\\') {
|
||||
*(head + 1) = '\0';
|
||||
break;
|
||||
void OsPathStripFilename(char* name) {
|
||||
auto n = name;
|
||||
while (*n) {
|
||||
n++;
|
||||
}
|
||||
if (n > name) {
|
||||
while (n > name) {
|
||||
if (*n == '/' || *n == '\\') {
|
||||
break;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
head--;
|
||||
|
||||
*n = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Get the directory containing the currently running executable
|
||||
void OsGetExePath(char* dest, size_t chars) {
|
||||
OsGetExeName(dest, chars);
|
||||
OsPathStripFilename(dest);
|
||||
void OsGetExePath(char* buffer, uint32_t buffersize) {
|
||||
OsGetExeName(buffer, buffersize);
|
||||
OsPathStripFilename(buffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#ifndef BC_OS_PATH_HPP
|
||||
#define BC_OS_PATH_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
void OsGetExePath(char* buffer, size_t chars);
|
||||
void OsGetExePath(char* buffer, uint32_t buffersize);
|
||||
|
||||
void OsGetExeName(char* buffer, size_t chars);
|
||||
void OsGetExeName(char* buffer, uint32_t buffersize);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
31
bc/string/Append.cpp
Normal file
31
bc/string/Append.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#include "bc/string/Append.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
int32_t Append(char* dst, const char* src, uint32_t count) {
|
||||
if (count == 0 || dst == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto dstend = dst + count;
|
||||
while (dst < dstend && *dst) {
|
||||
dst++;
|
||||
}
|
||||
if (dstend <= dst) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto dststart = dst;
|
||||
|
||||
while (dst < dstend && *src) {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
|
||||
return dst - dststart;
|
||||
}
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
14
bc/string/Append.hpp
Normal file
14
bc/string/Append.hpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef BC_STRING_APPEND_HPP
|
||||
#define BC_STRING_APPEND_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
int32_t Append(char* dst, const char* src, uint32_t count);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
42
bc/string/Copy.cpp
Normal file
42
bc/string/Copy.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#include "bc/string/Copy.hpp"
|
||||
#include <cstring>
|
||||
|
||||
int32_t Blizzard::String::Copy(char* dst, const char* src, uint32_t count) {
|
||||
if (!count || !dst) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!src) {
|
||||
*dst = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* v3 = dst + count - 1;
|
||||
|
||||
char v4;
|
||||
const char* v5;
|
||||
char* v6;
|
||||
|
||||
int32_t result;
|
||||
|
||||
if (dst < v3 && (v4 = *src, v5 = src, v6 = dst, *src)) {
|
||||
do {
|
||||
*v6++ = v4;
|
||||
|
||||
if (v3 <= v6) {
|
||||
break;
|
||||
}
|
||||
|
||||
v4 = (v5++)[1];
|
||||
} while (v4);
|
||||
|
||||
result = v6 - dst;
|
||||
} else {
|
||||
v6 = dst;
|
||||
result = 0;
|
||||
}
|
||||
|
||||
*v6 = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
14
bc/string/Copy.hpp
Normal file
14
bc/string/Copy.hpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef BC_STRING_COPY_HPP
|
||||
#define BC_STRING_COPY_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
int32_t Copy(char* dst, const char* src, uint32_t count);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
13
bc/string/Defines.hpp
Normal file
13
bc/string/Defines.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef BC_STRING_DEFINES_HPP
|
||||
#define BC_STRING_DEFINES_HPP
|
||||
|
||||
// How many bytes to when translating stacked filesystem names to large, native file paths
|
||||
#define BC_STRING_MAX_PATH 1024
|
||||
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
#define BC_STRING_PATH_SEPARATOR '\\'
|
||||
#else
|
||||
#define BC_STRING_PATH_SEPARATOR '/'
|
||||
#endif
|
||||
|
||||
#endif
|
||||
23
bc/string/Equal.cpp
Normal file
23
bc/string/Equal.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#include "bc/string/Equal.hpp"
|
||||
#include <cstring>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
bool Equal(const char* a, const char* b) {
|
||||
if (a && b) {
|
||||
return strcmp(a, b);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EqualI(const char* a, const char* b, uint32_t count) {
|
||||
if (a && b) {
|
||||
return strncasecmp(a, b, count);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
16
bc/string/Equal.hpp
Normal file
16
bc/string/Equal.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef BC_STRING_EQUAL_HPP
|
||||
#define BC_STRING_EQUAL_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
bool Equal(const char* a, const char* b);
|
||||
|
||||
bool EqualI(const char* a, const char* b, uint32_t count);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
39
bc/string/Find.cpp
Normal file
39
bc/string/Find.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include "bc/string/Find.hpp"
|
||||
|
||||
char* Blizzard::String::Find(char* str, char ch, int32_t count) {
|
||||
if (!str || !ch) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ptr = str;
|
||||
auto end = str + count;
|
||||
|
||||
while (ptr != end && *ptr) {
|
||||
if (ch == *ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* Find(const char* str, char ch, int32_t count) {
|
||||
if (!str || !ch) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto ptr = str;
|
||||
auto end = str + count;
|
||||
|
||||
while (ptr != end && *ptr) {
|
||||
if (ch == *ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
16
bc/string/Find.hpp
Normal file
16
bc/string/Find.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef BC_STRING_FIND_HPP
|
||||
#define BC_STRING_FIND_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
char* Find(char* str, char ch, int32_t count);
|
||||
|
||||
const char* Find(const char* str, char ch, int32_t count);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
60
bc/string/Format.cpp
Normal file
60
bc/string/Format.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
#include "bc/string/Format.hpp"
|
||||
#include "bc/string/Translate.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
void Format(char* buffer, uint32_t buffersize, const char* format, ...) {
|
||||
if (!buffer || buffersize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!format && buffersize >= 1) {
|
||||
*buffer = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
auto formatNative = format;
|
||||
|
||||
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
|
||||
constexpr size_t translatedSize = 2048;
|
||||
|
||||
// POSIX formatting convention requires %ll for 64-bit printing
|
||||
// find & replace all instances of %I64 with %ll
|
||||
char translated[translatedSize] = {0};
|
||||
|
||||
Translate(format, translated, translatedSize, "%I64", "%ll");
|
||||
|
||||
formatNative = translated;
|
||||
#endif
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
vsnprintf(buffer, buffersize, formatNative, args);
|
||||
|
||||
*buffer = '\0';
|
||||
}
|
||||
|
||||
void VFormat(char* buffer, uint32_t buffersize, const char* format, va_list args) {
|
||||
auto formatNative = format;
|
||||
|
||||
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
|
||||
char translatedformat[0x800];
|
||||
Translate(format, translatedformat, 0x800, "%I64", "%ll");
|
||||
formatNative = buffer;
|
||||
#endif
|
||||
if (format == nullptr) {
|
||||
if (buffer) {
|
||||
*buffer = '\0';
|
||||
}
|
||||
} else {
|
||||
vsnprintf(buffer, buffersize, formatNative, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
17
bc/string/Format.hpp
Normal file
17
bc/string/Format.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef BC_STRING_FORMAT_HPP
|
||||
#define BC_STRING_FORMAT_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdarg>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
void Format(char* buffer, uint32_t buffersize, const char* format, ...);
|
||||
|
||||
void VFormat(char* buffer, uint32_t buffersize, const char* format, va_list args);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
10
bc/string/Length.cpp
Normal file
10
bc/string/Length.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "bc/string/Length.hpp"
|
||||
#include <cstring>
|
||||
|
||||
uint32_t Blizzard::String::Length(const char* str) {
|
||||
if (str) {
|
||||
return strlen(str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
15
bc/string/Length.hpp
Normal file
15
bc/string/Length.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef BC_STRING_LENGTH_HPP
|
||||
#define BC_STRING_LENGTH_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
uint32_t Length(const char* str);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
|
||||
#endif
|
||||
22
bc/string/Memory.cpp
Normal file
22
bc/string/Memory.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#include "bc/string/Memory.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
void MemFill(void* dst, int32_t count, uint8_t fill) {
|
||||
memset(dst, fill, count);
|
||||
}
|
||||
|
||||
int32_t MemCompare(void* p1, void *p2, int32_t count) {
|
||||
return memcmp(p1, p2, count);
|
||||
}
|
||||
|
||||
void MemCopy(void* dst, const void* src, int32_t count) {
|
||||
memmove(dst, src, count);
|
||||
}
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
18
bc/string/Memory.hpp
Normal file
18
bc/string/Memory.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef BC_STRING_MEMORY_HPP
|
||||
#define BC_STRING_MEMORY_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
void MemFill(void* dst, int32_t count, uint8_t fill);
|
||||
|
||||
int32_t MemCompare(void* p1, void *p2, int32_t count);
|
||||
|
||||
void MemCopy(void* dst, const void* src, int32_t count);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
192
bc/string/Path.cpp
Normal file
192
bc/string/Path.cpp
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
#include "bc/string/Path.hpp"
|
||||
#include "bc/Debug.hpp"
|
||||
#include "bc/string/Defines.hpp"
|
||||
#include "bc/string/Length.hpp"
|
||||
#include "bc/string/Copy.hpp"
|
||||
#include "bc/string/Append.hpp"
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
static char s_empty[] = { 0 };
|
||||
|
||||
char* FindFilename(char* str) {
|
||||
char ch = 0;
|
||||
char* result = nullptr;
|
||||
auto ptr = str;
|
||||
|
||||
if (str == nullptr) {
|
||||
return s_empty;
|
||||
}
|
||||
|
||||
do {
|
||||
do {
|
||||
result = ptr;
|
||||
ch = *str;
|
||||
ptr = ++str;
|
||||
} while (ch == '/');
|
||||
} while ((ch == '\\') || (ptr = result, ch != '\0'));
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* FindFilename(const char* str) {
|
||||
char ch = 0;
|
||||
const char* result = nullptr;
|
||||
auto ptr = str;
|
||||
|
||||
if (str == nullptr) {
|
||||
return s_empty;
|
||||
}
|
||||
|
||||
do {
|
||||
do {
|
||||
result = ptr;
|
||||
ch = *str;
|
||||
ptr = ++str;
|
||||
} while (ch == '/');
|
||||
} while ((ch == '\\') || (ptr = result, ch != '\0'));
|
||||
return result;
|
||||
}
|
||||
|
||||
char FirstPathSeparator(const char* str) {
|
||||
while (*str) {
|
||||
if (*str == '/' || *str == '\\') {
|
||||
return *str;
|
||||
}
|
||||
|
||||
str++;
|
||||
}
|
||||
|
||||
return BC_STRING_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
void ForceTrailingSeparator(char* buf, int32_t bufMax, char separator) {
|
||||
if (buf == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (separator == '\0') {
|
||||
separator = FirstPathSeparator(buf);
|
||||
}
|
||||
|
||||
// buffer needs at least two characters.
|
||||
if (bufMax < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// slice off the end of the path buffer,
|
||||
// so that any existing* trailing separator is discarded.
|
||||
auto len = Length(buf);
|
||||
char last = '\0';
|
||||
if (len > 0) {
|
||||
last = buf[len - 1];
|
||||
}
|
||||
switch (last) {
|
||||
case '/':
|
||||
case '\\':
|
||||
len--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Add (back*) trailing separator
|
||||
BLIZZARD_ASSERT(len <= bufMax - 2);
|
||||
buf[len] = separator;
|
||||
buf[len + 1] = '\0'; // pad null
|
||||
}
|
||||
|
||||
void JoinPath(char* dst, int32_t count, const char* str1, const char* str2) {
|
||||
if (dst) {
|
||||
Copy(dst, str1, count);
|
||||
if (*dst) {
|
||||
ForceTrailingSeparator(dst, count, 0);
|
||||
}
|
||||
if (str2) {
|
||||
while (*str2 == '/' || *str2 == '\\') {
|
||||
str2++;
|
||||
}
|
||||
}
|
||||
Append(dst, str2, count);
|
||||
MakeConsistentPath(dst, dst, count);
|
||||
}
|
||||
}
|
||||
|
||||
char* MakeBackslashPath(const char* src, char* buffer, int32_t buffersize) {
|
||||
auto dst = buffer;
|
||||
if (buffer) {
|
||||
auto dstend = buffer + buffersize - 1;
|
||||
while (dst < dstend) {
|
||||
auto c = *src++;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
} else if (c == '/') {
|
||||
*dst = '\\';
|
||||
} else {
|
||||
*dst = c;
|
||||
}
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* MakeUnivPath(const char* src, char* buffer, int32_t buffersize) {
|
||||
auto dst = buffer;
|
||||
if (buffer) {
|
||||
auto dstend = buffer + buffersize - 1;
|
||||
while (dst < dstend) {
|
||||
auto c = *src++;
|
||||
if (c == '\0') {
|
||||
break;
|
||||
} else if (c == '\\') {
|
||||
*dst = '/';
|
||||
} else {
|
||||
*dst = c;
|
||||
}
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* MakeConsistentPath(const char* src, char* buffer, int32_t buffersize) {
|
||||
if (!buffer || (buffersize <= 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!src || (buffersize == 1)) {
|
||||
*buffer = '\0';
|
||||
return buffer;
|
||||
}
|
||||
|
||||
switch (FirstPathSeparator(src)) {
|
||||
case '\\':
|
||||
return MakeBackslashPath(src, buffer, buffersize);
|
||||
case '/':
|
||||
return MakeUnivPath(src, buffer, buffersize);
|
||||
}
|
||||
|
||||
Copy(buffer, src, buffersize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* MakeNativePath(const char* src, char* buffer, int32_t buffersize) {
|
||||
if (!src) {
|
||||
*buffer = '\0';
|
||||
return buffer;
|
||||
} else {
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
return MakeBackslashPath(src, buffer, buffersize);
|
||||
#else
|
||||
return MakeUnivPath(src, buffer, buffersize);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
30
bc/string/Path.hpp
Normal file
30
bc/string/Path.hpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef BC_STRING_PATH_HPP
|
||||
#define BC_STRING_PATH_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
const char* FindFilename(const char* str);
|
||||
|
||||
char* FindFilename(char* str);
|
||||
|
||||
char FirstPathSeparator(const char* str);
|
||||
|
||||
void ForceTrailingSeparator(char* buf, int32_t bufMax, char sep);
|
||||
|
||||
void JoinPath(char* dst, int32_t count, const char* str1, const char* str2);
|
||||
|
||||
char* MakeBackslashPath(const char* src, char* buffer, int32_t buffersize);
|
||||
|
||||
char* MakeConsistentPath(const char* src, char* buffer, int32_t buffersize);
|
||||
|
||||
char* MakeNativePath(const char* src, char* buffer, int32_t buffersize);
|
||||
|
||||
char* MakeUnivPath(const char* src, char* buffer, int32_t buffersize);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
32
bc/string/QuickFormat.hpp
Normal file
32
bc/string/QuickFormat.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef BC_STRING_QUICK_FORMAT_HPP
|
||||
#define BC_STRING_QUICK_FORMAT_HPP
|
||||
|
||||
#include "bc/string/Format.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
template<uint32_t N>
|
||||
class QuickFormat {
|
||||
private:
|
||||
char buffer[N];
|
||||
public:
|
||||
QuickFormat(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
VFormat(this->buffer, N, format, args);
|
||||
printf("QI %d '%s', '%s'\n", N, format, this->buffer);
|
||||
}
|
||||
|
||||
const char* ToString() {
|
||||
return this->buffer;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
46
bc/string/QuickNativePath.hpp
Normal file
46
bc/string/QuickNativePath.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef BC_STRING_QUICK_NATIVE_PATH_HPP
|
||||
#define BC_STRING_QUICK_NATIVE_PATH_HPP
|
||||
|
||||
#include "bc/String.hpp"
|
||||
#include "bc/Memory.hpp"
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
template <uint32_t N>
|
||||
class QuickNativePath {
|
||||
private:
|
||||
// string length of path, including NULL character
|
||||
uint32_t length;
|
||||
char* path;
|
||||
char buffer[N];
|
||||
|
||||
public:
|
||||
QuickNativePath(const char* name) {
|
||||
this->length = String::Length(name) + 1;
|
||||
|
||||
if (this->length > N) {
|
||||
this->path = reinterpret_cast<char*>(Memory::Allocate(this->length));
|
||||
MakeNativePath(name, this->path, this->length);
|
||||
} else {
|
||||
this->path = this->buffer;
|
||||
MakeNativePath(name, this->path, N);
|
||||
}
|
||||
}
|
||||
|
||||
~QuickNativePath() {
|
||||
if (this->path != this->buffer) {
|
||||
Memory::Free(this->path);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ToString() {
|
||||
return this->path;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
49
bc/string/Translate.cpp
Normal file
49
bc/string/Translate.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include "bc/string/Translate.hpp"
|
||||
#include "bc/string/Length.hpp"
|
||||
#include "bc/string/Memory.hpp"
|
||||
#include <cstring>
|
||||
|
||||
void Blizzard::String::Translate(const char* src, char* dst, int32_t dstmaxchars, const char* find, const char* replace) {
|
||||
if (dst == nullptr || find == nullptr || replace == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == nullptr) {
|
||||
src = dst;
|
||||
}
|
||||
|
||||
auto srcstart = src;
|
||||
auto dststart = dst;
|
||||
|
||||
auto dstmax = &dst[dstmaxchars - 1];
|
||||
auto srcmax = &src[Length(src) + 1];
|
||||
|
||||
auto findlength = Length(find);
|
||||
auto replacelength = Length(replace);
|
||||
while (dst < dstmax && src < srcmax) {
|
||||
auto srcchar = *src;
|
||||
|
||||
if (srcchar == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (srcchar == find[0]) {
|
||||
auto copylength = replacelength;
|
||||
if ((dst + copylength) >= dstmax) {
|
||||
copylength = dstmax - dst;
|
||||
}
|
||||
|
||||
auto substring = strstr(src, find);
|
||||
if (substring == src) {
|
||||
MemCopy(dst, replace, copylength);
|
||||
dst += replacelength;
|
||||
src += findlength;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
*dst = '\0';
|
||||
}
|
||||
14
bc/string/Translate.hpp
Normal file
14
bc/string/Translate.hpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef BC_STRING_TRANSLATE_HPP
|
||||
#define BC_STRING_TRANSLATE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace Blizzard {
|
||||
namespace String {
|
||||
|
||||
void Translate(const char* src, char* dst, int32_t dstmaxchars, const char* find, const char* replace);
|
||||
|
||||
} // namespace String
|
||||
} // namespace Blizzard
|
||||
|
||||
#endif
|
||||
|
|
@ -104,7 +104,7 @@ void TimeInit() {
|
|||
ULARGE_INTEGER ul = {};
|
||||
ul.HighPart = ft.dwHighDateTime;
|
||||
ul.LowPart = ft.dwLowDateTime;
|
||||
s_gmBegin = Time::FromWinFiletime(ul.QuadPart);
|
||||
s_gmBegin = Time::FromFileTime(ul.QuadPart);
|
||||
#endif
|
||||
|
||||
// Attempt to figure out the scale of TSC durations in real-time
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "bc/time/Time.hpp"
|
||||
#include "bc/time/TimeConst.hpp"
|
||||
#include "bc/system/System_Time.hpp"
|
||||
#include "bc/time/TimeConst.hpp"
|
||||
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
#include <windows.h>
|
||||
|
|
@ -70,25 +70,20 @@ Timestamp FromUnixTime(int32_t unixTime) {
|
|||
}
|
||||
|
||||
// Win32 FILETIME to y2k
|
||||
Timestamp FromWinFiletime(uint64_t winTime) {
|
||||
if (winTime < 33677863631452242ULL) {
|
||||
Timestamp FromFileTime(uint64_t filetime) {
|
||||
if (filetime < 33677863631452242ULL) {
|
||||
return std::numeric_limits<Timestamp>::min();
|
||||
}
|
||||
|
||||
if (winTime >= 218145301729837567ULL) {
|
||||
return std::numeric_limits<Timestamp>::max();;
|
||||
if (filetime >= 218145301729837567ULL) {
|
||||
return std::numeric_limits<Timestamp>::max();
|
||||
}
|
||||
|
||||
// 1601 (Gregorian) 100-nsec
|
||||
auto gregorian = static_cast<int64_t>(winTime);
|
||||
// Convert filetime from 1601 epoch to 2000 epoch.
|
||||
auto y2k = gregorian - TimeConst::WinFiletimeY2kDifference;
|
||||
// Convert 100-nsec intervals into nsec intervals
|
||||
return static_cast<Time::Timestamp>(y2k * 100LL);
|
||||
return (static_cast<Time::Timestamp>(filetime) * 100LL) + ~(TimeConst::FileTimeDelta*100LL) + 1;
|
||||
}
|
||||
|
||||
uint64_t ToWinFiletime(Timestamp y2k) {
|
||||
return (y2k + TimeConst::WinFiletimeY2kDifference) / 100ULL;
|
||||
uint64_t ToFileTime(Timestamp y2k) {
|
||||
return (static_cast<uint64_t>(y2k) + TimeConst::FileTimeDelta) / 100ULL;
|
||||
}
|
||||
|
||||
int32_t GetTimeElapsed(uint32_t start, uint32_t end) {
|
||||
|
|
@ -123,7 +118,7 @@ Timestamp MakeTime(const TimeRec& date) {
|
|||
|
||||
#if defined(WHOA_SYSTEM_WIN)
|
||||
// Win32 implementation
|
||||
FILETIME fileTime = {};
|
||||
FILETIME fileTime = {};
|
||||
SYSTEMTIME systemTime = {};
|
||||
|
||||
systemTime.wYear = static_cast<WORD>(date.year);
|
||||
|
|
@ -135,19 +130,14 @@ Timestamp MakeTime(const TimeRec& date) {
|
|||
systemTime.wMilliseconds = 0;
|
||||
|
||||
::SystemTimeToFileTime(&systemTime, &fileTime);
|
||||
|
||||
ULARGE_INTEGER ul = {};
|
||||
ul.HighPart = fileTime.dwHighDateTime;
|
||||
ul.LowPart = fileTime.dwLowDateTime;
|
||||
|
||||
timestamp = FromWinFiletime(ul.QuadPart);
|
||||
timestamp = FromFileTime(static_cast<uint64_t>(fileTime.dwHighDateTime) << 32 | static_cast<uint64_t>(fileTime.dwLowDateTime));
|
||||
#endif
|
||||
|
||||
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
|
||||
// UNIX implementation
|
||||
struct tm t;
|
||||
|
||||
t.tm_year = date.year - 1900;
|
||||
t.tm_year = date.year - 1900;
|
||||
t.tm_mon = date.month - 1;
|
||||
t.tm_mday = date.day;
|
||||
t.tm_hour = date.hour;
|
||||
|
|
@ -156,7 +146,7 @@ Timestamp MakeTime(const TimeRec& date) {
|
|||
|
||||
// Convert date into UNIX timestamp
|
||||
auto unixTime = ::timegm(&t);
|
||||
timestamp = FromUnixTime(unixTime);
|
||||
timestamp = FromUnixTime(unixTime);
|
||||
#endif
|
||||
// Add nsec to result
|
||||
auto nsec = date.nsec;
|
||||
|
|
@ -182,12 +172,12 @@ void BreakTime(Timestamp timestamp, TimeRec& date) {
|
|||
#if defined(WHOA_SYSTEM_WIN)
|
||||
// Win32 implementation
|
||||
ULARGE_INTEGER ul = {};
|
||||
ul.QuadPart = ToWinFiletime(timestamp);
|
||||
ul.QuadPart = ToFileTime(timestamp);
|
||||
|
||||
FILETIME fileTime = {};
|
||||
FILETIME fileTime = {};
|
||||
fileTime.dwHighDateTime = ul.HighPart;
|
||||
fileTime.dwLowDateTime = ul.LowPart;
|
||||
SYSTEMTIME systemTime = {};
|
||||
SYSTEMTIME systemTime = {};
|
||||
::FileTimeToSystemTime(&fileTime, &systemTime);
|
||||
|
||||
date.day = static_cast<uint32_t>(systemTime.wDay);
|
||||
|
|
@ -201,6 +191,7 @@ void BreakTime(Timestamp timestamp, TimeRec& date) {
|
|||
bool leapYear = (date.year % 400 == 0) || (date.year % 100 != 0 && ((systemTime.wYear & 3) == 0));
|
||||
|
||||
auto yearDay = s_monthDays[date.month] + -1 + static_cast<uint32_t>(systemTime.wDay);
|
||||
|
||||
date.yday = yearDay;
|
||||
if (leapYear && date.month > 2) {
|
||||
date.yday++;
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ int32_t ToUnixTime(Timestamp timestamp);
|
|||
Timestamp FromUnixTime(int32_t unixTime);
|
||||
|
||||
// Win32 FILETIME to y2k
|
||||
Timestamp FromWinFiletime(uint64_t winTime);
|
||||
Timestamp FromFileTime(uint64_t filetime);
|
||||
|
||||
uint64_t ToWinFiletime(Timestamp y2k);
|
||||
uint64_t ToFileTime(Timestamp y2k);
|
||||
|
||||
Timestamp GetTimestamp();
|
||||
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ namespace TimeConst {
|
|||
constexpr int64_t TimestampsPerSecond = 1000000000ULL;
|
||||
|
||||
// amount of win32 filetime units in a second
|
||||
constexpr int64_t WinUnitsPerSecond = (TimestampsPerSecond / 100ULL);
|
||||
constexpr int64_t FileTimeUnitsPerSecond = (TimestampsPerSecond / 100LL);
|
||||
|
||||
// the FILETIME value needed to move from 1601 epoch to the Year 2000 epoch that Blizzard prefers
|
||||
constexpr int64_t WinFiletimeY2kDifference = 125911584000000000ULL;
|
||||
constexpr uint64_t FileTimeDelta = 125911584000000000ULL;
|
||||
|
||||
} // namespace TimeConst
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue