]> git.saurik.com Git - wxWidgets.git/blame - src/xrc/xmlexpat.cpp
new files added
[wxWidgets.git] / src / xrc / xmlexpat.cpp
CommitLineData
78d14f80
VS
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/xrc/xmlio.h"
27
28#include "xmlparse.h"
29
30/*
31
32 FIXME:
33
34 - handle unknown encodings
35 - process all elements, including CDATA
b5d6954b 36 - XRC resources should automatically select desired encoding based on
78d14f80
VS
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.
44inline static wxString CharToString(const char *s, size_t len = wxSTRING_MAXLEN)
45{
46#if wxUSE_UNICODE
00393283 47 return wxString(s, wxConvUTF8, len);
78d14f80
VS
48#else
49 return wxString(s, len);
50#endif
51}
52
53bool 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
63struct wxXmlParsingContext
64{
65 wxXmlNode *root;
66 wxXmlNode *node;
67 wxXmlNode *lastAsText;
68 wxString encoding;
69 wxString version;
70};
71
72static 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
90static void EndElementHnd(void *userData, const char* WXUNUSED(name))
91{
92 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
93
94 ctx->node = ctx->node->GetParent();
95 ctx->lastAsText = NULL;
96}
97
98static 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
131static void CommentHnd(void *userData, const char *data)
132{
133 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
134
135 if (ctx->node)
136 {
137 // VS: ctx->node == NULL happens if there is a comment before
138 // the root element (e.g. wxDesigner's output). We ignore such
139 // comments, no big deal...
140 ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
141 wxT("comment"), CharToString(data)));
142 }
143 ctx->lastAsText = NULL;
144}
145
146static void DefaultHnd(void *userData, const char *s, int len)
147{
148 // XML header:
149 if (len > 6 && memcmp(s, "<?xml ", 6) == 0)
150 {
151 wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
152
153 wxString buf = CharToString(s, (size_t)len);
154 int pos;
155 pos = buf.Find(wxT("encoding="));
156 if (pos != wxNOT_FOUND)
157 ctx->encoding = buf.Mid(pos + 10).BeforeFirst(buf[(size_t)pos+9]);
158 pos = buf.Find(wxT("version="));
159 if (pos != wxNOT_FOUND)
160 ctx->version = buf.Mid(pos + 9).BeforeFirst(buf[(size_t)pos+8]);
161 }
162}
163
164bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
165{
166 const size_t BUFSIZE = 1024;
167 char buf[BUFSIZE];
168 wxXmlParsingContext ctx;
169 bool done;
170 XML_Parser parser = XML_ParserCreate(NULL);
171
172 ctx.root = ctx.node = NULL;
173 XML_SetUserData(parser, (void*)&ctx);
174 XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
175 XML_SetCharacterDataHandler(parser, TextHnd);
176 XML_SetCommentHandler(parser, CommentHnd);
177 XML_SetDefaultHandler(parser, DefaultHnd);
178
179 do
180 {
181 size_t len = stream.Read(buf, BUFSIZE).LastRead();
182 done = (len < BUFSIZE);
183 if (!XML_Parse(parser, buf, len, done))
184 {
185 wxLogError(_("XML parsing error: '%s' at line %d"),
186 XML_ErrorString(XML_GetErrorCode(parser)),
187 XML_GetCurrentLineNumber(parser));
188 return FALSE;
189 }
190 } while (!done);
191
192 doc.SetVersion(ctx.version);
193 doc.SetEncoding(ctx.encoding);
194 doc.SetRoot(ctx.root);
195
196 XML_ParserFree(parser);
197 return TRUE;
198}