summaryrefslogtreecommitdiff
path: root/src/skel/crossplatform.cpp
diff options
context:
space:
mode:
authorclaude-bot <[email protected]>2026-07-13 12:27:07 +0000
committerclaude-bot <[email protected]>2026-07-13 12:27:07 +0000
commit9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686 (patch)
treea84756b82513739a2672db3a1f0ec579db6d18ff /src/skel/crossplatform.cpp
downloadre3-miami.tar.gz
re3-miami.zip
Import Cai1Hsu/re3 @ miami (reVC / GTA:VC decompilation)HEADmiami
Snapshot import (no upstream history) into git.ancap.in.ua/claude, per @lzcnt. Source: https://github.com/Cai1Hsu/re3 branch miami.
Diffstat (limited to 'src/skel/crossplatform.cpp')
-rw-r--r--src/skel/crossplatform.cpp272
1 files changed, 272 insertions, 0 deletions
diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp
new file mode 100644
index 0000000..68df670
--- /dev/null
+++ b/src/skel/crossplatform.cpp
@@ -0,0 +1,272 @@
+#include "common.h"
+#include "crossplatform.h"
+
+// Codes compatible with Windows and Linux
+#ifndef _WIN32
+
+// For internal use
+// wMilliseconds is not needed
+void tmToSystemTime(const tm *tm, SYSTEMTIME *out) {
+ out->wYear = tm->tm_year + 1900;
+ out->wMonth = tm->tm_mon + 1;
+ out->wDayOfWeek = tm->tm_wday;
+ out->wDay = tm->tm_mday;
+ out->wHour = tm->tm_hour;
+ out->wMinute = tm->tm_min;
+ out->wSecond = tm->tm_sec;
+}
+
+void GetLocalTime_CP(SYSTEMTIME *out) {
+ time_t timestamp = time(nil);
+ tm *localTm = localtime(&timestamp);
+ tmToSystemTime(localTm, out);
+}
+#endif
+
+// Compatible with Linux/POSIX and MinGW on Windows
+#ifndef _WIN32
+HANDLE FindFirstFile(const char* pathname, WIN32_FIND_DATA* firstfile) {
+ char pathCopy[MAX_PATH];
+ strcpy(pathCopy, pathname);
+
+ char *folder = strtok(pathCopy, "*");
+ char *extension = strtok(NULL, "*");
+
+ // because I remember like strtok might not return NULL for last delimiter
+ if (extension && extension - folder == strlen(pathname))
+ extension = nil;
+
+ // Case-sensitivity and backslashes...
+ // Will be freed at the bottom
+ char *realFolder = casepath(folder);
+ if (realFolder) {
+ folder = realFolder;
+ }
+
+ strncpy(firstfile->folder, folder, sizeof(firstfile->folder));
+
+ if (extension)
+ strncpy(firstfile->extension, extension, sizeof(firstfile->extension));
+ else
+ firstfile->extension[0] = '\0';
+
+ if (realFolder)
+ free(realFolder);
+
+ HANDLE d;
+ if ((d = (HANDLE)opendir(firstfile->folder)) == NULL || !FindNextFile(d, firstfile))
+ return NULL;
+
+ return d;
+}
+
+bool FindNextFile(HANDLE d, WIN32_FIND_DATA* finddata) {
+ dirent *file;
+ static struct stat fileStats;
+ static char path[PATH_MAX], relativepath[NAME_MAX + sizeof(finddata->folder) + 1];
+ int extensionLen = strlen(finddata->extension);
+ while ((file = readdir((DIR*)d)) != NULL) {
+
+ // We only want "DT_REG"ular Files, but reportedly some FS and OSes gives DT_UNKNOWN as type.
+ if ((file->d_type == DT_UNKNOWN || file->d_type == DT_REG || file->d_type == DT_LNK) &&
+ (extensionLen == 0 || strncasecmp(&file->d_name[strlen(file->d_name) - extensionLen], finddata->extension, extensionLen) == 0)) {
+
+ sprintf(relativepath, "%s/%s", finddata->folder, file->d_name);
+ realpath(relativepath, path);
+ stat(path, &fileStats);
+ strncpy(finddata->cFileName, file->d_name, sizeof(finddata->cFileName));
+ finddata->ftLastWriteTime = fileStats.st_mtime;
+ return true;
+ }
+ }
+ return false;
+}
+
+void GetDateFormat(int unused1, int unused2, SYSTEMTIME* in, int unused3, char* out, int size) {
+ tm linuxTime;
+ linuxTime.tm_year = in->wYear - 1900;
+ linuxTime.tm_mon = in->wMonth - 1;
+ linuxTime.tm_wday = in->wDayOfWeek;
+ linuxTime.tm_mday = in->wDay;
+ linuxTime.tm_hour = in->wHour;
+ linuxTime.tm_min = in->wMinute;
+ linuxTime.tm_sec = in->wSecond;
+ strftime(out, size, nl_langinfo(D_FMT), &linuxTime);
+}
+
+void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) {
+ tm *ptm = gmtime(writeTime);
+ tmToSystemTime(ptm, out);
+}
+#endif
+
+// Because wchar length differs between platforms.
+wchar*
+AllocUnicode(const char* src)
+{
+ wchar *dst = (wchar*)malloc(strlen(src)*2 + 2);
+ wchar *i = dst;
+ while((*i++ = (unsigned char)*src++) != '\0');
+ return dst;
+}
+
+// Funcs/features from Windows that we need on other platforms
+#ifndef _WIN32
+char *strupr(char *s) {
+ char* tmp = s;
+
+ for (;*tmp;++tmp) {
+ *tmp = toupper((unsigned char) *tmp);
+ }
+
+ return s;
+}
+char *strlwr(char *s) {
+ char* tmp = s;
+
+ for (;*tmp;++tmp) {
+ *tmp = tolower((unsigned char) *tmp);
+ }
+
+ return s;
+}
+
+char *trim(char *s) {
+ char *ptr;
+ if (!s)
+ return NULL; // handle NULL string
+ if (!*s)
+ return s; // handle empty string
+ for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr);
+ ptr[1] = '\0';
+ return s;
+}
+
+FILE* _fcaseopen(char const* filename, char const* mode)
+{
+ FILE* result;
+ char* real = casepath(filename);
+ if (!real)
+ result = fopen(filename, mode);
+ else {
+ result = fopen(real, mode);
+ free(real);
+ }
+ return result;
+}
+
+// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
+// Returned string should freed manually (if exists)
+char* casepath(char const* path, bool checkPathFirst)
+{
+ if (checkPathFirst && access(path, F_OK) != -1) {
+ // File path is correct
+ return nil;
+ }
+
+ size_t l = strlen(path);
+ char* p = (char*)alloca(l + 1);
+ char* out = (char*)malloc(l + 3); // for extra ./
+ strcpy(p, path);
+
+ // my addon: linux doesn't handle filenames with spaces at the end nicely
+ p = trim(p);
+
+ size_t rl = 0;
+
+ DIR* d;
+ if (p[0] == '/' || p[0] == '\\')
+ {
+ d = opendir("/");
+ }
+ else
+ {
+ d = opendir(".");
+ out[0] = '.';
+ out[1] = 0;
+ rl = 1;
+ }
+
+ bool cantProceed = false; // just convert slashes in what's left in string, don't correct case of letters(because we can't)
+ bool mayBeTrailingSlash = false;
+ char* c;
+ while (c = strsep(&p, "/\\"))
+ {
+ // May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid)
+ if (*c == '\0')
+ {
+ mayBeTrailingSlash = true;
+ continue;
+ } else {
+ mayBeTrailingSlash = false;
+ }
+
+ out[rl] = '/';
+ rl += 1;
+ out[rl] = 0;
+
+ if (cantProceed)
+ {
+ strcpy(out + rl, c);
+ rl += strlen(c);
+ continue;
+ }
+
+ struct dirent* e;
+ while (e = readdir(d))
+ {
+ if (strcasecmp(c, e->d_name) == 0)
+ {
+ strcpy(out + rl, e->d_name);
+ int reportedLen = (int)strlen(e->d_name);
+ rl += reportedLen;
+ assert(reportedLen == strlen(c) && "casepath: This is not good at all");
+
+ closedir(d);
+ d = opendir(out);
+
+ // Either it wasn't a folder, or permission error, I/O error etc.
+ if (!d) {
+ cantProceed = true;
+ }
+
+ break;
+ }
+ }
+
+ if (!e)
+ {
+ printf("casepath couldn't find dir/file \"%s\", full path was %s\n", c, path);
+ // No match, add original name and continue converting further slashes.
+ strcpy(out + rl, c);
+ rl += strlen(c);
+ cantProceed = true;
+ }
+ }
+
+ if (d) closedir(d);
+ if (mayBeTrailingSlash) {
+ out[rl] = '/'; rl += 1;
+ out[rl] = '\0';
+ }
+
+ if (rl > l + 2) {
+ printf("\n\ncasepath: Corrected path length is longer then original+2:\n\tOriginal: %s (%zu chars)\n\tCorrected: %s (%zu chars)\n\n", path, l, out, rl);
+ }
+ return out;
+}
+#endif
+
+#if !defined(_MSC_VER) && !defined(__CWCC__)
+char *strdate(char *buf) {
+ time_t timestamp;
+ time(&timestamp);
+ tm *localTm = localtime(&timestamp);
+ strftime(buf, 10, "%m/%d/%y", localTm);
+ return buf;
+}
+
+char *_strdate(char *buf) {
+ return strdate(buf);
+}
+#endif