]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/xml/xmlexpat.cpp
fixed ID handling in 'unknown' handler
[wxWidgets.git] / contrib / src / xml / xmlexpat.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: xmlexpat.cpp
3 // Purpose: wxXmlDocument - XML reader via Expat
4 // Author: Vaclav Slavik
5 // Created: 2001/04/30
6 // RCS-ID: $Id$
7 // Copyright: (c) 2001 Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 #ifdef __GNUG__
12 // nothing - already in xml.cpp
13 #endif
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #include "wx/wfstream.h"
23 #include "wx/intl.h"
24 #include "wx/log.h"
25 #include "wx/strconv.h"
26 #include "wx/xml/xmlio.h"
27
28 #include "xmlparse.h"
29
30 /*
31
32 FIXME:
33
34 - handle unknown encodings
35 - process all elements, including CDATA
36 - XML resources should automatically select desired encoding besed on
37 runtime environment (?) (would need BIN and BINZ formats modification,
38 too)
39
40 */
41
42
43 // converts Expat-produced string in UTF-8 into wxString.
44 inline static wxString CharToString(const char *s, size_t len = wxSTRING_MAXLEN)
45 {
46 #if wxUSE_UNICODE
47 return wxString(s, wxMBConvUTF8, len);
48 #else
49 return wxString(s, len);
50 #endif
51 }
52
53 bool wxXmlIOHandlerExpat::CanLoad(wxInputStream& stream)
54 {
55 char cheader[7];
56 cheader[6] = 0;
57 stream.Read(cheader, 6);
58 stream.SeekI(-6, wxFromCurrent);
59 return (strcmp(cheader, "<?xml ") == 0);
60 }
61
62
63 struct wxXmlParsingContext
64 {
65 wxXmlNode *root;
66 wxXmlNode *node;
67 wxXmlNode *lastAsText;
68 wxString encoding;
69 wxString version;
70 };
71
72 static void StartElementHnd(void *userData, const char *name, const char **atts)
73 {
74 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
75 wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, CharToString(name));
76 const char **a = atts;
77 while (*a)
78 {
79 node->AddProperty(CharToString(a[0]), CharToString(a[1]));
80 a += 2;
81 }
82 if (ctx->root == NULL)
83 ctx->root = node;
84 else
85 ctx->node->AddChild(node);
86 ctx->node = node;
87 ctx->lastAsText = NULL;
88 }
89
90 static void EndElementHnd(void *userData, const char *name)
91 {
92 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
93
94 ctx->node = ctx->node->GetParent();
95 ctx->lastAsText = NULL;
96 }
97
98 static void TextHnd(void *userData, const char *s, int len)
99 {
100 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
101 char *buf = new char[len + 1];
102
103 buf[len] = '\0';
104 memcpy(buf, s, (size_t)len);
105
106 if (ctx->lastAsText)
107 {
108 ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
109 CharToString(buf));
110 }
111 else
112 {
113 bool whiteOnly = TRUE;
114 for (char *c = buf; *c != '\0'; c++)
115 if (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\r')
116 {
117 whiteOnly = FALSE;
118 break;
119 }
120 if (!whiteOnly)
121 {
122 ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
123 CharToString(buf));
124 ctx->node->AddChild(ctx->lastAsText);
125 }
126 }
127
128 delete[] buf;
129 }
130
131 static void CommentHnd(void *userData, const char *data)
132 {
133 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
134
135 ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
136 wxT("comment"), CharToString(data)));
137 ctx->lastAsText = NULL;
138 }
139
140 static void DefaultHnd(void *userData, const char *s, int len)
141 {
142 // XML header:
143 if (len > 6 && memcmp(s, "<?xml ", 6) == 0)
144 {
145 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
146
147 wxString buf = CharToString(s, (size_t)len);
148 int pos;
149 pos = buf.Find(wxT("encoding="));
150 if (pos != wxNOT_FOUND)
151 ctx->encoding = buf.Mid(pos + 10).BeforeFirst(buf[(size_t)pos+9]);
152 pos = buf.Find(wxT("version="));
153 if (pos != wxNOT_FOUND)
154 ctx->version = buf.Mid(pos + 9).BeforeFirst(buf[(size_t)pos+8]);
155 }
156 }
157
158 bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
159 {
160 const size_t BUFSIZE = 1024;
161 char buf[BUFSIZE];
162 wxXmlParsingContext ctx;
163 bool done;
164 XML_Parser parser = XML_ParserCreate(NULL);
165
166 ctx.root = ctx.node = NULL;
167 XML_SetUserData(parser, (void*)&ctx);
168 XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
169 XML_SetCharacterDataHandler(parser, TextHnd);
170 XML_SetCommentHandler(parser, CommentHnd);
171 XML_SetDefaultHandler(parser, DefaultHnd);
172
173 do
174 {
175 size_t len = stream.Read(buf, BUFSIZE).LastRead();
176 done = (len < BUFSIZE);
177 if (!XML_Parse(parser, buf, len, done))
178 {
179 wxLogError(_("XML parsing error: '%s' at line %d"),
180 XML_ErrorString(XML_GetErrorCode(parser)),
181 XML_GetCurrentLineNumber(parser));
182 return FALSE;
183 }
184 } while (!done);
185
186 doc.SetVersion(ctx.version);
187 doc.SetEncoding(ctx.encoding);
188 doc.SetRoot(ctx.root);
189
190 XML_ParserFree(parser);
191 return TRUE;
192 }