- Bugfix for UTF-8 strings

- insert more XS_vsnprintf() calls
- additional comments
- struct XMLWriter

svn path=/trunk/; revision=17973
This commit is contained in:
Martin Fuchs 2005-09-21 21:44:39 +00:00
parent a8f183303f
commit d4358bfc5e
2 changed files with 200 additions and 7 deletions

View file

@ -36,6 +36,10 @@
*/ */
#ifndef _NO_COMMENT
#define _NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files
#endif
//#include "xmlstorage.h" //#include "xmlstorage.h"
#include <precomp.h> #include <precomp.h>
@ -51,6 +55,7 @@ const LPCXSSTR XMLStorage::XS_NUMBERFMT = XS_TEXT("%d");
namespace XMLStorage { namespace XMLStorage {
/// remove escape characters from zero terminated string
static std::string unescape(const char* s, char b='"', char e='"') static std::string unescape(const char* s, char b='"', char e='"')
{ {
const char* end = s + strlen(s); const char* end = s + strlen(s);
@ -68,6 +73,7 @@ static std::string unescape(const char* s, char b='"', char e='"')
return std::string(s, end-s); return std::string(s, end-s);
} }
/// remove escape characters from string with specified length
static std::string unescape(const char* s, int l, char b='"', char e='"') static std::string unescape(const char* s, int l, char b='"', char e='"')
{ {
const char* end = s + l; const char* end = s + l;
@ -391,6 +397,7 @@ void XMLCALL XMLReaderBase::XML_DefaultHandler(void* userData, const XML_Char* s
} }
/// return error strings for Expat errors
std::string XMLReaderBase::get_error_string() const std::string XMLReaderBase::get_error_string() const
{ {
XML_Error error = XML_GetErrorCode(_parser); XML_Error error = XML_GetErrorCode(_parser);
@ -453,6 +460,7 @@ std::string XMLReaderBase::get_error_string() const
} }
/// encode XML string literals
std::string EncodeXMLString(const XS_String& str) std::string EncodeXMLString(const XS_String& str)
{ {
LPCXSSTR s = str.c_str(); LPCXSSTR s = str.c_str();
@ -492,6 +500,7 @@ std::string EncodeXMLString(const XS_String& str)
#endif #endif
} }
/// decode XML string literals
XS_String DecodeXMLString(const XS_String& str) XS_String DecodeXMLString(const XS_String& str)
{ {
LPCXSSTR s = str.c_str(); LPCXSSTR s = str.c_str();

View file

@ -140,8 +140,8 @@ struct XS_String
XS_String& operator=(LPCWSTR s) {assign(s); return *this;} XS_String& operator=(LPCWSTR s) {assign(s); return *this;}
#ifdef XS_STRING_UTF8 #ifdef XS_STRING_UTF8
void assign(const XS_String& s) {assign(s.c_str());} void assign(const XS_String& s) {assign(s.c_str());}
void assign(LPCWSTR s) {if (s) {int bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, bl, b, bl, 0, 0));} else erase();} void assign(LPCWSTR s) {if (s) {int bl=2*wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, bl, b, bl, 0, 0));} else erase();}
void assign(LPCWSTR s, int l) {int bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, l, b, bl, 0, 0));} else erase();} void assign(LPCWSTR s, int l) {int bl=2*l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, l, b, bl, 0, 0));} else erase();}
#else // if !UNICODE && !XS_STRING_UTF8 #else // if !UNICODE && !XS_STRING_UTF8
void assign(LPCWSTR s) {if (s) {int bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, bl, b, bl, 0, 0));} else erase();} void assign(LPCWSTR s) {if (s) {int bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, bl, b, bl, 0, 0));} else erase();}
void assign(LPCWSTR s, int l) {int bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, l, b, bl, 0, 0));} else erase();} void assign(LPCWSTR s, int l) {int bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, l, b, bl, 0, 0));} else erase();}
@ -169,7 +169,7 @@ struct XS_String
XS_CHAR b[BUFFER_LEN]; XS_CHAR b[BUFFER_LEN];
va_start(l, fmt); va_start(l, fmt);
super::assign(b, XS_vsprintf(b, fmt, l)); super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
va_end(l); va_end(l);
return *this; return *this;
@ -179,7 +179,7 @@ struct XS_String
{ {
XS_CHAR b[BUFFER_LEN]; XS_CHAR b[BUFFER_LEN];
super::assign(b, XS_vsprintf(b, fmt, l)); super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
return *this; return *this;
} }
@ -190,7 +190,7 @@ struct XS_String
XS_CHAR b[BUFFER_LEN]; XS_CHAR b[BUFFER_LEN];
va_start(l, fmt); va_start(l, fmt);
super::append(b, XS_vsprintf(b, fmt, l)); super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
va_end(l); va_end(l);
return *this; return *this;
@ -200,7 +200,7 @@ struct XS_String
{ {
XS_CHAR b[BUFFER_LEN]; XS_CHAR b[BUFFER_LEN];
super::append(b, XS_vsprintf(b, fmt, l)); super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
return *this; return *this;
} }
@ -336,6 +336,7 @@ typedef XS_String String_from_XML_Char;
#else #else
/// converter from Expat strings to XMLStorage internal strings
struct String_from_XML_Char : public XS_String struct String_from_XML_Char : public XS_String
{ {
String_from_XML_Char(const XML_Char* str) String_from_XML_Char(const XML_Char* str)
@ -397,6 +398,7 @@ struct XMLNode : public XS_String
typedef std::map<XS_String, XS_String> AttributeMap; typedef std::map<XS_String, XS_String> AttributeMap;
#endif #endif
/// internal children node list
struct Children : public std::list<XMLNode*> struct Children : public std::list<XMLNode*>
{ {
void assign(const Children& other) void assign(const Children& other)
@ -678,9 +680,10 @@ protected:
} }
#endif #endif
/// XPath find functions /// XPath find function (const)
const XMLNode* find_relative(const char* path) const; const XMLNode* find_relative(const char* path) const;
/// XPath find function
XMLNode* find_relative(const char* path) XMLNode* find_relative(const char* path)
{return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->find_relative(path));} {return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->find_relative(path));}
@ -708,6 +711,7 @@ struct XMLChildrenFilter
{ {
} }
/// internal iterator class
struct iterator struct iterator
{ {
typedef XMLNode::Children::iterator BaseIterator; typedef XMLNode::Children::iterator BaseIterator;
@ -806,6 +810,7 @@ struct const_XMLChildrenFilter
{ {
} }
/// internal iterator class
struct const_iterator struct const_iterator
{ {
typedef XMLNode::Children::const_iterator BaseIterator; typedef XMLNode::Children::const_iterator BaseIterator;
@ -954,6 +959,7 @@ struct XMLPos
return _cur->get(attr_name); return _cur->get(attr_name);
} }
/// attribute setting
void put(const XS_String& attr_name, const XS_String& value) void put(const XS_String& attr_name, const XS_String& value)
{ {
_cur->put(attr_name, value); _cur->put(attr_name, value);
@ -1230,6 +1236,7 @@ extern const LPCXSSTR XS_NUMBERFMT;
#endif #endif
/// type converter for boolean data
struct XMLBool struct XMLBool
{ {
XMLBool(bool value=false) XMLBool(bool value=false)
@ -1277,6 +1284,7 @@ private:
void operator=(const XMLBool&); // disallow assignment operations void operator=(const XMLBool&); // disallow assignment operations
}; };
/// type converter for boolean data with write access
struct XMLBoolRef struct XMLBoolRef
{ {
XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false) XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false)
@ -1318,6 +1326,7 @@ protected:
}; };
/// type converter for integer data
struct XMLInt struct XMLInt
{ {
XMLInt(int value) XMLInt(int value)
@ -1362,6 +1371,7 @@ private:
void operator=(const XMLInt&); // disallow assignment operations void operator=(const XMLInt&); // disallow assignment operations
}; };
/// type converter for integer data with write access
struct XMLIntRef struct XMLIntRef
{ {
XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0) XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0)
@ -1395,6 +1405,7 @@ protected:
}; };
/// type converter for string data
struct XMLString struct XMLString
{ {
XMLString(const XS_String& value) XMLString(const XS_String& value)
@ -1437,6 +1448,7 @@ private:
void operator=(const XMLString&); // disallow assignment operations void operator=(const XMLString&); // disallow assignment operations
}; };
/// type converter for string data with write access
struct XMStringRef struct XMStringRef
{ {
XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT("")) XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
@ -1580,6 +1592,7 @@ protected:
}; };
/// management of XML file headers
struct XMLHeader struct XMLHeader
{ {
XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="") XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="")
@ -1595,6 +1608,7 @@ struct XMLHeader
if (!_doctype.empty()) if (!_doctype.empty())
out << _doctype << '\n'; out << _doctype << '\n';
if (!_additional.empty()) if (!_additional.empty())
out << _additional << '\n'; out << _additional << '\n';
} }
@ -1606,6 +1620,7 @@ struct XMLHeader
}; };
/// XML document holder
struct XMLDoc : public XMLNode struct XMLDoc : public XMLNode
{ {
XMLDoc() XMLDoc()
@ -1715,6 +1730,7 @@ struct XMLDoc : public XMLNode
}; };
/// XML message wrapper
struct XMLMessage : public XMLDoc struct XMLMessage : public XMLDoc
{ {
XMLMessage(const char* name) XMLMessage(const char* name)
@ -1727,6 +1743,174 @@ struct XMLMessage : public XMLDoc
}; };
enum PRETTY_FLAGS {
PRETTY_PLAIN = 0,
PRETTY_LINEFEED = 1,
PRETTY_INDENT = 2
};
struct XMLWriter
{
XMLWriter(std::ostream& out, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader())
: _pofstream(NULL),
_out(out),
_pretty(pretty)
{
header.print(_out, false);
}
XMLWriter(LPCTSTR path, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader())
: _pofstream(new tofstream(path)),
_out(*_pofstream),
_pretty(pretty)
{
header.print(_out, false);
}
~XMLWriter()
{
_out << std::endl;
delete _pofstream;
}
/// create node and move to it
void create(const XS_String& name)
{
if (!_stack.empty()) {
StackEntry& last = _stack.top();
if (last._state < PRE_CLOSED) {
write_attributes(last);
close_pre(last);
}
++last._children;
}
StackEntry entry;
entry._node_name = name;
_stack.push(entry);
write_pre(entry);
}
/// go back to previous position
bool back()
{
if (!_stack.empty()) {
write_post(_stack.top());
_stack.pop();
return true;
} else
return false;
}
/// attribute setting
void put(const XS_String& attr_name, const XS_String& value)
{
if (!_stack.empty())
_stack.top()._attributes[attr_name] = value;
}
/// C++ write access to an attribute
XS_String& operator[](const XS_String& attr_name)
{
if (_stack.empty())
return s_empty_attr;
return _stack.top()._attributes[attr_name];
}
void set_content(const XS_String& s)
{
if (!_stack.empty())
_stack.top()._content = s;
}
// public for access in StackEntry
enum WRITESTATE {
NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST
};
protected:
tofstream* _pofstream;
std::ostream& _out;
PRETTY_FLAGS _pretty;
typedef XMLNode::AttributeMap AttrMap;
struct StackEntry {
XS_String _node_name;
AttrMap _attributes;
std::string _content;
WRITESTATE _state;
bool _children;
StackEntry() : _children(false), _state(NOTHING) {}
};
std::stack<StackEntry> _stack;
static XS_String s_empty_attr;
void close_pre(StackEntry& entry)
{
_out << '>';
entry._state = PRE_CLOSED;
}
void write_pre(StackEntry& entry)
{
if (_pretty >= PRETTY_LINEFEED)
_out << std::endl;
if (_pretty == PRETTY_INDENT)
for(int i=_stack.size(); --i>0; )
_out << XML_INDENT_SPACE;
_out << '<' << EncodeXMLString(entry._node_name);
//entry._state = PRE;
}
void write_attributes(StackEntry& entry)
{
for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it)
_out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
entry._state = ATTRIBUTES;
}
void write_post(StackEntry& entry)
{
if (entry._state < ATTRIBUTES)
write_attributes(entry);
if (entry._children || !entry._content.empty()) {
if (entry._state < PRE_CLOSED)
close_pre(entry);
_out << entry._content;
//entry._state = CONTENT;
if (_pretty>=PRETTY_LINEFEED && entry._content.empty())
_out << std::endl;
if (_pretty==PRETTY_INDENT && entry._content.empty())
for(int i=_stack.size(); --i>0; )
_out << XML_INDENT_SPACE;
_out << "</" << EncodeXMLString(entry._node_name) << ">";
} else {
_out << "/>";
}
entry._state = POST;
}
};
} // namespace XMLStorage } // namespace XMLStorage
#define _XMLSTORAGE_H #define _XMLSTORAGE_H