Search code examples
bufferwxwidgetswxstring

How to load/save wxString from/to wxStream or wxMemoryBuffer?


I have my own class (nBuffer) like wxMemoryBuffer and I use it to load/save custom data, it's more convenient than using streams because I have a lot of overloaded methods for different data types based on these:

class nBuffer
{   // ...
    bool wr(void* buf, long unsigned int length);// write
    bool rd(void* buf, long unsigned int length);// read
}

I'm trying to implemets methods to load/save wxString from/to this buffer. With wxWidgets 2.8 I've used the next code (simplified):

bool nBuffer::wrString(wxString s)
{   // save string:
    int32 lng=s.Length()*4;
    wr(&lng,4);// length
    wr(s.GetData(),lng);// string itself
    return true;
}
bool nBuffer::rdString(wxString &s)
{   // load string:
    uint32 lng;
    rd(&lng,4);// length
    s.Alloc(lng);
    rd(s.GetWriteBuf(lng),lng);// string itself
    s.UngetWriteBuf();
    s=s.Left(lng/4);
    return true;
}

This code is not good because:

  1. Is assumes there are 4 bytes of data for each string character (it might be less),

  2. With wxWidgets 3.0, wxString.GetData() returns wxCStrData instead of *void, so the compiler fails on wr(s.GetData(),lng); and I have no idea of how to convert it to a simple byte buffer.

Strange, but I found nothing googling that for hours... Also I've found nothing useful in wxWidgets docs.

The questions are:

  1. That is the preferred, correct and safe way to convert wxString to byte buffer,

  2. The same about converting the byte buffer back to wxString.


Solution

  • For arbitrary wxStrings you need to serialize them in either UTF-8 or UTF-16 format. The former is a de facto standard for data exchange, so I advise to use it, but you could prefer UTF-16 if you know that your data is biased to the sort of characters that take less space in it than in UTF-8 and if space saving is important for you.

    Assuming you use UTF-8, serializing is done using utf8_str() method:

    wxScopedCharBuffer const utf8 = s.utf8_str();
    wr(utf8.data(), utf8.length());
    

    Deserializing is as simple as using wxString::FromUTF8(data, length).

    For UTF-16 you would use general mb_str(wxMBConvUTF16) and wxString(data, wxMBConvUTF16, length) methods, which could also be used with wxMBConvUTF8, but the UTF-8-specific methods above are more convenient and, in some build configurations, more efficient.