Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Compat/Win/win_compat.cpp')
-rw-r--r--Source/Compat/Win/win_compat.cpp631
1 files changed, 631 insertions, 0 deletions
diff --git a/Source/Compat/Win/win_compat.cpp b/Source/Compat/Win/win_compat.cpp
new file mode 100644
index 00000000..13c2a1c6
--- /dev/null
+++ b/Source/Compat/Win/win_compat.cpp
@@ -0,0 +1,631 @@
+//-----------------------------------------------------------------------------
+// Name: win_compat.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#if !PLATFORM_WINDOWS
+#error Do not compile this.
+#endif
+#include "win_compat.h"
+
+#include <Compat/compat.h>
+#include <Compat/fileio.h>
+
+#include <Internal/integer.h>
+#include <Internal/error.h>
+#include <Internal/filesystem.h>
+
+#include <Logging/logdata.h>
+#include <Memory/allocation.h>
+
+#include <utf8/utf8.h>
+
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#define NOMINMAX
+#include <Windows.h>
+#include <direct.h>
+#include <tchar.h>
+#include <strsafe.h>
+#include <conio.h>
+
+#include <cassert>
+#include <iostream>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+/// here's where things start getting ugly, replacements for stuff windows doesn't have.
+#include <ShlObj.h>
+
+// X_OK should be execute bit, but non exists in io.h? Windows doesn't have execute rights?
+#define X_OK 0x0
+#define F_OK 0x0
+#define W_OK 0x02
+#define R_OK 0x04
+#define RW_OK 0x06
+
+using std::string;
+using std::wstring;
+using std::basic_string;
+using std::vector;
+using std::endl;
+
+int UTF8Access(const string &path, int access_mode){
+ return _waccess(UTF16fromUTF8(path).c_str(), access_mode);
+}
+
+bool chdir(char *dir) {
+ return (SetCurrentDirectoryW(UTF16fromUTF8(dir).c_str()) == TRUE)?true:false;
+}
+
+#define S_IRWXU 0x0000000
+
+#if 1
+#define dprintf printf
+#else
+static inline void dprintf(const char *fmt, ...) {}
+#endif
+
+char* strtok_r(
+ char *str,
+ const char *delim,
+ char **nextp)
+{
+ char *ret;
+
+ if (str == NULL)
+ {
+ str = *nextp;
+ }
+
+ str += strspn(str, delim);
+
+ if (*str == '\0')
+ {
+ return NULL;
+ }
+
+ ret = str;
+
+ str += strcspn(str, delim);
+
+ if (*str)
+ {
+ *str++ = '\0';
+ }
+
+ *nextp = str;
+
+ return ret;
+}
+
+string GetAbsPath(const char* full_rel_path)
+{
+ wstring w_full_rel_path = UTF16fromUTF8(full_rel_path);
+ wchar_t w_full_path[PATH_MAX];
+ _wfullpath(w_full_path, w_full_rel_path.c_str(), PATH_MAX);
+ return UTF8fromUTF16(wstring(w_full_path));
+}
+
+// Get the Windows write directory
+// ("$VOL:/$USERNAME/Documents/Wolfire/Overgrowth")
+int initWriteDir(char* writedir, int kPathBufferSize) {
+ // Read documents path into UTF16 char buffer
+ wchar_t writedir_utf16_buf[MAX_PATH];
+ HRESULT result = SHGetFolderPathW(
+ NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT,
+ writedir_utf16_buf);
+ if(result != S_OK){
+ return 1;
+ }
+
+ /*wchar_t short_writedir_utf16_buf[MAX_PATH];
+ DWORD err = GetShortPathNameW(writedir_utf16_buf, short_writedir_utf16_buf, MAX_PATH);
+
+ if(err == 0) {
+ LPVOID lpMsgBuf;
+ LOGF << "Failed at retrieving short path for write dir" << endl;
+ DWORD dw = GetLastError();
+ FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ DisplayError("Error init writedir", (const char*)lpMsgBuf, _ok, true);
+ LOGF << lpMsgBuf << endl;
+
+ LocalFree(lpMsgBuf);
+ return 4;
+ } else if( err > MAX_PATH ) {
+ LOGF << "Short path of write dir could not fit in buffer" << endl;
+ return 5;
+ }
+
+ if(!WideCharToMultiByte(CP_UTF8, 0, short_writedir_utf16_buf, -1,
+ writedir, kPathBufferSize, NULL, NULL))*/
+ if(!WideCharToMultiByte(CP_UTF8, 0, writedir_utf16_buf, -1,
+ writedir, kPathBufferSize, NULL, NULL))
+ {
+ return 2;
+ }
+ int len = strlen(writedir);
+ // Replace backslashes with forward slashes
+ for(int i=0; i<len; ++i){
+ if(writedir[i] == '\\'){
+ writedir[i] = '/';
+ }
+ }
+ // Append slash to the end if there isn't one already
+ if(writedir[len-1] != '/'){
+ if(len == kPathBufferSize){
+ return 3;
+ }
+ strcat(writedir, "/");
+ }
+ // Add program identifier
+ const char* to_append = "Wolfire/Overgrowth/";
+ if(len + (int)strlen(to_append) >= kPathBufferSize){
+ return 3;
+ }
+ strcat(writedir, to_append);
+ return 0;
+}
+
+static char *findBinaryInPath(const char *bin, char *envr) {
+ size_t alloc_size = 0;
+ char *exe = NULL;
+ char *start = envr;
+ char *ptr;
+ do {
+ size_t size;
+ ptr = strchr(start, ':'); // find next $PATH separator.
+ if (ptr)
+ *ptr = '\0';
+
+ size = strlen(start) + strlen(bin) + 2;
+ if (size > alloc_size) {
+ char *x = (char *) realloc(exe, size);
+ if (x == NULL) {
+ if (exe != NULL) {
+ free(exe);
+ }
+ return NULL;
+ }
+ alloc_size = size;
+ exe = x;
+ }
+ // build full binary path...
+ strcpy_s(exe, size, start);
+ if ((exe[0] == '\0') || (exe[strlen(exe) - 1] != '/'))
+ strcat_s(exe, size, "/");
+ strcat_s(exe, size, bin);
+ if (UTF8Access(exe, X_OK) == 0) { // Exists as executable? We're done.
+ strcpy_s(exe, size, start); // i'm lazy. piss off.
+ return(exe);
+ } /* if */
+ start = ptr + 1; // start points to beginning of next element.
+ } while (ptr != NULL);
+
+ if (exe != NULL) {
+ OG_FREE(exe);
+ }
+ return(NULL); // doesn't exist in path.
+}
+
+// Set home directory so file paths work properly when running from shortcuts
+void chdirToBasePath(char *argv0) {
+ basic_string<uint32_t> path_utf32;
+ {
+ wchar_t path_utf16_buf[kPathSize];
+ GetModuleFileNameW( NULL, path_utf16_buf, kPathSize);
+
+ // Convert path from UTF16 to UTF32 by way of UTF8
+ string path_utf8;
+ utf8::utf16to8(path_utf16_buf, &path_utf16_buf[wcsnlen(path_utf16_buf, kPathSize)-1], back_inserter(path_utf8));
+ utf8::utf8to32(path_utf8.begin(), path_utf8.end(), back_inserter(path_utf32));
+ }
+
+ // Eliminate everything after final '\\'
+ path_utf32 = path_utf32.substr(0, path_utf32.rfind('\\'));
+
+ wstring path_utf16;
+ {
+ // Convert path from UTF32 to UTF16 by way of UTF8
+ string path_utf8;
+ utf8::utf32to8(path_utf32.begin(), path_utf32.end(), back_inserter(path_utf8));
+ utf8::utf8to16(path_utf8.begin(), path_utf8.end(), back_inserter(path_utf16));
+ }
+
+ _wchdir(path_utf16.c_str());
+}
+
+void SetWorkingDir(const char* path) {
+ _wchdir(UTF16fromUTF8(path).c_str());
+}
+
+void caseCorrect(char* path) {
+ return;
+}
+
+string caseCorrect(const string & path ) {
+ return path;
+}
+
+static void caseCorrectFilename(char *path, bool inwritedir) {
+ if (*path == '\0') {
+ return; // this is the root directory ("/"), so just return.
+ }
+ if (UTF8Access(path, F_OK) == 0) {
+ return; // fast path: it definitely exists in acceptable case.
+ }
+ char *base = strrchr(path, '/');
+ if (base == path) {
+ } else if (base == NULL) {
+ base = path-1;
+ } else {
+ *base = '\0';
+ CreateDirectoryW(UTF16fromUTF8(path).c_str(), NULL);
+ *base = '/';
+ }
+ base++;
+}
+
+void ShortenWindowsPath(string &str) {
+ wstring path_utf16_buf;
+ wstring extra;
+ utf8::utf8to16(str.begin(), str.end(), back_inserter(path_utf16_buf));
+ struct _stat buf;
+ while(_wstat( &path_utf16_buf[0], &buf )!=0){
+ unsigned offset = path_utf16_buf.rfind('/');
+ if(offset == string::npos){
+ offset = path_utf16_buf.rfind('\\');
+ }
+ if(offset == string::npos){
+ return;
+ }
+ extra = path_utf16_buf.substr(offset, path_utf16_buf.size()-offset) + extra;
+ path_utf16_buf = path_utf16_buf.substr(0, offset);
+ }
+ wstring short_buf;
+ DWORD len = GetShortPathNameW(&path_utf16_buf[0], NULL, 0);
+
+ if(len == 0) {
+ LPVOID lpMsgBuf;
+
+ DWORD dw = GetLastError();
+ FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ DisplayError("Error init writedir", (const char*)lpMsgBuf, _ok, true);
+
+ LocalFree(lpMsgBuf);
+ }
+ short_buf.resize(len);
+ len = GetShortPathNameW(&path_utf16_buf[0], &short_buf[0], len);
+ if(len == 0) {
+ LPVOID lpMsgBuf;
+
+ DWORD dw = GetLastError();
+ FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPTSTR) &lpMsgBuf,
+ 0, NULL );
+
+ DisplayError("Error init writedir", (const char*)lpMsgBuf, _ok, true);
+
+ LocalFree(lpMsgBuf);
+ }
+ short_buf.resize(short_buf.size()-1);
+ short_buf += extra;
+ str.clear();
+ utf8::utf16to8(&short_buf[0], &short_buf[wcsnlen(&short_buf[0], kPathSize)], back_inserter(str));
+}
+
+void WorkingDir( string *dir ) {
+ wchar_t *buf = _wgetcwd(NULL, NULL);
+ string path_utf8;
+ utf8::utf16to8(buf, &buf[wcsnlen(buf, kPathSize)], back_inserter(path_utf8));
+ OG_FREE(buf);
+ *dir = path_utf8;
+}
+
+vector<string>& getSubdirectories( const char *basepath, vector<string>& mods )
+{
+ wstring path_utf16_buf;
+ string path(basepath);
+
+ path += "\\*";
+
+ utf8::utf8to16(path.begin(), path.end(), back_inserter(path_utf16_buf));
+
+ WIN32_FIND_DATAW ffd;
+ size_t length_of_arg;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ DWORD dwError=0;
+
+ // Check that the input path plus 1 is not longer than MAX_PATH.
+ StringCchLengthW(path_utf16_buf.c_str(), MAX_PATH, &length_of_arg);
+
+ if (length_of_arg > (MAX_PATH-1))
+ {
+ LOGE << "Directory path is too long." << endl;
+ }
+ else
+ {
+ // Find the first file in the directory.
+ hFind = FindFirstFileW(path_utf16_buf.c_str(), &ffd);
+
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ LOGE << "FindFirstFile failed " << GetLastError() << endl;
+ }
+ else
+ {
+ do
+ {
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ wstring output_utf16( ffd.cFileName );
+ string output;
+ utf8::utf16to8(output_utf16.begin(), output_utf16.end(), back_inserter(output));
+ //printf("modpath:%s\n", output.c_str() );
+ if( output != string(".") && output != string("..") )
+ {
+ mods.push_back(string(basepath) + "/" + output);
+ }
+ }
+ }
+ while (FindNextFileW(hFind, &ffd) != 0);
+
+ dwError = GetLastError();
+ if (dwError != ERROR_NO_MORE_FILES)
+ {
+ LOGE << "Error gettings subdirs: " << dwError << endl;
+ }
+ FindClose(hFind);
+ }
+ }
+ return mods;
+}
+
+vector<string>& getDeepManifest( const char *basepath, const char* prefix, vector<string>& files )
+{
+ string s_prefix( prefix );
+ wstring path_utf16_buf;
+ string path(basepath);
+
+ path += "\\*";
+
+ utf8::utf8to16(path.begin(), path.end(), back_inserter(path_utf16_buf));
+
+ WIN32_FIND_DATAW ffd;
+ size_t length_of_arg;
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ DWORD dwError=0;
+
+ // Check that the input path plus 1 is not longer than MAX_PATH.
+ StringCchLengthW(path_utf16_buf.c_str(), MAX_PATH, &length_of_arg);
+
+ if (length_of_arg > (MAX_PATH-1))
+ {
+ LOGE << "Directory path is too long." << endl;
+ }
+ else
+ {
+ // Find the first file in the directory.
+ hFind = FindFirstFileW(path_utf16_buf.c_str(), &ffd);
+
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ LOGE << "FindFirstFile failed " << GetLastError() << endl;
+ }
+ else
+ {
+ do
+ {
+
+ wstring output_utf16( ffd.cFileName );
+ string output;
+ utf8::utf16to8(output_utf16.begin(), output_utf16.end(), back_inserter(output));
+
+ string sub_prefix;
+
+ if( s_prefix.length() == 0 )
+ {
+ sub_prefix = output;
+ }
+ else
+ {
+ sub_prefix = s_prefix + "/" + output;
+ }
+
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ //printf("modpath:%s\n", output.c_str() );
+ if( output != string(".") && output != string("..") )
+ {
+ string fullpath = string(basepath) + "/" + output;
+
+ getDeepManifest( fullpath.c_str(), sub_prefix.c_str(), files );
+ }
+ }
+ else
+ {
+ files.push_back( sub_prefix );
+ }
+ }
+ while (FindNextFileW(hFind, &ffd) != 0);
+
+ dwError = GetLastError();
+ if (dwError != ERROR_NO_MORE_FILES)
+ {
+ LOGE << "Error gettings subdirs: " << dwError << endl;
+ }
+ FindClose(hFind);
+ }
+ }
+ return files;
+}
+
+bool fileExist( const char *path )
+{
+ return UTF8Access(string(path), F_OK) == 0;
+}
+
+bool fileReadable( const char* path )
+{
+ return UTF8Access(string(path), R_OK) == 0;
+}
+
+int os_copyfile( const char *source, const char *dest )
+{
+ return CopyFileW(UTF16fromUTF8(source).c_str(), UTF16fromUTF8(dest).c_str(), FALSE) == 0;
+}
+
+int os_movefile( const char *source, const char *dest )
+{
+ return MoveFileExW(UTF16fromUTF8(source).c_str(), UTF16fromUTF8(dest).c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0;
+}
+
+int os_deletefile( const char *path )
+{
+ return _wremove(UTF16fromUTF8(path).c_str());
+}
+
+int os_createfile( const char *path )
+{
+ FILE* file = _wfopen(UTF16fromUTF8(path).c_str(), L"w");
+
+ if(file) {
+ fclose(file);
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+int os_fileexists( const char *path )
+{
+ return _waccess(UTF16fromUTF8(path).c_str(), F_OK);
+}
+
+string dumpIntoFile( const void* buf, size_t nbyte )
+{
+ LOGF << "dumpIntoFile PLACEHOLDER" << endl;
+ exit(1);
+}
+
+bool isFile( const char* path )
+{
+ struct _stat buf;
+ if(_wstat( UTF16fromUTF8(path).c_str(), &buf )==0){
+ if(_S_IFREG & buf.st_mode){
+ return true; // It is a regular file
+ } else {
+ return false; // It might be a directory or pipe
+ }
+ } else {
+ return false; //No such file
+ }
+}
+
+bool checkFileAccess(const char* path)
+{
+ return _waccess(UTF16fromUTF8(path).c_str(), 04) != -1;
+}
+
+void createParentDirs(const char* abs_path) {
+ char build_path[kPathSize] = {'\0'};
+ for(int i=0; abs_path[i] != '\0'; ++i){
+ if(abs_path[i] == '/' || abs_path[i] == '\\') {
+ if(!CheckFileAccess(build_path)){
+ CreateDirectoryW(UTF16fromUTF8(build_path).c_str(), NULL);
+ }
+ }
+ build_path[i] = abs_path[i];
+ }
+}
+
+bool areSame(const char* path1, const char* path2 )
+{
+ wstring w_path1 = UTF16fromUTF8(path1);
+ wstring w_path2 = UTF16fromUTF8(path2);
+
+ LPCWSTR szPath1 = w_path1.c_str();
+ LPCWSTR szPath2 = w_path2.c_str();
+
+ //Validate the input
+ _ASSERT(szPath1 != NULL);
+ _ASSERT(szPath2 != NULL);
+
+ //Get file handles
+ HANDLE handle1 = ::CreateFileW(szPath1, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ HANDLE handle2 = ::CreateFileW(szPath2, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ bool bResult = false;
+
+ //if we could open both paths...
+ if (handle1 != INVALID_HANDLE_VALUE && handle2 != INVALID_HANDLE_VALUE)
+ {
+ BY_HANDLE_FILE_INFORMATION fileInfo1;
+ BY_HANDLE_FILE_INFORMATION fileInfo2;
+ if (::GetFileInformationByHandle(handle1, &fileInfo1) && ::GetFileInformationByHandle(handle2, &fileInfo2))
+ {
+ //the paths are the same if they refer to the same file (fileindex) on the same volume (volume serial number)
+ bResult = fileInfo1.dwVolumeSerialNumber == fileInfo2.dwVolumeSerialNumber &&
+ fileInfo1.nFileIndexHigh == fileInfo2.nFileIndexHigh &&
+ fileInfo1.nFileIndexLow == fileInfo2.nFileIndexLow;
+ }
+ }
+
+ //free the handles
+ if (handle1 != INVALID_HANDLE_VALUE )
+ {
+ ::CloseHandle(handle1);
+ }
+
+ if (handle2 != INVALID_HANDLE_VALUE )
+ {
+ ::CloseHandle(handle2);
+ }
+
+ //return the result
+ return bResult;
+}