]> git.saurik.com Git - wxWidgets.git/blobdiff - src/xml/xml.cpp
fixed passing of strings to vararg templates in ANSI build
[wxWidgets.git] / src / xml / xml.cpp
index 25ffc91ea9beb868186249494822ebb79cb81eaa..e45136bcb61bf239d6d223fdfd5a7655b825e779 100644 (file)
@@ -39,6 +39,9 @@ WX_CHECK_BUILD_OPTIONS("wxXML")
 IMPLEMENT_CLASS(wxXmlDocument, wxObject)
 
 
+// a private utility used by wxXML
+static bool wxIsWhiteOnly(const wxChar *buf);
+
 
 //-----------------------------------------------------------------------------
 //  wxXmlNode
@@ -178,21 +181,40 @@ void wxXmlNode::AddChild(wxXmlNode *child)
     child->m_parent = this;
 }
 
-void wxXmlNode::InsertChild(wxXmlNode *child, wxXmlNode *before_node)
+bool wxXmlNode::InsertChild(wxXmlNode *child, wxXmlNode *before_node)
 {
-    wxASSERT_MSG(before_node->GetParent() == this, wxT("wxXmlNode::InsertChild - the node has incorrect parent"));
+    wxCHECK_MSG(before_node == NULL || before_node->GetParent() == this, false,
+                 wxT("wxXmlNode::InsertChild - the node has incorrect parent"));
+    wxCHECK_MSG(child, false, wxT("Cannot insert a NULL pointer!"));
 
     if (m_children == before_node)
        m_children = child;
+    else if (m_children == NULL)
+    {
+        if (before_node != NULL)
+            return false;       // we have no children so we don't need to search
+        m_children = child;
+    }
+    else if (before_node == NULL)
+    {
+        // prepend child
+        child->m_parent = this;
+        child->m_next = m_children;
+        m_children = child;
+        return true;
+    }
     else
     {
         wxXmlNode *ch = m_children;
-        while (ch->m_next != before_node) ch = ch->m_next;
+        while (ch && ch->m_next != before_node) ch = ch->m_next;
+        if (!ch)
+            return false;       // before_node not found
         ch->m_next = child;
     }
 
     child->m_parent = this;
     child->m_next = before_node;
+    return true;
 }
 
 bool wxXmlNode::RemoveChild(wxXmlNode *child)
@@ -290,6 +312,28 @@ wxString wxXmlNode::GetNodeContent() const
     return wxEmptyString;
 }
 
+int wxXmlNode::GetDepth(wxXmlNode *grandparent) const
+{
+    const wxXmlNode *n = this;
+    int ret = -1;
+
+    do
+    {
+        ret++;
+        n = n->GetParent();
+        if (n == grandparent)
+            return ret;
+
+    } while (n);
+
+    return wxNOT_FOUND;
+}
+
+bool wxXmlNode::IsWhitespaceOnly() const
+{
+    return wxIsWhiteOnly(m_content);
+}
+
 
 
 //-----------------------------------------------------------------------------
@@ -342,19 +386,27 @@ void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
     m_encoding = doc.m_encoding;
 #endif
     m_fileEncoding = doc.m_fileEncoding;
-    m_root = new wxXmlNode(*doc.m_root);
+
+    if (doc.m_root)
+        m_root = new wxXmlNode(*doc.m_root);
+    else
+        m_root = NULL;
 }
 
-bool wxXmlDocument::Load(const wxString& filename, const wxString& encoding)
+bool wxXmlDocument::Load(const wxString& filename, const wxString& encoding, int flags)
 {
     wxFileInputStream stream(filename);
-    return Load(stream, encoding);
+    if (!stream.Ok())
+        return false;
+    return Load(stream, encoding, flags);
 }
 
-bool wxXmlDocument::Save(const wxString& filename) const
+bool wxXmlDocument::Save(const wxString& filename, int indentstep) const
 {
     wxFileOutputStream stream(filename);
-    return Save(stream);
+    if (!stream.Ok())
+        return false;
+    return Save(stream, indentstep);
 }
 
 
@@ -363,37 +415,38 @@ bool wxXmlDocument::Save(const wxString& filename) const
 //  wxXmlDocument loading routines
 //-----------------------------------------------------------------------------
 
