]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/xml/xmlpars.cpp
applied patch to prevent crashing when libxml DLL doesn't contain some symbols
[wxWidgets.git] / contrib / src / xml / xmlpars.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: xmlpars.cpp
3 // Purpose: wxXmlDocument - XML parser
4 // Author: Vaclav Slavik
5 // Created: 2000/03/05
6 // RCS-ID: $Id$
7 // Copyright: (c) 2000 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/dynlib.h"
26 #include "wx/xml/xmlio.h"
27
28 #include <libxml/parser.h>
29 #include <libxml/SAX.h>
30
31
32 // wxWindows SAX handlers for bugs reporting:
33
34 static void wxXmlParserError(void *ctx, const char *msg, ...)
35 {
36 wxString text;
37 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
38 if (ctxt->input)
39 text.Printf( _("XML parser error at line %d: "), ctxt->input->line );
40 va_list args;
41 wxString tmp;
42 va_start(args, msg);
43 tmp.PrintfV( msg, args );
44 va_end(args);
45 text += tmp;
46 wxLogError( text.c_str() );
47 }
48
49 static void wxXmlParserWarning(void *ctx, const char *msg, ...)
50 {
51 wxString text;
52 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
53 if (ctxt->input)
54 text.Printf( _("XML parser warning at line %d: "), ctxt->input->line );
55 va_list args;
56 wxString tmp;
57 va_start(args, msg);
58 tmp.PrintfV( msg, args );
59 va_end(args);
60 text += tmp;
61 wxLogWarning( text.c_str() );
62 }
63
64 static xmlSAXHandler gs_wxXmlSAXHandler;
65
66
67
68 // dynamically loaded functions from libxml:
69 typedef xmlParserCtxtPtr (*type_xmlCreatePushParserCtxt)
70 (xmlSAXHandlerPtr sax, void *, const char *, int, const char *);
71 typedef xmlNodePtr (*type_xmlNewText)(const xmlChar *);
72 typedef xmlAttrPtr (*type_xmlSetProp)(xmlNodePtr, const xmlChar *, const xmlChar *);
73 typedef int (*type_xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int);
74 typedef void (*type_xmlFreeParserCtxt)(xmlParserCtxtPtr);
75 typedef xmlDocPtr (*type_xmlNewDoc)(const xmlChar *);
76 typedef void (*type_xmlFreeDoc)(xmlDocPtr);
77 typedef xmlNodePtr (*type_xmlNewDocNode)(xmlDocPtr, xmlNsPtr, const xmlChar *, const xmlChar *);
78 typedef void (*type_xmlDocDumpMemory)(xmlDocPtr, xmlChar**, int *);
79 typedef xmlNodePtr (*type_xmlAddChild)(xmlNodePtr, xmlNodePtr);
80 typedef xmlNodePtr (*type_xmlNewChild)(xmlNodePtr, xmlNsPtr, const xmlChar *, const xmlChar *);
81 typedef xmlChar * (*type_xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int);
82 typedef xmlNodePtr (*type_xmlDocGetRootElement)(xmlDocPtr);
83 typedef xmlNodePtr (*type_xmlDocSetRootElement)(xmlDocPtr doc, xmlNodePtr root);
84 typedef void (*(*type_xmlFree))(void *);
85 typedef int (*type_xmlKeepBlanksDefault)(int);
86 typedef void (*type_xmlInitParser)(void);
87 typedef void (*type_xmlCleanupParser)(void);
88 typedef xmlSAXHandler *type_xmlDefaultSAXHandler;
89
90 static struct
91 {
92 wxDllType Handle;
93
94 type_xmlCreatePushParserCtxt xmlCreatePushParserCtxt;
95 type_xmlNewText xmlNewText;
96 type_xmlSetProp xmlSetProp;
97 type_xmlParseChunk xmlParseChunk;
98 type_xmlFreeParserCtxt xmlFreeParserCtxt;
99 type_xmlNewDoc xmlNewDoc;
100 type_xmlFreeDoc xmlFreeDoc;
101 type_xmlNewDocNode xmlNewDocNode;
102 type_xmlDocDumpMemory xmlDocDumpMemory;
103 type_xmlAddChild xmlAddChild;
104 type_xmlNewChild xmlNewChild;
105 type_xmlNodeListGetString xmlNodeListGetString;
106 type_xmlDocGetRootElement xmlDocGetRootElement;
107 type_xmlDocSetRootElement xmlDocSetRootElement;
108 type_xmlFree xmlFree;
109 type_xmlKeepBlanksDefault xmlKeepBlanksDefault;
110 type_xmlInitParser xmlInitParser;
111 type_xmlCleanupParser xmlCleanupParser;
112 type_xmlDefaultSAXHandler xmlDefaultSAXHandler;
113 } gs_libxmlDLL;
114
115 static bool gs_libxmlLoaded = FALSE;
116 static bool gs_libxmlLoadFailed = FALSE;
117
118
119
120 static void ReleaseLibxml()
121 {
122 if (gs_libxmlLoaded)
123 {
124 // Check for CleanupParser ..may have failed before initialised
125 // during LOAD_SYMBOL in LoadLibxml()
126 if (gs_libxmlDLL.xmlCleanupParser)
127 gs_libxmlDLL.xmlCleanupParser();
128 wxDllLoader::UnloadLibrary(gs_libxmlDLL.Handle);
129 }
130 gs_libxmlLoaded = FALSE;
131 gs_libxmlLoadFailed = FALSE;
132 }
133
134
135 static bool LoadLibxml()
136 {
137 if (gs_libxmlLoaded) return TRUE;
138 if (gs_libxmlLoadFailed) return FALSE;
139 gs_libxmlLoadFailed = TRUE;
140
141 {
142 wxLogNull lg;
143 #ifdef __UNIX__
144 gs_libxmlDLL.Handle =
145 wxDllLoader::LoadLibrary(_T("wxlibxml.so.2"), &gs_libxmlLoaded);
146 if (!gs_libxmlLoaded) gs_libxmlDLL.Handle =
147 wxDllLoader::LoadLibrary(_T("libxml.so.2"), &gs_libxmlLoaded);
148 #endif
149 #ifdef __WXMSW__
150 gs_libxmlDLL.Handle =
151 wxDllLoader::LoadLibrary(_T("wxlibxml2.dll"), &gs_libxmlLoaded);
152 if (!gs_libxmlLoaded) gs_libxmlDLL.Handle =
153 wxDllLoader::LoadLibrary(_T("libxml2.dll"), &gs_libxmlLoaded);
154 #endif
155 }
156
157 if (!gs_libxmlLoaded)
158 {
159 wxLogError(_("Failed to load libxml shared library."));
160 return FALSE;
161 }
162
163 #define LOAD_SYMBOL(sym) \
164 gs_libxmlDLL.sym = \
165 (type_##sym)wxDllLoader::GetSymbol(gs_libxmlDLL.Handle, _T(#sym)); \
166 if (!gs_libxmlDLL.sym) \
167 { \
168 ReleaseLibxml(); \
169 wxLogError(_("Failed to load libxml shared library.")); \
170 return FALSE; \
171 }
172
173 LOAD_SYMBOL(xmlCreatePushParserCtxt)
174 LOAD_SYMBOL(xmlNewText)
175 LOAD_SYMBOL(xmlSetProp)
176 LOAD_SYMBOL(xmlParseChunk)
177 LOAD_SYMBOL(xmlFreeParserCtxt)
178 LOAD_SYMBOL(xmlNewDoc)
179 LOAD_SYMBOL(xmlFreeDoc)
180 LOAD_SYMBOL(xmlNewDocNode)
181 LOAD_SYMBOL(xmlDocDumpMemory)
182 LOAD_SYMBOL(xmlAddChild)
183 LOAD_SYMBOL(xmlNewChild)
184 LOAD_SYMBOL(xmlNodeListGetString)
185 LOAD_SYMBOL(xmlDocGetRootElement)
186 LOAD_SYMBOL(xmlDocSetRootElement)
187 LOAD_SYMBOL(xmlFree)
188 LOAD_SYMBOL(xmlKeepBlanksDefault)
189 LOAD_SYMBOL(xmlInitParser)
190 LOAD_SYMBOL(xmlCleanupParser)
191 LOAD_SYMBOL(xmlDefaultSAXHandler)
192
193 #undef LOAD_SYMBOL
194
195 gs_libxmlLoadFailed = FALSE;
196
197 gs_libxmlDLL.xmlInitParser();
198 memcpy(&gs_wxXmlSAXHandler, gs_libxmlDLL.xmlDefaultSAXHandler,
199 sizeof(xmlSAXHandler));
200 gs_wxXmlSAXHandler.error = wxXmlParserError;
201 gs_wxXmlSAXHandler.fatalError = wxXmlParserError;
202 gs_wxXmlSAXHandler.warning = wxXmlParserWarning;
203
204 return TRUE;
205 }
206
207
208
209
210 bool wxXmlIOHandlerLibxml::CanLoad(wxInputStream& stream)
211 {
212 if (!LoadLibxml()) return FALSE;
213 char cheader[7];
214 cheader[6] = 0;
215 stream.Read(cheader, 6);
216 stream.SeekI(-6, wxFromCurrent);
217 return strcmp(cheader, "<?xml ") == 0;
218 }
219
220
221
222 bool wxXmlIOHandlerLibxml::CanSave()
223 {
224 return LoadLibxml();
225 }
226
227
228
229 static wxXmlProperty *CreateWXProperty(xmlDocPtr doc, xmlAttrPtr attr)
230 {
231 if (attr == NULL) return NULL;
232
233 unsigned char *val =
234 gs_libxmlDLL.xmlNodeListGetString(doc, attr->children, 1);
235 wxXmlProperty *prop =
236 new wxXmlProperty(attr->name, val, CreateWXProperty(doc, attr->next));
237 (*gs_libxmlDLL.xmlFree)(val);
238 return prop;
239 }
240
241
242
243 static wxXmlNode *CreateWXNode(xmlDocPtr doc, wxXmlNode *parent, xmlNodePtr node)
244 {
245 if (node == NULL) return NULL;
246
247 wxXmlNode *nd = new wxXmlNode(parent, (wxXmlNodeType)node->type,
248 node->name, node->content,
249 CreateWXProperty(doc, node->properties),
250 CreateWXNode(doc, parent, node->next));
251 CreateWXNode(doc, nd, node->children);
252 return nd;
253 }
254
255
256
257 bool wxXmlIOHandlerLibxml::Load(wxInputStream& stream, wxXmlDocument& doc)
258 {
259 if (!LoadLibxml()) return FALSE;
260
261 xmlDocPtr dc;
262 xmlParserCtxtPtr ctxt;
263
264 char buffer[1024];
265 int res;
266
267 res = stream.Read(buffer, 4).LastRead();
268 if (res > 0)
269 {
270 bool okay = TRUE;
271 gs_libxmlDLL.xmlKeepBlanksDefault(0);
272 ctxt = gs_libxmlDLL.xmlCreatePushParserCtxt(&gs_wxXmlSAXHandler,
273 NULL, buffer, res, ""/*docname*/);
274 while ((res = stream.Read(buffer, 1024).LastRead()) > 0)
275 if (gs_libxmlDLL.xmlParseChunk(ctxt, buffer, res, 0) != 0)
276 okay = FALSE;
277 if (gs_libxmlDLL.xmlParseChunk(ctxt, buffer, 0, 1) != 0) okay = FALSE;
278 dc = ctxt->myDoc;
279 gs_libxmlDLL.xmlFreeParserCtxt(ctxt);
280
281 doc.SetVersion(dc->version);
282 doc.SetEncoding(dc->encoding);
283 doc.SetRoot(CreateWXNode(dc, NULL, gs_libxmlDLL.xmlDocGetRootElement(dc)));
284
285 gs_libxmlDLL.xmlFreeDoc(dc);
286
287 return okay;
288 }
289 else return FALSE;
290 }
291
292
293
294 static void CreateLibxmlNode(xmlNodePtr node, wxXmlNode *wxnode)
295 {
296 node->type = (xmlElementType)wxnode->GetType();
297
298 wxXmlProperty *prop = wxnode->GetProperties();
299 while (prop)
300 {
301 gs_libxmlDLL.xmlSetProp(node, (xmlChar*)prop->GetName().mb_str(),
302 (xmlChar*)prop->GetValue().mb_str());
303 prop = prop->GetNext();
304 }
305
306 wxXmlNode *child = wxnode->GetChildren();
307 xmlNodePtr n;
308 xmlChar *content, *name;
309
310 while (child)
311 {
312 name = (xmlChar*)child->GetName().mb_str();
313 if (!child->GetContent()) content = NULL;
314 else content = (xmlChar*)child->GetContent().mb_str();
315 if (child->GetType() == wxXML_TEXT_NODE)
316 gs_libxmlDLL.xmlAddChild(node, n = gs_libxmlDLL.xmlNewText(content));
317 else
318 n = gs_libxmlDLL.xmlNewChild(node, NULL, name, content);
319 CreateLibxmlNode(n, child);
320 child = child->GetNext();
321 }
322 }
323
324
325
326 bool wxXmlIOHandlerLibxml::Save(wxOutputStream& stream, const wxXmlDocument& doc)
327 {
328 if (!LoadLibxml()) return FALSE;
329
330 xmlDocPtr dc;
331
332 wxASSERT_MSG(doc.GetRoot() != NULL, _("Trying to save empty document!"));
333
334 gs_libxmlDLL.xmlKeepBlanksDefault(0);
335 dc = gs_libxmlDLL.xmlNewDoc((xmlChar*)doc.GetVersion().mb_str());
336
337 gs_libxmlDLL.xmlDocSetRootElement(dc,
338 gs_libxmlDLL.xmlNewDocNode(dc, NULL,
339 (xmlChar*)doc.GetRoot()->GetName().mb_str(), NULL));
340 CreateLibxmlNode(gs_libxmlDLL.xmlDocGetRootElement(dc), doc.GetRoot());
341
342 xmlChar *buffer;
343 int size;
344
345 gs_libxmlDLL.xmlDocDumpMemory(dc, &buffer, &size);
346 gs_libxmlDLL.xmlFreeDoc(dc);
347 stream.Write(buffer, size);
348 (*gs_libxmlDLL.xmlFree)(buffer);
349 return stream.LastWrite() == (unsigned)size;
350 }
351
352
353
354
355 #include "wx/module.h"
356
357 class wxXmlLibxmlModule: public wxModule
358 {
359 DECLARE_DYNAMIC_CLASS(wxXmlLibxmlModule)
360 public:
361 wxXmlLibxmlModule() {}
362 bool OnInit() { return TRUE; }
363 void OnExit() { ReleaseLibxml(); }
364 };
365
366 IMPLEMENT_DYNAMIC_CLASS(wxXmlLibxmlModule, wxModule)