- WIP search path code

The Steam/GOG path getters were taken out of the frontends.
This also switches the Windows directory reader touse the wide string version to get Unicode file names.
Some paths were added to the config file instead of hard coding them.
This commit is contained in:
Christoph Oelckers 2019-10-29 01:00:44 +01:00
parent cfd9edbe71
commit 35342526a5
9 changed files with 690 additions and 1116 deletions

View file

@ -448,31 +448,6 @@ void G_LoadGroups()
pathsearchmode = bakpathsearchmode;
}
#if defined _WIN32
static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize)
{
// KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds
REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY };
for (auto &wow64key : wow64keys)
{
HKEY hkey;
LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey);
if (keygood != ERROR_SUCCESS)
continue;
LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize);
RegCloseKey(hkey);
if (retval == ERROR_SUCCESS)
return 1;
}
return 0;
}
#endif
static void G_LoadAddon(void)
{
@ -499,371 +474,8 @@ static void G_LoadAddon(void)
g_selectedGrp = grp;
}
#ifndef EDUKE32_TOUCH_DEVICES
#if defined EDUKE32_OSX || defined __linux__ || defined EDUKE32_BSD
static void G_AddSteamPaths(const char *basepath)
{
char buf[BMAX_PATH];
// Duke Nukem 3D: Megaton Edition (Steam)
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot", basepath);
addsearchpath(buf);
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
// Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015)
#if defined EDUKE32_OSX
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/Duke Nukem 3D.app/drive_c/Program Files/Duke Nukem 3D", basepath);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
#endif
// NAM (Steam)
#if defined EDUKE32_OSX
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/Nam.app/Contents/Resources/Nam.boxer/C.harddisk/NAM", basepath);
#else
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/NAM", basepath);
#endif
addsearchpath_user(buf, SEARCHPATH_NAM);
#if 0
// WWII GI (Steam)
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/World War II GI/WW2GI", basepath);
addsearchpath_user(buf, SEARCHPATH_WW2GI);
#endif
}
// A bare-bones "parser" for Valve's KeyValues VDF format.
// There is no guarantee this will function properly with ill-formed files.
static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend)
{
while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend)
(*vdfbuf)++;
// comments
if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/')
{
while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend)
(*vdfbuf)++;
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
}
}
static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend)
{
(*vdfbuf)++;
while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend)
(*vdfbuf)++;
}
static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend)
{
while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend)
(*vdfbuf)++;
}
static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend)
{
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
if (*vdfbuf == vdfbufend)
return;
if ((*vdfbuf)[0] == '{')
{
(*vdfbuf)++;
do
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
}
while ((*vdfbuf)[0] != '}');
(*vdfbuf)++;
}
else if ((*vdfbuf)[0] == '\"')
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
else if ((*vdfbuf)[0] != '}')
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
}
static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend)
{
char *token = *vdfbuf;
if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend)
{
token++;
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
(*vdfbuf)[0] = '\0';
// account for escape sequences
char *writeseeker = token, *readseeker = token;
while (readseeker <= *vdfbuf)
{
if (readseeker[0] == '\\')
readseeker++;
writeseeker[0] = readseeker[0];
writeseeker++;
readseeker++;
}
return token;
}
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
(*vdfbuf)[0] = '\0';
return token;
}
static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token)
{
char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
if (token != NULL) // pass in NULL to find the next key instead of a specific one
while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend)
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
}
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
}
static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token)
{
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
// end of scope
if ((*vdfbuf)[0] == '}')
return 0;
KeyValues_FindKey(vdfbuf, vdfbufend, token);
// ignore the wrong type
while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend)
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
KeyValues_FindKey(vdfbuf, vdfbufend, token);
}
if (*vdfbuf == vdfbufend)
return 0;
return 1;
}
static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token)
{
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
// end of scope
if ((*vdfbuf)[0] == '}')
return NULL;
KeyValues_FindKey(vdfbuf, vdfbufend, token);
// ignore the wrong type
while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend)
{
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
KeyValues_FindKey(vdfbuf, vdfbufend, token);
}
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
if (*vdfbuf == vdfbufend)
return NULL;
return KeyValues_NormalizeToken(vdfbuf, vdfbufend);
}
static void G_ParseSteamKeyValuesForPaths(const char *vdf)
{
buildvfs_fd fd = buildvfs_open_read(vdf);
int32_t size = buildvfs_length(fd);
char *vdfbufstart, *vdfbuf, *vdfbufend;
if (size <= 0)
return;
vdfbufstart = vdfbuf = (char*)Xmalloc(size);
size = (int32_t)buildvfs_read(fd, vdfbuf, size);
buildvfs_close(fd);
vdfbufend = vdfbuf + size;
if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders"))
{
char *result;
vdfbuf++;
while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL)
G_AddSteamPaths(result);
}
Xfree(vdfbufstart);
}
#endif
#endif
void G_AddSearchPaths(void)
{
#ifndef EDUKE32_TOUCH_DEVICES
#if defined __linux__ || defined EDUKE32_BSD
char buf[BMAX_PATH];
char *homepath = Bgethomedir();
Bsnprintf(buf, sizeof(buf), "%s/.steam/steam", homepath);
G_AddSteamPaths(buf);
Bsnprintf(buf, sizeof(buf), "%s/.steam/steam/steamapps/libraryfolders.vdf", homepath);
G_ParseSteamKeyValuesForPaths(buf);
Bfree(homepath);
addsearchpath("/usr/share/games/jfduke3d");
addsearchpath("/usr/local/share/games/jfduke3d");
addsearchpath("/usr/share/games/eduke32");
addsearchpath("/usr/local/share/games/eduke32");
#elif defined EDUKE32_OSX
char buf[BMAX_PATH];
int32_t i;
char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) };
char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) };
for (i = 0; i < 2; i++)
{
Bsnprintf(buf, sizeof(buf), "%s/Steam", support[i]);
G_AddSteamPaths(buf);
Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support[i]);
G_ParseSteamKeyValuesForPaths(buf);
// Duke Nukem 3D: Atomic Edition (GOG.com)
Bsnprintf(buf, sizeof(buf), "%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications[i]);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
}
for (i = 0; i < 2; i++)
{
Bsnprintf(buf, sizeof(buf), "%s/JFDuke3D", support[i]);
addsearchpath(buf);
Bsnprintf(buf, sizeof(buf), "%s/EDuke32", support[i]);
addsearchpath(buf);
}
for (i = 0; i < 2; i++)
{
Bfree(applications[i]);
Bfree(support[i]);
}
#elif defined (_WIN32)
char buf[BMAX_PATH] = {0};
DWORD bufsize;
// Duke Nukem 3D: 20th Anniversary World Tour (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 434050)", "InstallLocation", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_REMOVE);
}
// Duke Nukem 3D: Megaton Edition (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225140)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
DWORD const remaining = sizeof(buf) - bufsize;
Bstrncpy(suffix, "/gameroot", remaining);
addsearchpath(buf);
Bstrncpy(suffix, "/gameroot/addons/dc", remaining);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
Bstrncpy(suffix, "/gameroot/addons/nw", remaining);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
Bstrncpy(suffix, "/gameroot/addons/vacation", remaining);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
}
// Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 359850)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
DWORD const remaining = sizeof(buf) - bufsize;
Bstrncpy(suffix, "/Duke Nukem 3D", remaining);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
}
// Duke Nukem 3D: Atomic Edition (GOG.com)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_REMOVE);
}
// Duke Nukem 3D (3D Realms Anthology)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Duke Nukem 3D", NULL, buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
DWORD const remaining = sizeof(buf) - bufsize;
Bstrncpy(suffix, "/Duke Nukem 3D", remaining);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
}
// 3D Realms Anthology
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
DWORD const remaining = sizeof(buf) - bufsize;
Bstrncpy(suffix, "/Duke Nukem 3D", remaining);
addsearchpath_user(buf, SEARCHPATH_REMOVE);
}
// Redneck Rampage (GOG.com)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGREDNECKRAMPAGE", "PATH", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_RR);
}
// Redneck Rampage Rides Again (GOG.com)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGCREDNECKRIDESAGAIN", "PATH", buf, &bufsize))
{
addsearchpath_user(buf, SEARCHPATH_RRRA);
}
// NAM (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 329650)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
DWORD const remaining = sizeof(buf) - bufsize;
Bstrncpy(suffix, "/NAM", remaining);
addsearchpath_user(buf, SEARCHPATH_NAM);
}
#if 0
// WWII GI (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 376750)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
DWORD const remaining = sizeof(buf) - bufsize;
Bstrncpy(suffix, "/WW2GI", remaining);
addsearchpath_user(buf, SEARCHPATH_WW2GI);
}
#endif
#endif
#endif
}
void G_CleanupSearchPaths(void)
{