Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions src/plugins/gta3/std.asi/args_translator/translator_basic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,14 +401,17 @@ struct path_translator_base
// Gets the current working directory relative to the the game path
// If working directory is not anywhere near the game path, return null
// This is the manual version, where you send the current working directory (@fullpath) and game path (@gamepath)
static const char* GetCurrentDir(const char* fullpath, const char* gamePath, size_t max)
//
// Both strings MUST have the same character type, otherwise their comparison fails
template<class T>
static const T* GetCurrentDir(const T* fullpath, const T* gamePath, size_t max)
{
const char* currdir = 0;
const T* currdir = 0;

// Iterate on the game path comparing it with the current working dir
for(size_t i = 0; i < max; ++i)
{
if(gamePath[i] == 0) // End of game path?
if(gamePath[i] == T(0)) // End of game path?
{
// Then here starts the relative part
currdir = &fullpath[i];
Expand All @@ -417,7 +420,7 @@ struct path_translator_base
else if(gamePath[i] != fullpath[i]) // Piece of gamepath not equal to the working dir? wow
{
// Let's calm down, if working directory ended and game path is ending, we're still 'equal'
if(fullpath[i] == 0 && gamePath[i] == '\\' && gamePath[i+1] == 0)
if(fullpath[i] == T(0) && gamePath[i] == T('\\') && gamePath[i+1] == T(0))
{
// Point current directory to "\0" part of fullpath
currdir = &fullpath[i];
Expand All @@ -429,6 +432,34 @@ struct path_translator_base
return currdir;
}

// The game path in the same character type as the translated argument.
// Mod Loader stores the game path as a narrow (ANSI) string, so wide arguments (which is what
// C++/STL based modules pass to GetFileAttributesW/CreateFileW/... ) need a converted copy;
// comparing them against the narrow game path can never match.
static const char* GetGamePathFor(const char*)
{
return plugin_ptr->loader->gamepath;
}

static const wchar_t* GetGamePathFor(const wchar_t*)
{
static const std::wstring path = []() -> std::wstring
{
const char* narrow = plugin_ptr->loader->gamepath;
if(narrow == nullptr || narrow[0] == 0) return std::wstring();

// CP_ACP: the same conversion the ANSI Win32 APIs perform on this path
int length = MultiByteToWideChar(CP_ACP, 0, narrow, -1, nullptr, 0); // count includes the terminator
if(length <= 1) return std::wstring();

std::wstring wide(size_t(length) - 1, L'\0');
MultiByteToWideChar(CP_ACP, 0, narrow, -1, &wide[0], length); // rewrites the terminator
return wide;
}();

return path.c_str();
}


};

Expand Down
7 changes: 4 additions & 3 deletions src/plugins/gta3/std.asi/args_translator/xtranslator_path.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,14 @@ inline bool path_translator_base::CallInfo::GetCurrentDir(const T*& arg, char t
if(this->bAbsolutePath) // This argument is an absolute path?
{
// Get current directory assuming argument is the fullpath
currdir = GetCurrentDir( (const char*) arg, plugin_ptr->loader->gamepath, -1);
//
const T* relative = GetCurrentDir(arg, GetGamePathFor(arg), -1);

// If could get the currdir, set up some stuff and go ahead on the translation
// For SetDir, if currdir is empty, that means it should chdir into base dir, so don't touch it
if(currdir && (!bSetDir || currdir[0] != 0))
if(relative && (!bSetDir || relative[0] != 0))
{
arg = (T*) currdir;
arg = relative;
currdir = 0;
bCheckModules = true;
}
Expand Down