Merge pull request #591 from winterheart/ddio-update

Update DDIO and related to it's code OSIRIS
This commit is contained in:
Louis Gombert 2024-09-23 22:37:14 +02:00 committed by GitHub
commit 0e228aa9db
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 312 additions and 658 deletions

View File

@ -40,7 +40,7 @@
// input_channels (default 1)
// input_factor (compression factor) (default 4 for 22K, 8 for 44K)
// input_volscale (Volume scaling) (slightly <= 1.0, default ,97)
bool aenc_Compress(char *input_filename, char *output_filename, const int *input_levels = nullptr,
bool aenc_Compress(const char *input_filename, const char *output_filename, const int *input_levels = nullptr,
const int *input_samples = nullptr, const int *input_rate = nullptr,
const int *input_channels = nullptr, const float *input_factor = nullptr,
const float *input_volscale = nullptr);

View File

@ -36,7 +36,7 @@ int32_t aenc_ReadSamp(void *data) {
return (b << 8) | a;
}
bool aenc_Compress(char *input_filename, char *output_filename, const int *input_levels, const int *input_samples,
bool aenc_Compress(const char *input_filename, const char *output_filename, const int *input_levels, const int *input_samples,
const int *input_rate, const int *input_channels, const float *input_factor,
const float *input_volscale) {
FILE *in, *out;

View File

@ -645,10 +645,10 @@ void ForceEffectsInit(void) {
int lowid;
Force_time_since_last_shake = 0;
FORCEPROJECT prj;
char path[_MAX_PATH];
std::filesystem::path path;
if (cfexist("D3Force.ifr")) {
ddio_MakePath(path, Descent3_temp_directory, "D3Force.ifr", NULL);
path = Descent3_temp_directory / "D3Force.ifr";
cf_CopyFile(path, "D3Force.ifr", 0);
prj = ddio_ForceLoadProject(IGNORE_TABLE(path), kJoy1);
} else {
@ -708,6 +708,6 @@ void ForceEffectsInit(void) {
ddio_ForceUnloadProject(prj);
if (cfexist(path)) {
ddio_DeleteFile(path);
std::filesystem::remove(path);
}
}

View File

@ -111,7 +111,7 @@ DLLGameClose_fp DLLGameClose = NULL;
DLLGetGameInfo_fp DLLGetGameInfo = NULL;
dllinfo DLLInfo;
tOSIRISModuleInit Multi_d3m_osiris_funcs;
char Multi_game_dll_name[_MAX_PATH * 2];
std::filesystem::path Multi_game_dll_name;
static void DUMMYrend_DrawScaledBitmap(int x1, int y1, int x2, int y2, int bm, float u0, float v0, float u1, float v1,
float zval, int color, float *alphas) {
@ -551,9 +551,9 @@ void CloseGameModule(module *mod) {
// Clear out error queue
mod_GetLastError();
mod_FreeModule(mod);
if (Multi_game_dll_name[0] != '\0') {
if (Multi_game_dll_name.empty()) {
// Try deleting the file now!
if (!ddio_DeleteFile(Multi_game_dll_name)) {
if (!std::filesystem::remove(Multi_game_dll_name)) {
LOG_WARNING << "Couldn't delete the tmp dll";
}
}
@ -561,30 +561,26 @@ void CloseGameModule(module *mod) {
}
// this function will load up the DLL, but not get any symbols
bool InitGameModule(const char *name, module *mod) {
char lib_name[_MAX_PATH * 2];
char dll_name[_MAX_PATH * 2];
char tmp_dll_name[_MAX_PATH * 2];
std::filesystem::path lib_name;
std::filesystem::path dll_name;
std::filesystem::path tmp_dll_name;
// Make the hog filename
ddio_MakePath(lib_name, Base_directory, "netgames", name, NULL);
strcat(lib_name, ".d3m");
// Make the dll filename
#if defined(WIN32)
snprintf(dll_name, sizeof(dll_name), "%s.dll", name);
#elif defined(MACOSX)
snprintf(dll_name, sizeof(dll_name), "%s.dylib", name);
#else
snprintf(dll_name, sizeof(dll_name), "%s.so", name);
#endif
lib_name = std::filesystem::path(Base_directory) / "netgames" / name;
lib_name.replace_extension(".d3m");
// Make the dll filename
dll_name = name;
dll_name.replace_extension(MODULE_EXT);
// Open the hog file
if (!cf_OpenLibrary(lib_name)) {
ddio_MakePath(tmp_dll_name, Base_directory, "netgames", name, NULL);
strcat(tmp_dll_name, ".d3m");
Multi_game_dll_name[0] = '\0';
tmp_dll_name = std::filesystem::path(Base_directory) / "netgames" / name;
tmp_dll_name.replace_extension(".d3m");
Multi_game_dll_name.clear();
goto loaddll;
}
// get a temp file name
if (!ddio_GetTempFileName(Descent3_temp_directory, "d3m", tmp_dll_name)) {
tmp_dll_name = ddio_GetTmpFileName(Descent3_temp_directory, "d3m");
if (tmp_dll_name.empty()) {
return false;
}
// Copy the DLL
@ -592,7 +588,7 @@ bool InitGameModule(const char *name, module *mod) {
LOG_WARNING << "DLL copy failed!";
return false;
}
strcpy(Multi_game_dll_name, tmp_dll_name);
Multi_game_dll_name = tmp_dll_name;
loaddll:
// Clear out error queue
mod_GetLastError();

View File

@ -1,5 +1,5 @@
/*
* Descent 3
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
@ -400,6 +400,8 @@
*/
#include <cstdlib>
#include <filesystem>
#include <map>
#include "osiris_dll.h"
#include "pserror.h"
@ -425,7 +427,6 @@
#define OSIRISDEBUG
#endif
bool Show_osiris_debug = false;
#define MAX_LOADED_MODULES 96 // maximum number of dlls that can be loaded at a time
@ -510,13 +511,14 @@ struct {
#define OESF_USED 0x0001
#define OESF_MISSION 0x0002 // mission dlls
struct tExtractedScriptInfo {
uint8_t flags;
char *temp_filename;
char *real_filename;
uint8_t flags = 0;
std::filesystem::path temp_filename;
};
static tExtractedScriptInfo OSIRIS_Extracted_scripts[MAX_LOADED_MODULES];
static char *OSIRIS_Extracted_script_dir = NULL;
static std::map<std::filesystem::path, tExtractedScriptInfo> OSIRIS_Extracted_scripts;
static std::filesystem::path OSIRIS_Extracted_script_dir;
// Osiris_CreateModuleInitStruct
// Purpose:
@ -619,7 +621,7 @@ void Osiris_InitModuleLoader(void) {
Osiris_InitMemoryManager();
Osiris_InitOMMS();
OSIRIS_Extracted_script_dir = NULL;
OSIRIS_Extracted_script_dir.clear();
atexit(Osiris_ShutdownModuleLoader);
}
@ -769,16 +771,15 @@ void Osiris_DumpLoadedObjects(char *file) {
// Osiris_FindLoadedModule
// Purpose:
// Given the name of a module, it returns the id of a loaded OSIRIS module. -1 if it isn't loaded.
int Osiris_FindLoadedModule(char *module_name) {
int Osiris_FindLoadedModule(const std::filesystem::path &module_name) {
// search through the list of loaded modules and see if we can find a match
// strip off the extension
char real_name[_MAX_PATH];
ddio_SplitPath(module_name, NULL, real_name, NULL);
std::filesystem::path real_name = module_name.stem();
int i;
for (i = 0; i < MAX_LOADED_MODULES; i++) {
for (int i = 0; i < MAX_LOADED_MODULES; i++) {
if (OSIRIS_loaded_modules[i].flags & OSIMF_INUSE) {
if (OSIRIS_loaded_modules[i].module_name && (!stricmp(OSIRIS_loaded_modules[i].module_name, real_name))) {
if (OSIRIS_loaded_modules[i].module_name &&
(stricmp(OSIRIS_loaded_modules[i].module_name, real_name.u8string().c_str()) == 0)) {
// we found a match
return i;
}
@ -797,8 +798,8 @@ void Osiris_UnloadModule(int module_id) {
return;
if (OSIRIS_loaded_modules[module_id].flags & OSIMF_INUSE) {
// the module is in use
LOG_DEBUG_IF(Show_osiris_debug).printf("OSIRIS: Decrementing reference count for module (%s)",
OSIRIS_loaded_modules[module_id].module_name);
LOG_DEBUG_IF(Show_osiris_debug)
.printf("OSIRIS: Decrementing reference count for module (%s)", OSIRIS_loaded_modules[module_id].module_name);
OSIRIS_loaded_modules[module_id].reference_count--;
ASSERT(OSIRIS_loaded_modules[module_id].reference_count >= 0);
@ -815,8 +816,9 @@ void Osiris_UnloadModule(int module_id) {
OSIRIS_loaded_modules[module_id].module_name);
} else {
// time to unload this module
LOG_DEBUG_IF(Show_osiris_debug).printf("OSIRIS: Module (%s) reference count is at 0, unloading",
OSIRIS_loaded_modules[module_id].module_name);
LOG_DEBUG_IF(Show_osiris_debug)
.printf("OSIRIS: Module (%s) reference count is at 0, unloading",
OSIRIS_loaded_modules[module_id].module_name);
Osiris_FreeModule(module_id);
}
}
@ -880,31 +882,25 @@ void Osiris_UnloadLevelModule(void) {
// returns: -2 if not found
// -1 if it is in data\scripts
// 0-x which extracted script id it is
int _get_full_path_to_module(char *module_name, char *fullpath, char *basename) {
char ppath[_MAX_PATH], pext[256];
char adjusted_name[_MAX_PATH], adjusted_fname[_MAX_PATH];
char *p;
int get_full_path_to_module(const std::filesystem::path &module_name, std::filesystem::path &fullpath,
std::filesystem::path &basename) {
std::filesystem::path ppath;
std::filesystem::path adjusted_name, adjusted_fname;
ddio_SplitPath(module_name, ppath, basename, pext);
ppath = module_name.parent_path();
adjusted_fname = module_name.filename();
// make sure filename/ext is all lowercase, requirement for Linux, doesn't hurt Windows
p = basename;
while (p && *p) {
*p = tolower(*p);
p++;
}
p = pext;
while (p && *p) {
*p = tolower(*p);
p++;
}
strcpy(adjusted_fname, basename);
strcat(adjusted_fname, pext);
std::string p = adjusted_fname.u8string();
std::transform(p.begin(), p.end(), p.begin(), [](unsigned char c) { return std::tolower(c); });
adjusted_fname = p;
if (strlen(ppath) > 0) {
ddio_MakePath(adjusted_name, ppath, adjusted_fname, NULL);
basename = adjusted_fname.stem();
if (ppath.empty()) {
adjusted_name = adjusted_fname;
} else {
strcpy(adjusted_name, adjusted_fname);
adjusted_name = ppath / adjusted_fname;
}
// determine real name of script
@ -913,28 +909,23 @@ int _get_full_path_to_module(char *module_name, char *fullpath, char *basename)
int exist = cfexist(modfilename);
switch (exist) {
case CFES_ON_DISK:
ddio_MakePath(fullpath, LocalScriptDir, modfilename.u8string().c_str(), NULL);
fullpath = std::filesystem::path(LocalScriptDir) / modfilename;
return -1;
break;
case CFES_IN_LIBRARY: {
ASSERT(OSIRIS_Extracted_script_dir);
if (!OSIRIS_Extracted_script_dir)
ASSERT(!OSIRIS_Extracted_script_dir.empty());
if (OSIRIS_Extracted_script_dir.empty())
return -2;
// search through our list of extracted files to find it...
for (int i = 0; i < MAX_LOADED_MODULES; i++) {
if (OSIRIS_Extracted_scripts[i].flags & OESF_USED) {
if (!stricmp(basename, OSIRIS_Extracted_scripts[i].real_filename)) {
// this is it
ddio_MakePath(fullpath, OSIRIS_Extracted_script_dir, OSIRIS_Extracted_scripts[i].temp_filename, NULL);
return i;
}
}
if (OSIRIS_Extracted_scripts.find(std::filesystem::path(basename)) != OSIRIS_Extracted_scripts.end()) {
fullpath = OSIRIS_Extracted_script_dir / OSIRIS_Extracted_scripts[basename].temp_filename;
return 0;
}
Int3(); // this file was supposed to exist
} break;
default:
*fullpath = '\0';
fullpath.clear();
return -2;
};
return -2;
@ -947,7 +938,7 @@ int _get_full_path_to_module(char *module_name, char *fullpath, char *basename)
// before calling this function, it will return the id to where the module is, and will not reload
// the module. Returns -1 if the module does not exist. Returns -2 if the module couldn't initialize.
// Returns -3 if the module is not a level module. Returns -4 if no module slots are available.
int Osiris_LoadLevelModule(char *module_name) {
int Osiris_LoadLevelModule(const std::filesystem::path &module_name) {
if ((Game_mode & GM_MULTI) && (Netgame.local_role != LR_SERVER)) {
// no scripts for a client!
return -2;
@ -964,8 +955,9 @@ int Osiris_LoadLevelModule(char *module_name) {
if (loaded_id != -1) {
// the module is already loaded
OSIRIS_loaded_modules[loaded_id].reference_count++;
LOG_DEBUG_IF(Show_osiris_debug).printf("OSIRIS: Level Module (%s) reference count increased to %d",
module_name, OSIRIS_loaded_modules[loaded_id].reference_count);
LOG_DEBUG_IF(Show_osiris_debug)
.printf("OSIRIS: Level Module (%s) reference count increased to %d", module_name.u8string().c_str(),
OSIRIS_loaded_modules[loaded_id].reference_count);
return loaded_id;
}
@ -979,19 +971,19 @@ int Osiris_LoadLevelModule(char *module_name) {
if (loaded_id >= MAX_LOADED_MODULES) {
// no slots available
LOG_FATAL.printf("OSIRIS: Osiris_LoadLevelModule(%s): No available slots\n", module_name);
LOG_FATAL.printf("OSIRIS: Osiris_LoadLevelModule(%s): No available slots\n", module_name.u8string().c_str());
Int3();
return -4;
}
OSIRIS_loaded_modules[loaded_id].flags = 0; // set this to 0 as we fill in the data
char fullpath[_MAX_PATH], basename[_MAX_PATH];
int ret_val = _get_full_path_to_module(module_name, fullpath, basename);
std::filesystem::path fullpath, basename;
int ret_val = get_full_path_to_module(module_name, fullpath, basename);
switch (ret_val) {
case -2:
// the module does not exist
LOG_ERROR.printf("OSIRIS: Osiris_LoadLevelModule(%s): Module doesn't exist", module_name);
LOG_ERROR.printf("OSIRIS: Osiris_LoadLevelModule(%s): Module doesn't exist", module_name.u8string().c_str());
return -1;
break;
case -1:
@ -999,7 +991,8 @@ int Osiris_LoadLevelModule(char *module_name) {
break;
default:
// the module was an extracted file
LOG_DEBUG.printf("OSIRIS: Found module (%s) in a temp file", basename);
LOG_DEBUG.printf("OSIRIS: Found module (%s) in a temp file (%s)", basename.u8string().c_str(),
fullpath.u8string().c_str());
OSIRIS_loaded_modules[loaded_id].flags |= OSIMF_INTEMPDIR;
OSIRIS_loaded_modules[loaded_id].extracted_id = ret_val;
break;
@ -1008,7 +1001,7 @@ int Osiris_LoadLevelModule(char *module_name) {
// the module exists, now attempt to load it
if (!mod_LoadModule(&OSIRIS_loaded_modules[loaded_id].mod, fullpath)) {
// there was an error trying to load the module
LOG_FATAL.printf("OSIRIS: Osiris_LoadLevelModule(%s): Unable to load module", module_name);
LOG_FATAL.printf("OSIRIS: Osiris_LoadLevelModule(%s): Unable to load module", module_name.u8string().c_str());
Int3();
return -3;
}
@ -1039,7 +1032,7 @@ int Osiris_LoadLevelModule(char *module_name) {
osm->SaveRestoreState = (SaveRestoreState_fp)mod_GetSymbol(mod, "SaveRestoreState", 8);
osm->flags |= OSIMF_INUSE | OSIMF_LEVEL;
osm->module_name = mem_strdup(basename);
osm->module_name = mem_strdup(basename.u8string().c_str());
osm->reference_count = 1;
#ifdef OSIRISDEBUG
@ -1052,7 +1045,7 @@ int Osiris_LoadLevelModule(char *module_name) {
!osm->GetCOScriptList || !osm->CreateInstance || !osm->DestroyInstance || !osm->SaveRestoreState ||
!osm->CallInstanceEvent) {
// there was an error importing a function
LOG_ERROR.printf("OSIRIS: Osiris_LoadLevelModule(%s) couldn't import function.", module_name);
LOG_ERROR.printf("OSIRIS: Osiris_LoadLevelModule(%s) couldn't import function.", module_name.u8string().c_str());
Int3();
osm->flags = 0;
if (osm->module_name)
@ -1064,14 +1057,15 @@ int Osiris_LoadLevelModule(char *module_name) {
// check to see if there is a corresponding string table to load
char stringtablename[_MAX_PATH];
strcpy(stringtablename, basename);
strcpy(stringtablename, basename.u8string().c_str());
strcat(stringtablename, ".str");
if (cfexist(stringtablename)) {
// there is a string table, load it up
bool ret = CreateStringTable(stringtablename, &osm->string_table, &osm->strings_loaded);
if (!ret) {
LOG_ERROR.printf("OSIRIS: Unable to load string table (%s) for (%s)\n", stringtablename, basename);
LOG_ERROR.printf("OSIRIS: Unable to load string table (%s) for (%s)", stringtablename,
basename.u8string().c_str());
Int3();
osm->string_table = NULL;
osm->strings_loaded = 0;
@ -1090,7 +1084,7 @@ int Osiris_LoadLevelModule(char *module_name) {
// when we get to this point we nearly have a loaded module, we just need to initialize it
if (!osm->InitializeDLL(&Osiris_module_init)) {
// there was an error initializing the module
LOG_ERROR.printf("OSIRIS: Osiris_LoadLevelModule(%s) error initializing module.", basename);
LOG_ERROR.printf("OSIRIS: Osiris_LoadLevelModule(%s) error initializing module.", basename.u8string().c_str());
if (osm->string_table) {
DestroyStringTable(osm->string_table, osm->strings_loaded);
}
@ -1133,8 +1127,8 @@ int Osiris_LoadLevelModule(char *module_name) {
tOSIRISCurrentLevel.instance =
OSIRIS_loaded_modules[loaded_id].CreateInstance(0); // level scripts always have id of 0 in a level dll
LOG_INFO.printf("OSIRIS: Level Module (%s) loaded successfully (%d custom handles)", basename,
tOSIRISCurrentLevel.num_customs);
LOG_INFO.printf("OSIRIS: Level Module (%s) loaded successfully (%d custom handles)", basename.u8string().c_str(),
tOSIRISCurrentLevel.num_customs);
Osiris_level_script_loaded = true;
return loaded_id;
}
@ -1146,8 +1140,8 @@ int Osiris_LoadLevelModule(char *module_name) {
// before calling this function, it will return the id to where the module is, and will not reload
// the module. Returns -1 if the module does not exist. Returns -2 if the module couldn't initialize.
// Returns -3 if the module is not a game module. Returns -4 if no module slots are available.
int Osiris_LoadGameModule(char *module_name) {
if (module_name[0] == '\0') {
int Osiris_LoadGameModule(const std::filesystem::path &module_name) {
if (module_name.empty()) {
return -1;
}
@ -1157,8 +1151,8 @@ int Osiris_LoadGameModule(char *module_name) {
// the module is already loaded
OSIRIS_loaded_modules[loaded_id].reference_count++;
if (Show_osiris_debug) {
LOG_DEBUG.printf("OSIRIS: Game Module (%s) reference count increased to %d", module_name,
OSIRIS_loaded_modules[loaded_id].reference_count);
LOG_DEBUG.printf("OSIRIS: Game Module (%s) reference count increased to %d", module_name.u8string().c_str(),
OSIRIS_loaded_modules[loaded_id].reference_count);
}
return loaded_id;
}
@ -1173,19 +1167,19 @@ int Osiris_LoadGameModule(char *module_name) {
if (loaded_id >= MAX_LOADED_MODULES) {
// no slots available
LOG_FATAL.printf("OSIRIS: Osiris_LoadGameModule(%s): No available slots", module_name);
LOG_FATAL.printf("OSIRIS: Osiris_LoadGameModule(%s): No available slots", module_name.u8string().c_str());
Int3();
return -4;
}
OSIRIS_loaded_modules[loaded_id].flags = 0; // set this to 0 as we fill in the data
char fullpath[_MAX_PATH], basename[_MAX_PATH];
int ret_val = _get_full_path_to_module(module_name, fullpath, basename);
std::filesystem::path fullpath, basename;
int ret_val = get_full_path_to_module(module_name, fullpath, basename);
switch (ret_val) {
case -2:
// the module does not exist
LOG_WARNING.printf("OSIRIS: Osiris_LoadLevelModule(%s): Module doesn't exist", module_name);
LOG_WARNING.printf("OSIRIS: Osiris_LoadLevelModule(%s): Module doesn't exist", module_name.u8string().c_str());
return -1;
break;
case -1:
@ -1193,7 +1187,7 @@ int Osiris_LoadGameModule(char *module_name) {
break;
default:
// the module was an extracted file
LOG_INFO.printf("OSIRIS: Found module (%s) in a temp file", basename);
LOG_INFO.printf("OSIRIS: Found module (%s) in a temp file", basename.u8string().c_str());
OSIRIS_loaded_modules[loaded_id].flags |= OSIMF_INTEMPDIR;
OSIRIS_loaded_modules[loaded_id].extracted_id = ret_val;
break;
@ -1202,7 +1196,7 @@ int Osiris_LoadGameModule(char *module_name) {
// the module exists, now attempt to load it
if (!mod_LoadModule(&OSIRIS_loaded_modules[loaded_id].mod, fullpath)) {
// there was an error trying to load the module
LOG_FATAL.printf("OSIRIS: Osiris_LoadGameModule(%s): Unable to load module", module_name);
LOG_FATAL.printf("OSIRIS: Osiris_LoadGameModule(%s): Unable to load module", module_name.u8string().c_str());
Int3();
return -3;
}
@ -1223,52 +1217,53 @@ int Osiris_LoadGameModule(char *module_name) {
osm->InitializeDLL = (InitializeDLL_fp)mod_GetSymbol(mod, "InitializeDLL", 4);
osm->ShutdownDLL = (ShutdownDLL_fp)mod_GetSymbol(mod, "ShutdownDLL", 0);
osm->GetGOScriptID = (GetGOScriptID_fp)mod_GetSymbol(mod, "GetGOScriptID", 8);
osm->GetTriggerScriptID = NULL;
osm->GetCOScriptList = NULL;
osm->GetTriggerScriptID = nullptr;
osm->GetCOScriptList = nullptr;
osm->CreateInstance = (CreateInstance_fp)mod_GetSymbol(mod, "CreateInstance", 4);
osm->DestroyInstance = (DestroyInstance_fp)mod_GetSymbol(mod, "DestroyInstance", 8);
osm->CallInstanceEvent = (CallInstanceEvent_fp)mod_GetSymbol(mod, "CallInstanceEvent", 16);
osm->SaveRestoreState = (SaveRestoreState_fp)mod_GetSymbol(mod, "SaveRestoreState", 8);
osm->flags |= OSIMF_INUSE;
osm->module_name = mem_strdup(basename);
osm->module_name = mem_strdup(basename.u8string().c_str());
osm->reference_count = 1;
#ifdef OSIRISDEBUG
ASSERT(osm->RefRoot == NULL);
osm->RefRoot = NULL;
ASSERT(osm->RefRoot == nullptr);
osm->RefRoot = nullptr;
#endif
// make sure all of the functions imported ok
if (!osm->InitializeDLL || !osm->ShutdownDLL || !osm->GetGOScriptID || !osm->CreateInstance ||
!osm->DestroyInstance || !osm->SaveRestoreState || !osm->CallInstanceEvent) {
// there was an error importing a function
LOG_WARNING.printf("OSIRIS: Osiris_LoadGameModule(%s) couldn't import function.", basename);
LOG_WARNING.printf("OSIRIS: Osiris_LoadGameModule(%s) couldn't import function.", basename.u8string().c_str());
Int3();
osm->flags = 0;
if (osm->module_name)
mem_free(osm->module_name);
osm->module_name = NULL;
osm->module_name = nullptr;
mod_FreeModule(mod);
return -3;
}
// check to see if there is a corresponding string table to load
char stringtablename[_MAX_PATH];
strcpy(stringtablename, basename);
strcpy(stringtablename, basename.u8string().c_str());
strcat(stringtablename, ".str");
if (cfexist(stringtablename)) {
// there is a string table, load it up
bool ret = CreateStringTable(stringtablename, &osm->string_table, &osm->strings_loaded);
if (!ret) {
LOG_FATAL.printf("OSIRIS: Unable to load string table (%s) for (%s)", stringtablename, basename);
LOG_FATAL.printf("OSIRIS: Unable to load string table (%s) for (%s)", stringtablename,
basename.u8string().c_str());
Int3();
osm->string_table = NULL;
osm->string_table = nullptr;
osm->strings_loaded = 0;
}
} else {
osm->string_table = NULL;
osm->string_table = nullptr;
osm->strings_loaded = 0;
}
Osiris_module_init.string_count = osm->strings_loaded;
@ -1280,7 +1275,7 @@ int Osiris_LoadGameModule(char *module_name) {
// when we get to this point we nearly have a loaded module, we just need to initialize it
if (!osm->InitializeDLL(&Osiris_module_init)) {
// there was an error initializing the module
LOG_ERROR.printf("OSIRIS: Osiris_LoadGameModule(%s) error initializing module.", basename);
LOG_ERROR.printf("OSIRIS: Osiris_LoadGameModule(%s) error initializing module.", basename.u8string().c_str());
if (osm->string_table) {
DestroyStringTable(osm->string_table, osm->strings_loaded);
}
@ -1301,7 +1296,7 @@ int Osiris_LoadGameModule(char *module_name) {
}
// we have a successful module load
LOG_INFO.printf("OSIRIS: Game Module (%s) loaded successfully", basename);
LOG_INFO.printf("OSIRIS: Game Module (%s) loaded successfully", basename.u8string().c_str());
return loaded_id;
}
@ -1376,8 +1371,8 @@ int Osiris_LoadMissionModule(module *module_handle, const char *filename) {
osm->reference_count = 1;
#ifdef OSIRISDEBUG
ASSERT(osm->RefRoot == NULL);
osm->RefRoot = NULL;
ASSERT(osm->RefRoot == nullptr);
osm->RefRoot = nullptr;
#endif
// make sure all of the functions imported ok
@ -1653,7 +1648,7 @@ bool Osiris_BindScriptsToObject(object *obj) {
if (!gos_instance) {
// we had an error obtaining the instance of the COS...doh!
LOG_FATAL.printf("OSIRIS: Unable to create COS instance from level dll for (%s)",
(page_name) ? (page_name) : "<No Name>");
(page_name) ? (page_name) : "<No Name>");
Int3();
} else {
// ok, everything is valid
@ -2740,9 +2735,9 @@ bool Osiris_RestoreSystemState(CFILE *file) {
// when the state was saved. This means that things are not going to be restored exactly for
// sure. We'll skip over those that are not loaded. We're int3 here because I want to know
// when this happens.
LOG_ERROR.printf(
"OSIRIS: Restoring global state, the number of loaded modules is not the same as the restored count (%d vs. %d)",
loaded_module_count, read_module_count);
LOG_ERROR.printf("OSIRIS: Restoring global state, the number of loaded modules is not the same as the restored "
"count (%d vs. %d)",
loaded_module_count, read_module_count);
if (Demo_flags != DF_PLAYBACK) {
Int3();
}
@ -3098,18 +3093,6 @@ void Osiris_RestoreMemoryChunks(CFILE *file) {
}
}
void _extractscript(char *script, char *tempfilename) { cf_CopyFile(tempfilename, script); }
int _getfreeextractslot(void) {
// find a free slot
for (int q = 0; q < MAX_LOADED_MODULES; q++) {
if (!(OSIRIS_Extracted_scripts[q].flags & OESF_USED)) {
return q;
}
}
return -1;
}
void _clearextractedall(void) { Osiris_ClearExtractedScripts(false); }
int Osiris_ExtractScriptsFromHog(int library_handle, bool is_mission_hog) {
@ -3118,17 +3101,18 @@ int Osiris_ExtractScriptsFromHog(int library_handle, bool is_mission_hog) {
LOG_INFO << "OSIRIS: Extracting Scripts From Hog";
char filename[_MAX_PATH], temp_filename[_MAX_PATH];
char tempdir[_MAX_PATH], temp_file[_MAX_PATH], temp_fileext[_MAX_EXT];
char temp_realname[_MAX_PATH];
char filename[_MAX_PATH];
std::filesystem::path temp_filename;
std::filesystem::path tempdir;
std::filesystem::path temp_file;
std::string temp_realname;
tExtractedScriptInfo t;
if (!OSIRIS_Extracted_script_dir) {
strcpy(tempdir, Descent3_temp_directory);
OSIRIS_Extracted_script_dir = mem_strdup(tempdir);
if (!OSIRIS_Extracted_script_dir)
Error("Out of memory");
if (OSIRIS_Extracted_script_dir.empty()) {
tempdir = Descent3_temp_directory;
OSIRIS_Extracted_script_dir = Descent3_temp_directory;
} else {
strcpy(tempdir, OSIRIS_Extracted_script_dir);
tempdir = OSIRIS_Extracted_script_dir;
}
int count = 0;
@ -3141,69 +3125,58 @@ int Osiris_ExtractScriptsFromHog(int library_handle, bool is_mission_hog) {
#elif defined(WIN32)
script_extension = "*.dll";
#else
#error Unsupported platform!
#error Unsupported platform!
#endif
int index;
index = _getfreeextractslot();
if (index == -1) {
LOG_FATAL << "OSIRIS: Out of slots extracting scripts!";
Int3();
goto ex_error;
}
LOG_DEBUG << "Search started";
if (cf_LibraryFindFirst(library_handle, script_extension, filename)) {
if (!ddio_GetTempFileName(tempdir, "d3s", temp_filename))
temp_filename = ddio_GetTmpFileName(tempdir, "d3s");
if (temp_filename.empty())
Int3();
else {
ddio_SplitPath(temp_filename, NULL, temp_file, temp_fileext);
strcat(temp_file, temp_fileext);
// extract it out
cf_CopyFile(temp_filename, filename);
OSIRIS_Extracted_scripts[index].flags = OESF_USED;
OSIRIS_Extracted_scripts[index].temp_filename = mem_strdup(temp_file);
ddio_SplitPath(filename, NULL, temp_realname, NULL);
OSIRIS_Extracted_scripts[index].real_filename = mem_strdup(temp_realname);
temp_file = temp_filename.filename();
temp_realname = std::filesystem::path(filename).stem().u8string();
// Lowercase for optimized search
std::transform(temp_realname.begin(), temp_realname.end(), temp_realname.begin(), [](unsigned char c) {
return std::tolower(c);
});
if (is_mission_hog) {
OSIRIS_Extracted_scripts[index].flags |= OESF_MISSION;
t.flags = OESF_MISSION;
}
t.temp_filename = temp_file;
OSIRIS_Extracted_scripts.insert_or_assign(temp_realname, t);
// extract it out
_extractscript(filename, temp_filename);
LOG_DEBUG.printf("Extracted %s as %s", filename, temp_filename);
LOG_DEBUG.printf("Extracted %s as %s", temp_realname.c_str(), temp_filename.u8string().c_str());
count++;
while (cf_LibraryFindNext(filename)) {
index = _getfreeextractslot();
if (index == -1) {
LOG_FATAL << "OSIRIS: Out of slots extracting scripts!";
Int3();
goto ex_error;
}
// generate temp filename
if (!ddio_GetTempFileName(tempdir, "d3s", temp_filename))
temp_filename = ddio_GetTmpFileName(tempdir, "d3s");
if (temp_filename.empty())
Int3();
else {
ddio_SplitPath(temp_filename, NULL, temp_file, temp_fileext);
strcat(temp_file, temp_fileext);
// extract it out
cf_CopyFile(temp_filename, filename);
OSIRIS_Extracted_scripts[index].flags = OESF_USED;
OSIRIS_Extracted_scripts[index].temp_filename = mem_strdup(temp_file);
ddio_SplitPath(filename, NULL, temp_realname, NULL);
OSIRIS_Extracted_scripts[index].real_filename = mem_strdup(temp_realname);
temp_file = temp_filename.filename();
temp_realname = std::filesystem::path(filename).stem().u8string();
// Lowercase for optimized search
std::transform(temp_realname.begin(), temp_realname.end(), temp_realname.begin(), [](unsigned char c) {
return std::tolower(c);
});
if (is_mission_hog) {
OSIRIS_Extracted_scripts[index].flags |= OESF_MISSION;
t.flags = OESF_MISSION;
}
t.temp_filename = temp_file;
OSIRIS_Extracted_scripts.insert_or_assign(temp_realname, t);
// extract it out
_extractscript(filename, temp_filename);
LOG_DEBUG.printf("Extracted %s as %s", filename, temp_filename);
LOG_DEBUG.printf("Extracted %s as %s", temp_realname.c_str(), temp_filename.u8string().c_str());
count++;
}
@ -3211,17 +3184,11 @@ int Osiris_ExtractScriptsFromHog(int library_handle, bool is_mission_hog) {
}
}
LOG_DEBUG << "Done Extracting";
LOG_DEBUG.printf("Extracted %d scripts", count);
ex_error:
cf_LibraryFindClose();
static bool atex = false;
if (!atex) {
atexit(_clearextractedall);
atex = true;
}
atexit(_clearextractedall);
return count;
}
@ -3229,35 +3196,20 @@ ex_error:
void Osiris_ClearExtractedScripts(bool mission_only) {
LOG_DEBUG << "OSIRIS: Removing Extracted DLLs";
char fullpath[_MAX_PATH];
if (!OSIRIS_Extracted_script_dir) {
if (OSIRIS_Extracted_script_dir.empty()) {
return;
}
for (int i = 0; i < MAX_LOADED_MODULES; i++) {
if (OSIRIS_Extracted_scripts[i].flags & OESF_USED) {
if (mission_only && (!(OSIRIS_Extracted_scripts[i].flags & OESF_MISSION)))
continue;
for (auto it = OSIRIS_Extracted_scripts.begin(); it != OSIRIS_Extracted_scripts.end(); ++it) {
if (mission_only && (!(it->second.flags & OESF_MISSION)))
continue;
ASSERT(OSIRIS_Extracted_scripts[i].temp_filename);
ASSERT(OSIRIS_Extracted_scripts[i].real_filename);
if (!(OSIRIS_Extracted_scripts[i].temp_filename && OSIRIS_Extracted_scripts[i].real_filename))
continue;
ddio_MakePath(fullpath, OSIRIS_Extracted_script_dir, OSIRIS_Extracted_scripts[i].temp_filename, NULL);
ddio_DeleteFile(fullpath);
mem_free(OSIRIS_Extracted_scripts[i].temp_filename);
mem_free(OSIRIS_Extracted_scripts[i].real_filename);
OSIRIS_Extracted_scripts[i].temp_filename = NULL;
OSIRIS_Extracted_scripts[i].real_filename = NULL;
OSIRIS_Extracted_scripts[i].flags &= ~OESF_USED;
}
std::filesystem::remove(OSIRIS_Extracted_script_dir / it->second.temp_filename);
OSIRIS_Extracted_scripts.erase(it);
}
if (!mission_only) {
mem_free(OSIRIS_Extracted_script_dir);
OSIRIS_Extracted_script_dir = NULL;
OSIRIS_Extracted_script_dir.clear();
}
}
@ -3313,7 +3265,8 @@ OMMSHANDLE OMMS_Find(uint32_t unique_identifier,char *script_identifier);
// Returns information about the OMMS memory given its handle returned from the OMMS_Find() or
// OMMS_Malloc(). Returns 0 if the handle was invalid, 1 if the information has been filled in;
// Pass NULL in for those parameters you don't need information about.
char OMMS_GetInfo(OMMSHANDLE handle,uint32_t *mem_size,uint32_t *uid,uint16_t *reference_count,uint8_t *has_free_been_called);
char OMMS_GetInfo(OMMSHANDLE handle,uint32_t *mem_size,uint32_t *uid,uint16_t *reference_count,uint8_t
*has_free_been_called);
******************************************************************************
@ -3537,7 +3490,7 @@ void Osiris_RestoreOMMS(CFILE *file) {
cf_ReadBytes((uint8_t *)node->memory_ptr, node->size_of_memory, file);
}
} // end reading nodes
} // end reading hash nodes
} // end reading hash nodes
}
// Searches through the hash nodes and looks for the one associated with

View File

@ -221,10 +221,9 @@ bool taunt_ImportWave(const char *wave_filename, const char *outputfilename) {
int amount_to_flush;
tWaveFile wavdata;
int samples, rate, chan;
char temp_filename[_MAX_PATH];
char osftemp_filename[_MAX_PATH];
std::filesystem::path temp_filename;
std::filesystem::path osftemp_filename;
uint8_t *StaticFileBuffer = NULL;
*temp_filename = *osftemp_filename = '\0';
OSFArchive osf;
CFILE *fpin = NULL;
bool osfopened;
@ -291,7 +290,8 @@ bool taunt_ImportWave(const char *wave_filename, const char *outputfilename) {
// now we need to compress it, first it must be written as raw data to a temp
// file.
if (!ddio_GetTempFileName(Descent3_temp_directory, "d3o", temp_filename)) {
temp_filename = ddio_GetTmpFileName(Descent3_temp_directory, "d3o");
if (temp_filename.empty()) {
LOG_WARNING << "TAUNT: Unable to create temp filename";
ret = false;
TauntLastError = TAUNTIMPERR_INTERNALERR;
@ -346,14 +346,15 @@ bool taunt_ImportWave(const char *wave_filename, const char *outputfilename) {
rate = wavdata.samples_per_second;
chan = wavdata.number_channels;
if (!ddio_GetTempFileName(Descent3_temp_directory, "d3o", osftemp_filename)) {
osftemp_filename = ddio_GetTmpFileName(Descent3_temp_directory, "d3o");
if (osftemp_filename.empty()) {
LOG_WARNING << "TAUNT: Unable to create osftemp filename";
TauntLastError = TAUNTIMPERR_INTERNALERR;
ret = false;
goto error;
}
if (!aenc_Compress(temp_filename, osftemp_filename, NULL, &samples, &rate, &chan, NULL, NULL)) {
if (!aenc_Compress(temp_filename.u8string().c_str(), osftemp_filename.u8string().c_str(), NULL, &samples, &rate, &chan, NULL, NULL)) {
// unable to compress
LOG_WARNING << "Unable to compress";
ret = false;
@ -467,11 +468,11 @@ error:
}
if (cfexist(osftemp_filename)) {
ddio_DeleteFile(osftemp_filename);
std::filesystem::remove(osftemp_filename);
}
if (cfexist(temp_filename)) {
ddio_DeleteFile(temp_filename);
std::filesystem::remove(temp_filename);
}
if (StaticFileBuffer) {

View File

@ -427,7 +427,7 @@ bool Descent_overrided_intro = false;
bool Katmai = true;
char Descent3_temp_directory[_MAX_PATH]; // temp directory to put temp files
std::filesystem::path Descent3_temp_directory; // temp directory to put temp files
// ---------------------------------------------------------------------------
// Descent3: Choke 1
// Initializes game elements and invokes the MainLoop

View File

@ -193,7 +193,7 @@ extern std::filesystem::path orig_pwd;
extern grScreen *Game_screen; // The Descent 3 screen.
extern oeApplication *Descent; // The Descent object
extern oeAppDatabase *Database; // The Database
extern char Descent3_temp_directory[_MAX_PATH]; // temp directory to put temp files
extern std::filesystem::path Descent3_temp_directory; // temp directory to put temp files
extern bool Katmai; // whether or not katmai is detected
// ---------------------------------------------------------------------------
// Functions

View File

@ -1468,7 +1468,7 @@ void InitIOSystems(bool editor) {
// Init hogfiles
INIT_MESSAGE(("Checking for HOG files."));
int d3_hid = -1, extra_hid = -1, sys_hid = -1, extra13_hid = -1;
int d3_hid, extra_hid, sys_hid, extra13_hid;
char fullname[_MAX_PATH];
#ifdef DEMO
@ -1536,14 +1536,10 @@ void InitIOSystems(bool editor) {
// extract from extra.hog first, so its DLL files are listed ahead of d3.hog's
INIT_MESSAGE(("Initializing OSIRIS."));
Osiris_InitModuleLoader();
if (extra13_hid != -1)
Osiris_ExtractScriptsFromHog(extra13_hid, false);
if (extra_hid != -1)
Osiris_ExtractScriptsFromHog(extra_hid, false);
if (merc_hid != -1)
Osiris_ExtractScriptsFromHog(merc_hid, false);
if (sys_hid != -1)
Osiris_ExtractScriptsFromHog(sys_hid, false);
Osiris_ExtractScriptsFromHog(extra13_hid, false);
Osiris_ExtractScriptsFromHog(extra_hid, false);
Osiris_ExtractScriptsFromHog(merc_hid, false);
Osiris_ExtractScriptsFromHog(sys_hid, false);
Osiris_ExtractScriptsFromHog(d3_hid, false);
}
@ -1958,7 +1954,7 @@ void SetupTempDirectory(void) {
int t_arg = FindArg("-tempdir");
if (t_arg) {
strcpy(Descent3_temp_directory, GameArgs[t_arg + 1]);
Descent3_temp_directory = GameArgs[t_arg + 1];
} else {
std::error_code ec;
std::filesystem::path tempPath = std::filesystem::temp_directory_path(ec);
@ -1966,29 +1962,22 @@ void SetupTempDirectory(void) {
Error("Could not find temporary directory: \"%s\"", ec.message().c_str() );
exit(1);
}
ddio_MakePath(Descent3_temp_directory, tempPath.u8string().c_str(), "Descent3",
"cache", NULL);
Descent3_temp_directory = tempPath / "Descent3" / "cache";
}
std::error_code ec;
std::filesystem::create_directories(Descent3_temp_directory, ec);
if (ec) {
Error("Could not create temporary directory: \"%s\"", Descent3_temp_directory);
Error("Could not create temporary directory: \"%s\"", Descent3_temp_directory.u8string().c_str());
exit(1);
}
// verify that temp directory exists
if (!ddio_SetWorkingDir(Descent3_temp_directory)) {
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory);
exit(1);
}
char tempfilename[_MAX_PATH];
std::filesystem::path tempfilename = ddio_GetTmpFileName(Descent3_temp_directory, "d3t");
// verify that we can write to the temp directory
if (!ddio_GetTempFileName(Descent3_temp_directory, "d3t", tempfilename)) {
if (tempfilename.empty()) {
LOG_WARNING << "Unable to get temp file name";
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory);
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory.u8string().c_str());
exit(1);
}
@ -1997,7 +1986,7 @@ void SetupTempDirectory(void) {
if (!file) {
// unable to open file for writing
LOG_WARNING << "Unable to open temp file name for writing";
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory);
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory.u8string().c_str());
exit(1);
}
@ -2009,8 +1998,8 @@ void SetupTempDirectory(void) {
if (!file) {
// unable to open file for reading
LOG_WARNING << "Unable to open temp file name for reading";
ddio_DeleteFile(tempfilename);
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory);
std::filesystem::remove(tempfilename);
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory.u8string().c_str());
exit(1);
}
@ -2018,22 +2007,23 @@ void SetupTempDirectory(void) {
// verify failed
LOG_WARNING << "Temp file verify failed";
cfclose(file);
ddio_DeleteFile(tempfilename);
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory);
std::filesystem::remove(tempfilename);
Error("Unable to set temporary directory to: \"%s\"", Descent3_temp_directory.u8string().c_str());
exit(1);
}
cfclose(file);
// temp directory is valid!
ddio_DeleteFile(tempfilename);
std::filesystem::remove(tempfilename);
LOG_INFO << "Temp directory set to: " << Descent3_temp_directory;
// Lock the directory
if (!ddio_CreateLockFile(std::filesystem::path(Descent3_temp_directory))) {
LOG_WARNING << "Lock file NOT created in temp dir " << Descent3_temp_directory;
Error("Unable to set temporary directory to: \"%s\"\nUnable to create lock file", Descent3_temp_directory);
Error("Unable to set temporary directory to: \"%s\"\nUnable to create lock file",
Descent3_temp_directory.u8string().c_str());
exit(1);
}
// restore working dir

View File

@ -277,6 +277,8 @@
* $NoKeywords: $
*/
#include <filesystem>
#include "chrono_timer.h"
#include "ui.h"
#include "newui.h"
@ -370,7 +372,7 @@ char Auto_login_name[MAX_AUTO_LOGIN_STUFF_LEN];
char Auto_login_pass[MAX_AUTO_LOGIN_STUFF_LEN];
char Auto_login_addr[MAX_AUTO_LOGIN_STUFF_LEN];
char Auto_login_port[MAX_AUTO_LOGIN_STUFF_LEN];
char Multi_conn_dll_name[_MAX_PATH * 2] = "";
std::filesystem::path Multi_conn_dll_name;
char PXO_hosted_lobby_name[100] = "global";
bool Supports_score_api = false;
#ifdef USE_DIRECTPLAY
@ -576,19 +578,20 @@ void FreeMultiDLL() {
DLLMultiClose();
mod_FreeModule(&MultiDLLHandle);
// Try deleting the file now!
if (!ddio_DeleteFile(Multi_conn_dll_name)) {
if (!std::filesystem::remove(Multi_conn_dll_name)) {
LOG_WARNING << "Couldn't delete the tmp dll";
}
DLLMultiCall = NULL;
DLLMultiInit = NULL;
DLLMultiClose = NULL;
}
// Loads the Multi dll. Returns 1 on success, else 0 on failure
int LoadMultiDLL(const char *name) {
static int first = 1;
char lib_name[_MAX_PATH * 2];
char dll_name[_MAX_PATH * 2];
char tmp_dll_name[_MAX_PATH * 2];
std::filesystem::path lib_name;
std::filesystem::path dll_name;
std::filesystem::path tmp_dll_name;
MultiFlushAllIncomingBuffers();
// Delete old dlls
@ -605,35 +608,30 @@ int LoadMultiDLL(const char *name) {
});
// Make the hog filename
ddio_MakePath(lib_name, Base_directory, "online", name, NULL);
strcat(lib_name, ".d3c");
// Make the dll filename
#if defined(WIN32)
snprintf(dll_name, sizeof(dll_name), "%s.dll", name);
#elif defined(MACOSX)
snprintf(dll_name, sizeof(dll_name), "%s.dylib", name);
#else
snprintf(dll_name, sizeof(dll_name), "%s.so", name);
#endif
lib_name = std::filesystem::path(Base_directory) / "online" / name;
lib_name.replace_extension(".d3c");
// Make the dll filename
dll_name = name;
dll_name.replace_extension(MODULE_EXT);
// Open the hog file
if (!cf_OpenLibrary(lib_name)) {
ddio_MakePath(tmp_dll_name, Base_directory, "online", name, NULL);
strcat(tmp_dll_name, ".d3c");
Multi_conn_dll_name[0] = 0;
tmp_dll_name = std::filesystem::path(Base_directory) / "online" / name;
tmp_dll_name.replace_extension(".d3c");
Multi_conn_dll_name.clear();
goto loaddll;
}
// get a temp file name
if (!ddio_GetTempFileName(Descent3_temp_directory, "d3c", tmp_dll_name)) {
tmp_dll_name = ddio_GetTmpFileName(Descent3_temp_directory, "d3c");
if (tmp_dll_name.empty()) {
return 0;
}
// Copy the DLL
// ddio_MakePath(dll_path_name,Base_directory,"online",tmp_dll_name,NULL);
if (!cf_CopyFile(tmp_dll_name, dll_name)) {
LOG_WARNING << "DLL copy failed!";
return 0;
}
strcpy(Multi_conn_dll_name, tmp_dll_name);
Multi_conn_dll_name = tmp_dll_name;
loaddll:
if (!mod_LoadModule(&MultiDLLHandle, tmp_dll_name)) {
@ -700,6 +698,7 @@ loaddll:
}
return 1;
}
// The chokepoint function to call the dll function
void CallMultiDLL(int eventnum) {
if (MultiDLLHandle.handle && DLLMultiCall)

View File

@ -138,7 +138,7 @@ extern void Osiris_ShutdownModuleLoader(void);
// Osiris_FindLoadedModule
// Purpose:
// Given the name of a module, it returns the id of a loaded OSIRIS module. -1 if it isn't loaded.
extern int Osiris_FindLoadedModule(char *filename);
extern int Osiris_FindLoadedModule(const std::filesystem::path &module_name);
// Osiris_LoadLevelModule
// Purpose:
@ -147,7 +147,7 @@ extern int Osiris_FindLoadedModule(char *filename);
// before calling this function, it will return the id to where the module is, and will not reload
// the module. Returns -1 if the module does not exist. Returns -2 if the module couldn't initialize.
// Returns -3 if the module is not a level module. Returns -4 if no module slots are available.
extern int Osiris_LoadLevelModule(char *module_name);
extern int Osiris_LoadLevelModule(const std::filesystem::path &module_name);
// Osiris_UnloadLevelModule
// Purpose:
@ -163,7 +163,7 @@ extern void Osiris_UnloadLevelModule(void);
// before calling this function, it will return the id to where the module is, and will not reload
// the module. Returns -1 if the module does not exist. Returns -2 if the module couldn't initialize.
// Returns -3 if the module is not a game module. Returns -4 if no module slots are available.
extern int Osiris_LoadGameModule(char *module_name);
extern int Osiris_LoadGameModule(const std::filesystem::path &module_name);
// Osiris_UnloadModule
// Purpose:

View File

@ -1965,10 +1965,10 @@ bool ImportGraphic(const char *pathname, char *newfile) {
bm_ChangeSize(bm_handle, 64, 64);
char tempfilename[_MAX_PATH];
std::filesystem::path tempfilename = ddio_GetTmpFileName(Descent3_temp_directory, "d3i");
// Create a temporary filename, so that we can temporarily save the graphic to this file
if (!ddio_GetTempFileName(Descent3_temp_directory, "d3i", tempfilename)) {
if (tempfilename.empty()) {
// there was an error trying to create a temporary filename
bm_FreeBitmap(bm_handle);
LOG_WARNING << "Error creating temp filename";
@ -2004,7 +2004,7 @@ bool ImportGraphic(const char *pathname, char *newfile) {
// p contains the real filename
// tempfilename contains old filename
bm_handle = bm_AllocLoadFileBitmap(IGNORE_TABLE(tempfilename), 0);
bm_handle = bm_AllocLoadFileBitmap(IGNORE_TABLE(tempfilename.u8string().c_str()), 0);
if (bm_handle <= BAD_BITMAP_HANDLE) {
LOG_WARNING << "Error reloading bitmap for rename";
std::filesystem::remove(tempfilename, ec);

View File

@ -39,3 +39,7 @@ target_include_directories(ddio PUBLIC
${PROJECT_SOURCE_DIR}/ddio
>
)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()

View File

@ -374,27 +374,14 @@ void ddio_MakePath(char *newPath, const char *absolutePathHeader, const char *su
void ddio_DoForeachFile(const std::filesystem::path &search_path, const std::regex &regex,
const std::function<void(std::filesystem::path)> &func);
// given a path (with no filename), it will return the parent path
// srcPath is the source given path
// dest is where the parent path will be placed
// returns true on success
// dest should be at least _MAX_PATH in length
bool ddio_GetParentPath(char *dest, const char *srcPath);
// given a path, it cleans it up (if the path is c:\windows\..\dos it would make it c:\dos)
// srcPath is the original path
// dest is the finished cleaned path.
// dest should be at least _MAX_PATH in size
void ddio_CleanPath(char *dest, const char *srcPath);
// Generates a temporary filename based on the prefix, and basedir
// Parameters:
// basedir - directory to put the files
// prefix - prefix for the temp filename
// filename - buffer to hold generated filename (must be at least _MAX_PATH in length)
//
// Returns TRUE if successful, FALSE if an error
bool ddio_GetTempFileName(const char *basedir, const char *prefix, char *filename);
/**
* Generates a temporary filename based on the prefix in basedir. Function ensures that generated
* filename does not exists in basedir directory.
* @param basedir directory to put the files
* @param prefix prefix for the temp filename
* @return generated filename with ".tmp" extension in basedir directory or empty path on failure
*/
std::filesystem::path ddio_GetTmpFileName(const std::filesystem::path &basedir, const char *prefix);
/**
* Check process existence by PID
@ -425,4 +412,4 @@ bool ddio_CreateLockFile(const std::filesystem::path &dir);
*/
bool ddio_DeleteLockFile(const std::filesystem::path &dir);
#endif
#endif

View File

@ -17,13 +17,16 @@
*/
#include <array>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <iterator>
#include <regex>
#include "IOOps.h"
#include "chrono_timer.h"
#include "ddio.h"
#include "mem.h"
#include "pserror.h"
const std::array<char, 4> LOCK_TAG = {'L', 'O', 'C', 'K'};
@ -156,3 +159,36 @@ void ddio_DoForeachFile(const std::filesystem::path &search_path, const std::reg
}
}
}
std::filesystem::path ddio_GetTmpFileName(const std::filesystem::path &basedir, const char *prefix) {
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
// size of random part
const int len = 10;
const char *ext = ".tmp";
std::filesystem::path result;
size_t len_result = strlen((basedir / prefix).u8string().c_str());
char *random_name = (char *)mem_malloc(len_result + len + strlen(ext) + 1);
strncpy(random_name, (basedir / prefix).u8string().c_str(), len_result);
srand(D3::ChronoTimer::GetTimeMS());
int tries = 20;
while (tries > 0) {
for (size_t i = len_result; i < len_result + len; i++) {
random_name[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
}
random_name[len_result + len] = '\0';
strcat(random_name, ext);
if (!std::filesystem::exists(random_name)) {
// Found unique name, break the loop
result = random_name;
break;
}
tries--;
}
mem_free(random_name);
return result;
}

View File

@ -266,216 +266,6 @@ int ddio_GetFileSysRoots(char **roots, int max_roots) {
return 1;
}
// given a path, it cleans it up (if the path is /usr/lib/../src it would make it /usr/src)
// srcPath is the original path
// dest is the finished cleaned path.
// dest should be at least _MAX_PATH in size
void ddio_CleanPath(char *dest, const char *srcPath) {
// NOTE: we may want to use getcwd() here if we don't want symbolic links
// but I think we do
////////////////////////////////////////////////////////////////////////
strcpy(dest, srcPath);
// break the path into directories
char **directories;
int dirs;
int path_length;
// make sure the path ends with a / for sanity
path_length = strlen(dest);
if (dest[path_length - 1] != '/') {
dest[path_length] = '/';
dest[path_length + 1] = '\0';
path_length++;
}
// now divide the full path into separate NULL terminated strings,counting the number
// of directories in the process
dirs = 0;
char *strptr;
if (dest[0] == '/')
strptr = dest + 1; // skip first / of root dir
else
strptr = dest;
while (*strptr != '\0') {
if (*strptr == '/') {
*strptr = '\0';
dirs++;
}
strptr++;
}
// check to make sure we have a directory, if we don't then return the original path given
if (dirs == 0) {
strcpy(dest, srcPath);
return;
}
// allocate the memory needed for the separate strings of each directory
directories = mem_rmalloc<char *>(dirs);
if (!directories) {
strcpy(dest, srcPath);
return;
}
// now get all the directories, and place into the individual strings
strptr = dest;
int count = 0;
while (count < dirs) {
directories[count] = mem_strdup(strptr);
strptr += strlen(strptr) + 1;
count++;
}
// now the fun part, figure out the correct order of the directories
int *dir_order;
dir_order = mem_rmalloc<int>(dirs);
if (!dir_order) {
strcpy(dest, srcPath);
return;
}
for (count = 0; count < dirs; count++)
dir_order[count] = -1; // a -1 means the end of the sequence
// now build the order based on the indicies
int curr_index = 0;
for (count = 0; count < dirs; count++) {
if (!stricmp(directories[count], "..")) {
// we have to back up a directory
curr_index--; // back up
if (curr_index < 0)
curr_index = 0; // can't go further than root
dir_order[curr_index] = -1; // invalidate current slot
} else if (stricmp(directories[count], ".")) {
// we have a normal directory, add its index
dir_order[curr_index] = count;
curr_index++;
}
}
// now rebuild the correct path for use, when we hit -1, we're done
dest[0] = '\0';
for (count = 0; count < dirs; count++) {
if (dir_order[count] == -1)
break;
else {
strcat(dest, directories[dir_order[count]]);
strcat(dest, "/");
}
}
// now remove trailing / char
path_length = strlen(dest);
if ((path_length > 0) && (dest[path_length - 1] == '/'))
dest[path_length - 1] = '\0';
// free up all the allocated memory and we're done
for (count = 0; count < dirs; count++) {
if (directories[count])
mem_free(directories[count]);
}
if (directories)
mem_free(directories);
if (dir_order)
mem_free(dir_order);
}
// given a path (with no filename), it will return the parent path
// srcPath is the source given path
// dest is where the parent path will be placed
// returns true on success
// dest should be at least _MAX_PATH in length
bool ddio_GetParentPath(char *dest, const char *srcPath) {
assert(srcPath);
assert(dest);
#define PARENT_DELIM ".."
int spath_len = strlen(srcPath);
char *temp;
temp = (char *)mem_malloc(spath_len + strlen(PARENT_DELIM) + 3);
if (!temp) {
return false;
}
ddio_MakePath(temp, srcPath, PARENT_DELIM, NULL);
ddio_CleanPath(dest, temp);
mem_free(temp);
return true;
}
// Generates a temporary filename based on the prefix, and basedir
// Parameters:
// basedir - directory to put the files
// prefix - prefix for the temp filename
// filename - buffer to hold generated filename (must be at least _MAX_PATH in length)
//
// Returns TRUE if successful, FALSE if an error
bool ddio_GetTempFileName(const char *basedir, const char *prefix, char *filename) {
char old_workdir[_MAX_PATH];
bool success = false;
if (strlen(prefix) > 64)
return false;
ddio_GetWorkingDir(old_workdir, _MAX_PATH);
if (!ddio_SetWorkingDir(basedir)) {
return false; // invalid base directory
}
char randname[10];
int index;
int tries = 0;
char rc;
bool created = false;
index = 0;
while (!success && tries < 20) {
// generate a bunch of random characters
rc = (rand() % 128);
if ((rc >= 'a' && rc <= 'z') || (rc >= 'A' && rc <= 'Z') || (rc >= '0' && rc <= '9')) {
// valid character
randname[index] = rc;
index++;
if (index == 10) {
// we hit the size of our max, see if we generated a unique filename
char t[_MAX_PATH];
randname[9] = '\0';
snprintf(t, sizeof(t), "%s%s.tmp", prefix, randname);
// see if we can find this file
FILE *fd = fopen(t, "rb");
if (!fd) {
// we found a good file!
ddio_MakePath(filename, basedir, t, NULL);
success = true;
created = true;
} else {
// already taken
fclose(fd);
tries++;
index = 0;
}
}
} else {
continue; // try again
}
}
ddio_SetWorkingDir(old_workdir);
return created;
}
bool ddio_CheckProcess(int pid) {
if (kill(pid, 0) == -1) {
/* some other error, log it */

View File

@ -40,6 +40,7 @@
* $NoKeywords: $
*/
#include <filesystem>
#include "pstring.h"
#include "forcefeedback.h"
@ -286,7 +287,7 @@ bool ddio_ffjoy_SupportAutoCenter(tDevice) { return false; }
// for it. It returns a handle to that resource.
// If it returns NULL, then it couldn't load the project.
// Make sure device is aquired before calling.
FORCEPROJECT ddio_ForceLoadProject(char *filename, tDevice dev) { return NULL; }
FORCEPROJECT ddio_ForceLoadProject(std::filesystem::path &filename, tDevice dev) { return NULL; }
// Unloads a FORCEPROJECT file
void ddio_ForceUnloadProject(FORCEPROJECT prj) {}

10
ddio/tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,10 @@
set(CMAKE_FOLDER "tests")
add_executable(ddio_tests
ddio_tests.cpp
)
target_link_libraries(ddio_tests PRIVATE
GTest::gtest_main
ddio
)
gtest_discover_tests(ddio_tests)

30
ddio/tests/ddio_tests.cpp Normal file
View File

@ -0,0 +1,30 @@
/*
* Descent 3
* Copyright (C) 2024 Descent Developers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <filesystem>
#include <gtest/gtest.h>
#include "ddio.h"
TEST(D3, DDIO_GetTmpFileName) {
std::filesystem::path temp_dir = std::filesystem::temp_directory_path();
std::filesystem::path result = ddio_GetTmpFileName(temp_dir, "prefix_");
EXPECT_FALSE(result.empty());
EXPECT_EQ(result.extension(), ".tmp");
EXPECT_TRUE(canonical(result.parent_path()) == canonical(temp_dir));
}

View File

@ -271,14 +271,6 @@ void ddio_MakePath(char *newPath, const char *absolutePathHeader, const char *su
va_end(args);
}
bool ddio_GetTempFileName(const char *basedir, const char *prefix, char *filename) {
if (!GetTempFileName(basedir, prefix, 0, filename))
return false;
else
return true;
}
// retrieve root names, free up roots array (allocated with malloc) after use
int ddio_GetFileSysRoots(char **roots, int max_roots) {
char buffer[100];
@ -354,141 +346,6 @@ std::vector<std::filesystem::path> ddio_GetSysRoots() {
return result;
};
// given a path, it cleans it up (if the path is c:\windows\..\dos it would make it c:\dos)
// srcPath is the original path
// dest is the finished cleaned path.
// dest should be at least _MAX_PATH in size
void ddio_CleanPath(char *dest, const char *srcPath) {
strcpy(dest, srcPath);
// break the path into directories
char **directories;
int dirs;
int path_length;
// make sure the path ends with a \ for sanity
path_length = strlen(dest);
if (dest[path_length - 1] != '\\') {
dest[path_length] = '\\';
dest[path_length + 1] = '\0';
path_length++;
}
// now divide the full path into separate NULL terminated strings,counting the number
// of directories in the process
dirs = 0;
char *strptr = dest;
while (*strptr != '\0') {
if (*strptr == '\\') {
*strptr = '\0';
dirs++;
}
strptr++;
}
// check to make sure we have a directory, if we don't then return the original path given
if (dirs == 0) {
strcpy(dest, srcPath);
return;
}
// allocate the memory needed for the separate strings of each directory
directories = mem_rmalloc<char *>(dirs);
if (!directories) {
strcpy(dest, srcPath);
return;
}
// now get all the directories, and place into the individual strings
strptr = dest;
int count = 0;
while (count < dirs) {
directories[count] = mem_strdup(strptr);
strptr += strlen(strptr) + 1;
count++;
}
// now the fun part, figure out the correct order of the directories
int *dir_order;
dir_order = mem_rmalloc<int>(dirs);
if (!dir_order) {
strcpy(dest, srcPath);
return;
}
for (count = 0; count < dirs; count++)
dir_order[count] = -1; // a -1 means the end of the sequence
// now build the order based on the indicies
int curr_index = 0;
for (count = 0; count < dirs; count++) {
if (!stricmp(directories[count], "..")) {
// we have to back up a directory
curr_index--; // back up
if (curr_index < 0)
curr_index = 0; // can't go further than root
dir_order[curr_index] = -1; // invalidate current slot
} else if (stricmp(directories[count], ".")) {
// we have a normal directory, add its index
dir_order[curr_index] = count;
curr_index++;
}
}
// now rebuild the correct path for use, when we hit -1, we're done
dest[0] = '\0';
for (count = 0; count < dirs; count++) {
if (dir_order[count] == -1)
break;
else {
strcat(dest, directories[dir_order[count]]);
strcat(dest, "\\");
}
}
// now remove trailing \ char
path_length = strlen(dest);
if ((path_length > 0) && (dest[path_length - 1] == '\\'))
dest[path_length - 1] = '\0';
// free up all the allocated memory and we're done
for (count = 0; count < dirs; count++) {
if (directories[count])
mem_free(directories[count]);
}
if (directories)
mem_free(directories);
if (dir_order)
mem_free(dir_order);
}
// given a path (with no filename), it will return the parent path
// srcPath is the source given path
// dest is where the parent path will be placed
// returns true on success
// dest should be at least _MAX_PATH in length
bool ddio_GetParentPath(char *dest, const char *srcPath) {
assert(srcPath);
assert(dest);
#define PARENT_DELIM ".."
int spath_len = strlen(srcPath);
char *temp;
temp = (char *)mem_malloc(spath_len + strlen(PARENT_DELIM) + 3);
if (!temp) {
return false;
}
ddio_MakePath(temp, srcPath, PARENT_DELIM, NULL);
ddio_CleanPath(dest, temp);
mem_free(temp);
return true;
}
bool ddio_CheckProcess(int pid) {
HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
if (proc) {

View File

@ -287,7 +287,6 @@ inline void CFileList::setPath(CString path) {
if (!buffer)
return;
// ddio_CleanPath(buffer,temp.GetBuffer(0));
strcpy(buffer, temp.GetBuffer(0));
m_csPath = buffer;

View File

@ -73,6 +73,7 @@
#ifndef __DDIO_FORCEFEEDBACK_H_
#define __DDIO_FORCEFEEDBACK_H_
#include <cstdint>
#include <filesystem>
#include "pstypes.h"
#include "string.h"
#define kMAX_Str 80
@ -430,7 +431,7 @@ bool ddio_ffjoy_SupportAutoCenter(tDevice dev);
// for it. It returns a handle to that resource.
// If it returns NULL, then it couldn't load the project.
// Make sure device is aquired before calling.
FORCEPROJECT ddio_ForceLoadProject(char *filename, tDevice dev);
FORCEPROJECT ddio_ForceLoadProject(std::filesystem::path &filename, tDevice dev);
// Unloads a FORCEPROJECT file
void ddio_ForceUnloadProject(FORCEPROJECT prj);
// Given a handle to a resource, and the name of the effect to load