I’m using boost::serialize to serialize a document wherein I use f.i. a juce::String. Like so:
template<class Archive>
void serialize( Archive & ar, const unsigned int version )
{
ar & boost::serialization::make_nvp("title", m_docTitle);
...
}
For boost::serialize to accept juce::String as a primitive type I did:
#include <boost/serialization/string.hpp>
template<class IStream>
inline IStream& operator >> (IStream& stream, juce::String& s)
{
std::wstring t;
stream >> t;
s = juce::String(t.c_str());
return stream;
}
BOOST_CLASS_IMPLEMENTATION(juce::String, boost::serialization::primitive_type)
which compiles nicely. Serialization works fine, I get the entry in the XML:
<title>DocumentTitle</title>
as it should be. However when deserializing I can trace in the >> operator that the string returned is:
"DocumentTitle</title>"
i.e. some of the XML has been “chewed up”, which later of course leads to an “input stream error” exception.
The oddest part is though that I had this working up until a week ago… 🙁 and I have no idea what makes it NOT work now…
Edit: A little example code that shows reproduces the behavior, only dependency is boost:
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>
#include <boost/archive/xml_woarchive.hpp>
#include <boost/archive/xml_wiarchive.hpp>
#include <sstream>
class JuceString
{
public:
JuceString(const std::wstring& str = L"") : m_str(str) {;}
JuceString(const JuceString& other) : m_str(other.m_str) {;}
JuceString& operator = (const JuceString& other)
{
if (this != &other)
{
m_str = other.m_str;
}
return *this;
}
const wchar_t* toWideCharPointer() const {
return m_str.c_str();
}
private:
std::wstring m_str;
};
template <class OStream>
OStream& operator<< (OStream& stream, const JuceString& stringToWrite)
{
return stream << stringToWrite.toWideCharPointer();
}
template <class IStream>
IStream& operator>> (IStream& stream, JuceString& s)
{
std::wstring t;
stream >> t;
s = JuceString(t.c_str());
return stream;
}
BOOST_CLASS_IMPLEMENTATION(JuceString, boost::serialization::primitive_type)
class Doc
{
friend class boost::serialization::access;
template<class Archive>
void serialize( Archive & ar, const unsigned int version )
{
ar & boost::serialization::make_nvp("title", m_title);
}
public:
Doc() {;}
Doc(const std::wstring& s) : m_title(s) {;}
private:
JuceString m_title;
};
int main (int argc, char* argv[])
{
std::wstringstream stream;
{
// Serializing document
Doc doc(L"DocumentTitle");
boost::archive::xml_woarchive oa(stream);
oa << boost::serialization::make_nvp("Document", doc);
}
{
// Deserializing document
Doc doc;
try
{
boost::archive::xml_wiarchive ia(stream);
ia >> boost::serialization::make_nvp("Document", doc);
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
return 0;
}
Using the text archive instead works just fine both ways…
Finally I got it to work (for XML archive nota bene), by using boost basic_xml_grammar to parse the string in operator>> , like so:
That will make sure that the string is parsed correctly.