- Bugfix for UTF-8 strings
- insert more XS_vsnprintf() calls
- additional comments
- struct XMLWriter
Modified: trunk/reactos/subsys/system/explorer/utility/xmlstorage.cpp
Modified: trunk/reactos/subsys/system/explorer/utility/xmlstorage.h

Modified: trunk/reactos/subsys/system/explorer/utility/xmlstorage.cpp
--- trunk/reactos/subsys/system/explorer/utility/xmlstorage.cpp	2005-09-21 18:24:16 UTC (rev 17972)
+++ trunk/reactos/subsys/system/explorer/utility/xmlstorage.cpp	2005-09-21 21:44:39 UTC (rev 17973)
@@ -36,6 +36,10 @@
 
 */
 
+#ifndef _NO_COMMENT
+#define _NO_COMMENT	// no #pragma comment(lib, ...) statements in .lib files
+#endif
+
 //#include "xmlstorage.h"
 #include <precomp.h>
 
@@ -51,6 +55,7 @@
 namespace XMLStorage {
 
 
+ /// remove escape characters from zero terminated string
 static std::string unescape(const char* s, char b='"', char e='"')
 {
 	const char* end = s + strlen(s);
@@ -68,6 +73,7 @@
 	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='"')
 {
 	const char* end = s + l;
@@ -391,6 +397,7 @@
 }
 
 
+ /// return error strings for Expat errors
 std::string XMLReaderBase::get_error_string() const
 {
 	XML_Error error = XML_GetErrorCode(_parser);
@@ -453,6 +460,7 @@
 }
 
 
+ /// encode XML string literals
 std::string EncodeXMLString(const XS_String& str)
 {
 	LPCXSSTR s = str.c_str();
@@ -492,6 +500,7 @@
 #endif
 }
 
+ /// decode XML string literals
 XS_String DecodeXMLString(const XS_String& str)
 {
 	LPCXSSTR s = str.c_str();

Modified: trunk/reactos/subsys/system/explorer/utility/xmlstorage.h
--- trunk/reactos/subsys/system/explorer/utility/xmlstorage.h	2005-09-21 18:24:16 UTC (rev 17972)
+++ trunk/reactos/subsys/system/explorer/utility/xmlstorage.h	2005-09-21 21:44:39 UTC (rev 17973)
@@ -140,8 +140,8 @@
 	XS_String& operator=(LPCWSTR s) {assign(s); return *this;}
 #ifdef XS_STRING_UTF8
 	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, 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) {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=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
 	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();}
@@ -169,7 +169,7 @@
 		XS_CHAR b[BUFFER_LEN];
 
 		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);
 
 		return *this;
@@ -179,7 +179,7 @@
 	{
 		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;
 	}
@@ -190,7 +190,7 @@
 		XS_CHAR b[BUFFER_LEN];
 
 		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);
 
 		return *this;
@@ -200,7 +200,7 @@
 	{
 		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;
 	}
@@ -336,6 +336,7 @@
 
 #else
 
+ /// converter from Expat strings to XMLStorage internal strings
 struct String_from_XML_Char : public XS_String
 {
 	String_from_XML_Char(const XML_Char* str)
@@ -397,6 +398,7 @@
 	typedef std::map<XS_String, XS_String> AttributeMap;
 #endif
 
+	 /// internal children node list
 	struct Children : public std::list<XMLNode*>
 	{
 		void assign(const Children& other)
@@ -678,9 +680,10 @@
 	}
 #endif
 
-	 /// XPath find functions
+	 /// XPath find function (const)
 	const XMLNode* find_relative(const char* path) const;
 
+	 /// XPath find function
 	XMLNode* find_relative(const char* path)
 		{return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->find_relative(path));}
 
@@ -708,6 +711,7 @@
 	{
 	}
 
+	 /// internal iterator class
 	struct iterator
 	{
 		typedef XMLNode::Children::iterator BaseIterator;
@@ -806,6 +810,7 @@
 	{
 	}
 
+	 /// internal iterator class
 	struct const_iterator
 	{
 		typedef XMLNode::Children::const_iterator BaseIterator;
@@ -954,6 +959,7 @@
 		return _cur->get(attr_name);
 	}
 
+	 /// attribute setting
 	void put(const XS_String& attr_name, const XS_String& value)
 	{
 		_cur->put(attr_name, value);
@@ -1230,6 +1236,7 @@
 #endif
 
 
+ /// type converter for boolean data
 struct XMLBool
 {
 	XMLBool(bool value=false)
@@ -1277,6 +1284,7 @@
 	void operator=(const XMLBool&); // disallow assignment operations
 };
 
+ /// type converter for boolean data with write access
 struct XMLBoolRef
 {
 	XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false)
@@ -1318,6 +1326,7 @@
 };
 
 
+ /// type converter for integer data
 struct XMLInt
 {
 	XMLInt(int value)
@@ -1362,6 +1371,7 @@
 	void operator=(const XMLInt&); // disallow assignment operations
 };
 
+ /// type converter for integer data with write access
 struct XMLIntRef
 {
 	XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0)
@@ -1395,6 +1405,7 @@
 };
 
 
+ /// type converter for string data
 struct XMLString
 {
 	XMLString(const XS_String& value)
@@ -1437,6 +1448,7 @@
 	void operator=(const XMLString&); // disallow assignment operations
 };
 
+ /// type converter for string data with write access
 struct XMStringRef
 {
 	XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
@@ -1580,6 +1592,7 @@
 };
 
 
+ /// management of XML file headers
 struct XMLHeader
 {
 	XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="")
@@ -1595,6 +1608,7 @@
 
 		if (!_doctype.empty())
 			out << _doctype << '\n';
+
 		if (!_additional.empty())
 			out << _additional << '\n';
 	}
@@ -1606,6 +1620,7 @@
 };
 
 
+ /// XML document holder
 struct XMLDoc : public XMLNode
 {
 	XMLDoc()
@@ -1715,6 +1730,7 @@
 };
 
 
+ /// XML message wrapper
 struct XMLMessage : public XMLDoc
 {
 	XMLMessage(const char* name)
@@ -1727,6 +1743,174 @@
 };
 
 
+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
 
 #define _XMLSTORAGE_H