Home > Net >  Retrieve CString file path from XML file
Retrieve CString file path from XML file

Time:07-16

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

  1. Need to use the heap, which will be slow, and can leak memory if the memory isn't deleted later
  2. 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.

  • Related