refactor(bc): improve consistency (across platforms esp.) and readability of string conversion

This commit is contained in:
phaneron 2025-03-15 22:25:07 -04:00
parent 5d96890167
commit 99f6576a12
35 changed files with 1106 additions and 624 deletions

View file

@ -1,25 +1,18 @@
file(GLOB BC_SOURCES file(GLOB BC_SOURCES
"*.cpp" "*.cpp"
"memory/*.cpp" "string/*.cpp"
"lock/*.cpp"
"os/*.cpp"
"file/*.cpp" "file/*.cpp"
"file/path/*.cpp" "lock/*.cpp"
"time/*.cpp" "memory/*.cpp"
"os/*.cpp"
"os/file/*.cpp"
"system/*.cpp" "system/*.cpp"
"system/file/*.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 add_library(bc STATIC
${BC_SOURCES} ${BC_SOURCES}
) )

View file

@ -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

View file

@ -1,66 +1,16 @@
#ifndef BC_STRING_HPP #ifndef BC_STRING_HPP
#define BC_STRING_HPP #define BC_STRING_HPP
#include <cstdint> #include "bc/string/Append.hpp"
#include <cstdlib> #include "bc/string/Copy.hpp"
#include <cstdarg> #include "bc/string/Defines.hpp"
#include "bc/string/Find.hpp"
#if defined(WHOA_SYSTEM_WIN) #include "bc/string/Format.hpp"
#define BC_FILE_SYSTEM_PATH_SEPARATOR '\\' #include "bc/string/Length.hpp"
#else #include "bc/string/Memory.hpp"
#define BC_FILE_SYSTEM_PATH_SEPARATOR '/' #include "bc/string/Path.hpp"
#endif #include "bc/string/QuickFormat.hpp"
#include "bc/string/QuickNativePath.hpp"
namespace Blizzard { #include "bc/string/Translate.hpp"
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
#endif #endif

239
bc/Unicode.cpp Normal file
View 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
View 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

View file

@ -1,7 +1,6 @@
#include "bc/os/CommandLine.hpp" #include "bc/os/CommandLine.hpp"
#include "bc/Debug.hpp" #include "bc/string/Append.hpp"
#include <string>
#include <cstring> #include <cstring>
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
@ -10,10 +9,66 @@
// Variables // Variables
char commandline[1024] = {0}; #if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
char commandline[65535];
#endif
// Functions // 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() { const char* OsGetCommandLine() {
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
return GetCommandLine(); return GetCommandLine();
@ -24,40 +79,11 @@ const char* OsGetCommandLine() {
#endif #endif
} }
std::string QuoteArgument(std::string argument) { void OsSetCommandLine(int argc, char* argv[]) {
std::string result = ""; #if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
int i = 0;
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 = "";
while (i < argc) { while (i < argc) {
if (i > 0) { append_commandline(commandline, sizeof(commandline), argv[i]);
result += " ";
}
result += CheckArgument(argv[i]);
i++;
} }
#endif
strncpy(commandline, result.c_str(), sizeof(commandline));
} }

View file

@ -1,10 +1,8 @@
#ifndef BC_OS_COMMAND_LINE_HPP #ifndef BC_OS_COMMAND_LINE_HPP
#define BC_OS_COMMAND_LINE_HPP #define BC_OS_COMMAND_LINE_HPP
#include <cstdint>
const char* OsGetCommandLine(); const char* OsGetCommandLine();
void OsSetCommandLine(int32_t argc, char** argv); void OsSetCommandLine(int argc, char* argv[]);
#endif #endif

View file

@ -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);
}

View file

