diff --git a/Juliet/include/Core/Common/String.h b/Juliet/include/Core/Common/String.h index 9a8ed22..fd7c20f 100644 --- a/Juliet/include/Core/Common/String.h +++ b/Juliet/include/Core/Common/String.h @@ -1,4 +1,6 @@ #pragma once + +#include #include namespace Juliet @@ -6,21 +8,31 @@ namespace Juliet #define ConstString(str) { const_cast((str)), sizeof(str) - 1 } #define CStr(str) ((str).Data) #define InplaceString(name, size) \ - char name##_[size]; \ - String name = { name##_, sizeof(name##_) } + char name##_[size]; \ + MemSet(name##_, 0, sizeof(uint32)); \ + String name = { name##_, 0 } + // Everything is Little Endian + enum class StringEncoding : uint8 + { + Unknown = 0, + ASCII, + LATIN1, + UTF8, + UTF16, + UTF32, + UCS2, + UCS4, + }; + + // Represents a UTF-8 String. + // Not null terminated. struct String { char* Data; size_t Size; }; - struct String16 - { - char16_t* Data; - size_t Size; - }; - inline size_t StringLength(String str) { return str.Size; @@ -28,16 +40,20 @@ namespace Juliet inline size_t StringLength(const char* str) { - size_t counter = 0; + size_t length = 0; if (str) { - while (*str++) + while (char ch = *str) { - ++counter; + if ((ch & 0xC0) != 0x80) + { + ++length; + } + ++str; } } - return counter; + return length; } inline bool StringIsValid(String str) @@ -101,14 +117,20 @@ namespace Juliet return result; } - inline int8 StringCompareCaseInsensitive(String str1, String str2) - { - return 0; - } + // Case insensitive compare. Supports ASCII only + // TODO: Support UNICODE + extern JULIET_API int8 StringCompareCaseInsensitive(String str1, String str2); // Do not allocate anything, you must allocate your out buffer yourself // TODO: Version taking arena that can allocate - extern JULIET_API bool ConvertString(String from, String to, String in, String& out); + // Do not take String type because we dont know the string encoding we are going from/to + // src and dst will be casted based on the encoding. + // size will correspond to the number of characters + // Will convert \0 character if present. + extern JULIET_API bool ConvertString(StringEncoding from, StringEncoding to, const char* src, size_t srcLen, + char*& dst, size_t& dstLen, size_t dstCapacity); + extern JULIET_API bool ConvertString(String from, String to, const char* src, size_t srcLen, char*& dst, + size_t& dstLen, size_t dstCapacity); } // namespace Juliet diff --git a/Juliet/include/Core/Memory/Utils.h b/Juliet/include/Core/Memory/Utils.h index 30eb822..94dadc4 100644 --- a/Juliet/include/Core/Memory/Utils.h +++ b/Juliet/include/Core/Memory/Utils.h @@ -1,13 +1,15 @@ #pragma once +#include + #define ArraySize(array) (sizeof(array) / sizeof(array[0])) namespace Juliet { inline int32 MemCompare(const void* leftValue, const void* rightValue, size_t size) { - const unsigned char* left = static_cast(leftValue); - const unsigned char* right = static_cast(rightValue); + auto left = static_cast(leftValue); + auto right = static_cast(rightValue); while (size && *left == *right) { ++left; @@ -15,4 +17,6 @@ namespace Juliet } return size ? *left - *right : 0; } -} \ No newline at end of file + +#define MemSet memset +} // namespace Juliet diff --git a/Juliet/src/Core/Common/String.cpp b/Juliet/src/Core/Common/String.cpp index 2ae7519..9e23d3d 100644 --- a/Juliet/src/Core/Common/String.cpp +++ b/Juliet/src/Core/Common/String.cpp @@ -7,82 +7,345 @@ namespace Juliet { namespace { - enum class Encoding : uint8 - { - Unknown = 0, - ASCII, - LATIN1, - UTF8, - UTF16, - UTF32, - UCS2, - UCS4, - }; + constexpr char kUnknown_ASCII = '?'; + constexpr int32 kUnknown_UNICODE = 0xFFFD; struct { - const char* name; - Encoding format; + String Name; + StringEncoding Format; } Encodings[] = { /* *INDENT-OFF* */ // clang-format off - { "ASCII", Encoding::ASCII }, - { "US-ASCII", Encoding::ASCII }, - { "8859-1", Encoding::LATIN1 }, - { "ISO-8859-1", Encoding::LATIN1 }, + { ConstString("ASCII"), StringEncoding::ASCII }, + { ConstString("US-ASCII"), StringEncoding::ASCII }, + { ConstString("8859-1"), StringEncoding::LATIN1 }, + { ConstString("ISO-8859-1"), StringEncoding::LATIN1 }, #if defined(JULIET_WIN32) - { "WCHAR_T", Encoding::UTF16 }, + { ConstString("WCHAR_T"), StringEncoding::UTF16 }, #else - { "WCHAR_T", Encoding::UCS4 }, + { ConstString("WCHAR_T"), StringEncoding::UCS4 }, #endif - { "UTF8", Encoding::UTF8 }, - { "UTF-8", Encoding::UTF8 }, - { "UTF16", Encoding::UTF16 }, - { "UTF-16", Encoding::UTF16 }, - { "UTF32", Encoding::UTF32 }, - { "UTF-32", Encoding::UTF32 }, - { "UCS2", Encoding::UCS2 }, - { "UCS-2", Encoding::UCS2 }, - { "UCS-2-INTERNAL", Encoding::UCS2 }, - { "UCS4", Encoding::UCS4 }, - { "UCS-4", Encoding::UCS4 }, - { "UCS-4-INTERNAL", Encoding::UCS4 }, + { ConstString("UTF8"), StringEncoding::UTF8 }, + { ConstString("UTF-8"), StringEncoding::UTF8 }, + { ConstString("UTF16"), StringEncoding::UTF16 }, + { ConstString("UTF-16"), StringEncoding::UTF16 }, + { ConstString("UTF32"), StringEncoding::UTF32 }, + { ConstString("UTF-32"), StringEncoding::UTF32 }, + { ConstString("UCS2"), StringEncoding::UCS2 }, + { ConstString("UCS-2"), StringEncoding::UCS2 }, + { ConstString("UCS-2-INTERNAL"), StringEncoding::UCS2 }, + { ConstString("UCS4"), StringEncoding::UCS4 }, + { ConstString("UCS-4"), StringEncoding::UCS4 }, + { ConstString("UCS-4-INTERNAL"), StringEncoding::UCS4 }, /* *INDENT-ON* */ // clang-format on }; + // Returns the number of codepoint case folded (lowercase equivalent in the language) + // Takes an UTF-8 codepoint (uint32) and codefold it to up to 3 uint32 + // TODO Supports more than low ASCI :) + int8 CaseFoldUnicode(uint32 from, uint32* to) + { + if (from < 128) + { + // low-ASCII, easy! + if ((from >= 'A') && (from <= 'Z')) + { + *to = 'a' + (from - 'A'); + return 1; + } + } + *to = from; + return 1; + } + + void Step(String& inStr, size_t byteToStep) + { + Assert(inStr.Size >= byteToStep); + + inStr.Data += byteToStep; + inStr.Size -= byteToStep; + } + + uint32 StepUTF8(String& inStr, size_t byteToRead) + { + /* + * From rfc3629, the UTF-8 spec: + * https://www.ietf.org/rfc/rfc3629.txt + * + * Char. number range | UTF-8 octet sequence + * (hexadecimal) | (binary) + * --------------------+--------------------------------------------- + * 0000 0000-0000 007F | 0xxxxxxx + * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + + // If string is empty then it's done. + if (inStr.Size == 0) + { + return 0; + } + + auto str = reinterpret_cast(CStr(inStr)); + const uint32 octet = byteToRead ? *str : 0; + + if (octet == 0) + { + return 0; + } + if ((octet & 0x80) == 0x0) // One byte code point + { + Step(inStr, 1); + return octet; + } + Assert(false && "StepUTF8 only supports one byte codepoints for now"); + return 0; + } } // namespace - bool ConvertString(String from, String to, String in, String& out) + int8 StringCompareCaseInsensitive(String str1, String str2) + { + // TODO: Support UTF8. For now ASCII only. + uint32 left = 0; + uint32 right = 0; + while (true) + { + { + uint32 leftFolded[3]; + int8 num_folded = CaseFoldUnicode(StepUTF8(str1, 4), leftFolded); + Assert(num_folded == 1); // Only one uint32 codepoint supported for now (low ascii) + left = leftFolded[0]; + } + { + uint32 rightFolded[3]; + int8 num_folded = CaseFoldUnicode(StepUTF8(str2, 4), rightFolded); + Assert(num_folded == 1); // Only one uint32 codepoint supported for now (low ascii) + right = rightFolded[0]; + } + if (left < right) + { + return -1; + } + if (left > right) + { + return 1; + } + if (left == 0) + { + break; + } + } + return 0; + } + + bool ConvertString(StringEncoding from, StringEncoding to, const char* src, size_t srcLen, char*& dst, size_t& dstLen, size_t dstCapacity) + { + Assert(src && *src); + + const char* srcStr = src; + char* dstStr = dst; + + uint32 character = 0; + while (srcLen > 0) + { + // Decode in character + switch (from) + { + case StringEncoding::UTF8: // Uses RFC 3629 + { + auto p = reinterpret_cast(srcStr); + size_t left = 0; + bool overlong = false; + if (p[0] >= 0xF0) + { + if ((p[0] & 0xF8) != 0xF0) + { + character = kUnknown_UNICODE; + } + else + { + if (p[0] == 0xF0 && srcLen > 1 && (p[1] & 0xF0) == 0x80) + { + overlong = true; + } + character = static_cast(p[0] & 0x07); + left = 3; + } + } + else if (p[0] >= 0xE0) + { + if ((p[0] & 0xF0) != 0xE0) + { + character = kUnknown_UNICODE; + } + else + { + if (p[0] == 0xE0 && srcLen > 1 && (p[1] & 0xE0) == 0x80) + { + overlong = true; + } + character = static_cast(p[0] & 0x0F); + left = 2; + } + } + else if (p[0] >= 0xC0) + { + if ((p[0] & 0xE0) != 0xC0) + { + character = kUnknown_UNICODE; + } + else + { + if ((p[0] & 0xDE) == 0xC0) + { + overlong = true; + } + character = static_cast(p[0] & 0x1F); + left = 1; + } + } + else + { + if (p[0] & 0x80) + { + character = kUnknown_UNICODE; + } + else + { + character = static_cast(p[0]); + } + } + ++srcStr; + --srcLen; + if (srcLen < left) + { + Log(LogLevel::Error, LogCategory::Core, "ConvertString: Failed to convert string. Incomplete input sequence"); + return false; + } + while (left--) + { + ++p; + if ((p[0] & 0xC0) != 0x80) + { + character = kUnknown_UNICODE; + break; + } + character <<= 6; + character |= (p[0] & 0x3F); + ++srcStr; + --srcLen; + } + if (overlong) + { + character = kUnknown_UNICODE; + } + if ((character >= 0xD800 && character <= 0xDFFF) || (character == 0xFFFE || character == 0xFFFF) || + character > 0x10FFFF) + { + character = kUnknown_UNICODE; + } + break; + } + case StringEncoding::Unknown: Assert(false && "ConvertString: Invalid Source Format: Unknown"); break; + case StringEncoding::ASCII: + case StringEncoding::LATIN1: + case StringEncoding::UTF16: + case StringEncoding::UTF32: + case StringEncoding::UCS2: + case StringEncoding::UCS4: Assert(false && "ConvertString: Unsupported Source Format"); break; + } + + // Encode out character + switch (to) + { + case StringEncoding::UTF16: // RFC 2781 + { + auto p = reinterpret_cast(dstStr); + if (character > 0x10FFFF) + { + character = kUnknown_UNICODE; + } + if (character < 0x10000) + { + if (dstCapacity < 2) + { + Log(LogLevel::Error, LogCategory::Core, "ConvertString: Destination buffer too short to fit UTF16"); + return false; + } + p[1] = static_cast(character >> 8); + p[0] = static_cast(character); + + dstStr += 2; + dstLen += 1; + dstCapacity -= 2; + } + else + { + if (dstCapacity < 4) + { + Log(LogLevel::Error, LogCategory::Core, "ConvertString: Destination buffer too short to fit UTF16"); + return false; + } + character = character - 0x10000; + uint16 word1 = 0xD800 | static_cast((character >> 10) & 0x3FF); + uint16 word2 = 0xDC00 | static_cast(character & 0x3FF); + p[1] = static_cast(word1 >> 8); + p[0] = static_cast(word1); + p[3] = static_cast(word2 >> 8); + p[2] = static_cast(word2); + + dstStr += 4; + dstLen += 1; + dstCapacity -= 4; + } + break; + } + case StringEncoding::Unknown: Assert(false && "ConvertString: Invalid Source Format: Unknown"); break; + case StringEncoding::ASCII: + case StringEncoding::LATIN1: + case StringEncoding::UTF8: + case StringEncoding::UTF32: + case StringEncoding::UCS2: + case StringEncoding::UCS4: Assert(false && "ConvertString: Unsupported Destination Format"); break; + } + } + return true; + } + + bool ConvertString(String from, String to, const char* src, size_t srcSize, char*& dst, size_t& dstSize, size_t dstCapacity) { - Assert(in.Size <= out.Size); Assert(StringIsValid(from)); Assert(StringIsValid(to)); - Assert(StringIsValid(in)); -for (size_t idx = 0; idx < ArraySize(Encodings); ++idx) -{ + // First find the encoding of the strings + auto sourceFormat = StringEncoding::Unknown; + auto destFormat = StringEncoding::Unknown; + for (auto& encoding : Encodings) + { + if (StringCompareCaseInsensitive(from, encoding.Name) == 0) + { + sourceFormat = encoding.Format; + if (destFormat != StringEncoding::Unknown) + { + break; + } + } + if (StringCompareCaseInsensitive(to, encoding.Name) == 0) + { + destFormat = encoding.Format; + if (sourceFormat != StringEncoding::Unknown) + { + break; + } + } + } -} - // for (i = 0; i < SDL_arraysize(encodings); ++i) { - // if (SDL_strcasecmp(fromcode, encodings[i].name) == 0) { - // src_fmt = encodings[i].format; - // if (dst_fmt != ENCODING_UNKNOWN) { - // break; - // } - // } - // if (SDL_strcasecmp(tocode, encodings[i].name) == 0) { - // dst_fmt = encodings[i].format; - // if (src_fmt != ENCODING_UNKNOWN) { - // break; - // } - // } - // } - // if (src_fmt != ENCODING_UNKNOWN && dst_fmt != ENCODING_UNKNOWN) { - // SDL_iconv_t cd = (SDL_iconv_t)SDL_malloc(sizeof(*cd)); - // if (cd) { - // cd->src_fmt = src_fmt; - // cd->dst_fmt = dst_fmt; - // return cd; - // } - // } + if (sourceFormat == StringEncoding::Unknown || destFormat == StringEncoding::Unknown) + { + return false; + } + + return ConvertString(sourceFormat, destFormat, src, srcSize, dst, dstSize, dstCapacity); } } // namespace Juliet diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp index 82305c7..a319b71 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp +++ b/Juliet/src/Core/HAL/Display/Win32/Win32DisplayEvent.cpp @@ -134,10 +134,10 @@ namespace Juliet::Win32 { uint8 peekedMessageCount = 0; MSG message = {}; - while (PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) + while (PeekMessageA(&message, nullptr, 0, 0, PM_REMOVE)) { TranslateMessage(&message); - DispatchMessage(&message); + DispatchMessageA(&message); // Since we peek at all messages of the program, it's possible that it stall here so we limit the number of peeked messages to an arbitrary limit if (++peekedMessageCount > kPeekMessageLimit) @@ -155,7 +155,7 @@ namespace Juliet::Win32 auto* windowState = GetWindowStateFromHandle(handle); if (!windowState) { - return CallWindowProc(DefWindowProc, handle, message, wParam, lParam); + return CallWindowProcA(DefWindowProcA, handle, message, wParam, lParam); } switch (message) @@ -267,6 +267,6 @@ namespace Juliet::Win32 return returnCode; } - return CallWindowProc(DefWindowProc, handle, message, wParam, lParam); + return CallWindowProcA(DefWindowProcA, handle, message, wParam, lParam); } } // namespace Juliet::Win32 diff --git a/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp b/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp index 61b51cf..c07c69a 100644 --- a/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp +++ b/Juliet/src/Core/HAL/Display/Win32/Win32Window.cpp @@ -9,8 +9,8 @@ namespace Juliet::Win32 { namespace { - constexpr auto WindowClassName = L"JulietWindowClass"; - constexpr LPCWSTR WindowClassPtr = WindowClassName; + constexpr auto WindowClassName = "JulietWindowClass"; + constexpr LPCSTR WindowClassPtr = WindowClassName; bool SetupWindowState(NonNullPtr self, NonNullPtr window, HWND handle) { @@ -46,7 +46,7 @@ namespace Juliet::Win32 HINSTANCE instance = GetModuleHandle(nullptr); // TODO : Put outside, we should not create a new class for each new window - WNDCLASSEX WindowClass = {}; + WNDCLASSEXA WindowClass = {}; WindowClass.cbSize = sizeof(WNDCLASSEX); WindowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; WindowClass.lpfnWndProc = Win32MainWindowCallback; @@ -54,7 +54,7 @@ namespace Juliet::Win32 WindowClass.hCursor = LoadCursor(0, IDC_ARROW); WindowClass.hbrBackground = static_cast(GetStockObject(LTGRAY_BRUSH)); WindowClass.lpszClassName = WindowClassName; - if (!RegisterClassEx(&WindowClass)) + if (!RegisterClassExA(&WindowClass)) { return false; } @@ -64,8 +64,8 @@ namespace Juliet::Win32 int x = CW_USEDEFAULT, y = CW_USEDEFAULT; const int w = window->Width, h = window->Height; - HWND handle = CreateWindowEx(styleEx, WindowClassPtr, L"JULIET TODO PASS TITLE", style, x, y, w, h, nullptr, - nullptr, instance, nullptr); + HWND handle = CreateWindowExA(styleEx, WindowClassPtr, "JULIET TODO PASS TITLE", style, x, y, w, h, nullptr, + nullptr, instance, nullptr); PumpEvents(self); @@ -97,69 +97,4 @@ namespace Juliet::Win32 auto& win32State = reinterpret_cast(*window->State); ::ShowWindow(win32State.Handle, SW_HIDE); } - - /* - namespace - { - LRESULT CALLBACK Win32MainWindowCallback(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam); - } - - void CreateOSWindow(WindowState& state, uint16 width, uint16 height) - { - auto& win32State = reinterpret_cast(state); - - HINSTANCE Instance = GetModuleHandle(0); - - WNDCLASSA WindowClass = {}; - WindowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; - WindowClass.lpfnWndProc = Win32MainWindowCallback; - WindowClass.hInstance = Instance; - WindowClass.hCursor = LoadCursor(0, IDC_ARROW); - WindowClass.hbrBackground = static_cast(GetStockObject(LTGRAY_BRUSH)); - WindowClass.lpszClassName = WindowClassName; - - if (RegisterClassA(&WindowClass)) - { - HWND handle = CreateWindowExA(0, WindowClass.lpszClassName, "Juliet", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, - CW_USEDEFAULT, width, height, 0, 0, Instance, 0); - if (handle) - { - win32State.Handle = handle; - SetWindowLongPtr(win32State.Handle, GWLP_USERDATA, reinterpret_cast(&win32State)); - ShowWindow(handle, SW_SHOW); - win32State.IsOpen = true; - } - else - { - Assert(false); - // Win32ErrorMessage(PlatformError_Fatal, - // "Unable to open game window."); - } - } - else - { - Assert(false); - // Win32ErrorMessage(PlatformError_Fatal, - // "Unable to register game window handle."); - } - } - - void DestroyOSWindow(WindowState& state) - { - auto& win32State = reinterpret_cast(state); - ::DestroyWindow(win32State.Handle); - UnregisterClassA(WindowClassName, ::GetModuleHandle(nullptr)); - } - - void UpdateOSWindowState(WindowState& state) - { - auto& win32State = reinterpret_cast(state); - MSG msg = {}; - while (::PeekMessage(&msg, win32State.Handle, 0, 0, PM_REMOVE)) - { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - } -*/ } // namespace Juliet::Win32 diff --git a/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp b/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp index c01bf41..12fce36 100644 --- a/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp +++ b/Juliet/src/Core/HAL/DynLib/Win32/DynamicLibrary.cpp @@ -5,38 +5,6 @@ namespace Juliet { - namespace - { - // TODO : Move into string file - // Use portable code + pass the memory array into parameter and not use new - // This is from http://www.rohitab.com/discuss/topic/41257-char-to-lpcwstr/ - static wchar_t* UTF8ToWideChar(const char* utf8) - { - wchar_t* w; - - int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, 0, 0); - if (len <= 0) - { - return nullptr; - } - - w = new wchar_t[len]; - - if (!w) - { - return nullptr; - } - - if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, w, len) <= 0) - { - delete[] w; - return nullptr; - } - - return w; - } - } // namespace - DynamicLibrary* LoadDynamicLibrary(const char* filename) { if (!filename) @@ -45,9 +13,7 @@ namespace Juliet return nullptr; } - LPWSTR wstr = UTF8ToWideChar(filename); - HMODULE handle = LoadLibraryW(wstr); - delete[] wstr; + HMODULE handle = LoadLibraryA(filename); // Generate an error message if all loads failed if (!handle) diff --git a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp index 9ee32df..ed8fb0e 100644 --- a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp +++ b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp @@ -7,43 +7,13 @@ namespace Juliet::Platform { - namespace - { - // TODO : Move into string file - // Use portable code + pass the memory array into parameter and not use new - // From: https://stackoverflow.com/questions/215963/how-do-you-properly-use-widechartomultibyte - char* WideCharToUTF8(char16_t* wcharStr) - { - char* result = nullptr; - size_t length = WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast(wcharStr), -1, nullptr, 0, nullptr, nullptr); - if (length <= 0) - { - return nullptr; - } - - result = new char[length]; - if (!result) - { - return nullptr; - } - - if (WideCharToMultiByte(CP_UTF8, 0, reinterpret_cast(wcharStr), -1, result, length, nullptr, nullptr) <= 0) - { - delete[] result; - return nullptr; - } - - return result; - } - } // namespace - String GetBasePath() { // Allocate a buffer that could fit the module size. // Max Path is a good start but could be bigger if the path include long path prefix - String16 buffer{ .Data = nullptr, .Size = MAX_PATH }; - buffer.Data = static_cast(Calloc(MAX_PATH, sizeof(WCHAR))); - if (buffer.Data == nullptr) + size_t bufferSize=MAX_PATH; + auto buffer = static_cast(Calloc(MAX_PATH, sizeof(char))); + if (buffer == nullptr) { return {}; } @@ -51,14 +21,13 @@ namespace Juliet::Platform size_t moduleFilenameLength = 0; while (true) { - moduleFilenameLength = - GetModuleFileNameW(nullptr, reinterpret_cast(buffer.Data), static_cast(buffer.Size)); + moduleFilenameLength = GetModuleFileNameA(nullptr, buffer, static_cast(bufferSize)); // If the module filename length is bigger than the buffer size, we need to reallocate a bigger buffer - if (moduleFilenameLength >= buffer.Size - 1) + if (moduleFilenameLength >= bufferSize - 1) { - buffer.Size *= 2; - buffer.Data = static_cast(Realloc(buffer.Data, buffer.Size * sizeof(WCHAR))); + bufferSize *= 2; + buffer = static_cast(Realloc(buffer, bufferSize * sizeof(char))); } else { @@ -68,26 +37,23 @@ namespace Juliet::Platform if (moduleFilenameLength == 0) { - SafeFree(buffer.Data); + SafeFree(buffer); Log(LogLevel::Error, LogCategory::Core, "Filesystem: Cannot locate executable path"); } + size_t idx = 0; for (idx = moduleFilenameLength - 1; idx > 0; --idx) { - if (buffer.Data[idx] == '\\') + if (buffer[idx] == '\\') { break; } } Assert(idx > 0 && "Path is not absolute!"); - buffer.Data[idx + 1] = '\0'; // Chop chop + buffer[idx + 1] = '\0'; // Chop chop - // TODO: Add utils to Convert to/from UTF8W - char* basePath = WideCharToUTF8(buffer.Data); - SafeFree(buffer.Data); - - return WrapString(basePath); + return WrapString(buffer); } } // namespace Juliet::Platform diff --git a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp index d3c12f0..9a950bd 100644 --- a/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp +++ b/Juliet/src/Core/HAL/IO/Win32/Win32IOStream.cpp @@ -8,8 +8,6 @@ namespace Juliet::Internal { IOStream* IOFromFile(String filename, String mode) { - HANDLE hFile; - // "r" = reading, file must exist // "w" = writing, truncate existing, file may not exist // "r+"= reading or writing, file must exist @@ -49,18 +47,11 @@ namespace Juliet::Internal return nullptr; } -// Prevent opening a dialog box when file doesnt exits (windows does that) -// old_error_mode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); + HANDLE hFile = CreateFileA(CStr(filename), (canWrite | canRead), (canWrite) ? 0 : FILE_SHARE_READ, nullptr, + (openExisting | createAlways | openAlways), FILE_ATTRIBUTE_NORMAL, nullptr); + if (FAILED(hFile)) { - // LPWSTR str = WIN_UTF8ToStringW(filename); - // h = CreateFileW(str, - // (w_right | r_right), - // (w_right) ? 0 : FILE_SHARE_READ, - // NULL, - // (must_exist | truncate | a_mode), - // FILE_ATTRIBUTE_NORMAL, - // NULL); - // SDL_free(str); + Log(LogLevel::Error, LogCategory::Core, "IOFromFile: CreateFileW failed"); } return nullptr; diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 7085e20..ff2a678 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -46,7 +46,7 @@ void JulietApplication::Init() { Log(LogLevel::Message, LogCategory::Editor, "Initializing Juliet Application..."); - Log(LogLevel::Message, LogCategory::Editor, "%s", GetBasePath()); + Log(LogLevel::Message, LogCategory::Editor, "%s", CStr(GetBasePath())); GraphicsConfig config; GraphicsDevice = CreateGraphicsDevice(config); diff --git a/JulietShaderCompiler/main.cpp b/JulietShaderCompiler/main.cpp index 92e644c..10ed0b3 100644 --- a/JulietShaderCompiler/main.cpp +++ b/JulietShaderCompiler/main.cpp @@ -44,6 +44,6 @@ void Compile() int main(int argc, char* argv[]) { - auto* stream = IOFromFile(ConstString("bleeblou"), ConstString("w")); + auto* stream = IOFromFile(ConstString("XF"), ConstString("w")); return 0; }