Changeset 56215

Show
Ignore:
Timestamp:
10/10/08 09:13:53 (6 weeks ago)
Author:
VZ
Message:

just return false instead of crashing if the document contents can't be converted to the target encoding (#10064)

Location:
wxWidgets/trunk
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • wxWidgets/trunk/src/xml/xml.cpp

    r54721 r56215  
    3030#include "wx/zstream.h" 
    3131#include "wx/strconv.h" 
     32#include "wx/ptr_scpd.h" 
    3233 
    3334#include "expat.h" // from Expat 
     
    393394 
    394395wxXmlDocument::wxXmlDocument() 
    395     : m_version(wxT("1.0")), m_fileEncoding(wxT("utf-8")), m_root(NULL) 
     396    : m_version(wxS("1.0")), m_fileEncoding(wxS("utf-8")), m_root(NULL) 
    396397{ 
    397398#if !wxUSE_UNICODE 
    398     m_encoding = wxT("UTF-8"); 
     399    m_encoding = wxS("UTF-8"); 
    399400#endif 
    400401} 
     
    495496    { 
    496497        wxChar c = *i; 
    497         if ( c != wxT(' ') && c != wxT('\t') && c != wxT('\n') && c != wxT('\r')) 
     498        if ( c != wxS(' ') && c != wxS('\t') && c != wxS('\n') && c != wxS('\r')) 
    498499            return false; 
    499500    } 
     
    595596        { 
    596597            wxXmlNode *textnode = 
    597                 new wxXmlNode(wxXML_TEXT_NODE, wxT("text"), str, 
     598                new wxXmlNode(wxXML_TEXT_NODE, wxS("text"), str, 
    598599                              XML_GetCurrentLineNumber(ctx->parser)); 
    599600 
     
    610611 
    611612    wxXmlNode *textnode = 
    612         new wxXmlNode(wxXML_CDATA_SECTION_NODE, wxT("cdata"), wxT(""), 
     613        new wxXmlNode(wxXML_CDATA_SECTION_NODE, wxS("cdata"), wxS(""), 
    613614                      XML_GetCurrentLineNumber(ctx->parser)); 
    614615 
     
    626627        wxXmlNode *commentnode = 
    627628            new wxXmlNode(wxXML_COMMENT_NODE, 
    628                           wxT("comment"), CharToString(ctx->conv, data), 
     629                          wxS("comment"), CharToString(ctx->conv, data), 
    629630                          XML_GetCurrentLineNumber(ctx->parser)); 
    630631 
     
    649650        wxString buf = CharToString(ctx->conv, s, (size_t)len); 
    650651        int pos; 
    651         pos = buf.Find(wxT("encoding=")); 
     652        pos = buf.Find(wxS("encoding=")); 
    652653        if (pos != wxNOT_FOUND) 
    653654            ctx->encoding = buf.Mid(pos + 10).BeforeFirst(buf[(size_t)pos+9]); 
    654         pos = buf.Find(wxT("version=")); 
     655        pos = buf.Find(wxS("version=")); 
    655656        if (pos != wxNOT_FOUND) 
    656657            ctx->version = buf.Mid(pos + 9).BeforeFirst(buf[(size_t)pos+8]); 
     
    705706    XML_Parser parser = XML_ParserCreate(NULL); 
    706707 
    707     ctx.encoding = wxT("UTF-8"); // default in absence of encoding="" 
     708    ctx.encoding = wxS("UTF-8"); // default in absence of encoding="" 
    708709    ctx.conv = NULL; 
    709710#if !wxUSE_UNICODE 
    710     if ( encoding.CmpNoCase(wxT("UTF-8")) != 0 ) 
     711    if ( encoding.CmpNoCase(wxS("UTF-8")) != 0 ) 
    711712        ctx.conv = new wxCSConv(encoding); 
    712713#endif 
     
    768769//----------------------------------------------------------------------------- 
    769770 
     771// helpers for XML generation 
     772namespace 
     773{ 
     774 
    770775// write string to output: 
    771 inline static void OutputString(wxOutputStream& stream, const wxString& str, 
    772                                 wxMBConv *convMem = NULL, 
    773                                 wxMBConv *convFile = NULL) 
     776bool OutputString(wxOutputStream& stream, 
     777                  const wxString& str, 
     778                  wxMBConv *convMem, 
     779                  wxMBConv *convFile) 
    774780{ 
    775781    if (str.empty()) 
    776         return; 
     782        return true; 
    777783 
    778784#if wxUSE_UNICODE 
    779785    wxUnusedVar(convMem); 
    780786 
    781     const wxWX2MBbuf buf(str.mb_str(*(convFile ? convFile : &wxConvUTF8))); 
    782     stream.Write((const char*)buf, strlen((const char*)buf)); 
     787    const wxWX2MBbuf buf(str.mb_str(convFile ? *convFile : wxConvUTF8)); 
     788    if ( !buf ) 
     789        return false; 
     790 
     791    stream.Write(buf, strlen(buf)); 
    783792#else // !wxUSE_UNICODE 
    784793    if ( convFile && convMem ) 
    785794    { 
    786795        wxString str2(str.wc_str(*convMem), *convFile); 
    787         stream.Write(str2.mb_str(), str2.Len()); 
     796        stream.Write(str2.mb_str(), str2.length()); 
    788797    } 
    789798    else // no conversions to do 
    790799    { 
    791         stream.Write(str.mb_str(), str.Len()); 
     800        stream.Write(str.mb_str(), str.length()); 
    792801    } 
    793802#endif // wxUSE_UNICODE/!wxUSE_UNICODE 
     803 
     804    return stream.IsOk(); 
    794805} 
    795806 
     
    802813// Same as above, but create entities first. 
    803814// Translates '<' to "&lt;", '>' to "&gt;" and '&' to "&amp;" 
    804 static void OutputStringEnt(wxOutputStream& stream, const wxString& str, 
    805                             wxMBConv *convMem = NULL, 
    806                             wxMBConv *convFile = NULL, 
    807                             int flags = 0) 
    808 { 
    809     wxString buf; 
    810     size_t i, last, len; 
    811     wxChar c; 
    812  
    813     len = str.Len(); 
    814     last = 0; 
     815bool OutputStringEnt(wxOutputStream& stream, 
     816                     const wxString& str, 
     817                     wxMBConv *convMem, 
     818                     wxMBConv *convFile, 
     819                     int flags = 0) 
     820{ 
     821    const size_t len = str.length(); 
     822    size_t i, 
     823           last = 0; 
    815824    for (i = 0; i < len; i++) 
    816825    { 
    817         c = str.GetChar(i); 
    818         if (c == wxT('<') || c == wxT('>') || 
    819             (c == wxT('&') && str.Mid(i+1, 4) != wxT("amp;")) || 
    820             ((flags & XML_ESCAPE_QUOTES) && c == wxT('"'))) 
     826        wxChar c = str.GetChar(i); 
     827        if (c == wxS('<') || c == wxS('>') || 
     828            (c == wxS('&') && str.Mid(i+1, 4) != wxS("amp;")) || 
     829            ((flags & XML_ESCAPE_QUOTES) && c == wxS('"'))) 
    821830        { 
    822             OutputString(stream, str.Mid(last, i - last), convMem, convFile); 
    823             switch (c) 
     831            if ( !OutputString(stream, str.substr(last, i), convMem, convFile) ) 
     832                return false; 
     833 
     834            const char *escaped; 
     835            switch ( c ) 
    824836            { 
    825                 case wxT('<'): 
    826                     OutputString(stream, wxT("&lt;")); 
     837                case wxS('<'): 
     838                    escaped = "&lt;"; 
    827839                    break; 
    828                 case wxT('>'): 
    829                     OutputString(stream, wxT("&gt;")); 
     840                case wxS('>'): 
     841                    escaped = "&gt;"; 
    830842                    break; 
    831                 case wxT('&'): 
    832                     OutputString(stream, wxT("&amp;")); 
     843                case wxS('&'): 
     844                    escaped = "&amp;"; 
    833845                    break; 
    834                 case wxT('"'): 
    835                     OutputString(stream, wxT("&quot;")); 
     846                case wxS('"'): 
     847                    escaped = "&quot;"; 
    836848                    break; 
    837849                default: 
    838                     break; 
     850                    wxFAIL_MSG( "logic error in the code" ); 
     851                    return false; 
    839852            } 
     853 
     854            if ( !OutputString(stream, escaped, convMem, convFile) ) 
     855                return false; 
     856 
    840857            last = i + 1; 
    841858        } 
    842859    } 
    843     OutputString(stream, str.Mid(last, i - last), convMem, convFile); 
    844 } 
    845  
    846 inline static void OutputIndentation(wxOutputStream& stream, int indent) 
    847 { 
    848     wxString str = wxT("\n"); 
    849     for (int i = 0; i < indent; i++) 
    850         str << wxT(' ') << wxT(' '); 
    851     OutputString(stream, str); 
    852 } 
    853  
    854 static void OutputNode(wxOutputStream& stream, wxXmlNode *node, int indent, 
    855                        wxMBConv *convMem, wxMBConv *convFile, int indentstep) 
    856 { 
    857     wxXmlNode *n, *prev; 
    858     wxXmlAttribute *attr; 
    859  
     860 
     861    return OutputString(stream, str.substr(last, i), convMem, convFile); 
     862} 
     863 
     864bool OutputIndentation(wxOutputStream& stream, 
     865                       int indent, 
     866                       wxMBConv *convMem, 
     867                       wxMBConv *convFile) 
     868{ 
     869    wxString str(wxS("\n")); 
     870    str += wxString(2*indent, wxS(' ')); 
     871    return OutputString(stream, str, convMem, convFile); 
     872} 
     873 
     874bool OutputNode(wxOutputStream& stream, 
     875                wxXmlNode *node, 
     876                int indent, 
     877                wxMBConv *convMem, 
     878                wxMBConv *convFile, 
     879                int indentstep) 
     880{ 
     881    bool rc; 
    860882    switch (node->GetType()) 
    861883    { 
    862884        case wxXML_CDATA_SECTION_NODE: 
    863             OutputString( stream, wxT("<![CDATA[")); 
    864             OutputString( stream, node->GetContent() ); 
    865             OutputString( stream, wxT("]]>") ); 
     885            rc = OutputString(stream, wxS("<![CDATA["), convMem, convFile) && 
     886                 OutputString(stream, node->GetContent(), convMem, convFile) && 
     887                 OutputString(stream, wxS("]]>"), convMem, convFile); 
    866888            break; 
    867889 
    868890        case wxXML_TEXT_NODE: 
    869             OutputStringEnt(stream, node->GetContent(), convMem, convFile); 
     891            rc = OutputStringEnt(stream, node->GetContent(), convMem, convFile); 
    870892            break; 
    871893 
    872894        case wxXML_ELEMENT_NODE: 
    873             OutputString(stream, wxT("<")); 
    874             OutputString(stream, node->GetName()); 
    875  
    876             attr = node->GetAttributes(); 
    877             while (attr) 
     895            rc = OutputString(stream, wxS("<"), convMem, convFile) && 
     896                 OutputString(stream, node->GetName(), convMem, convFile); 
     897 
     898            if ( rc ) 
    878899            { 
    879                 OutputString(stream, wxT(" ") + attr->GetName() +  wxT("=\"")); 
    880                 OutputStringEnt(stream, attr->GetValue(), convMem, convFile, 
    881                                 XML_ESCAPE_QUOTES); 
    882                 OutputString(stream, wxT("\"")); 
    883                 attr = attr->GetNext(); 
     900                for ( wxXmlAttribute *attr = node->GetAttributes(); 
     901                      attr && rc; 
     902                      attr = attr->GetNext() ) 
     903                { 
     904                    rc = OutputString(stream, 
     905                                      wxS(" ") + attr->GetName() +  wxS("=\""), 
     906                                      convMem, convFile) && 
     907                         OutputStringEnt(stream, attr->GetValue(), 
     908                                         convMem, convFile, 
     909                                         XML_ESCAPE_QUOTES) && 
     910                         OutputString(stream, wxS("\""), convMem, convFile); 
     911                } 
    884912            } 
    885913 
    886             if (node->GetChildren()) 
     914            if ( node->GetChildren() ) 
    887915            { 
    888                 OutputString(stream, wxT(">")); 
    889                 prev = NULL; 
    890                 n = node->GetChildren(); 
    891                 while (n) 
     916                rc = OutputString(stream, wxS(">"), convMem, convFile); 
     917 
     918                wxXmlNode *prev = NULL; 
     919                for ( wxXmlNode *n = node->GetChildren(); 
     920                      n && rc; 
     921                      n = n->GetNext() ) 
    892922                { 
    893                     if (indentstep >= 0 && n && n->GetType() != wxXML_TEXT_NODE) 
    894                         OutputIndentation(stream, indent + indentstep); 
    895                     OutputNode(stream, n, indent + indentstep, convMem, convFile, indentstep); 
     923                    if ( indentstep >= 0 && n->GetType() != wxXML_TEXT_NODE ) 
     924                    { 
     925                        rc = OutputIndentation(stream, indent + indentstep, 
     926                                               convMem, convFile); 
     927                    } 
     928 
     929                    if ( rc ) 
     930                        rc = OutputNode(stream, n, indent + indentstep, 
     931                                        convMem, convFile, indentstep); 
     932 
    896933                    prev = n; 
    897                     n = n->GetNext(); 
    898934                } 
    899                 if (indentstep >= 0 && prev && prev->GetType() != wxXML_TEXT_NODE) 
    900                     OutputIndentation(stream, indent); 
    901                 OutputString(stream, wxT("</")); 
    902                 OutputString(stream, node->GetName()); 
    903                 OutputString(stream, wxT(">")); 
     935 
     936                if ( rc && indentstep >= 0 && 
     937                        prev && prev->GetType() != wxXML_TEXT_NODE ) 
     938                { 
     939                    rc = OutputIndentation(stream, indent, convMem, convFile); 
     940                } 
     941 
     942                if ( rc ) 
     943                { 
     944                    rc = OutputString(stream, wxS("</"), convMem, convFile) && 
     945                         OutputString(stream, node->GetName(), 
     946                                      convMem, convFile) && 
     947                         OutputString(stream, wxS(">"), convMem, convFile); 
     948                } 
    904949            } 
    905             else 
    906                 OutputString(stream, wxT("/>")); 
     950            else // no children, output "<foo/>" 
     951            { 
     952                rc = OutputString(stream, wxS("/>"), convMem, convFile); 
     953            } 
    907954            break; 
    908955 
    909956        case wxXML_COMMENT_NODE: 
    910             OutputString(stream, wxT("<!--")); 
    911             OutputString(stream, node->GetContent(), convMem, convFile); 
    912             OutputString(stream, wxT("-->")); 
     957            rc = OutputString(stream, wxS("<!--"), convMem, convFile) && 
     958                 OutputString(stream, node->GetContent(), convMem, convFile) && 
     959                 OutputString(stream, wxS("-->"), convMem, convFile); 
    913960            break; 
    914961 
    915962        default: 
    916             wxFAIL_MSG(wxT("unsupported node type")); 
    917     } 
    918 } 
     963            wxFAIL_MSG("unsupported node type"); 
     964            rc = false; 
     965    } 
     966 
     967    return rc; 
     968} 
     969 
     970} // anonymous namespace 
    919971 
    920972bool wxXmlDocument::Save(wxOutputStream& stream, int indentstep) const 
     
    923975        return false; 
    924976 
    925     wxString s; 
    926  
    927     wxMBConv *convMem = NULL, 
    928              *convFile; 
     977    wxScopedPtr<wxMBConv> convMem, convFile; 
    929978 
    930979#if wxUSE_UNICODE 
    931     convFile = new wxCSConv(GetFileEncoding()); 
    932     convMem = NULL; 
     980    convFile.reset(new wxCSConv(GetFileEncoding())); 
    933981#else 
    934982    if ( GetFileEncoding().CmpNoCase(GetEncoding()) != 0 ) 
    935983    { 
    936         convFile = new wxCSConv(GetFileEncoding()); 
    937         convMem = new wxCSConv(GetEncoding()); 
    938     } 
    939     else // file and in-memory encodings are the same, no conversion needed 
    940     { 
    941         convFile = 
    942         convMem = NULL; 
    943     } 
     984        convFile.reset(new wxCSConv(GetFileEncoding())); 
     985        convMem.reset(new wxCSConv(GetEncoding())); 
     986    } 
     987    //else: file and in-memory encodings are the same, no conversion needed 
    944988#endif 
    945989 
    946     s.Printf(wxT("<?xml version=\"%s\" encoding=\"%s\"?>\n"), 
    947              GetVersion().c_str(), GetFileEncoding().c_str()); 
    948     OutputString(stream, s); 
    949  
    950     OutputNode(stream, GetRoot(), 0, convMem, convFile, indentstep); 
    951     OutputString(stream, wxT("\n")); 
    952  
    953     delete convFile; 
    954     delete convMem; 
    955  
    956     return true; 
     990    return OutputString(stream, 
     991                        wxString::Format 
     992                        ( 
     993                         wxS("<?xml version=\"%s\" encoding=\"%s\"?>\n"), 
     994                         GetVersion(), GetFileEncoding() 
     995                        ), 
     996                        convMem.get(), 
     997                        convFile.get()) && 
     998           OutputNode(stream, GetRoot(), 0, 
     999                      convMem.get(), convFile.get(), indentstep) && 
     1000           OutputString(stream, wxS("\n"), convMem.get(), convFile.get()); 
    9571001} 
    9581002 
  • wxWidgets/trunk/tests/xml/xmltest.cpp

    r56212 r56215  
    164164 
    165165    CPPUNIT_ASSERT_EQUAL( xmlText, sos.GetString() ); 
     166 
     167 
     168    const char *utf8xmlText = 
     169"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 
     170"<word>\n" 
     171"  <lang name=\"fr\">\xc3\xa9t\xc3\xa9</lang>\n" 
     172"  <lang name=\"ru\">\xd0\xbb\xd0\xb5\xd1\x82\xd0\xbe</lang>\n" 
     173"</word>\n" 
     174    ; 
     175 
     176    wxStringInputStream sis8(wxString::FromUTF8(utf8xmlText)); 
     177    CPPUNIT_ASSERT( doc.Load(sis8) ); 
     178 
     179    // this contents can't be represented in Latin-1 as it contains Cyrillic 
     180    // letters 
     181    doc.SetFileEncoding("ISO-8859-1"); 
     182    CPPUNIT_ASSERT( !doc.Save(sos) ); 
     183 
     184    // but it should work in UTF-8 
     185    wxStringOutputStream sos8; 
     186    doc.SetFileEncoding("UTF-8"); 
     187    CPPUNIT_ASSERT( doc.Save(sos8) ); 
     188    CPPUNIT_ASSERT_EQUAL( utf8xmlText, sos8.GetString().ToUTF8() ); 
    166189} 
    167190