@ -1,6 +1,5 @@
#include "bc/os/Path.hpp" #include "bc/os/Path.hpp"
#include "bc/String.hpp" #include "bc/String.hpp"
#include "bc/file/Path.hpp"
// Win32 // Win32
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
@ -12,54 +11,54 @@
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#endif #endif
// procfs
#if defined(WHOA_SYSTEM_LINUX) #if defined(WHOA_SYSTEM_LINUX)
#include <unistd.h> #include <unistd.h>
#endif #endif
// Get the full path of the currently running .exe/ELF/Mach-O executable // 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) #if defined(WHOA_SYSTEM_WIN)
// Win32 ::GetModuleFileName(nullptr, buffer, buffersize);
GetModuleFileName(nullptr, buffer, chars);
#endif #endif
#if defined(WHOA_SYSTEM_MAC) #if defined(WHOA_SYSTEM_MAC)
// Darwin char executablepathbuffer[4096];
char path[1024] = {0}; uint32_t executablepathbuffersize = sizeof(executablepathbuffer);
uint32_t bufsize = 1024; ::_NSGetExecutablePath(executable, &executablepathbuffersize);
_NSGetExecutablePath(path, &bufsize);
char actualPath[1024] = {0}; char realpathbuffer[4096];
realpath(path, actualPath); ::realpath(executablepathbuffer, realpathbuffer);
Blizzard::File::Path::MakeBackslashPath(actualPath, buffer, chars); Blizzard::String::Copy(buffer, realpathbuffer, buffersize);
#endif #endif
#if defined(WHOA_SYSTEM_LINUX) #if defined(WHOA_SYSTEM_LINUX)
// procfs // procfs
char actualPath[4096] = {0}; if (::readlink("/proc/self/exe", buffer, buffersize) == -1) {
readlink("/proc/self/exe", actualPath, chars); *buffer = '\0';
Blizzard::File::Path::MakeBackslashPath(actualPath, buffer, chars); }
#endif #endif
} }
void OsPathStripFilename(char* path) { void OsPathStripFilename(char* name) {
auto length = Blizzard::String::Length(path); auto n = name;
while (*n) {
char* head = &path[length-1]; n++;
}
while ((head != (path-1)) && (*head != '\0')) { if (n > name) {
if (*head == '\\') { while (n > name) {
*(head + 1) = '\0'; if (*n == '/' || *n == '\\') {
break; break;
}
n--;
} }
head--;
*n = '\0';
} }
} }
// Get the directory containing the currently running executable // Get the directory containing the currently running executable
void OsGetExePath(char* dest, size_t chars) { void OsGetExePath(char* buffer, uint32_t buffersize) {
OsGetExeName(dest, chars); OsGetExeName(buffer, buffersize);
OsPathStripFilename(dest); OsPathStripFilename(buffer);
} }

View file

@ -1,10 +1,10 @@
#ifndef BC_OS_PATH_HPP #ifndef BC_OS_PATH_HPP
#define 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 #endif

31
bc/string/Append.cpp Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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
View 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

View file

