--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: xml.h
+// Purpose: wxXmlDocument - XML parser & data holder class
+// Author: Vaclav Slavik
+// Created: 2000/03/05
+// RCS-ID: $Id$
+// Copyright: (c) 2000 Vaclav Slavik
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+
+/* ************************************************************************* *
+ * CAUTION! *
+ * *
+ * The API defined in this header *WILL* change in the future and backward *
+ * compatibility will *not* be preserved. If you use these classes in your *
+ * application, it probably won't compile with future wxWindows releases. *
+ * Use on your own risk. *
+ * *
+ * ************************************************************************* */
+
+#ifndef _WX_XML_H_
+#define _WX_XML_H_
+
+#if defined(__GNUG__) && !defined(__APPLE__)
+#pragma interface "xml.h"
+#endif
+
+#include "wx/defs.h"
+
+#if wxUSE_XML
+
+#include "wx/string.h"
+#include "wx/object.h"
+#include "wx/list.h"
+
+#ifdef WXMAKINGDLL_XML
+ #define WXDLLIMPEXP_XML WXEXPORT
+#elif defined(WXUSINGDLL)
+ #define WXDLLIMPEXP_XML WXIMPORT
+#else // not making nor using DLL
+ #define WXDLLIMPEXP_XML
+#endif
+
+class WXDLLIMPEXP_XML wxXmlNode;
+class WXDLLIMPEXP_XML wxXmlProperty;
+class WXDLLIMPEXP_XML wxXmlDocument;
+class WXDLLIMPEXP_XML wxXmlIOHandler;
+class WXDLLIMPEXP_BASE wxInputStream;
+class WXDLLIMPEXP_BASE wxOutputStream;
+
+
+// Represents XML node type.
+enum wxXmlNodeType
+{
+ // note: values are synchronized with xmlElementType from libxml
+ wxXML_ELEMENT_NODE = 1,
+ wxXML_ATTRIBUTE_NODE = 2,
+ wxXML_TEXT_NODE = 3,
+ wxXML_CDATA_SECTION_NODE = 4,
+ wxXML_ENTITY_REF_NODE = 5,
+ wxXML_ENTITY_NODE = 6,
+ wxXML_PI_NODE = 7,
+ wxXML_COMMENT_NODE = 8,
+ wxXML_DOCUMENT_NODE = 9,
+ wxXML_DOCUMENT_TYPE_NODE = 10,
+ wxXML_DOCUMENT_FRAG_NODE = 11,
+ wxXML_NOTATION_NODE = 12,
+ wxXML_HTML_DOCUMENT_NODE = 13
+};
+
+
+// Represents node property(ies).
+// Example: in <img src="hello.gif" id="3"/> "src" is property with value
+// "hello.gif" and "id" is prop. with value "3".
+
+class WXDLLIMPEXP_XML wxXmlProperty
+{
+public:
+ wxXmlProperty() : m_next(NULL) {}
+ wxXmlProperty(const wxString& name, const wxString& value,
+ wxXmlProperty *next)
+ : m_name(name), m_value(value), m_next(next) {}
+
+ wxString GetName() const { return m_name; }
+ wxString GetValue() const { return m_value; }
+ wxXmlProperty *GetNext() const { return m_next; }
+
+ void SetName(const wxString& name) { m_name = name; }
+ void SetValue(const wxString& value) { m_value = value; }
+ void SetNext(wxXmlProperty *next) { m_next = next; }
+
+private:
+ wxString m_name;
+ wxString m_value;
+ wxXmlProperty *m_next;
+};
+
+
+
+// Represents node in XML document. Node has name and may have content
+// and properties. Most common node types are wxXML_TEXT_NODE (name and props
+// are irrelevant) and wxXML_ELEMENT_NODE (e.g. in <title>hi</title> there is
+// element with name="title", irrelevant content and one child (wxXML_TEXT_NODE
+// with content="hi").
+//
+// If wxUSE_UNICODE is 0, all strings are encoded in the encoding given to Load
+// (default is UTF-8).
+
+class WXDLLIMPEXP_XML wxXmlNode
+{
+public:
+ wxXmlNode() : m_properties(NULL), m_parent(NULL),
+ m_children(NULL), m_next(NULL) {}
+ wxXmlNode(wxXmlNode *parent,wxXmlNodeType type,
+ const wxString& name, const wxString& content,
+ wxXmlProperty *props, wxXmlNode *next);
+ ~wxXmlNode();
+
+ // copy ctor & operator=. Note that this does NOT copy syblings
+ // and parent pointer, i.e. m_parent and m_next will be NULL
+ // after using copy ctor and are never unmodified by operator=.
+ // On the other hand, it DOES copy children and properties.
+ wxXmlNode(const wxXmlNode& node);
+ wxXmlNode& operator=(const wxXmlNode& node);
+
+ // user-friendly creation:
+ wxXmlNode(wxXmlNodeType type, const wxString& name,
+ const wxString& content = wxEmptyString);
+ void AddChild(wxXmlNode *child);
+ void InsertChild(wxXmlNode *child, wxXmlNode *before_node);
+ bool RemoveChild(wxXmlNode *child);
+ void AddProperty(const wxString& name, const wxString& value);
+ bool DeleteProperty(const wxString& name);
+
+ // access methods:
+ wxXmlNodeType GetType() const { return m_type; }
+ wxString GetName() const { return m_name; }
+ wxString GetContent() const { return m_content; }
+
+ wxXmlNode *GetParent() const { return m_parent; }
+ wxXmlNode *GetNext() const { return m_next; }
+ wxXmlNode *GetChildren() const { return m_children; }
+
+ wxXmlProperty *GetProperties() const { return m_properties; }
+ bool GetPropVal(const wxString& propName, wxString *value) const;
+ wxString GetPropVal(const wxString& propName,
+ const wxString& defaultVal) const;
+ bool HasProp(const wxString& propName) const;
+
+ void SetType(wxXmlNodeType type) { m_type = type; }
+ void SetName(const wxString& name) { m_name = name; }
+ void SetContent(const wxString& con) { m_content = con; }
+
+ void SetParent(wxXmlNode *parent) { m_parent = parent; }
+ void SetNext(wxXmlNode *next) { m_next = next; }
+ void SetChildren(wxXmlNode *child) { m_children = child; }
+
+ void SetProperties(wxXmlProperty *prop) { m_properties = prop; }
+ void AddProperty(wxXmlProperty *prop);
+
+private:
+ wxXmlNodeType m_type;
+ wxString m_name;
+ wxString m_content;
+ wxXmlProperty *m_properties;
+ wxXmlNode *m_parent, *m_children, *m_next;
+
+ void DoCopy(const wxXmlNode& node);
+};
+
+
+
+
+
+
+
+// This class holds XML data/document as parsed by XML parser.
+
+class WXDLLIMPEXP_XML wxXmlDocument : public wxObject
+{
+public:
+ wxXmlDocument();
+ wxXmlDocument(const wxString& filename,
+ const wxString& encoding = wxT("UTF-8"));
+ wxXmlDocument(wxInputStream& stream,
+ const wxString& encoding = wxT("UTF-8"));
+ ~wxXmlDocument() { delete m_root; }
+
+ wxXmlDocument(const wxXmlDocument& doc);
+ wxXmlDocument& operator=(const wxXmlDocument& doc);
+
+ // Parses .xml file and loads data. Returns TRUE on success, FALSE
+ // otherwise.
+ bool Load(const wxString& filename,
+ const wxString& encoding = wxT("UTF-8"));
+ bool Load(wxInputStream& stream,
+ const wxString& encoding = wxT("UTF-8"));
+
+ // Saves document as .xml file.
+ bool Save(const wxString& filename) const;
+ bool Save(wxOutputStream& stream) const;
+
+ bool IsOk() const { return m_root != NULL; }
+
+ // Returns root node of the document.
+ wxXmlNode *GetRoot() const { return m_root; }
+
+ // Returns version of document (may be empty).
+ wxString GetVersion() const { return m_version; }
+ // Returns encoding of document (may be empty).
+ // Note: this is the encoding original file was saved in, *not* the
+ // encoding of in-memory representation!
+ wxString GetFileEncoding() const { return m_fileEncoding; }
+
+ // Write-access methods:
+ void SetRoot(wxXmlNode *node) { delete m_root ; m_root = node; }
+ void SetVersion(const wxString& version) { m_version = version; }
+ void SetFileEncoding(const wxString& encoding) { m_fileEncoding = encoding; }
+
+#if !wxUSE_UNICODE
+ // Returns encoding of in-memory representation of the document
+ // (same as passed to Load or ctor, defaults to UTF-8).
+ // NB: this is meaningless in Unicode build where data are stored as wchar_t*
+ wxString GetEncoding() const { return m_encoding; }
+ void SetEncoding(const wxString& enc) { m_encoding = enc; }
+#endif
+
+private:
+ wxString m_version;
+ wxString m_fileEncoding;
+#if !wxUSE_UNICODE
+ wxString m_encoding;
+#endif
+ wxXmlNode *m_root;
+
+ void DoCopy(const wxXmlDocument& doc);
+};
+
+#endif // wxUSE_XML
+
+#endif // _WX_XML_H_
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: xml.cpp
+// Purpose: wxXmlDocument - XML parser & data holder class
+// Author: Vaclav Slavik
+// Created: 2000/03/05
+// RCS-ID: $Id$
+// Copyright: (c) 2000 Vaclav Slavik
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation "xml.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#include "wx/xml/xml.h"
+
+#if wxUSE_XML
+
+#include "wx/wfstream.h"
+#include "wx/datstrm.h"
+#include "wx/zstream.h"
+#include "wx/log.h"
+#include "wx/intl.h"
+#include "wx/strconv.h"
+
+#include "expat.h" // from Expat
+
+//-----------------------------------------------------------------------------
+// wxXmlNode
+//-----------------------------------------------------------------------------
+
+wxXmlNode::wxXmlNode(wxXmlNode *parent,wxXmlNodeType type,
+ const wxString& name, const wxString& content,
+ wxXmlProperty *props, wxXmlNode *next)
+ : m_type(type), m_name(name), m_content(content),
+ m_properties(props), m_parent(parent),
+ m_children(NULL), m_next(next)
+{
+ if (m_parent)
+ {
+ if (m_parent->m_children)
+ {
+ m_next = m_parent->m_children;
+ m_parent->m_children = this;
+ }
+ else
+ m_parent->m_children = this;
+ }
+}
+
+wxXmlNode::wxXmlNode(wxXmlNodeType type, const wxString& name,
+ const wxString& content)
+ : m_type(type), m_name(name), m_content(content),
+ m_properties(NULL), m_parent(NULL),
+ m_children(NULL), m_next(NULL)
+{}
+
+wxXmlNode::wxXmlNode(const wxXmlNode& node)
+{
+ m_next = NULL;
+ m_parent = NULL;
+ DoCopy(node);
+}
+
+wxXmlNode::~wxXmlNode()
+{
+ wxXmlNode *c, *c2;
+ for (c = m_children; c; c = c2)
+ {
+ c2 = c->m_next;
+ delete c;
+ }
+
+ wxXmlProperty *p, *p2;
+ for (p = m_properties; p; p = p2)
+ {
+ p2 = p->GetNext();
+ delete p;
+ }
+}
+
+wxXmlNode& wxXmlNode::operator=(const wxXmlNode& node)
+{
+ wxDELETE(m_properties);
+ wxDELETE(m_children);
+ DoCopy(node);
+ return *this;
+}
+
+void wxXmlNode::DoCopy(const wxXmlNode& node)
+{
+ m_type = node.m_type;
+ m_name = node.m_name;
+ m_content = node.m_content;
+ m_children = NULL;
+
+ wxXmlNode *n = node.m_children;
+ while (n)
+ {
+ AddChild(new wxXmlNode(*n));
+ n = n->GetNext();
+ }
+
+ m_properties = NULL;
+ wxXmlProperty *p = node.m_properties;
+ while (p)
+ {
+ AddProperty(p->GetName(), p->GetValue());
+ p = p->GetNext();
+ }
+}
+
+bool wxXmlNode::HasProp(const wxString& propName) const
+{
+ wxXmlProperty *prop = GetProperties();
+
+ while (prop)
+ {
+ if (prop->GetName() == propName) return TRUE;
+ prop = prop->GetNext();
+ }
+
+ return FALSE;
+}
+
+bool wxXmlNode::GetPropVal(const wxString& propName, wxString *value) const
+{
+ wxXmlProperty *prop = GetProperties();
+
+ while (prop)
+ {
+ if (prop->GetName() == propName)
+ {
+ *value = prop->GetValue();
+ return TRUE;
+ }
+ prop = prop->GetNext();
+ }
+
+ return FALSE;
+}
+
+wxString wxXmlNode::GetPropVal(const wxString& propName, const wxString& defaultVal) const
+{
+ wxString tmp;
+ if (GetPropVal(propName, &tmp))
+ return tmp;
+ else
+ return defaultVal;
+}
+
+void wxXmlNode::AddChild(wxXmlNode *child)
+{
+ if (m_children == NULL)
+ m_children = child;
+ else
+ {
+ wxXmlNode *ch = m_children;
+ while (ch->m_next) ch = ch->m_next;
+ ch->m_next = child;
+ }
+ child->m_next = NULL;
+ child->m_parent = this;
+}
+
+void wxXmlNode::InsertChild(wxXmlNode *child, wxXmlNode *before_node)
+{
+ wxASSERT_MSG(before_node->GetParent() == this, wxT("wxXmlNode::InsertChild - the node has incorrect parent"));
+
+ if (m_children == before_node)
+ m_children = child;
+ else
+ {
+ wxXmlNode *ch = m_children;
+ while (ch->m_next != before_node) ch = ch->m_next;
+ ch->m_next = child;
+ }
+
+ child->m_parent = this;
+ child->m_next = before_node;
+}
+
+bool wxXmlNode::RemoveChild(wxXmlNode *child)
+{
+ if (m_children == NULL)
+ return FALSE;
+ else if (m_children == child)
+ {
+ m_children = child->m_next;
+ child->m_parent = NULL;
+ child->m_next = NULL;
+ return TRUE;
+ }
+ else
+ {
+ wxXmlNode *ch = m_children;
+ while (ch->m_next)
+ {
+ if (ch->m_next == child)
+ {
+ ch->m_next = child->m_next;
+ child->m_parent = NULL;
+ child->m_next = NULL;
+ return TRUE;
+ }
+ ch = ch->m_next;
+ }
+ return FALSE;
+ }
+}
+
+void wxXmlNode::AddProperty(const wxString& name, const wxString& value)
+{
+ AddProperty(new wxXmlProperty(name, value, NULL));
+}
+
+void wxXmlNode::AddProperty(wxXmlProperty *prop)
+{
+ if (m_properties == NULL)
+ m_properties = prop;
+ else
+ {
+ wxXmlProperty *p = m_properties;
+ while (p->GetNext()) p = p->GetNext();
+ p->SetNext(prop);
+ }
+}
+
+bool wxXmlNode::DeleteProperty(const wxString& name)
+{
+ wxXmlProperty *prop;
+
+ if (m_properties == NULL)
+ return FALSE;
+
+ else if (m_properties->GetName() == name)
+ {
+ prop = m_properties;
+ m_properties = prop->GetNext();
+ prop->SetNext(NULL);
+ delete prop;
+ return TRUE;
+ }
+
+ else
+ {
+ wxXmlProperty *p = m_properties;
+ while (p->GetNext())
+ {
+ if (p->GetNext()->GetName() == name)
+ {
+ prop = p->GetNext();
+ p->SetNext(prop->GetNext());
+ prop->SetNext(NULL);
+ delete prop;
+ return TRUE;
+ }
+ p = p->GetNext();
+ }
+ return FALSE;
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// wxXmlDocument
+//-----------------------------------------------------------------------------
+
+wxXmlDocument::wxXmlDocument()
+ : m_version(wxT("1.0")), m_fileEncoding(wxT("utf-8")), m_root(NULL)
+{
+#if !wxUSE_UNICODE
+ m_encoding = wxT("UTF-8");
+#endif
+}
+
+wxXmlDocument::wxXmlDocument(const wxString& filename, const wxString& encoding)
+ : wxObject(), m_root(NULL)
+{
+ if ( !Load(filename, encoding) )
+ {
+ wxDELETE(m_root);
+ }
+}
+
+wxXmlDocument::wxXmlDocument(wxInputStream& stream, const wxString& encoding)
+ : wxObject(), m_root(NULL)
+{
+ if ( !Load(stream, encoding) )
+ {
+ wxDELETE(m_root);
+ }
+}
+
+wxXmlDocument::wxXmlDocument(const wxXmlDocument& doc)
+{
+ DoCopy(doc);
+}
+
+wxXmlDocument& wxXmlDocument::operator=(const wxXmlDocument& doc)
+{
+ wxDELETE(m_root);
+ DoCopy(doc);
+ return *this;
+}
+
+void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
+{
+ m_version = doc.m_version;
+#if !wxUSE_UNICODE
+ m_encoding = doc.m_encoding;
+#endif
+ m_fileEncoding = doc.m_fileEncoding;
+ m_root = new wxXmlNode(*doc.m_root);
+}
+
+bool wxXmlDocument::Load(const wxString& filename, const wxString& encoding)
+{
+ wxFileInputStream stream(filename);
+ return Load(stream, encoding);
+}
+
+bool wxXmlDocument::Save(const wxString& filename) const
+{
+ wxFileOutputStream stream(filename);
+ return Save(stream);
+}
+
+
+
+//-----------------------------------------------------------------------------
+// wxXmlDocument loading routines
+//-----------------------------------------------------------------------------
+
+/*
+ FIXME:
+ - process all elements, including CDATA
+ */
+
+// converts Expat-produced string in UTF-8 into wxString.
+inline static wxString CharToString(wxMBConv *conv,
+ const char *s, size_t len = wxSTRING_MAXLEN)
+{
+#if wxUSE_UNICODE
+ (void)conv;
+ return wxString(s, wxConvUTF8, len);
+#else
+ if ( conv )
+ {
+ size_t nLen = (len != wxSTRING_MAXLEN) ? len :
+ nLen = wxConvUTF8.MB2WC((wchar_t*) NULL, s, 0);
+
+ wchar_t *buf = new wchar_t[nLen+1];
+ wxConvUTF8.MB2WC(buf, s, nLen);
+ buf[nLen] = 0;
+ wxString str(buf, *conv, len);
+ delete[] buf;
+ return str;
+ }
+ else
+ return wxString(s, len);
+#endif
+}
+
+struct wxXmlParsingContext
+{
+ wxMBConv *conv;
+ wxXmlNode *root;
+ wxXmlNode *node;
+ wxXmlNode *lastAsText;
+ wxString encoding;
+ wxString version;
+};
+
+static void StartElementHnd(void *userData, const char *name, const char **atts)
+{
+ wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
+ wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, CharToString(ctx->conv, name));
+ const char **a = atts;
+ while (*a)
+ {
+ node->AddProperty(CharToString(ctx->conv, a[0]), CharToString(ctx->conv, a[1]));
+ a += 2;
+ }
+ if (ctx->root == NULL)
+ ctx->root = node;
+ else
+ ctx->node->AddChild(node);
+ ctx->node = node;
+ ctx->lastAsText = NULL;
+}
+
+static void EndElementHnd(void *userData, const char* WXUNUSED(name))
+{
+ wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
+
+ ctx->node = ctx->node->GetParent();
+ ctx->lastAsText = NULL;
+}
+
+static void TextHnd(void *userData, const char *s, int len)
+{
+ wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
+ char *buf = new char[len + 1];
+
+ buf[len] = '\0';
+ memcpy(buf, s, (size_t)len);
+
+ if (ctx->lastAsText)
+ {
+ ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
+ CharToString(ctx->conv, buf));
+ }
+ else
+ {
+ bool whiteOnly = TRUE;
+ for (char *c = buf; *c != '\0'; c++)
+ if (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\r')
+ {
+ whiteOnly = FALSE;
+ break;
+ }
+ if (!whiteOnly)
+ {
+ ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
+ CharToString(ctx->conv, buf));
+ ctx->node->AddChild(ctx->lastAsText);
+ }
+ }
+
+ delete[] buf;
+}
+
+static void CommentHnd(void *userData, const char *data)
+{
+ wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
+
+ if (ctx->node)
+ {
+ // VS: ctx->node == NULL happens if there is a comment before
+ // the root element (e.g. wxDesigner's output). We ignore such
+ // comments, no big deal...
+ ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
+ wxT("comment"), CharToString(ctx->conv, data)));
+ }
+ ctx->lastAsText = NULL;
+}
+
+static void DefaultHnd(void *userData, const char *s, int len)
+{
+ // XML header:
+ if (len > 6 && memcmp(s, "<?xml ", 6) == 0)
+ {
+ wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
+
+ wxString buf = CharToString(ctx->conv, s, (size_t)len);
+ int pos;
+ pos = buf.Find(wxT("encoding="));
+ if (pos != wxNOT_FOUND)
+ ctx->encoding = buf.Mid(pos + 10).BeforeFirst(buf[(size_t)pos+9]);
+ pos = buf.Find(wxT("version="));
+ if (pos != wxNOT_FOUND)
+ ctx->version = buf.Mid(pos + 9).BeforeFirst(buf[(size_t)pos+8]);
+ }
+}
+
+static int UnknownEncodingHnd(void * WXUNUSED(encodingHandlerData),
+ const XML_Char *name, XML_Encoding *info)
+{
+ // We must build conversion table for expat. The easiest way to do so
+ // is to let wxCSConv convert as string containing all characters to
+ // wide character representation:
+ wxCSConv conv(wxString(name, wxConvLibc));
+ char mbBuf[2];
+ wchar_t wcBuf[10];
+ size_t i;
+
+ mbBuf[1] = 0;
+ info->map[0] = 0;
+ for (i = 0; i < 255; i++)
+ {
+ mbBuf[0] = (char)(i+1);
+ if (conv.MB2WC(wcBuf, mbBuf, 2) == (size_t)-1)
+ {
+ // invalid/undefined byte in the encoding:
+ info->map[i+1] = -1;
+ }
+ info->map[i+1] = (int)wcBuf[0];
+ }
+
+ info->data = NULL;
+ info->convert = NULL;
+ info->release = NULL;
+
+ return 1;
+}
+
+bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding)
+{
+#if wxUSE_UNICODE
+ (void)encoding;
+#else
+ m_encoding = encoding;
+#endif
+
+ const size_t BUFSIZE = 1024;
+ char buf[BUFSIZE];
+ wxXmlParsingContext ctx;
+ bool done;
+ XML_Parser parser = XML_ParserCreate(NULL);
+
+ ctx.root = ctx.node = NULL;
+ ctx.encoding = wxT("UTF-8"); // default in absence of encoding=""
+ ctx.conv = NULL;
+#if !wxUSE_UNICODE
+ if ( encoding != wxT("UTF-8") && encoding != wxT("utf-8") )
+ ctx.conv = new wxCSConv(encoding);
+#endif
+
+ XML_SetUserData(parser, (void*)&ctx);
+ XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
+ XML_SetCharacterDataHandler(parser, TextHnd);
+ XML_SetCommentHandler(parser, CommentHnd);
+ XML_SetDefaultHandler(parser, DefaultHnd);
+ XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
+
+ bool ok = true;
+ do
+ {
+ size_t len = stream.Read(buf, BUFSIZE).LastRead();
+ done = (len < BUFSIZE);
+ if (!XML_Parse(parser, buf, len, done))
+ {
+ wxLogError(_("XML parsing error: '%s' at line %d"),
+ XML_ErrorString(XML_GetErrorCode(parser)),
+ XML_GetCurrentLineNumber(parser));
+ ok = false;
+ break;
+ }
+ } while (!done);
+
+ if (ok)
+ {
+ SetVersion(ctx.version);
+ SetFileEncoding(ctx.encoding);
+ SetRoot(ctx.root);
+ }
+
+ XML_ParserFree(parser);
+#if !wxUSE_UNICODE
+ if ( ctx.conv )
+ delete ctx.conv;
+#endif
+
+ return ok;
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// wxXmlDocument saving routines
+//-----------------------------------------------------------------------------
+
+// write string to output:
+inline static void OutputString(wxOutputStream& stream, const wxString& str,
+ wxMBConv *convMem, wxMBConv *convFile)
+{
+ if (str.IsEmpty()) return;
+#if wxUSE_UNICODE
+ const wxWX2MBbuf buf(str.mb_str(convFile ? *convFile : wxConvUTF8));
+ stream.Write((const char*)buf, strlen((const char*)buf));
+#else
+ if ( convFile == NULL )
+ stream.Write(str.mb_str(), str.Len());
+ else
+ {
+ wxString str2(str.wc_str(*convMem), *convFile);
+ stream.Write(str2.mb_str(), str2.Len());
+ }
+#endif
+}
+
+// Same as above, but create entities first.
+// Translates '<' to "<", '>' to ">" and '&' to "&"
+static void OutputStringEnt(wxOutputStream& stream, const wxString& str,
+ wxMBConv *convMem, wxMBConv *convFile)
+{
+ wxString buf;
+ size_t i, last, len;
+ wxChar c;
+
+ len = str.Len();
+ last = 0;
+ for (i = 0; i < len; i++)
+ {
+ c = str.GetChar(i);
+ if (c == wxT('<') || c == wxT('>') ||
+ (c == wxT('&') && str.Mid(i+1, 4) != wxT("amp;")))
+ {
+ OutputString(stream, str.Mid(last, i - last), convMem, convFile);
+ switch (c)
+ {
+ case wxT('<'):
+ OutputString(stream, wxT("<"), NULL, NULL);
+ break;
+ case wxT('>'):
+ OutputString(stream, wxT(">"), NULL, NULL);
+ break;
+ case wxT('&'):
+ OutputString(stream, wxT("&"), NULL, NULL);
+ break;
+ default: break;
+ }
+ last = i + 1;
+ }
+ }
+ OutputString(stream, str.Mid(last, i - last), convMem, convFile);
+}
+
+inline static void OutputIndentation(wxOutputStream& stream, int indent)
+{
+ wxString str = wxT("\n");
+ for (int i = 0; i < indent; i++)
+ str << wxT(' ') << wxT(' ');
+ OutputString(stream, str, NULL, NULL);
+}
+
+static void OutputNode(wxOutputStream& stream, wxXmlNode *node, int indent,
+ wxMBConv *convMem, wxMBConv *convFile)
+{
+ wxXmlNode *n, *prev;
+ wxXmlProperty *prop;
+
+ switch (node->GetType())
+ {
+ case wxXML_TEXT_NODE:
+ OutputStringEnt(stream, node->GetContent(), convMem, convFile);
+ break;
+
+ case wxXML_ELEMENT_NODE:
+ OutputString(stream, wxT("<"), NULL, NULL);
+ OutputString(stream, node->GetName(), NULL, NULL);
+
+ prop = node->GetProperties();
+ while (prop)
+ {
+ OutputString(stream, wxT(" ") + prop->GetName() +
+ wxT("=\"") + prop->GetValue() + wxT("\""),
+ NULL, NULL);
+ // FIXME - what if prop contains '"'?
+ prop = prop->GetNext();
+ }
+
+ if (node->GetChildren())
+ {
+ OutputString(stream, wxT(">"), NULL, NULL);
+ prev = NULL;
+ n = node->GetChildren();
+ while (n)
+ {
+ if (n && n->GetType() != wxXML_TEXT_NODE)
+ OutputIndentation(stream, indent + 1);
+ OutputNode(stream, n, indent + 1, convMem, convFile);
+ prev = n;
+ n = n->GetNext();
+ }
+ if (prev && prev->GetType() != wxXML_TEXT_NODE)
+ OutputIndentation(stream, indent);
+ OutputString(stream, wxT("</"), NULL, NULL);
+ OutputString(stream, node->GetName(), NULL, NULL);
+ OutputString(stream, wxT(">"), NULL, NULL);
+ }
+ else
+ OutputString(stream, wxT("/>"), NULL, NULL);
+ break;
+
+ case wxXML_COMMENT_NODE:
+ OutputString(stream, wxT("<!--"), NULL, NULL);
+ OutputString(stream, node->GetContent(), convMem, convFile);
+ OutputString(stream, wxT("-->"), NULL, NULL);
+ break;
+
+ default:
+ wxFAIL_MSG(wxT("unsupported node type"));
+ }
+}
+
+bool wxXmlDocument::Save(wxOutputStream& stream) const
+{
+ if ( !IsOk() )
+ return FALSE;
+
+ wxString s;
+
+ wxMBConv *convMem = NULL, *convFile = NULL;
+#if wxUSE_UNICODE
+ convFile = new wxCSConv(GetFileEncoding());
+#else
+ if ( GetFileEncoding() != GetEncoding() )
+ {
+ convFile = new wxCSConv(GetFileEncoding());
+ convMem = new wxCSConv(GetEncoding());
+ }
+#endif
+
+ s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
+ GetVersion().c_str(), GetFileEncoding().c_str());
+ OutputString(stream, s, NULL, NULL);
+
+ OutputNode(stream, GetRoot(), 0, convMem, convFile);
+ OutputString(stream, wxT("\n"), NULL, NULL);
+
+ if ( convFile )
+ delete convFile;
+ if ( convMem )
+ delete convMem;
+
+ return TRUE;
+}
+
+#endif // wxUSE_XML