2022-05-28 01:57:32 -07:00
|
|
|
#include "platform_compat.h"
|
|
|
|
|
2022-05-28 13:17:48 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
2022-05-29 08:15:48 -07:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
|
2022-05-28 14:22:40 -07:00
|
|
|
#ifdef _WIN32
|
2022-07-25 10:38:11 -07:00
|
|
|
#include <direct.h>
|
2022-05-28 14:22:40 -07:00
|
|
|
#include <io.h>
|
|
|
|
#include <stdio.h>
|
2022-07-25 10:48:35 -07:00
|
|
|
#include <stdlib.h>
|
2022-05-28 14:22:40 -07:00
|
|
|
#else
|
2023-04-26 07:45:36 -07:00
|
|
|
#include <dirent.h>
|
2022-07-25 10:38:11 -07:00
|
|
|
#include <sys/stat.h>
|
2022-05-28 14:22:40 -07:00
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2022-05-29 08:15:48 -07:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <timeapi.h>
|
|
|
|
#else
|
2022-06-02 11:11:23 -07:00
|
|
|
#include <chrono>
|
2022-05-29 08:15:48 -07:00
|
|
|
#endif
|
|
|
|
|
2022-09-15 02:38:23 -07:00
|
|
|
#include <SDL.h>
|
|
|
|
|
2022-09-23 05:43:44 -07:00
|
|
|
namespace fallout {
|
|
|
|
|
2022-05-28 01:57:32 -07:00
|
|
|
int compat_stricmp(const char* string1, const char* string2)
|
|
|
|
{
|
|
|
|
return SDL_strcasecmp(string1, string2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int compat_strnicmp(const char* string1, const char* string2, size_t size)
|
|
|
|
{
|
|
|
|
return SDL_strncasecmp(string1, string2, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* compat_strupr(char* string)
|
|
|
|
{
|
|
|
|
return SDL_strupr(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* compat_strlwr(char* string)
|
|
|
|
{
|
|
|
|
return SDL_strlwr(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
char* compat_itoa(int value, char* buffer, int radix)
|
|
|
|
{
|
|
|
|
return SDL_itoa(value, buffer, radix);
|
|
|
|
}
|
2022-05-28 13:17:48 -07:00
|
|
|
|
|
|
|
void compat_splitpath(const char* path, char* drive, char* dir, char* fname, char* ext)
|
|
|
|
{
|
2022-07-25 10:48:35 -07:00
|
|
|
#ifdef _WIN32
|
2022-05-28 13:17:48 -07:00
|
|
|
_splitpath(path, drive, dir, fname, ext);
|
|
|
|
#else
|
2022-07-29 06:04:05 -07:00
|
|
|
const char* driveStart = path;
|
2022-07-25 10:38:11 -07:00
|
|
|
if (path[0] == '/' && path[1] == '/') {
|
|
|
|
path += 2;
|
|
|
|
while (*path != '\0' && *path != '/' && *path != '.') {
|
|
|
|
path++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-28 13:17:48 -07:00
|
|
|
if (drive != NULL) {
|
2022-07-25 10:38:11 -07:00
|
|
|
size_t driveSize = path - driveStart;
|
|
|
|
if (driveSize > COMPAT_MAX_DRIVE - 1) {
|
|
|
|
driveSize = COMPAT_MAX_DRIVE - 1;
|
|
|
|
}
|
|
|
|
strncpy(drive, path, driveSize);
|
|
|
|
drive[driveSize] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* dirStart = path;
|
|
|
|
const char* fnameStart = path;
|
|
|
|
const char* extStart = NULL;
|
|
|
|
|
|
|
|
const char* end = path;
|
|
|
|
while (*end != '\0') {
|
|
|
|
if (*end == '/') {
|
|
|
|
fnameStart = end + 1;
|
|
|
|
} else if (*end == '.') {
|
|
|
|
extStart = end;
|
|
|
|
}
|
|
|
|
end++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extStart == NULL) {
|
|
|
|
extStart = end;
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dir != NULL) {
|
2022-07-25 10:38:11 -07:00
|
|
|
size_t dirSize = fnameStart - dirStart;
|
|
|
|
if (dirSize > COMPAT_MAX_DIR - 1) {
|
|
|
|
dirSize = COMPAT_MAX_DIR - 1;
|
|
|
|
}
|
|
|
|
strncpy(dir, path, dirSize);
|
|
|
|
dir[dirSize] = '\0';
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fname != NULL) {
|
2022-07-25 10:38:11 -07:00
|
|
|
size_t fileNameSize = extStart - fnameStart;
|
|
|
|
if (fileNameSize > COMPAT_MAX_FNAME - 1) {
|
|
|
|
fileNameSize = COMPAT_MAX_FNAME - 1;
|
|
|
|
}
|
|
|
|
strncpy(fname, fnameStart, fileNameSize);
|
|
|
|
fname[fileNameSize] = '\0';
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
2022-07-25 10:48:35 -07:00
|
|
|
|
2022-05-28 13:17:48 -07:00
|
|
|
if (ext != NULL) {
|
2022-07-25 10:38:11 -07:00
|
|
|
size_t extSize = end - extStart;
|
|
|
|
if (extSize > COMPAT_MAX_EXT - 1) {
|
|
|
|
extSize = COMPAT_MAX_EXT - 1;
|
|
|
|
}
|
|
|
|
strncpy(ext, extStart, extSize);
|
|
|
|
ext[extSize] = '\0';
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void compat_makepath(char* path, const char* drive, const char* dir, const char* fname, const char* ext)
|
|
|
|
{
|
2022-07-25 10:48:35 -07:00
|
|
|
#ifdef _WIN32
|
2022-05-28 13:17:48 -07:00
|
|
|
_makepath(path, drive, dir, fname, ext);
|
|
|
|
#else
|
2022-07-25 10:38:11 -07:00
|
|
|
path[0] = '\0';
|
2022-05-28 13:17:48 -07:00
|
|
|
|
|
|
|
if (drive != NULL) {
|
2022-07-25 10:38:11 -07:00
|
|
|
if (*drive != '\0') {
|
|
|
|
strcpy(path, drive);
|
|
|
|
path = strchr(path, '\0');
|
2022-07-29 06:04:05 -07:00
|
|
|
|
2022-07-25 10:38:11 -07:00
|
|
|
if (path[-1] == '/') {
|
|
|
|
path--;
|
|
|
|
} else {
|
|
|
|
*path = '/';
|
|
|
|
}
|
|
|
|
}
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dir != NULL) {
|
2022-07-25 10:38:11 -07:00
|
|
|
if (*dir != '\0') {
|
|
|
|
if (*dir != '/' && *path == '/') {
|
|
|
|
path++;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(path, dir);
|
|
|
|
path = strchr(path, '\0');
|
|
|
|
|
|
|
|
if (path[-1] == '/') {
|
|
|
|
path--;
|
|
|
|
} else {
|
|
|
|
*path = '/';
|
|
|
|
}
|
|
|
|
}
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
|
|
|
|
2022-07-25 10:38:11 -07:00
|
|
|
if (fname != NULL && *fname != '\0') {
|
|
|
|
if (*fname != '/' && *path == '/') {
|
|
|
|
path++;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(path, fname);
|
|
|
|
path = strchr(path, '\0');
|
|
|
|
} else {
|
|
|
|
if (*path == '/') {
|
|
|
|
path++;
|
|
|
|
}
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ext != NULL) {
|
2022-07-25 10:38:11 -07:00
|
|
|
if (*ext != '\0') {
|
|
|
|
if (*ext != '.') {
|
|
|
|
*path++ = '.';
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(path, ext);
|
|
|
|
path = strchr(path, '\0');
|
|
|
|
}
|
2022-05-28 13:17:48 -07:00
|
|
|
}
|
|
|
|
|
2022-07-25 10:38:11 -07:00
|
|
|
*path = '\0';
|
2022-05-28 13:17:48 -07:00
|
|
|
#endif
|
|
|
|
}
|
2022-05-28 14:22:40 -07:00
|
|
|
|
2022-05-29 14:40:09 -07:00
|
|
|
long compat_tell(int fd)
|
|
|
|
{
|
|
|
|
return lseek(fd, 0, SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
2022-05-28 14:22:40 -07:00
|
|
|
long compat_filelength(int fd)
|
|
|
|
{
|
|
|
|
long originalOffset = lseek(fd, 0, SEEK_CUR);
|
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
long filesize = lseek(fd, 0, SEEK_END);
|
|
|
|
lseek(fd, originalOffset, SEEK_SET);
|
|
|
|
return filesize;
|
|
|
|
}
|
2022-05-29 08:08:55 -07:00
|
|
|
|
|
|
|
int compat_mkdir(const char* path)
|
|
|
|
{
|
2022-06-18 00:58:15 -07:00
|
|
|
char nativePath[COMPAT_MAX_PATH];
|
|
|
|
strcpy(nativePath, path);
|
|
|
|
compat_windows_path_to_native(nativePath);
|
2023-04-26 07:45:36 -07:00
|
|
|
compat_resolve_path(nativePath);
|
2022-06-18 00:58:15 -07:00
|
|
|
|
2022-07-25 10:38:11 -07:00
|
|
|
#ifdef _WIN32
|
|
|
|
return mkdir(nativePath);
|
|
|
|
#else
|
|
|
|
return mkdir(nativePath, 0755);
|
|
|
|
#endif
|
2022-05-29 08:08:55 -07:00
|
|
|
}
|
2022-05-29 08:15:48 -07:00
|
|
|
|
|
|
|
unsigned int compat_timeGetTime()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
return timeGetTime();
|
|
|
|
#else
|
2022-06-02 11:11:23 -07:00
|
|
|
static auto start = std::chrono::steady_clock::now();
|
|
|
|
auto now = std::chrono::steady_clock::now();
|
|
|
|
return static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count());
|
2022-05-29 08:15:48 -07:00
|
|
|
#endif
|
|
|
|
}
|
2022-06-18 00:58:15 -07:00
|
|
|
|
|
|
|
FILE* compat_fopen(const char* path, const char* mode)
|
|
|
|
{
|
|
|
|
char nativePath[COMPAT_MAX_PATH];
|
|
|
|
strcpy(nativePath, path);
|
|
|
|
compat_windows_path_to_native(nativePath);
|
2023-04-26 07:45:36 -07:00
|
|
|
compat_resolve_path(nativePath);
|
2022-06-18 00:58:15 -07:00
|
|
|
return fopen(nativePath, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
gzFile compat_gzopen(const char* path, const char* mode)
|
|
|
|
{
|
|
|
|
char nativePath[COMPAT_MAX_PATH];
|
|
|
|
strcpy(nativePath, path);
|
|
|
|
compat_windows_path_to_native(nativePath);
|
2023-04-26 07:45:36 -07:00
|
|
|
compat_resolve_path(nativePath);
|
2022-06-18 00:58:15 -07:00
|
|
|
return gzopen(nativePath, mode);
|
|
|
|
}
|
|
|
|
|
2023-04-11 10:00:38 -07:00
|
|
|
char* compat_fgets(char* buffer, int maxCount, FILE* stream)
|
|
|
|
{
|
|
|
|
buffer = fgets(buffer, maxCount, stream);
|
|
|
|
|
|
|
|
if (buffer != NULL) {
|
|
|
|
size_t len = strlen(buffer);
|
|
|
|
if (len >= 2 && buffer[len - 1] == '\n' && buffer[len - 2] == '\r') {
|
|
|
|
buffer[len - 2] = '\n';
|
|
|
|
buffer[len - 1] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* compat_gzgets(gzFile stream, char* buffer, int maxCount)
|
|
|
|
{
|
|
|
|
buffer = gzgets(stream, buffer, maxCount);
|
|
|
|
|
|
|
|
if (buffer != NULL) {
|
|
|
|
size_t len = strlen(buffer);
|
|
|
|
if (len >= 2 && buffer[len - 1] == '\n' && buffer[len - 2] == '\r') {
|
|
|
|
buffer[len - 2] = '\n';
|
|
|
|
buffer[len - 1] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2022-06-18 00:58:15 -07:00
|
|
|
int compat_remove(const char* path)
|
|
|
|
{
|
|
|
|
char nativePath[COMPAT_MAX_PATH];
|
|
|
|
strcpy(nativePath, path);
|
|
|
|
compat_windows_path_to_native(nativePath);
|
2023-04-26 07:45:36 -07:00
|
|
|
compat_resolve_path(nativePath);
|
2022-06-18 00:58:15 -07:00
|
|
|
return remove(nativePath);
|
|
|
|
}
|
|
|
|
|
|
|
|
int compat_rename(const char* oldFileName, const char* newFileName)
|
|
|
|
{
|
|
|
|
char nativeOldFileName[COMPAT_MAX_PATH];
|
|
|
|
strcpy(nativeOldFileName, oldFileName);
|
|
|
|
compat_windows_path_to_native(nativeOldFileName);
|
2023-04-26 07:45:36 -07:00
|
|
|
compat_resolve_path(nativeOldFileName);
|
2022-06-18 00:58:15 -07:00
|
|
|
|
|
|
|
char nativeNewFileName[COMPAT_MAX_PATH];
|
|
|
|
strcpy(nativeNewFileName, newFileName);
|
|
|
|
compat_windows_path_to_native(nativeNewFileName);
|
2023-04-26 07:45:36 -07:00
|
|
|
compat_resolve_path(nativeNewFileName);
|
2022-06-18 00:58:15 -07:00
|
|
|
|
|
|
|
return rename(nativeOldFileName, nativeNewFileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
void compat_windows_path_to_native(char* path)
|
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
char* pch = path;
|
|
|
|
while (*pch != '\0') {
|
|
|
|
if (*pch == '\\') {
|
|
|
|
*pch = '/';
|
|
|
|
}
|
|
|
|
pch++;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2022-08-31 20:48:26 -07:00
|
|
|
|
2023-04-26 07:45:36 -07:00
|
|
|
void compat_resolve_path(char* path)
|
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
char* pch = path;
|
|
|
|
|
|
|
|
DIR *dir;
|
|
|
|
if (pch[0] == '/') {
|
|
|
|
dir = opendir("/");
|
|
|
|
pch++;
|
|
|
|
} else {
|
|
|
|
dir = opendir(".");
|
|
|
|
}
|
|
|
|
|
|
|
|
while (dir != NULL) {
|
|
|
|
char* sep = strchr(pch, '/');
|
|
|
|
size_t length;
|
|
|
|
if (sep != NULL) {
|
|
|
|
length = sep - pch;
|
|
|
|
} else {
|
|
|
|
length = strlen(pch);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
struct dirent* entry = readdir(dir);
|
|
|
|
while (entry != NULL) {
|
|
|
|
if (strlen(entry->d_name) == length && compat_strnicmp(pch, entry->d_name, length) == 0) {
|
|
|
|
strncpy(pch, entry->d_name, length);
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
entry = readdir(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
dir = NULL;
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sep == NULL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
*sep = '\0';
|
|
|
|
dir = opendir(path);
|
|
|
|
*sep = '/';
|
|
|
|
|
|
|
|
pch = sep + 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2022-08-31 20:48:26 -07:00
|
|
|
char* compat_strdup(const char* string)
|
|
|
|
{
|
|
|
|
return SDL_strdup(string);
|
|
|
|
}
|
2022-08-31 21:37:00 -07:00
|
|
|
|
|
|
|
// It's a replacement for compat_filelength(fileno(stream)) on platforms without
|
|
|
|
// fileno defined.
|
|
|
|
long getFileSize(FILE* stream)
|
|
|
|
{
|
|
|
|
long originalOffset = ftell(stream);
|
|
|
|
fseek(stream, 0, SEEK_END);
|
|
|
|
long filesize = ftell(stream);
|
|
|
|
fseek(stream, originalOffset, SEEK_SET);
|
|
|
|
return filesize;
|
|
|
|
}
|
2022-09-23 05:43:44 -07:00
|
|
|
|
|
|
|
} // namespace fallout
|