Created
July 4, 2020 22:30
-
-
Save acerspyro/b4f1d2ee13a28709800b6cee6c45fb61 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Resolves a given path relative to the game's home directory | |
* | |
* @param relpath | |
* relpath is a special string that can represent path parameters. | |
* | |
* 1. Find all &'s and split the string at that point | |
* 2. Find <, > and all the text in-between and strips everything from the string | |
* 3. Find . and .. notations and resolve them | |
* 4. Loop until no more &'s are found | |
* | |
* This method converts an std::string into a C string for pointer manipulation purposes. | |
* @replaces path() | |
* @return | |
*/ | |
std::string tools::resolvepath(std::string relpath) | |
{ | |
/* String to work on, memory copy of relpath's C string */ | |
char *curpart = strdup(relpath.c_str()); | |
/* Loop over strings separated by & */ | |
while(true) | |
{ | |
/** | |
* Find the first occurence of '&' and replace with \0 | |
* This cuts the string into two C strings, essentially a separate file | |
*/ | |
char *endpart = strchr(curpart, '&'); | |
if(endpart) *endpart = '\0'; // Only null-terminate if endpart isn't nullptr | |
/** | |
* Find the first < and the last > and cull anything in-between | |
* Anything between < and > is a special string and must be stripped for parsing | |
*/ | |
if(curpart[0] == '<') | |
{ | |
char *filepart = strrchr(curpart, '>'); | |
if(!filepart) return relpath; // Fail | |
curpart = filepart + 1; // Move pointer to the end of what we found (+1 to account for the last >) | |
} | |
char *prevdir; | |
char *curdir = curpart; | |
/** | |
* Find single and double dots (., ..) and resolves them | |
* Produces a clean path string | |
*/ | |
while(true) | |
{ | |
prevdir = curdir[0] == PATHDIV | |
? curdir + 1 | |
: curdir; | |
curdir = strchr(prevdir, PATHDIV); | |
if(!curdir) break; | |
/* Found single dot, strip it out as it's useless */ | |
if(prevdir + 1 == curdir && prevdir[0] == '.') | |
{ | |
memmove(prevdir, curdir + 1, strlen(curdir + 1) + 1); // Double +1 for null termination | |
curdir = prevdir; | |
} | |
/* Found double dot, remove double dot and previous directory */ | |
else if(curdir[1] == '.' && curdir[2] == '.' && curdir[3] == PATHDIV) | |
{ | |
if(prevdir + 2 == curdir && prevdir[0] == '.' && prevdir[1] == '.') continue; | |
memmove(prevdir, curdir + 4, strlen(curdir + 4) + 1); | |
if(prevdir - 2 >= curpart && prevdir[-1] == PATHDIV) | |
{ | |
prevdir -= 2; | |
while(prevdir - 1 >= curpart && prevdir[-1] != PATHDIV) --prevdir; | |
} | |
curdir = prevdir; | |
} | |
} | |
/** | |
* Small hack to make sure the string doesn't break | |
* Place back the & we replaced with \0 at the beginning of the loop | |
* Then, move on to the next piece of string | |
*/ | |
if(endpart) | |
{ | |
*endpart = '&'; | |
curpart = endpart + 1; | |
} | |
else break; | |
} | |
return std::string(curpart); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment