]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/xml/xmlpars.cpp
fixed bug in zlib compressed binary xml resources saving (crashed due to a typo)
[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
30 // dynamically loaded functions from libxml:
31 typedef xmlParserCtxtPtr (*type_xmlCreatePushParserCtxt)
32 (xmlSAXHandlerPtr sax, void *, const char *, int, const char *);
33 typedef xmlNodePtr (*type_xmlNewText)(const xmlChar *);
34 typedef xmlAttrPtr (*type_xmlSetProp)(xmlNodePtr, const xmlChar *, const xmlChar *);
35 typedef int (*type_xmlParseChunk)(xmlParserCtxtPtr, const char *, int, int);
36 typedef void (*type_xmlFreeParserCtxt)(xmlParserCtxtPtr);
37 typedef xmlDocPtr (*type_xmlNewDoc)(const xmlChar *);
38 typedef void (*type_xmlFreeDoc)(xmlDocPtr);
39 typedef xmlNodePtr (*type_xmlNewDocNode)(xmlDocPtr, xmlNsPtr, const xmlChar *, const xmlChar *);
40 typedef void (*type_xmlDocDumpMemory)(xmlDocPtr, xmlChar**, int *);
41 typedef xmlNodePtr (*type_xmlAddChild)(xmlNodePtr, xmlNodePtr);
42 typedef xmlNodePtr (*type_xmlNewChild)(xmlNodePtr, xmlNsPtr, const xmlChar *, const xmlChar *);
43 typedef xmlChar * (*type_xmlNodeListGetString)(xmlDocPtr, xmlNodePtr, int);
44 typedef xmlNodePtr (*type_xmlDocGetRootElement)(xmlDocPtr);
45 typedef xmlNodePtr (*type_xmlDocSetRootElement)(xmlDocPtr doc, xmlNodePtr root);
46 typedef void (*(*type_xmlFree))(void *);
47 typedef int (*type_xmlKeepBlanksDefault)(int);
48
49 static struct
50 {
51 wxDllType Handle;
52
53 type_xmlCreatePushParserCtxt xmlCreatePushParserCtxt;
54 type_xmlNewText xmlNewText;
55 type_xmlSetProp xmlSetProp;
56 type_xmlParseChunk xmlParseChunk;
57 type_xmlFreeParserCtxt xmlFreeParserCtxt;
58 type_xmlNewDoc xmlNewDoc;
59 type_xmlFreeDoc xmlFreeDoc;
60 type_xmlNewDocNode xmlNewDocNode;
61 type_xmlDocDumpMemory xmlDocDumpMemory;
62 type_xmlAddChild xmlAddChild;
63 type_xmlNewChild xmlNewChild;
64 type_xmlNodeListGetString xmlNodeListGetString;
65 type_xmlDocGetRootElement xmlDocGetRootElement;
66 type_xmlDocSetRootElement xmlDocSetRootElement;
67 type_xmlFree xmlFree;
68 type_xmlKeepBlanksDefault xmlKeepBlanksDefault;
69 } gs_libxmlDLL;
70
71 static bool gs_libxmlLoaded = FALSE;
72 static bool gs_libxmlLoadFailed = FALSE;
73
74
75
76 static void ReleaseLibxml()
77 {
78 if (gs_libxmlLoaded)
79 {
80 wxDllLoader::UnloadLibrary(gs_libxmlDLL.Handle);
81 }
82 gs_libxmlLoaded = FALSE;
83 gs_libxmlLoadFailed = FALSE;
84 }
85
86
87 static bool LoadLibxml()
88 {
89 if (gs_libxmlLoaded) return TRUE;
90 if (gs_libxmlLoadFailed) return FALSE;
91 gs_libxmlLoadFailed = TRUE;
92
93 {
94 wxLogNull lg;
95 #ifdef __UNIX__
96 gs_libxmlDLL.Handle =
97 wxDllLoader::LoadLibrary(_T("wxlibxml.so.2"), &gs_libxmlLoaded);
98 if (!gs_libxmlLoaded) gs_libxmlDLL.Handle =
99 wxDllLoader::LoadLibrary(_T("libxml.so.2"), &gs_libxmlLoaded);
100 #endif
101 #ifdef __WXMSW__
102 gs_libxmlDLL.Handle =
103 wxDllLoader::LoadLibrary(_T("wxlibxml2.dll"), &gs_libxmlLoaded);
104 if (!gs_libxmlLoaded) gs_libxmlDLL.Handle =
105 wxDllLoader::LoadLibrary(_T("libxml2.dll"), &gs_libxmlLoaded);
106 #endif
107 }
108
109 if (!gs_libxmlLoaded)
110 {
111 wxLogError(_("Failed to load libxml shared library."));
112 return FALSE;
113 }
114
115 #define LOAD_SYMBOL(sym) \
116 gs_libxmlDLL.sym = \
117 (type_##sym)wxDllLoader::GetSymbol(gs_libxmlDLL.Handle, _T(#sym)); \
118 if (!gs_libxmlDLL.sym) \
119 { \
120 ReleaseLibxml(); \
121 wxLogError(_("Failed to load libxml shared library.")); \
122 return FALSE; \
123 }
124
125 LOAD_SYMBOL(xmlCreatePushParserCtxt)
126 LOAD_SYMBOL(xmlNewText)
127 LOAD_SYMBOL(xmlSetProp)
128 LOAD_SYMBOL(xmlParseChunk)
129 LOAD_SYMBOL(xmlFreeParserCtxt)
130 LOAD_SYMBOL(xmlNewDoc)
131 LOAD_SYMBOL(xmlFreeDoc)
132 LOAD_SYMBOL(xmlNewDocNode)
133 LOAD_SYMBOL(xmlDocDumpMemory)
134 LOAD_SYMBOL(xmlAddChild)
135 LOAD_SYMBOL(xmlNewChild)
136 LOAD_SYMBOL(xmlNodeListGetString)
137 LOAD_SYMBOL(xmlDocGetRootElement)
138 LOAD_SYMBOL(xmlDocSetRootElement)
139 LOAD_SYMBOL(xmlFree)
140 LOAD_SYMBOL(xmlKeepBlanksDefault)
141
142 #undef LOAD_SYMBOL
143
144 gs_libxmlLoadFailed = FALSE;
145
146 return TRUE;
147 }
148
149
150
151
152 bool wxXmlIOHandlerLibxml::CanLoad(wxInputStream& stream)
153 {
154 if (!LoadLibxml()) return FALSE;
155 char cheader[7];
156 cheader[6] = 0;
157 stream.Read(cheader, 6);
158 stream.SeekI(-6, wxFromCurrent);
159 return strcmp(cheader, "<?xml ") == 0;
160 }
161
162
163
164 bool wxXmlIOHandlerLibxml::CanSave()
165 {
166 return LoadLibxml();
167 }
168
169
170
171 static wxXmlProperty *CreateWXProperty(xmlDocPtr doc, xmlAttrPtr attr)
172 {
173 if (attr == NULL) return NULL;
174
175 unsigned char *val =
176 gs_libxmlDLL.xmlNodeListGetString(doc, attr->children, 1);
177 wxXmlProperty *prop =
178 new wxXmlProperty(attr->name, val, CreateWXProperty(doc, attr->next));
179 (*gs_libxmlDLL.xmlFree)(val);
180 return prop;
181 }
182
183
184
185 static wxXmlNode *CreateWXNode(xmlDocPtr doc, wxXmlNode *parent, xmlNodePtr node)
186 {
187 if (node == NULL) return NULL;
188
189 wxXmlNode *nd = new wxXmlNode(parent, (wxXmlNodeType)node->type,
190 node->name, node->content,
191 CreateWXProperty(doc, node->properties),
192 CreateWXNode(doc, parent, node->next));
193 CreateWXNode(doc, nd, node->children);
194 return nd;
195 }
196
197
198
199 bool wxXmlIOHandlerLibxml::Load(wxInputStream& stream, wxXmlDocument& doc)
200 {
201 if (!LoadLibxml()) return FALSE;
202
203 xmlDocPtr dc;
204 xmlParserCtxtPtr ctxt;
205
206 char buffer[1024];
207 int res;
208
209 res = stream.Read(buffer, 4).LastRead();
210 if (res > 0)
211 {
212 bool okay = TRUE;
213 gs_libxmlDLL.xmlKeepBlanksDefault(0);
214 ctxt = gs_libxmlDLL.xmlCreatePushParserCtxt(NULL, NULL,
215 buffer, res, ""/*docname*/);
216 while ((res = stream.Read(buffer, 1024).LastRead()) > 0)
217 if (gs_libxmlDLL.xmlParseChunk(ctxt, buffer, res, 0) != 0)
218 okay = FALSE;
219 if (gs_libxmlDLL.xmlParseChunk(ctxt, buffer, 0, 1) != 0) okay = FALSE;
220 dc = ctxt->myDoc;
221 gs_libxmlDLL.xmlFreeParserCtxt(ctxt);
222
223 doc.SetVersion(dc->version);
224 doc.SetEncoding(dc->encoding);
225 doc.SetRoot(CreateWXNode(dc, NULL, gs_libxmlDLL.xmlDocGetRootElement(dc)));
226
227 gs_libxmlDLL.xmlFreeDoc(dc);
228
229 return okay;
230 }
231 else return FALSE;
232 }
233
234
235
236 static void CreateLibxmlNode(xmlNodePtr node, wxXmlNode *wxnode)
237 {
238 node->type = (xmlElementType)wxnode->GetType();
239
240 wxXmlProperty *prop = wxnode->GetProperties();
241 while (prop)
242 {
243 gs_libxmlDLL.xmlSetProp(node, (xmlChar*)prop->GetName().mb_str(),
244 (xmlChar*)prop->GetValue().mb_str());
245 prop = prop->GetNext();
246 }
247
248 wxXmlNode *child = wxnode->GetChildren();
249 xmlNodePtr n;
250 xmlChar *content, *name;
251
252 while (child)
253 {
254 name = (xmlChar*)child->GetName().mb_str();
255 if (!child->GetContent()) content = NULL;
256 else content = (xmlChar*)child->GetContent().mb_str();
257 if (child->GetType() == wxXML_TEXT_NODE)
258 gs_libxmlDLL.xmlAddChild(node, n = gs_libxmlDLL.xmlNewText(content));
259 else
260 n = gs_libxmlDLL.xmlNewChild(node, NULL, name, content);
261 CreateLibxmlNode(n, child);
262 child = child->GetNext();
263 }
264 }
265
266
267
268 bool wxXmlIOHandlerLibxml::Save(wxOutputStream& stream, const wxXmlDocument& doc)
269 {
270 if (!LoadLibxml()) return FALSE;
271
272 xmlDocPtr dc;
273
274 wxASSERT_MSG(doc.GetRoot() != NULL, _("Trying to save empty document!"));
275
276 gs_libxmlDLL.xmlKeepBlanksDefault(0);
277 dc = gs_libxmlDLL.xmlNewDoc((xmlChar*)doc.GetVersion().mb_str());
278
279 gs_libxmlDLL.xmlDocSetRootElement(dc,
280 gs_libxmlDLL.xmlNewDocNode(dc, NULL,
281 (xmlChar*)doc.GetRoot()->GetName().mb_str(), NULL));
282 CreateLibxmlNode(gs_libxmlDLL.xmlDocGetRootElement(dc), doc.GetRoot());
283
284 xmlChar *buffer;
285 int size;
286
287 gs_libxmlDLL.xmlDocDumpMemory(dc, &buffer, &size);
288 gs_libxmlDLL.xmlFreeDoc(dc);
289 stream.Write(buffer, size);
290 (*gs_libxmlDLL.xmlFree)(buffer);
291 return stream.LastWrite() == (unsigned)size;
292 }
293
294
295
296
297 #include "wx/module.h"
298
299 class wxXmlLibxmlModule: public wxModule
300 {
301 DECLARE_DYNAMIC_CLASS(wxXmlLibxmlModule)
302 public:
303 wxXmlLibxmlModule() {}
304 bool OnInit() { return TRUE; }
305 void OnExit() { ReleaseLibxml(); }
306 };
307
308 IMPLEMENT_DYNAMIC_CLASS(wxXmlLibxmlModule, wxModule)