From Wang Rui, "I've fixed the problem that osgx format doesn't read the Font property and wrapped string correctly. The first problem happened because the matchString() made a mistake in comparing two strings with the same start but different size. The second just needs complete rewriting of writeWrappedString() and readWrappedString() in src/osgPlugins/osg/XmlStreamOperator.h
I also fixed a possible bug in osgDB::XmlParser that doesn't handle control characters (like " to ") when reading node attributes, because the writeWrappedString() and readWrappedString() now depend heavily on control characters. An additional improvement is that osgx now supports comments."
This commit is contained in:
@@ -148,6 +148,8 @@ class OSGDB_EXPORT XmlNode : public osg::Referenced
|
||||
|
||||
bool writeChildren(const ControlMap& controlMap, std::ostream& fout, const std::string& indent) const;
|
||||
bool writeProperties(const ControlMap& controlMap, std::ostream& fout) const;
|
||||
|
||||
bool readAndReplaceControl(std::string& contents, Input& input);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -258,8 +258,13 @@ bool XmlNode::read(Input& input)
|
||||
++input;
|
||||
while((c=input[0])>=0 && c!='"')
|
||||
{
|
||||
value.push_back(c);
|
||||
++input;
|
||||
if (c=='&')
|
||||
readAndReplaceControl(value, input);
|
||||
else
|
||||
{
|
||||
value.push_back(c);
|
||||
++input;
|
||||
}
|
||||
}
|
||||
++input;
|
||||
}
|
||||
@@ -268,8 +273,13 @@ bool XmlNode::read(Input& input)
|
||||
++input;
|
||||
while((c=input[0])>=0 && c!='\'')
|
||||
{
|
||||
value.push_back(c);
|
||||
++input;
|
||||
if (c=='&')
|
||||
readAndReplaceControl(value, input);
|
||||
else
|
||||
{
|
||||
value.push_back(c);
|
||||
++input;
|
||||
}
|
||||
}
|
||||
++input;
|
||||
}
|
||||
@@ -335,20 +345,7 @@ bool XmlNode::read(Input& input)
|
||||
|
||||
if (c=='&')
|
||||
{
|
||||
std::string value;
|
||||
while(input && (c=input.get())!=';') { value.push_back(c); }
|
||||
value.push_back(c);
|
||||
|
||||
if (input._controlToCharacterMap.count(value)!=0)
|
||||
{
|
||||
c = input._controlToCharacterMap[value];
|
||||
OSG_INFO<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
|
||||
contents.push_back(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_NOTICE<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
|
||||
}
|
||||
readAndReplaceControl(contents, input);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -459,3 +456,24 @@ bool XmlNode::writeProperties(const ControlMap& controlMap, std::ostream& fout)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlNode::readAndReplaceControl(std::string& contents, XmlNode::Input& input)
|
||||
{
|
||||
int c = 0;
|
||||
std::string value;
|
||||
while(input && (c=input.get())!=';') { value.push_back(c); }
|
||||
value.push_back(c);
|
||||
|
||||
if (input._controlToCharacterMap.count(value)!=0)
|
||||
{
|
||||
c = input._controlToCharacterMap[value];
|
||||
OSG_INFO<<"Read control character "<<value<<" converted to "<<char(c)<<std::endl;
|
||||
contents.push_back(c);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_NOTICE<<"Warning: read control character "<<value<<", but have no mapping to convert it to."<<std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,11 +156,13 @@ public:
|
||||
std::string realStr;
|
||||
for ( std::string::const_iterator itr=str.begin(); itr!=str.end(); ++itr )
|
||||
{
|
||||
if ( *itr=='\"' )
|
||||
realStr += "''";
|
||||
else
|
||||
realStr += *itr;
|
||||
char ch = *itr;
|
||||
if ( ch=='\"' ) realStr += '\\';
|
||||
else if ( ch=='\\' ) realStr += '\\';
|
||||
realStr += ch;
|
||||
}
|
||||
realStr.insert( 0, 1, '\"' );
|
||||
realStr += '\"';
|
||||
addToCurrentNode( realStr );
|
||||
}
|
||||
|
||||
@@ -432,31 +434,56 @@ public:
|
||||
|
||||
virtual void readWrappedString( std::string& str )
|
||||
{
|
||||
std::string realStr;
|
||||
if ( prepareStream() ) std::getline( _sstream, realStr );
|
||||
for ( std::string::const_iterator itr=realStr.begin(); itr!=realStr.end(); ++itr )
|
||||
if ( !prepareStream() ) return;
|
||||
|
||||
// Read available string in the stream buffer
|
||||
unsigned int availSize = _sstream.rdbuf()->in_avail();
|
||||
std::string realStr = _sstream.str();
|
||||
_sstream.str("");
|
||||
|
||||
// Find the first quot or valid character
|
||||
bool hasQuot = false;
|
||||
std::string::iterator itr = realStr.begin() + (realStr.size() - availSize);
|
||||
for ( ; itr!=realStr.end(); ++itr )
|
||||
{
|
||||
if ( *itr=='\'' )
|
||||
char ch = *itr;
|
||||
if ((ch==' ') || (ch=='\n') || (ch=='\r')) continue;
|
||||
else if (ch=='"') hasQuot = true;
|
||||
else str += ch;
|
||||
|
||||
itr++;
|
||||
break;
|
||||
}
|
||||
|
||||
for ( ; itr!=realStr.end(); ++itr )
|
||||
{
|
||||
char ch = *itr;
|
||||
if (ch=='\\')
|
||||
{
|
||||
itr++;
|
||||
if ( itr==realStr.end() ) break;
|
||||
|
||||
if ( *itr=='\'' ) str += '\"';
|
||||
else str += '\'' + *itr;
|
||||
if (itr == realStr.end()) break;
|
||||
str += *itr;
|
||||
}
|
||||
else if (hasQuot && ch=='"')
|
||||
{
|
||||
// Get to the end of the wrapped string
|
||||
itr++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
str += *itr;
|
||||
str += ch;
|
||||
}
|
||||
if (itr != realStr.end())
|
||||
{
|
||||
_sstream << std::string(itr, realStr.end());
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool matchString( const std::string& str )
|
||||
{
|
||||
prepareStream();
|
||||
unsigned int size = str.length();
|
||||
if ( _sstream.str().length()<size ) return false;
|
||||
|
||||
int result = _sstream.str().compare( 0, size, str );
|
||||
if ( !result )
|
||||
std::string strInStream = osgDB::trimEnclosingSpaces(_sstream.str());
|
||||
if ( strInStream==str )
|
||||
{
|
||||
std::string prop; readString( prop );
|
||||
return true;
|
||||
@@ -476,26 +503,28 @@ protected:
|
||||
_sstream.clear();
|
||||
|
||||
osgDB::XmlNode* current = _nodePath.back().get();
|
||||
if ( !current->name.empty() )
|
||||
if ( current->type!=osgDB::XmlNode::COMMENT )
|
||||
{
|
||||
_sstream.str( current->name );
|
||||
current->name.clear();
|
||||
return true;
|
||||
if ( !current->name.empty() )
|
||||
{
|
||||
_sstream.str( current->name );
|
||||
current->name.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( current->properties.size()>0 )
|
||||
{
|
||||
if ( applyPropertyToStream(current, "attribute") ) return true;
|
||||
else if ( applyPropertyToStream(current, "text") ) return true;
|
||||
}
|
||||
|
||||
if ( current->children.size()>0 )
|
||||
{
|
||||
_nodePath.push_back( current->children.front() );
|
||||
current->children.erase( current->children.begin() );
|
||||
return prepareStream();
|
||||
}
|
||||
}
|
||||
|
||||
if ( current->properties.size()>0 )
|
||||
{
|
||||
if ( applyPropertyToStream(current, "attribute") ) return true;
|
||||
else if ( applyPropertyToStream(current, "text") ) return true;
|
||||
}
|
||||
|
||||
if ( current->children.size()>0 )
|
||||
{
|
||||
_nodePath.push_back( current->children.front() );
|
||||
current->children.erase( current->children.begin() );
|
||||
return prepareStream();
|
||||
}
|
||||
|
||||
_nodePath.pop_back();
|
||||
return prepareStream();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user