-/*
-    FIXME:
-       - process all elements, including CDATA
- */
-
 // converts Expat-produced string in UTF-8 into wxString using the specified
 // conv or keep in UTF-8 if conv is NULL
 static wxString CharToString(wxMBConv *conv,
-                                    const char *s, size_t len = wxSTRING_MAXLEN)
+                             const char *s, size_t len = wxString::npos)
 {
-#if wxUSE_UNICODE
-    wxUnusedVar(conv);
-
-    return wxString(s, wxConvUTF8, len);
-#else // !wxUSE_UNICODE
+#if !wxUSE_UNICODE
     if ( conv )
     {
         // there can be no embedded NULs in this string so we don't need the
         // output length, it will be NUL-terminated
         const wxWCharBuffer wbuf(
-            wxConvUTF8.cMB2WC(s, len == wxSTRING_MAXLEN ? wxNO_LEN : len, NULL));
+            wxConvUTF8.cMB2WC(s, len == wxString::npos ? wxNO_LEN : len, NULL));
 
         return wxString(wbuf, *conv);
     }
-    else // already in UTF-8, no conversion needed
-    {
-        return wxString(s, len != wxSTRING_MAXLEN ? len : strlen(s));
-    }
-#endif // wxUSE_UNICODE/!wxUSE_UNICODE
+    // else: the string is wanted in UTF-8
+#endif // !wxUSE_UNICODE
+
+    wxUnusedVar(conv);
+    return wxString::FromUTF8(s, len);
+}
+
+// returns true if the given string contains only whitespaces
+bool wxIsWhiteOnly(const wxChar *buf)
+{
+    for (const wxChar *c = buf; *c != wxT('\0'); c++)
+        if (*c != wxT(' ') && *c != wxT('\t') && *c != wxT('\n') && *c != wxT('\r'))
+            return false;
+    return true;
 }
 
+
 struct wxXmlParsingContext
 {
     wxMBConv  *conv;
@@ -402,6 +455,8 @@ struct wxXmlParsingContext
     wxXmlNode *lastAsText;
     wxString   encoding;
     wxString   version;
+    bool       bLastCdata;
+    bool       removeWhiteOnlyNodes;
 };
 
 extern "C" {
@@ -438,34 +493,53 @@ extern "C" {
 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);
+    wxString str = CharToString(ctx->conv, s, len);
 
     if (ctx->lastAsText)
     {
-        ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
-                                    CharToString(ctx->conv, buf));
+        if ( ctx->bLastCdata )
+        {
+            ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
+                                        CharToString(NULL, s, len));
+        }
+        else
+        {
+            ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() + str);
+        }
     }
     else
     {
-        bool whiteOnly = true;
-        for (char *c = buf; *c != '\0'; c++)
-            if (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\r')
-            {
-                whiteOnly = false;
-                break;
-            }
+        bool whiteOnly = false;
+        if (ctx->removeWhiteOnlyNodes)
+            whiteOnly = wxIsWhiteOnly(str);
+
         if (!whiteOnly)
         {
-            ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
-                                            CharToString(ctx->conv, buf));
+            ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"), str);
             ctx->node->AddChild(ctx->lastAsText);
         }
     }
+}
+}
 
-    delete[] buf;
+extern "C" {
+static void StartCdataHnd(void *userData)
+{
+    wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
+
+    ctx->bLastCdata = true;
+
+    ctx->lastAsText = new wxXmlNode(wxXML_CDATA_SECTION_NODE, wxT("cdata"),wxT(""));
+    ctx->node->AddChild(ctx->lastAsText);
+}
+}
+
+extern "C" {
+static void EndCdataHnd(void *userData)
+{
+    wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
+
+    ctx->bLastCdata = false;
 }
 }
 
@@ -540,7 +614,7 @@ static int UnknownEncodingHnd(void * WXUNUSED(encodingHandlerData),
 }
 }
 
-bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding)
+bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding, int flags)
 {
 #if wxUSE_UNICODE
     (void)encoding;
@@ -558,13 +632,16 @@ bool wxXmlDocument::Load(wxInputStream& stream, const wxString& encoding)
     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") )
+    if ( encoding.CmpNoCase(wxT("UTF-8")) != 0 )
         ctx.conv = new wxCSConv(encoding);
 #endif
+    ctx.removeWhiteOnlyNodes = (flags & wxXMLDOC_KEEP_WHITESPACE_NODES) == 0;
+    ctx.bLastCdata = false;
 
     XML_SetUserData(parser, (void*)&ctx);
     XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
     XML_SetCharacterDataHandler(parser, TextHnd);
+    XML_SetCdataSectionHandler(parser, StartCdataHnd, EndCdataHnd );
     XML_SetCommentHandler(parser, CommentHnd);
     XML_SetDefaultHandler(parser, DefaultHnd);
     XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
@@ -700,13 +777,19 @@ inline static void OutputIndentation(wxOutputStream& stream, int indent)
 }
 
 static void OutputNode(wxOutputStream& stream, wxXmlNode *node, int indent,
-                       wxMBConv *convMem, wxMBConv *convFile)
+                       wxMBConv *convMem, wxMBConv *convFile, int indentstep)
 {
     wxXmlNode *n, *prev;
     wxXmlProperty *prop;
 
     switch (node->GetType())
     {
+        case wxXML_CDATA_SECTION_NODE:
+            OutputString( stream, wxT("<![CDATA["));
+            OutputString( stream, node->GetContent() );
+            OutputString( stream, wxT("]]>") );
+            break;
+
         case wxXML_TEXT_NODE:
             OutputStringEnt(stream, node->GetContent(), convMem, convFile);
             break;
@@ -732,13 +815,13 @@ static void OutputNode(wxOutputStream& stream, wxXmlNode *node, int indent,
                 n = node->GetChildren();
                 while (n)
                 {
-                    if (n && n->GetType() != wxXML_TEXT_NODE)
-                        OutputIndentation(stream, indent + 1);
-                    OutputNode(stream, n, indent + 1, convMem, convFile);
+                    if (indentstep >= 0 && n && n->GetType() != wxXML_TEXT_NODE)
+                        OutputIndentation(stream, indent + indentstep);
+                    OutputNode(stream, n, indent + indentstep, convMem, convFile, indentstep);
                     prev = n;
                     n = n->GetNext();
                 }
-                if (prev && prev->GetType() != wxXML_TEXT_NODE)
+                if (indentstep >= 0 && prev && prev->GetType() != wxXML_TEXT_NODE)
                     OutputIndentation(stream, indent);
                 OutputString(stream, wxT("</"));
                 OutputString(stream, node->GetName());
@@ -759,37 +842,41 @@ static void OutputNode(wxOutputStream& stream, wxXmlNode *node, int indent,
     }
 }
 
-bool wxXmlDocument::Save(wxOutputStream& stream) const
+bool wxXmlDocument::Save(wxOutputStream& stream, int indentstep) const
 {
     if ( !IsOk() )
         return false;
 
     wxString s;
 
-    wxMBConv *convMem = NULL;
+    wxMBConv *convMem = NULL,
+             *convFile;
 
 #if wxUSE_UNICODE
-    wxMBConv *convFile = new wxCSConv(GetFileEncoding());
+    convFile = new wxCSConv(GetFileEncoding());
+    convMem = NULL;
 #else
-    wxMBConv *convFile = NULL;
-    if ( GetFileEncoding() != GetEncoding() )
+    if ( GetFileEncoding().CmpNoCase(GetEncoding()) != 0 )
     {
         convFile = new wxCSConv(GetFileEncoding());
         convMem = new wxCSConv(GetEncoding());
     }
+    else // file and in-memory encodings are the same, no conversion needed
+    {
+        convFile =
+        convMem = NULL;
+    }
 #endif
 
     s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"),
              GetVersion().c_str(), GetFileEncoding().c_str());
     OutputString(stream, s);
 
-    OutputNode(stream, GetRoot(), 0, convMem, convFile);
+    OutputNode(stream, GetRoot(), 0, convMem, convFile, indentstep);
     OutputString(stream, wxT("\n"));
 
-    if ( convFile )
-        delete convFile;
-    if ( convMem )
-        delete convMem;
+    delete convFile;
+    delete convMem;
 
     return true;
 }