I have an XML file with many values and a working C function that can retrieve these values
Two of these values are (1) a file path such as: "C:\foo1\foo2" and (2) a file name: "foo3.txt" Combining these together, they would become "C:\foo1\foo2\foo3.txt"
However, while trying to set a CString to save a file path, it will give an error because using the character, '\', in a string is not allowed due to string notation and its interaction with the '\' character.
// Funnily enough, even while typing this question, I must use an extra \ character, or the quotations will just appear as ''.
I am using MFC, and I know Windows32 allows you to create a file path with '/' instead of '\', so: "C:/foo1/foo2/foo3.txt" would work . I tested this in Windows Explorer and it worked.
I would like to collect the file path from XML file, but when it comes in, it will have '\' instead of '/' in its file path, meaning it will not be possible to replace the character (the string coming in will have an error already due to XML not having a problem with the \ character.
How do I safely retrieve the path as a CString, ideally while converting any \ character to a / character.
Thank you in advance ! :D
CodePudding user response:
Now I'm not familiar with the "CString" class you are refering to. Googling the API documentation just has the standard c style char array format commands, so I'm going to assume rightly or wrongly cstring is a char array.
The fact we are going to need to use an object that is not resizable means we either
- Need to use the heap, which will be slow, and can leak memory if the memory isn't deleted later
- Allow a maximum string length and accept it will be truncated if below this
Heap example (NOTE: I'm not using smart pointers as I assume they don't have access to them, else you'd just std::string and not do this.)
char* escapeString(const char* data, unsigned int length){
//multiplying by 1.5 means this could still truncate,
//but I'm making an educated guess it's not all bad characters.
const int newLen = (length 1) * 1.5;
char* escaped = new char[newLen 1];
unsigned int index = 0;
for(unsigned int i = 0; i < length && i < newLen; i ){
if(data[i] == '\\' || data[i] == '\"'){
escaped[index ] = '\\';
}
else if(data[i] == '%'){
escaped[index ] = '%';
}
//else anything else you want to escape
escaped[index ] = data[i];
}
//Make sure a null string is null terminatedescaped
escaped[index] = '\0';
return escaped;
}
int main() {
const char* stringWithBadChars = "I\"m not a %%good \\string";
char* escapedString = escapeString(stringWithBadChars, strlen(stringWithBadChars));
std::cout << escapedString;
delete [] escapedString;
return 0;
}
If we do this on the stack instead it would be a lot faster, but we are limited by the size of the buffer we give, and the size of the buffer in the function. We will return a bool if either fails.
bool escapeString(char* data, unsigned int length){
const int newLen = 1000;
char escaped[1001];
unsigned int index = 0;
for(unsigned int i = 0; i < length && i < newLen; i ){
if(data[i] == '\\' || data[i] == '\"'){
escaped[index ] = '\\';
}
else if(data[i] == '%'){
escaped[index ] = '%';
}
escaped[index ] = data[i];
}
//Make sure a null string is null terminatedescaped
memcpy(data, escaped, index);
escaped[index] = '\0';
return index < length && index < 1000;
}
You could probably get even more efficiency using memmov rather than copy it character by character. Doing it this way you also wouldn't need the second char array.