@ -104,7 +104,7 @@ void TimeInit() {
ULARGE_INTEGER ul = {}; ULARGE_INTEGER ul = {};
ul.HighPart = ft.dwHighDateTime; ul.HighPart = ft.dwHighDateTime;
ul.LowPart = ft.dwLowDateTime; ul.LowPart = ft.dwLowDateTime;
s_gmBegin = Time::FromWinFiletime(ul.QuadPart); s_gmBegin = Time::FromFileTime(ul.QuadPart);
#endif #endif
// Attempt to figure out the scale of TSC durations in real-time // Attempt to figure out the scale of TSC durations in real-time

View file

@ -1,6 +1,6 @@
#include "bc/time/Time.hpp" #include "bc/time/Time.hpp"
#include "bc/time/TimeConst.hpp"
#include "bc/system/System_Time.hpp" #include "bc/system/System_Time.hpp"
#include "bc/time/TimeConst.hpp"
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
#include <windows.h> #include <windows.h>
@ -70,25 +70,20 @@ Timestamp FromUnixTime(int32_t unixTime) {
} }
// Win32 FILETIME to y2k // Win32 FILETIME to y2k
Timestamp FromWinFiletime(uint64_t winTime) { Timestamp FromFileTime(uint64_t filetime) {
if (winTime < 33677863631452242ULL) { if (filetime < 33677863631452242ULL) {
return std::numeric_limits<Timestamp>::min(); return std::numeric_limits<Timestamp>::min();
} }
if (winTime >= 218145301729837567ULL) { if (filetime >= 218145301729837567ULL) {
return std::numeric_limits<Timestamp>::max();; return std::numeric_limits<Timestamp>::max();
} }
// 1601 (Gregorian) 100-nsec return (static_cast<Time::Timestamp>(filetime) * 100LL) + ~(TimeConst::FileTimeDelta*100LL) + 1;
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);
} }
uint64_t ToWinFiletime(Timestamp y2k) { uint64_t ToFileTime(Timestamp y2k) {
return (y2k + TimeConst::WinFiletimeY2kDifference) / 100ULL; return (static_cast<uint64_t>(y2k) + TimeConst::FileTimeDelta) / 100ULL;
} }
int32_t GetTimeElapsed(uint32_t start, uint32_t end) { int32_t GetTimeElapsed(uint32_t start, uint32_t end) {
@ -123,7 +118,7 @@ Timestamp MakeTime(const TimeRec& date) {
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
// Win32 implementation // Win32 implementation
FILETIME fileTime = {}; FILETIME fileTime = {};
SYSTEMTIME systemTime = {}; SYSTEMTIME systemTime = {};
systemTime.wYear = static_cast<WORD>(date.year); systemTime.wYear = static_cast<WORD>(date.year);
@ -135,19 +130,14 @@ Timestamp MakeTime(const TimeRec& date) {
systemTime.wMilliseconds = 0; systemTime.wMilliseconds = 0;
::SystemTimeToFileTime(&systemTime, &fileTime); ::SystemTimeToFileTime(&systemTime, &fileTime);
timestamp = FromFileTime(static_cast<uint64_t>(fileTime.dwHighDateTime) << 32 | static_cast<uint64_t>(fileTime.dwLowDateTime));
ULARGE_INTEGER ul = {};
ul.HighPart = fileTime.dwHighDateTime;
ul.LowPart = fileTime.dwLowDateTime;
timestamp = FromWinFiletime(ul.QuadPart);
#endif #endif
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) #if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
// UNIX implementation // UNIX implementation
struct tm t; struct tm t;
t.tm_year = date.year - 1900; t.tm_year = date.year - 1900;
t.tm_mon = date.month - 1; t.tm_mon = date.month - 1;
t.tm_mday = date.day; t.tm_mday = date.day;
t.tm_hour = date.hour; t.tm_hour = date.hour;
@ -156,7 +146,7 @@ Timestamp MakeTime(const TimeRec& date) {
// Convert date into UNIX timestamp // Convert date into UNIX timestamp
auto unixTime = ::timegm(&t); auto unixTime = ::timegm(&t);
timestamp = FromUnixTime(unixTime); timestamp = FromUnixTime(unixTime);
#endif #endif
// Add nsec to result // Add nsec to result
auto nsec = date.nsec; auto nsec = date.nsec;
@ -182,12 +172,12 @@ void BreakTime(Timestamp timestamp, TimeRec& date) {
#if defined(WHOA_SYSTEM_WIN) #if defined(WHOA_SYSTEM_WIN)
// Win32 implementation // Win32 implementation
ULARGE_INTEGER ul = {}; ULARGE_INTEGER ul = {};
ul.QuadPart = ToWinFiletime(timestamp); ul.QuadPart = ToFileTime(timestamp);
FILETIME fileTime = {}; FILETIME fileTime = {};
fileTime.dwHighDateTime = ul.HighPart; fileTime.dwHighDateTime = ul.HighPart;
fileTime.dwLowDateTime = ul.LowPart; fileTime.dwLowDateTime = ul.LowPart;
SYSTEMTIME systemTime = {}; SYSTEMTIME systemTime = {};
::FileTimeToSystemTime(&fileTime, &systemTime); ::FileTimeToSystemTime(&fileTime, &systemTime);
date.day = static_cast<uint32_t>(systemTime.wDay); 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)); 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); auto yearDay = s_monthDays[date.month] + -1 + static_cast<uint32_t>(systemTime.wDay);
date.yday = yearDay; date.yday = yearDay;
if (leapYear && date.month > 2) { if (leapYear && date.month > 2) {
date.yday++; date.yday++;

View file

@ -13,9 +13,9 @@ int32_t ToUnixTime(Timestamp timestamp);
Timestamp FromUnixTime(int32_t unixTime); Timestamp FromUnixTime(int32_t unixTime);
// Win32 FILETIME to y2k // 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(); Timestamp GetTimestamp();

View file

@ -9,10 +9,10 @@ namespace TimeConst {
constexpr int64_t TimestampsPerSecond = 1000000000ULL; constexpr int64_t TimestampsPerSecond = 1000000000ULL;
// amount of win32 filetime units in a second // 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 // 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 } // namespace TimeConst