Merge lp:~adrianboguszewski/inkscape/sax-parser into lp:~inkscape.dev/inkscape/trunk
- sax-parser
- Merge into trunk
Proposed by
Adrian Boguszewski
Status: | Needs review |
---|---|
Proposed branch: | lp:~adrianboguszewski/inkscape/sax-parser |
Merge into: | lp:~inkscape.dev/inkscape/trunk |
Diff against target: |
6517 lines (+4413/-1153) 67 files modified
CMakeLists.txt (+1/-0) CMakeScripts/ConfigCompileFlags.cmake (+1/-1) src/CMakeLists.txt (+2/-0) src/document.cpp (+3/-2) src/extension/implementation/xslt.cpp (+8/-5) src/extension/internal/filter/filter-file.cpp (+3/-2) src/extension/internal/filter/filter.cpp (+2/-1) src/extension/internal/svg.cpp (+4/-4) src/extension/loader.h (+2/-1) src/extension/prefdialog.cpp (+2/-1) src/extension/system.cpp (+3/-2) src/inkscape.cpp (+11/-15) src/libxml++/CMakeLists.txt (+34/-0) src/libxml++/README (+8/-0) src/libxml++/document.cc (+126/-0) src/libxml++/document.h (+139/-0) src/libxml++/dtd.cc (+147/-0) src/libxml++/dtd.h (+136/-0) src/libxml++/exceptions/exception.cc (+125/-0) src/libxml++/exceptions/exception.h (+99/-0) src/libxml++/exceptions/internal_error.cc (+23/-0) src/libxml++/exceptions/internal_error.h (+39/-0) src/libxml++/exceptions/parse_error.cc (+23/-0) src/libxml++/exceptions/parse_error.h (+42/-0) src/libxml++/exceptions/validity_error.cc (+23/-0) src/libxml++/exceptions/validity_error.h (+42/-0) src/libxml++/exceptions/wrapped_exception.cc (+46/-0) src/libxml++/exceptions/wrapped_exception.h (+56/-0) src/libxml++/io/istreamparserinputbuffer.cc (+44/-0) src/libxml++/io/istreamparserinputbuffer.h (+36/-0) src/libxml++/io/parserinputbuffer.cc (+84/-0) src/libxml++/io/parserinputbuffer.h (+75/-0) src/libxml++/keepblanks.cc (+29/-0) src/libxml++/keepblanks.h (+35/-0) src/libxml++/libxml++config.h (+26/-0) src/libxml++/noncopyable.cc (+21/-0) src/libxml++/noncopyable.h (+31/-0) src/libxml++/parsers/parser.cc (+365/-0) src/libxml++/parsers/parser.h (+220/-0) src/libxml++/parsers/saxparser.cc (+711/-0) src/libxml++/parsers/saxparser.h (+261/-0) src/preferences.cpp (+5/-3) src/shortcuts.cpp (+16/-16) src/ui/dialog/template-load-tab.cpp (+2/-1) src/ui/interface.cpp (+2/-1) src/xml/CMakeLists.txt (+3/-1) src/xml/comment-node.h (+9/-0) src/xml/node.h (+27/-4) src/xml/pi-node.h (+6/-0) src/xml/repr-io.cpp (+169/-1060) src/xml/repr-io.h (+45/-0) src/xml/repr-util.cpp (+7/-2) src/xml/repr.h (+0/-25) src/xml/simple-document.cpp (+12/-0) src/xml/simple-document.h (+2/-0) src/xml/simple-node.cpp (+89/-0) src/xml/simple-node.h (+25/-3) src/xml/svg-parser.cpp (+266/-0) src/xml/svg-parser.h (+85/-0) src/xml/text-node.h (+15/-0) testfiles/CMakeLists.txt (+5/-1) testfiles/doc-per-case-test.cpp (+4/-0) testfiles/src/object-set-test.cpp (+1/-1) testfiles/src/repr-io-test.cpp (+73/-0) testfiles/src/sp-object-test.cpp (+1/-1) testfiles/src/svg-parser-test.cpp (+237/-0) testfiles/src/svg-writer-test.cpp (+219/-0) |
To merge this branch: | bzr merge lp:~adrianboguszewski/inkscape/sax-parser |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mc | Pending | ||
Review via email: mp+310142@code.launchpad.net |
Commit message
Description of the change
Added new file loading and saving, new sax parser and libxml++.
To post a comment you must log in.
Unmerged revisions
- 15065. By Adrian Boguszewski
-
Merged trunk
- 15064. By Adrian Boguszewski
-
Fixed Windows file loading
- 15063. By Adrian Boguszewski
-
Merged trunk
- 15062. By Adrian Boguszewski
-
Fixed libxml++ compilation on Windows
- 15061. By Adrian Boguszewski
-
Merged trunk
- 15060. By Adrian Boguszewski
-
Fixed memory management in sax parser
- 15059. By Adrian Boguszewski
-
Renamed some variables
- 15058. By Adrian Boguszewski
-
Added empty entity to sax parser
- 15057. By Adrian Boguszewski
-
Improved compressed file reading
- 15056. By Adrian Boguszewski
-
Fixed too many text nodes
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-10-01 06:05:10 +0000 |
3 | +++ CMakeLists.txt 2016-11-06 17:18:04 +0000 |
4 | @@ -86,6 +86,7 @@ |
5 | message("No gmock/gtest found! Perhaps you wish to run 'bash download-gtest.sh' to download it.") |
6 | endif() |
7 | |
8 | +include(CMakeScripts/ConfigCompileFlags.cmake) |
9 | include(CMakeScripts/DefineDependsandFlags.cmake) # Includes, Compiler Flags, and Link Libraries |
10 | include(CMakeScripts/HelperMacros.cmake) # Misc Utility Macros |
11 | |
12 | |
13 | === modified file 'CMakeScripts/ConfigCompileFlags.cmake' |
14 | --- CMakeScripts/ConfigCompileFlags.cmake 2016-08-09 09:33:34 +0000 |
15 | +++ CMakeScripts/ConfigCompileFlags.cmake 2016-11-06 17:18:04 +0000 |
16 | @@ -14,6 +14,6 @@ |
17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 ${COMPILE_PROFILING_FLAGS} ") |
18 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 ${COMPILE_PROFILING_FLAGS} ") |
19 | |
20 | -set(CMAKE_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM} ") |
21 | +set(CMAKE_MAKE_PROGRAM ${CMAKE_MAKE_PROGRAM}) |
22 | |
23 | message(STATUS "${CMAKE_CXX_FLAGS}") |
24 | |
25 | === modified file 'src/CMakeLists.txt' |
26 | --- src/CMakeLists.txt 2016-10-22 22:11:58 +0000 |
27 | +++ src/CMakeLists.txt 2016-11-06 17:18:04 +0000 |
28 | @@ -458,6 +458,7 @@ |
29 | add_subdirectory(inkgc) |
30 | add_subdirectory(libuemf) |
31 | add_subdirectory(libvpsc) |
32 | +add_subdirectory(libxml++) |
33 | add_subdirectory(livarot) |
34 | add_subdirectory(libnrtype) |
35 | add_subdirectory(libdepixelize) |
36 | @@ -515,6 +516,7 @@ |
37 | avoid_LIB |
38 | cola_LIB |
39 | vpsc_LIB |
40 | + xmlpp_LIB |
41 | livarot_LIB |
42 | uemf_LIB |
43 | 2geom_LIB |
44 | |
45 | === modified file 'src/document.cpp' |
46 | --- src/document.cpp 2016-10-02 22:44:54 +0000 |
47 | +++ src/document.cpp 2016-11-06 17:18:04 +0000 |
48 | @@ -42,6 +42,7 @@ |
49 | #include <string> |
50 | #include <cstring> |
51 | #include <2geom/transforms.h> |
52 | +#include <xml/repr-io.h> |
53 | |
54 | #include "widgets/desktop-widget.h" |
55 | #include "desktop.h" |
56 | @@ -496,7 +497,7 @@ |
57 | Inkscape::XML::Node *rroot; |
58 | gchar *s, *p; |
59 | /* Try to fetch repr from file */ |
60 | - rdoc = sp_repr_read_file(uri, SP_SVG_NS_URI); |
61 | + rdoc = Inkscape::XML::read_svg_file(uri, false, SP_SVG_NS_URI); |
62 | /* If file cannot be loaded, return NULL without warning */ |
63 | if (rdoc == NULL) return NULL; |
64 | rroot = rdoc->root(); |
65 | @@ -542,7 +543,7 @@ |
66 | { |
67 | SPDocument *doc = NULL; |
68 | |
69 | - Inkscape::XML::Document *rdoc = sp_repr_read_mem(buffer, length, SP_SVG_NS_URI); |
70 | + Inkscape::XML::Document *rdoc = Inkscape::XML::read_svg_buffer(buffer, false, SP_SVG_NS_URI); |
71 | if ( rdoc ) { |
72 | // Only continue to create a non-null doc if it could be loaded |
73 | Inkscape::XML::Node *rroot = rdoc->root(); |
74 | |
75 | === modified file 'src/extension/implementation/xslt.cpp' |
76 | --- src/extension/implementation/xslt.cpp 2016-08-03 13:29:38 +0000 |
77 | +++ src/extension/implementation/xslt.cpp 2016-11-06 17:18:04 +0000 |
78 | @@ -29,8 +29,7 @@ |
79 | |
80 | #include <libxslt/transform.h> |
81 | #include <libxslt/xsltutils.h> |
82 | - |
83 | -Inkscape::XML::Document * sp_repr_do_read (xmlDocPtr doc, const gchar * default_ns); |
84 | +#include <xml/repr-io.h> |
85 | |
86 | /* Namespaces */ |
87 | namespace Inkscape { |
88 | @@ -146,9 +145,14 @@ |
89 | xmlDocPtr result = xsltApplyStylesheet(_stylesheet, filein, params); |
90 | xmlFreeDoc(filein); |
91 | |
92 | - Inkscape::XML::Document * rdoc = sp_repr_do_read( result, SP_SVG_NS_URI); |
93 | + xmlChar *str; |
94 | + int size; |
95 | + xmlDocDumpMemory(result, &str, &size); |
96 | xmlFreeDoc(result); |
97 | |
98 | + Inkscape::XML::Document * rdoc = Inkscape::XML::read_svg_buffer((char*) str, false, SP_SVG_NS_URI); |
99 | + xmlFree(str); |
100 | + |
101 | if (rdoc == NULL) { |
102 | return NULL; |
103 | } |
104 | @@ -197,8 +201,7 @@ |
105 | return; |
106 | } |
107 | |
108 | - if (!sp_repr_save_rebased_file(repr->document(), tempfilename_out.c_str(), SP_SVG_NS_URI, |
109 | - doc->getBase(), filename)) { |
110 | + if (!Inkscape::XML::save_svg_file(repr->document(), tempfilename_out.c_str(), SP_SVG_NS_URI, doc->getBase(), filename)) { |
111 | throw Inkscape::Extension::Output::save_failed(); |
112 | } |
113 | |
114 | |
115 | === modified file 'src/extension/internal/filter/filter-file.cpp' |
116 | --- src/extension/internal/filter/filter-file.cpp 2014-06-26 19:40:39 +0000 |
117 | +++ src/extension/internal/filter/filter-file.cpp 2016-11-06 17:18:04 +0000 |
118 | @@ -21,6 +21,7 @@ |
119 | /* System includes */ |
120 | #include <glibmm/i18n.h> |
121 | #include <glibmm/fileutils.h> |
122 | +#include <xml/repr-io.h> |
123 | |
124 | namespace Inkscape { |
125 | namespace Extension { |
126 | @@ -84,7 +85,7 @@ |
127 | void |
128 | Filter::filters_load_file (gchar * filename, gchar * menuname) |
129 | { |
130 | - Inkscape::XML::Document *doc = sp_repr_read_file(filename, INKSCAPE_EXTENSION_URI); |
131 | + Inkscape::XML::Document *doc = Inkscape::XML::read_svg_file(filename, true, INKSCAPE_EXTENSION_URI); |
132 | if (doc == NULL) { |
133 | g_warning("File (%s) is not parseable as XML. Ignored.", filename); |
134 | return; |
135 | @@ -162,7 +163,7 @@ |
136 | node->setAttribute("xmlns:inkscape", SP_INKSCAPE_NS_URI); |
137 | |
138 | mywriter writer; |
139 | - sp_repr_write_stream(node, writer, 0, FALSE, g_quark_from_static_string("svg"), 0, 0); |
140 | + node->serialize(writer, "svg", 0, 0, false, false); |
141 | |
142 | Inkscape::Extension::build_from_mem(xml_str, new Filter(g_strdup(writer.c_str()))); |
143 | g_free(xml_str); |
144 | |
145 | === modified file 'src/extension/internal/filter/filter.cpp' |
146 | --- src/extension/internal/filter/filter.cpp 2016-07-03 18:53:39 +0000 |
147 | +++ src/extension/internal/filter/filter.cpp 2016-11-06 17:18:04 +0000 |
148 | @@ -7,6 +7,7 @@ |
149 | * Released under GNU GPL, read the file 'COPYING' for more information |
150 | */ |
151 | |
152 | +#include <xml/repr-io.h> |
153 | #include "desktop.h" |
154 | #include "selection.h" |
155 | #include "document-private.h" |
156 | @@ -64,7 +65,7 @@ |
157 | Inkscape::XML::Document * |
158 | Filter::get_filter (Inkscape::Extension::Extension * ext) { |
159 | gchar const * filter = get_filter_text(ext); |
160 | - return sp_repr_read_mem(filter, strlen(filter), NULL); |
161 | + return Inkscape::XML::read_svg_buffer(filter, true); |
162 | } |
163 | |
164 | void |
165 | |
166 | === modified file 'src/extension/internal/svg.cpp' |
167 | --- src/extension/internal/svg.cpp 2016-10-01 21:30:34 +0000 |
168 | +++ src/extension/internal/svg.cpp 2016-11-06 17:18:04 +0000 |
169 | @@ -15,7 +15,7 @@ |
170 | */ |
171 | |
172 | #ifdef HAVE_CONFIG_H |
173 | -# include <config.h> |
174 | +#include <config.h> |
175 | #endif |
176 | #include "sp-object.h" |
177 | #include "svg.h" |
178 | @@ -25,11 +25,12 @@ |
179 | #include <vector> |
180 | #include "xml/attribute-record.h" |
181 | #include "xml/simple-document.h" |
182 | +#include "xml/repr-io.h" |
183 | #include "sp-root.h" |
184 | #include "document.h" |
185 | |
186 | #ifdef WITH_GNOME_VFS |
187 | -# include <libgnomevfs/gnome-vfs.h> |
188 | +#include <libgnomevfs/gnome-vfs.h> |
189 | #endif |
190 | |
191 | namespace Inkscape { |
192 | @@ -293,8 +294,7 @@ |
193 | rdoc = new_rdoc; |
194 | } |
195 | |
196 | - if (!sp_repr_save_rebased_file(rdoc, filename, SP_SVG_NS_URI, |
197 | - doc->getBase(), filename)) { |
198 | + if (!Inkscape::XML::save_svg_file(rdoc, filename, SP_SVG_NS_URI, doc->getBase(), filename)) { |
199 | throw Inkscape::Extension::Output::save_failed(); |
200 | } |
201 | |
202 | |
203 | === modified file 'src/extension/loader.h' |
204 | --- src/extension/loader.h 2016-08-03 15:12:14 +0000 |
205 | +++ src/extension/loader.h 2016-11-06 17:18:04 +0000 |
206 | @@ -1,4 +1,5 @@ |
207 | -/** @file |
208 | +/** @file#include <config.h> |
209 | + |
210 | * Loader for external plug-ins. |
211 | *//* |
212 | * |
213 | |
214 | === modified file 'src/extension/prefdialog.cpp' |
215 | --- src/extension/prefdialog.cpp 2016-07-28 10:22:07 +0000 |
216 | +++ src/extension/prefdialog.cpp 2016-11-06 17:18:04 +0000 |
217 | @@ -12,6 +12,7 @@ |
218 | #include <gtkmm/checkbutton.h> |
219 | #include <gtkmm/separator.h> |
220 | #include <glibmm/i18n.h> |
221 | +#include <xml/repr-io.h> |
222 | |
223 | #include "ui/dialog-events.h" |
224 | #include "xml/repr.h" |
225 | @@ -81,7 +82,7 @@ |
226 | |
227 | if (_effect != NULL && !_effect->no_live_preview) { |
228 | if (_param_preview == NULL) { |
229 | - XML::Document * doc = sp_repr_read_mem(live_param_xml, strlen(live_param_xml), NULL); |
230 | + XML::Document * doc = Inkscape::XML::read_svg_buffer(live_param_xml, true); |
231 | if (doc == NULL) { |
232 | std::cout << "Error encountered loading live parameter XML !!!" << std::endl; |
233 | return; |
234 | |
235 | === modified file 'src/extension/system.cpp' |
236 | --- src/extension/system.cpp 2016-08-03 13:29:38 +0000 |
237 | +++ src/extension/system.cpp 2016-11-06 17:18:04 +0000 |
238 | @@ -40,6 +40,7 @@ |
239 | #include "loader.h" |
240 | |
241 | #include <glibmm/miscutils.h> |
242 | +#include <xml/repr-io.h> |
243 | |
244 | namespace Inkscape { |
245 | namespace Extension { |
246 | @@ -546,7 +547,7 @@ |
247 | Extension * |
248 | build_from_file(gchar const *filename) |
249 | { |
250 | - Inkscape::XML::Document *doc = sp_repr_read_file(filename, INKSCAPE_EXTENSION_URI); |
251 | + Inkscape::XML::Document *doc = Inkscape::XML::read_svg_file(filename, true, INKSCAPE_EXTENSION_URI); |
252 | std::string dir = Glib::path_get_dirname(filename); |
253 | Extension *ext = build_from_reprdoc(doc, NULL, &dir); |
254 | if (ext != NULL) |
255 | @@ -568,7 +569,7 @@ |
256 | Extension * |
257 | build_from_mem(gchar const *buffer, Implementation::Implementation *in_imp) |
258 | { |
259 | - Inkscape::XML::Document *doc = sp_repr_read_mem(buffer, strlen(buffer), INKSCAPE_EXTENSION_URI); |
260 | + Inkscape::XML::Document *doc = Inkscape::XML::read_svg_buffer(buffer, true, INKSCAPE_EXTENSION_URI); |
261 | g_return_val_if_fail(doc != NULL, NULL); |
262 | Extension *ext = build_from_reprdoc(doc, in_imp, NULL); |
263 | Inkscape::GC::release(doc); |
264 | |
265 | === modified file 'src/inkscape.cpp' |
266 | --- src/inkscape.cpp 2016-09-02 22:45:03 +0000 |
267 | +++ src/inkscape.cpp 2016-11-06 17:18:04 +0000 |
268 | @@ -48,6 +48,7 @@ |
269 | #include <glibmm/i18n.h> |
270 | #include <glibmm/miscutils.h> |
271 | #include <glibmm/convert.h> |
272 | +#include <xml/repr-io.h> |
273 | |
274 | #include "desktop.h" |
275 | |
276 | @@ -322,21 +323,17 @@ |
277 | baseName = 0; |
278 | |
279 | // Try to save the file |
280 | - FILE *file = Inkscape::IO::fopen_utf8name(full_path, "w"); |
281 | gchar *errortext = 0; |
282 | - if (file) { |
283 | - try{ |
284 | - sp_repr_save_stream(repr->document(), file, SP_SVG_NS_URI); |
285 | - } catch (Inkscape::Extension::Output::no_extension_found &e) { |
286 | - errortext = g_strdup(_("Autosave failed! Could not find inkscape extension to save document.")); |
287 | - } catch (Inkscape::Extension::Output::save_failed &e) { |
288 | + try { |
289 | + if (!Inkscape::XML::save_svg_file(repr->document(), full_path, SP_SVG_NS_URI)) { |
290 | gchar *safeUri = Inkscape::IO::sanitizeString(full_path); |
291 | errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri); |
292 | g_free(safeUri); |
293 | } |
294 | - fclose(file); |
295 | - } |
296 | - else { |
297 | + |
298 | + } catch (Inkscape::Extension::Output::no_extension_found &e) { |
299 | + errortext = g_strdup(_("Autosave failed! Could not find inkscape extension to save document.")); |
300 | + } catch (Inkscape::Extension::Output::save_failed &e) { |
301 | gchar *safeUri = Inkscape::IO::sanitizeString(full_path); |
302 | errortext = g_strdup_printf(_("Autosave failed! File %s could not be saved."), safeUri); |
303 | g_free(safeUri); |
304 | @@ -701,15 +698,14 @@ |
305 | file = Inkscape::IO::fopen_utf8name(filename, "w"); |
306 | if (file) { |
307 | g_snprintf (c, 1024, "%s", filename); // we want the complete path to be stored in c (for reporting purposes) |
308 | + fclose (file); |
309 | break; |
310 | } |
311 | } |
312 | |
313 | // Save |
314 | - if (file) { |
315 | - sp_repr_save_stream (repr->document(), file, SP_SVG_NS_URI); |
316 | + if (Inkscape::XML::save_svg_file(repr->document(), c, SP_SVG_NS_URI)) { |
317 | savednames = g_slist_prepend (savednames, g_strdup (c)); |
318 | - fclose (file); |
319 | } else { |
320 | failednames = g_slist_prepend (failednames, (doc->getName()) ? g_strdup(doc->getName()) : g_strdup (_("Untitled document"))); |
321 | } |
322 | @@ -819,7 +815,7 @@ |
323 | |
324 | if ( g_file_get_contents(fn, &menus_xml, &len, NULL) ) { |
325 | // load the menus_xml file |
326 | - _menus = sp_repr_read_mem(menus_xml, len, NULL); |
327 | + _menus = Inkscape::XML::read_svg_buffer(menus_xml, true); |
328 | |
329 | g_free(menus_xml); |
330 | menus_xml = 0; |
331 | @@ -828,7 +824,7 @@ |
332 | fn = 0; |
333 | |
334 | if ( !_menus ) { |
335 | - _menus = sp_repr_read_mem(menus_skeleton, MENUS_SKELETON_SIZE, NULL); |
336 | + _menus = Inkscape::XML::read_svg_buffer(menus_skeleton, true); |
337 | } |
338 | |
339 | return (_menus != 0); |
340 | |
341 | === added directory 'src/libxml++' |
342 | === added file 'src/libxml++/CMakeLists.txt' |
343 | --- src/libxml++/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
344 | +++ src/libxml++/CMakeLists.txt 2016-11-06 17:18:04 +0000 |
345 | @@ -0,0 +1,34 @@ |
346 | +set(libxmlpp_SRC |
347 | + document.cc |
348 | + dtd.cc |
349 | + keepblanks.cc |
350 | + noncopyable.cc |
351 | + exceptions/exception.cc |
352 | + exceptions/internal_error.cc |
353 | + exceptions/parse_error.cc |
354 | + exceptions/validity_error.cc |
355 | + exceptions/wrapped_exception.cc |
356 | + io/istreamparserinputbuffer.cc |
357 | + io/parserinputbuffer.cc |
358 | + parsers/parser.cc |
359 | + parsers/saxparser.cc |
360 | + |
361 | + # ------- |
362 | + # Headers |
363 | + document.h |
364 | + dtd.h |
365 | + keepblanks.h |
366 | + libxml++config.h |
367 | + noncopyable.h |
368 | + exceptions/exception.h |
369 | + exceptions/internal_error.h |
370 | + exceptions/parse_error.h |
371 | + exceptions/validity_error.h |
372 | + exceptions/wrapped_exception.h |
373 | + io/istreamparserinputbuffer.h |
374 | + io/parserinputbuffer.h |
375 | + parsers/parser.h |
376 | + parsers/saxparser.h |
377 | + ) |
378 | + |
379 | +add_inkscape_lib(xmlpp_LIB "${libxmlpp_SRC}") |
380 | |
381 | === added file 'src/libxml++/README' |
382 | --- src/libxml++/README 1970-01-01 00:00:00 +0000 |
383 | +++ src/libxml++/README 2016-11-06 17:18:04 +0000 |
384 | @@ -0,0 +1,8 @@ |
385 | +This code is a part of libxml++ library (ver 3.0) with local modifications |
386 | +inter alia: |
387 | +* DOM parser and node classes are removed |
388 | +* Enabled SAX2 interface |
389 | +* Added new SAX parser methods to handle Processing Instructions |
390 | + and namespace information from nodes |
391 | + |
392 | +Full library is available here: http://libxmlplusplus.sourceforge.net/ |
393 | \ No newline at end of file |
394 | |
395 | === added file 'src/libxml++/document.cc' |
396 | --- src/libxml++/document.cc 1970-01-01 00:00:00 +0000 |
397 | +++ src/libxml++/document.cc 2016-11-06 17:18:04 +0000 |
398 | @@ -0,0 +1,126 @@ |
399 | +/* document.cc |
400 | + * this file is part of libxml++ |
401 | + * |
402 | + * copyright (C) 2003 by the libxml++ development team |
403 | + * |
404 | + * this file is covered by the GNU Lesser General Public License, |
405 | + * which should be included with libxml++ as the file COPYING. |
406 | + */ |
407 | + |
408 | +#include <libxml++/document.h> |
409 | +#include <libxml++/exceptions/internal_error.h> |
410 | + |
411 | +#include <libxml/tree.h> |
412 | + |
413 | +namespace xmlpp |
414 | +{ |
415 | + |
416 | +static const char* get_encoding_or_utf8(const Glib::ustring& encoding) |
417 | +{ |
418 | + if(encoding.empty()) |
419 | + { |
420 | + //If we don't specify this to the xmlDocDump* functions (using nullptr instead), |
421 | + //then some other encoding is used, causing them to fail on non-ASCII characters. |
422 | + return "UTF-8"; |
423 | + } |
424 | + else |
425 | + return encoding.c_str(); |
426 | +} |
427 | + |
428 | + |
429 | +Document::Init::Init() |
430 | +{ |
431 | + xmlInitParser(); //Not always necessary, but necessary for thread safety. |
432 | +} |
433 | + |
434 | +Document::Init::~Init() noexcept |
435 | +{ |
436 | + //We don't call this because it breaks libxml generally and should only be |
437 | + //called at the very end of a process, such as at the end of a main(). |
438 | + //libxml might still be used by the application, so we don't want to break |
439 | + //that. |
440 | + //This is important even here, which usually happens only when the library |
441 | + //is unloaded, because that might happen during normal application use, |
442 | + //if the application does dynamic library loading, for instance to load |
443 | + //plugins. |
444 | + //See http://xmlsoft.org/html/libxml-parser.html#xmlCleanupParser |
445 | + //xmlCleanupParser(); //As per xmlInitParser(), or memory leak will happen. |
446 | +} |
447 | + |
448 | +Document::Init Document::init_; |
449 | + |
450 | +Document::Document(const Glib::ustring& version) |
451 | + : impl_(xmlNewDoc((const xmlChar*)version.c_str())) |
452 | +{ |
453 | + if (!impl_) |
454 | + throw internal_error("Could not create Document."); |
455 | + impl_->_private = this; |
456 | +} |
457 | + |
458 | +Document::Document(xmlDoc* doc) |
459 | + : impl_(doc) |
460 | +{ |
461 | + if (!impl_) |
462 | + throw internal_error("xmlDoc pointer cannot be nullptr"); |
463 | + |
464 | + impl_->_private = this; |
465 | +} |
466 | + |
467 | +Document::~Document() |
468 | +{ |
469 | + xmlFreeDoc(impl_); |
470 | +} |
471 | + |
472 | +Glib::ustring Document::get_encoding() const |
473 | +{ |
474 | + Glib::ustring encoding; |
475 | + if(impl_->encoding) |
476 | + encoding = (const char*)impl_->encoding; |
477 | + |
478 | + return encoding; |
479 | +} |
480 | + |
481 | +Dtd* Document::get_internal_subset() const |
482 | +{ |
483 | + auto dtd = xmlGetIntSubset(impl_); |
484 | + if(!dtd) |
485 | + return nullptr; |
486 | + |
487 | + if(!dtd->_private) |
488 | + dtd->_private = new Dtd(dtd); |
489 | + |
490 | + return reinterpret_cast<Dtd*>(dtd->_private); |
491 | +} |
492 | + |
493 | +void Document::set_internal_subset(const Glib::ustring& name, |
494 | + const Glib::ustring& external_id, |
495 | + const Glib::ustring& system_id) |
496 | +{ |
497 | + auto dtd = xmlCreateIntSubset(impl_, |
498 | + (const xmlChar*)name.c_str(), |
499 | + external_id.empty() ? nullptr : (const xmlChar*)external_id.c_str(), |
500 | + system_id.empty() ? nullptr : (const xmlChar*)system_id.c_str()); |
501 | + |
502 | + if (dtd && !dtd->_private) |
503 | + dtd->_private = new Dtd(dtd); |
504 | +} |
505 | + |
506 | +void Document::set_entity_declaration(const Glib::ustring& name, XmlEntityType type, |
507 | + const Glib::ustring& publicId, const Glib::ustring& systemId, |
508 | + const Glib::ustring& content) |
509 | +{ |
510 | + auto entity = xmlAddDocEntity(impl_, (const xmlChar*)name.c_str(), |
511 | + static_cast<int>(type), |
512 | + publicId.empty() ? nullptr : (const xmlChar*)publicId.c_str(), |
513 | + systemId.empty() ? nullptr : (const xmlChar*)systemId.c_str(), |
514 | + (const xmlChar*)content.c_str()); |
515 | + if (!entity) |
516 | + throw internal_error("Could not add entity declaration " + name); |
517 | +} |
518 | + |
519 | +_xmlEntity* Document::get_entity(const Glib::ustring& name) |
520 | +{ |
521 | + return xmlGetDocEntity(impl_, (const xmlChar*) name.c_str()); |
522 | +} |
523 | + |
524 | +} //namespace xmlpp |
525 | |
526 | === added file 'src/libxml++/document.h' |
527 | --- src/libxml++/document.h 1970-01-01 00:00:00 +0000 |
528 | +++ src/libxml++/document.h 2016-11-06 17:18:04 +0000 |
529 | @@ -0,0 +1,139 @@ |
530 | +/* document.h |
531 | + * this file is part of libxml++ |
532 | + * |
533 | + * parts of the code copyright (C) 2003 by Stefan Seefeld |
534 | + * others copyright (C) 2003 by libxml++ developer's team |
535 | + * |
536 | + * this file is covered by the GNU Lesser General Public License, |
537 | + * which should be included with libxml++ as the file COPYING. |
538 | + */ |
539 | + |
540 | +#ifndef __LIBXMLPP_DOCUMENT_H |
541 | +#define __LIBXMLPP_DOCUMENT_H |
542 | + |
543 | +#include <libxml++/dtd.h> |
544 | + |
545 | +#include <string> |
546 | +#include <ostream> |
547 | + |
548 | +/* std::string or Glib::ustring in function prototypes in libxml++? |
549 | + * |
550 | + * If it's propagated to a libxml2 function that takes a xmlChar*, it's |
551 | + * UTF-8 encoded, and Glib::ustring is the right choice. |
552 | + * |
553 | + * If it's propagated to a libxml2 function that takes a char*, it's not |
554 | + * necessarily UTF-8 encoded, and std::string is usually the right choice. |
555 | + * Most of these strings are filenames or URLs. |
556 | + */ |
557 | + |
558 | +#ifndef DOXYGEN_SHOULD_SKIP_THIS |
559 | +extern "C" { |
560 | + struct _xmlDoc; |
561 | + struct _xmlEntity; |
562 | +} |
563 | +#endif //DOXYGEN_SHOULD_SKIP_THIS |
564 | + |
565 | +namespace xmlpp |
566 | +{ |
567 | + |
568 | +// xmlpp::XmlEntityType is similar to xmlEntityType in libxml2. |
569 | +/** The valid entity types. |
570 | + */ |
571 | +enum class XmlEntityType |
572 | +{ |
573 | + INTERNAL_GENERAL = 1, |
574 | + EXTERNAL_GENERAL_PARSED = 2, |
575 | + EXTERNAL_GENERAL_UNPARSED = 3, |
576 | + INTERNAL_PARAMETER = 4, |
577 | + EXTERNAL_PARAMETER = 5, |
578 | + INTERNAL_PREDEFINED = 6 |
579 | +}; |
580 | + |
581 | +//TODO: Make Document inherit from Node, when we can break ABI one day? |
582 | +// |
583 | +//libxml might intend xmlDoc to derive (theoretically) from xmlNode. |
584 | +//This is suggested because the xmlNodeSet returned by xmlXPathEval (see the |
585 | +//Node::find() implementation) can contain either xmlNode or xmlDocument elements. |
586 | +// See https://bugzilla.gnome.org/show_bug.cgi?id=754673#c8 for an explanation |
587 | +// why it has not been done in libxml++ 3.0. |
588 | +/** |
589 | + * Represents an XML document in the DOM model. |
590 | + */ |
591 | +class Document : public NonCopyable |
592 | +{ |
593 | + //Ensure that libxml is properly initialised: |
594 | + class Init |
595 | + { |
596 | + public: |
597 | + Init(); |
598 | + ~Init() noexcept; |
599 | + }; |
600 | + |
601 | + friend class SaxParser; |
602 | + |
603 | +public: |
604 | + /** Create a new document. |
605 | + * @param version XML version. |
606 | + * @throws xmlpp::internal_error If memory allocation fails. |
607 | + */ |
608 | + explicit Document(const Glib::ustring& version = "1.0"); |
609 | + |
610 | + /** Create a new C++ wrapper for an xmlDoc struct. |
611 | + * The created xmlpp::Document takes ownership of the xmlDoc. |
612 | + * When the Document is deleted, so is the xmlDoc and all its nodes. |
613 | + * @param doc A pointer to an xmlDoc struct. Must not be <tt>nullptr</tt>. |
614 | + * @throws xmlpp::internal_error If @a doc is <tt>nullptr</tt>. |
615 | + */ |
616 | + explicit Document(_xmlDoc* doc); |
617 | + |
618 | + ~Document() override; |
619 | + |
620 | + /** @return The encoding used in the source from which the document has been loaded. |
621 | + */ |
622 | + Glib::ustring get_encoding() const; |
623 | + |
624 | + /** Get the internal subset of this document. |
625 | + * @returns A pointer to the DTD, or <tt>nullptr</tt> if not found. |
626 | + */ |
627 | + Dtd* get_internal_subset() const; |
628 | + |
629 | + /** Create the internal subset of this document. |
630 | + * If the document already has an internal subset, a new one is not created. |
631 | + * @param name The DTD name. |
632 | + * @param external_id The external (PUBLIC) ID, or an empty string. |
633 | + * @param system_id The system ID, or an empty string. |
634 | + */ |
635 | + void set_internal_subset(const Glib::ustring& name, |
636 | + const Glib::ustring& external_id, |
637 | + const Glib::ustring& system_id); |
638 | + |
639 | + /** Add an Entity declaration to the document. |
640 | + * @param name The name of the entity that will be used in an entity reference. |
641 | + * @param type The type of entity. |
642 | + * @param publicId The public ID of the subset. |
643 | + * @param systemId The system ID of the subset. |
644 | + * @param content The value of the Entity. In entity reference substitutions, this |
645 | + * is the replacement value. |
646 | + * @throws xmlpp::internal_error |
647 | + */ |
648 | + virtual void set_entity_declaration(const Glib::ustring& name, XmlEntityType type, |
649 | + const Glib::ustring& publicId, const Glib::ustring& systemId, |
650 | + const Glib::ustring& content); |
651 | + |
652 | +protected: |
653 | + /** Retrieve an Entity. |
654 | + * The entity can be from an external subset or internally declared. |
655 | + * @param name The name of the entity to get. |
656 | + * @returns A pointer to the libxml2 entity structure, or <tt>nullptr</tt> if not found. |
657 | + */ |
658 | + _xmlEntity* get_entity(const Glib::ustring& name); |
659 | + |
660 | +private: |
661 | + static Init init_; |
662 | + |
663 | + _xmlDoc* impl_; |
664 | +}; |
665 | + |
666 | +} //namespace xmlpp |
667 | + |
668 | +#endif //__LIBXMLPP_DOCUMENT_H |
669 | |
670 | === added file 'src/libxml++/dtd.cc' |
671 | --- src/libxml++/dtd.cc 1970-01-01 00:00:00 +0000 |
672 | +++ src/libxml++/dtd.cc 2016-11-06 17:18:04 +0000 |
673 | @@ -0,0 +1,147 @@ |
674 | +/* dtd.cc |
675 | + * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and |
676 | + * are covered by the GNU Lesser General Public License, which should be |
677 | + * included with libxml++ as the file COPYING. |
678 | + */ |
679 | + |
680 | +#include <libxml++/dtd.h> |
681 | +#include <libxml++/exceptions/parse_error.h> |
682 | +#include <libxml++/io/istreamparserinputbuffer.h> |
683 | + |
684 | +#include <libxml/tree.h> |
685 | + |
686 | +namespace xmlpp |
687 | +{ |
688 | + |
689 | +struct Dtd::Impl |
690 | +{ |
691 | + Impl() noexcept : dtd(nullptr), is_dtd_owner(false) {} |
692 | + |
693 | + _xmlDtd* dtd; |
694 | + bool is_dtd_owner; |
695 | +}; |
696 | + |
697 | +Dtd::Dtd() |
698 | +: pimpl_(new Impl) |
699 | +{ |
700 | +} |
701 | + |
702 | +Dtd::Dtd(_xmlDtd* dtd, bool take_ownership) |
703 | +: pimpl_(new Impl) |
704 | +{ |
705 | + pimpl_->dtd = dtd; |
706 | + if (dtd) |
707 | + { |
708 | + pimpl_->dtd->_private = this; |
709 | + pimpl_->is_dtd_owner = take_ownership; |
710 | + } |
711 | +} |
712 | + |
713 | +Dtd::Dtd(const std::string& filename) |
714 | +: pimpl_(new Impl) |
715 | +{ |
716 | + parse_subset("", filename); |
717 | +} |
718 | + |
719 | +Dtd::Dtd(const Glib::ustring& external, const Glib::ustring& system) |
720 | +: pimpl_(new Impl) |
721 | +{ |
722 | + parse_subset(external, system); |
723 | +} |
724 | + |
725 | +Dtd::~Dtd() |
726 | +{ |
727 | + release_underlying(); |
728 | +} |
729 | + |
730 | +void Dtd::parse_file(const std::string& filename) |
731 | +{ |
732 | + parse_subset("", filename); |
733 | +} |
734 | + |
735 | +void Dtd::parse_subset(const Glib::ustring& external, const Glib::ustring& system) |
736 | +{ |
737 | + release_underlying(); // Free any existing dtd. |
738 | + xmlResetLastError(); |
739 | + |
740 | + auto dtd = xmlParseDTD( |
741 | + external.empty() ? nullptr : (const xmlChar*)external.c_str(), |
742 | + system.empty() ? nullptr : (const xmlChar*)system.c_str()); |
743 | + |
744 | + if (!dtd) |
745 | + { |
746 | + throw parse_error("Dtd could not be parsed.\n" + format_xml_error()); |
747 | + } |
748 | + |
749 | + pimpl_->dtd = dtd; |
750 | + pimpl_->dtd->_private = this; |
751 | + pimpl_->is_dtd_owner = true; |
752 | +} |
753 | + |
754 | +void Dtd::parse_memory(const Glib::ustring& contents) |
755 | +{ |
756 | + // Prepare an istream with buffer |
757 | + std::istringstream is(contents); |
758 | + |
759 | + parse_stream(is); |
760 | +} |
761 | + |
762 | +void Dtd::parse_stream(std::istream& in) |
763 | +{ |
764 | + release_underlying(); // Free any existing dtd. |
765 | + xmlResetLastError(); |
766 | + |
767 | + IStreamParserInputBuffer ibuff(in); |
768 | + |
769 | + auto dtd = xmlIOParseDTD(nullptr, ibuff.cobj(), XML_CHAR_ENCODING_UTF8); |
770 | + |
771 | + if (!dtd) |
772 | + { |
773 | + throw parse_error("Dtd could not be parsed.\n" + format_xml_error()); |
774 | + } |
775 | + |
776 | + pimpl_->dtd = dtd; |
777 | + pimpl_->dtd->_private = this; |
778 | + pimpl_->is_dtd_owner = true; |
779 | +} |
780 | + |
781 | +Glib::ustring Dtd::get_name() const |
782 | +{ |
783 | + return (pimpl_->dtd && pimpl_->dtd->name) ? (const char*)pimpl_->dtd->name : ""; |
784 | +} |
785 | + |
786 | +Glib::ustring Dtd::get_external_id() const |
787 | +{ |
788 | + return (pimpl_->dtd && pimpl_->dtd->ExternalID) ? (const char*)pimpl_->dtd->ExternalID : ""; |
789 | +} |
790 | + |
791 | +Glib::ustring Dtd::get_system_id() const |
792 | +{ |
793 | + return (pimpl_->dtd && pimpl_->dtd->SystemID) ? (const char*)pimpl_->dtd->SystemID : ""; |
794 | +} |
795 | + |
796 | +_xmlDtd* Dtd::cobj() noexcept |
797 | +{ |
798 | + return pimpl_->dtd; |
799 | +} |
800 | + |
801 | +const _xmlDtd* Dtd::cobj() const noexcept |
802 | +{ |
803 | + return pimpl_->dtd; |
804 | +} |
805 | + |
806 | +void Dtd::release_underlying() |
807 | +{ |
808 | + if (pimpl_->dtd) |
809 | + { |
810 | + pimpl_->dtd->_private = nullptr; |
811 | + if (pimpl_->is_dtd_owner) |
812 | + { |
813 | + xmlFreeDtd(pimpl_->dtd); |
814 | + pimpl_->is_dtd_owner = false; |
815 | + } |
816 | + pimpl_->dtd = nullptr; |
817 | + } |
818 | +} |
819 | + |
820 | +} //namespace xmlpp |
821 | |
822 | === added file 'src/libxml++/dtd.h' |
823 | --- src/libxml++/dtd.h 1970-01-01 00:00:00 +0000 |
824 | +++ src/libxml++/dtd.h 2016-11-06 17:18:04 +0000 |
825 | @@ -0,0 +1,136 @@ |
826 | +/* dtd.h |
827 | + * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and |
828 | + * are covered by the GNU Lesser General Public License, which should be |
829 | + * included with libxml++ as the file COPYING. |
830 | + */ |
831 | + |
832 | +#ifndef __LIBXMLPP_DTD_H |
833 | +#define __LIBXMLPP_DTD_H |
834 | + |
835 | +#include <libxml++/noncopyable.h> |
836 | +#include <glibmm/ustring.h> |
837 | +#include <string> |
838 | +#include <memory> // std::unique_ptr |
839 | + |
840 | +#ifndef DOXYGEN_SHOULD_SKIP_THIS |
841 | +extern "C" { |
842 | + struct _xmlDtd; |
843 | +} |
844 | +#endif //DOXYGEN_SHOULD_SKIP_THIS |
845 | + |
846 | +namespace xmlpp |
847 | +{ |
848 | + |
849 | +//TODO: Derive from Node? |
850 | +// See https://bugzilla.gnome.org/show_bug.cgi?id=754673#c8 for an explanation |
851 | +// why it has not been done in libxml++ 3.0. |
852 | +/** Represents an XML DTD for validating XML files. |
853 | + * DTD = Document Type Definition |
854 | + */ |
855 | +class Dtd : public NonCopyable |
856 | +{ |
857 | +public: |
858 | + Dtd(); |
859 | + |
860 | + /** Create a Dtd from the underlying libxml DTD element. |
861 | + * @param dtd A pointer to the libxml DTD element. |
862 | + * @param take_ownership If <tt>true</tt>, this Dtd instance takes ownership of |
863 | + * the libxml DTD element. The caller must not delete it.<br> |
864 | + * If <tt>false</tt>, this Dtd does not take ownership of the libxml |
865 | + * DTD element. The caller must guarantee that the libxml DTD element |
866 | + * exists as long as this Dtd keeps a pointer to it. The caller is |
867 | + * responsible for deleting the libxml DTD element when it's no longer |
868 | + * needed, unless it belongs to a Document, in which case it's deleted |
869 | + * when the Document is deleted. |
870 | + */ |
871 | + explicit Dtd(_xmlDtd* dtd, bool take_ownership = false); |
872 | + |
873 | + /** Create a Dtd and parse an external subset (DTD file) immediately. |
874 | + * |
875 | + * @newin{3,0} |
876 | + * |
877 | + * @param filename The URL of the DTD. |
878 | + * @throws xmlpp::parse_error |
879 | + */ |
880 | + explicit Dtd(const std::string& filename); |
881 | + |
882 | + /** Create a Dtd and parse an external subset (DTD file) immediately. |
883 | + * |
884 | + * @newin{3,0} |
885 | + * |
886 | + * @param external The external ID of the DTD. |
887 | + * @param system The URL of the DTD. |
888 | + * @throws xmlpp::parse_error |
889 | + */ |
890 | + Dtd(const Glib::ustring& external, const Glib::ustring& system); |
891 | + |
892 | + ~Dtd() override; |
893 | + |
894 | + /** Parse an external subset (DTD file). |
895 | + * If another DTD has been parsed before, that DTD is replaced by the new one |
896 | + * (deleted if this Dtd owns it). |
897 | + * |
898 | + * @newin{3,0} |
899 | + * |
900 | + * @param filename The URL of the DTD. |
901 | + * @throws xmlpp::parse_error |
902 | + */ |
903 | + void parse_file(const std::string& filename); |
904 | + |
905 | + /** Parse an external subset (DTD file). |
906 | + * If another DTD has been parsed before, that DTD is replaced by the new one |
907 | + * (deleted if this Dtd owns it). |
908 | + * |
909 | + * @newin{3,0} |
910 | + * |
911 | + * @param external The external ID of the DTD. |
912 | + * @param system The URL of the DTD. |
913 | + * @throws xmlpp::parse_error |
914 | + */ |
915 | + void parse_subset(const Glib::ustring& external, const Glib::ustring& system); |
916 | + |
917 | + /** Parse a DTD from a string. |
918 | + * If another DTD has been parsed before, that DTD is replaced by the new one |
919 | + * (deleted if this Dtd owns it). |
920 | + * |
921 | + * @newin{3,0} |
922 | + * |
923 | + * @param contents The DTD as a string. |
924 | + * @throws xmlpp::parse_error |
925 | + */ |
926 | + void parse_memory(const Glib::ustring& contents); |
927 | + |
928 | + /** Parse a DTD from a stream. |
929 | + * If another DTD has been parsed before, that DTD is replaced by the new one |
930 | + * (deleted if this Dtd owns it). |
931 | + * |
932 | + * @newin{3,0} |
933 | + * |
934 | + * @param in The stream. |
935 | + * @throws xmlpp::parse_error |
936 | + */ |
937 | + void parse_stream(std::istream& in); |
938 | + |
939 | + Glib::ustring get_name() const; |
940 | + Glib::ustring get_external_id() const; |
941 | + Glib::ustring get_system_id() const; |
942 | + |
943 | + /** Access the underlying libxml implementation. |
944 | + */ |
945 | + _xmlDtd* cobj() noexcept; |
946 | + |
947 | + /** Access the underlying libxml implementation. |
948 | + */ |
949 | + const _xmlDtd* cobj() const noexcept; |
950 | + |
951 | +protected: |
952 | + void release_underlying(); |
953 | + |
954 | +private: |
955 | + struct Impl; |
956 | + std::unique_ptr<Impl> pimpl_; |
957 | +}; |
958 | + |
959 | +} // namespace xmlpp |
960 | + |
961 | +#endif //__LIBXMLPP_DTD_H |
962 | |
963 | === added directory 'src/libxml++/exceptions' |
964 | === added file 'src/libxml++/exceptions/exception.cc' |
965 | --- src/libxml++/exceptions/exception.cc 1970-01-01 00:00:00 +0000 |
966 | +++ src/libxml++/exceptions/exception.cc 2016-11-06 17:18:04 +0000 |
967 | @@ -0,0 +1,125 @@ |
968 | +#include "exception.h" |
969 | +#include <libxml/xmlerror.h> |
970 | +#include <libxml/parser.h> |
971 | +#include <cstdio> |
972 | +#include <vector> |
973 | + |
974 | +namespace xmlpp { |
975 | + |
976 | +exception::exception(const Glib::ustring& message) |
977 | +: message_(message) |
978 | +{ |
979 | +} |
980 | + |
981 | +exception::~exception() noexcept |
982 | +{} |
983 | + |
984 | +const char* exception::what() const noexcept |
985 | +{ |
986 | + return message_.c_str(); |
987 | +} |
988 | + |
989 | +void exception::raise() const |
990 | +{ |
991 | + throw *this; |
992 | +} |
993 | + |
994 | +exception* exception::clone() const |
995 | +{ |
996 | + return new exception(*this); |
997 | +} |
998 | + |
999 | +Glib::ustring format_xml_error(const _xmlError* error) |
1000 | +{ |
1001 | + if (!error) |
1002 | + error = xmlGetLastError(); |
1003 | + |
1004 | + if (!error || error->code == XML_ERR_OK) |
1005 | + return ""; // No error |
1006 | + |
1007 | + Glib::ustring str; |
1008 | + |
1009 | + if (error->file && *error->file != '\0') |
1010 | + { |
1011 | + str += "File "; |
1012 | + str += error->file; |
1013 | + } |
1014 | + |
1015 | + if (error->line > 0) |
1016 | + { |
1017 | + str += (str.empty() ? "Line " : ", line ") + Glib::ustring::format(error->line); |
1018 | + if (error->int2 > 0) |
1019 | + str += ", column " + Glib::ustring::format(error->int2); |
1020 | + } |
1021 | + |
1022 | + const bool two_lines = !str.empty(); |
1023 | + if (two_lines) |
1024 | + str += ' '; |
1025 | + |
1026 | + switch (error->level) |
1027 | + { |
1028 | + case XML_ERR_WARNING: |
1029 | + str += "(warning):"; |
1030 | + break; |
1031 | + case XML_ERR_ERROR: |
1032 | + str += "(error):"; |
1033 | + break; |
1034 | + case XML_ERR_FATAL: |
1035 | + str += "(fatal):"; |
1036 | + break; |
1037 | + default: |
1038 | + str += "():"; |
1039 | + break; |
1040 | + } |
1041 | + |
1042 | + str += two_lines ? '\n' : ' '; |
1043 | + |
1044 | + if (error->message && *error->message != '\0') |
1045 | + str += error->message; |
1046 | + else |
1047 | + str += "Error code " + Glib::ustring::format(error->code); |
1048 | + |
1049 | + // If the string does not end with end-of-line, append an end-of-line. |
1050 | + if (*str.rbegin() != '\n') |
1051 | + str += '\n'; |
1052 | + |
1053 | + return str; |
1054 | +} |
1055 | + |
1056 | +Glib::ustring format_xml_parser_error(const _xmlParserCtxt* parser_context) |
1057 | +{ |
1058 | + if (!parser_context) |
1059 | + return "Error. xmlpp::format_xml_parser_error() called with parser_context == nullptr\n"; |
1060 | + |
1061 | + const auto error = xmlCtxtGetLastError(const_cast<_xmlParserCtxt*>(parser_context)); |
1062 | + |
1063 | + if (!error) |
1064 | + return ""; // No error |
1065 | + |
1066 | + Glib::ustring str; |
1067 | + |
1068 | + if (!parser_context->wellFormed) |
1069 | + str += "Document not well-formed.\n"; |
1070 | + |
1071 | + return str + format_xml_error(error); |
1072 | +} |
1073 | + |
1074 | +Glib::ustring format_printf_message(const char* fmt, va_list args) |
1075 | +{ |
1076 | + // This code was inspired by the example at |
1077 | + // http://en.cppreference.com/w/cpp/io/c/vfprintf |
1078 | + va_list args2; |
1079 | + va_copy(args2, args); |
1080 | + // Number of characters (bytes) in the resulting string; |
1081 | + // error, if < 0. |
1082 | + const int nchar = std::vsnprintf(nullptr, 0, fmt, args2); |
1083 | + va_end(args2); |
1084 | + if (nchar < 0) |
1085 | + return Glib::ustring::format("Error code from std::vsnprintf = ", nchar); |
1086 | + |
1087 | + std::vector<char> buf(nchar+1); |
1088 | + std::vsnprintf(buf.data(), buf.size(), fmt, args); |
1089 | + return Glib::ustring(buf.data()); |
1090 | +} |
1091 | + |
1092 | +} //namespace xmlpp |
1093 | |
1094 | === added file 'src/libxml++/exceptions/exception.h' |
1095 | --- src/libxml++/exceptions/exception.h 1970-01-01 00:00:00 +0000 |
1096 | +++ src/libxml++/exceptions/exception.h 2016-11-06 17:18:04 +0000 |
1097 | @@ -0,0 +1,99 @@ |
1098 | +/* exception.h |
1099 | + * |
1100 | + * Copyright (C) 2002 The libxml++ development team |
1101 | + * |
1102 | + * This library is free software; you can redistribute it and/or |
1103 | + * modify it under the terms of the GNU Library General Public |
1104 | + * License as published by the Free Software Foundation; either |
1105 | + * version 2 of the License, or (at your option) any later version. |
1106 | + * |
1107 | + * This library is distributed in the hope that it will be useful, |
1108 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1109 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1110 | + * Library General Public License for more details. |
1111 | + * |
1112 | + * You should have received a copy of the GNU Library General Public |
1113 | + * License along with this library; if not, write to the Free |
1114 | + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
1115 | + */ |
1116 | + |
1117 | +#ifndef __LIBXMLPP_EXCEPTION_H |
1118 | +#define __LIBXMLPP_EXCEPTION_H |
1119 | + |
1120 | +#include <exception> |
1121 | +#include <cstdarg> // va_list |
1122 | +#include <glibmm/ustring.h> |
1123 | + |
1124 | +#include <libxml++/libxml++config.h> |
1125 | + |
1126 | +extern "C" { |
1127 | + struct _xmlError; |
1128 | + struct _xmlParserCtxt; |
1129 | +} |
1130 | + |
1131 | +namespace xmlpp |
1132 | +{ |
1133 | + |
1134 | +/** Base class for all xmlpp exceptions. |
1135 | + */ |
1136 | +class LIBXMLPP_API exception : public std::exception |
1137 | +{ |
1138 | +public: |
1139 | + explicit exception(const Glib::ustring& message); |
1140 | + ~exception() noexcept override; |
1141 | + |
1142 | + const char* what() const noexcept override; |
1143 | + |
1144 | + virtual void raise() const; |
1145 | + virtual exception* clone() const; |
1146 | + |
1147 | +private: |
1148 | + Glib::ustring message_; |
1149 | +}; |
1150 | + |
1151 | +/** Format an _xmlError struct into a text string, suitable for printing. |
1152 | + * |
1153 | + * @newin{2,36} |
1154 | + * |
1155 | + * @param error Pointer to an _xmlError struct or <tt>nullptr</tt>. |
1156 | + * If <tt>nullptr</tt>, the error returned by xmlGetLastError() is used. |
1157 | + * @returns A formatted text string. If the error struct does not contain an |
1158 | + * error (error->code == XML_ERR_OK), an empty string is returned. |
1159 | + */ |
1160 | +Glib::ustring format_xml_error(const _xmlError* error = nullptr); |
1161 | + |
1162 | +/** Format a parser error into a text string, suitable for printing. |
1163 | + * |
1164 | + * @newin{2,36} |
1165 | + * |
1166 | + * @param parser_context Pointer to an _xmlParserCtxt struct. |
1167 | + * @returns A formatted text string. If the parser context does not contain an |
1168 | + * error (parser_context->lastError.code == XML_ERR_OK), an empty |
1169 | + * string is returned. |
1170 | + */ |
1171 | +Glib::ustring format_xml_parser_error(const _xmlParserCtxt* parser_context); |
1172 | + |
1173 | +/** Format a message from a function with C-style variadic parameters. |
1174 | + * |
1175 | + * Helper function that formats a message supplied in the form of a printf-style |
1176 | + * format specification and zero or more ... parameters. |
1177 | + * |
1178 | + * @code |
1179 | + * // Typical call: |
1180 | + * void f(const char* fmt, ...) |
1181 | + * { |
1182 | + * va_list args; |
1183 | + * va_start(args, fmt); |
1184 | + * Glib::ustring msg = xmlpp::format_printf_message(fmt, args); |
1185 | + * va_end(args); |
1186 | + * // ... |
1187 | + * } |
1188 | + * @endcode |
1189 | + * |
1190 | + * @newin{3,0} |
1191 | + */ |
1192 | +Glib::ustring format_printf_message(const char* fmt, va_list args); |
1193 | + |
1194 | +} // namespace xmlpp |
1195 | + |
1196 | +#endif // __LIBXMLPP_EXCEPTION_H |
1197 | |
1198 | === added file 'src/libxml++/exceptions/internal_error.cc' |
1199 | --- src/libxml++/exceptions/internal_error.cc 1970-01-01 00:00:00 +0000 |
1200 | +++ src/libxml++/exceptions/internal_error.cc 2016-11-06 17:18:04 +0000 |
1201 | @@ -0,0 +1,23 @@ |
1202 | +#include "internal_error.h" |
1203 | + |
1204 | +namespace xmlpp { |
1205 | + |
1206 | +internal_error::internal_error(const Glib::ustring& message) |
1207 | +: exception(message) |
1208 | +{ |
1209 | +} |
1210 | + |
1211 | +internal_error::~internal_error() noexcept |
1212 | +{} |
1213 | + |
1214 | +void internal_error::raise() const |
1215 | +{ |
1216 | + throw *this; |
1217 | +} |
1218 | + |
1219 | +exception* internal_error::clone() const |
1220 | +{ |
1221 | + return new internal_error(*this); |
1222 | +} |
1223 | + |
1224 | +} //namespace xmlpp |
1225 | |
1226 | === added file 'src/libxml++/exceptions/internal_error.h' |
1227 | --- src/libxml++/exceptions/internal_error.h 1970-01-01 00:00:00 +0000 |
1228 | +++ src/libxml++/exceptions/internal_error.h 2016-11-06 17:18:04 +0000 |
1229 | @@ -0,0 +1,39 @@ |
1230 | +/* internal_error.h |
1231 | + * |
1232 | + * Copyright (C) 2002 The libxml++ development team |
1233 | + * |
1234 | + * This library is free software; you can redistribute it and/or |
1235 | + * modify it under the terms of the GNU Library General Public |
1236 | + * License as published by the Free Software Foundation; either |
1237 | + * version 2 of the License, or (at your option) any later version. |
1238 | + * |
1239 | + * This library is distributed in the hope that it will be useful, |
1240 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1241 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1242 | + * Library General Public License for more details. |
1243 | + * |
1244 | + * You should have received a copy of the GNU Library General Public |
1245 | + * License along with this library; if not, write to the Free |
1246 | + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
1247 | + */ |
1248 | + |
1249 | +#ifndef __LIBXMLPP_INTERNAL_ERROR_H |
1250 | +#define __LIBXMLPP_INTERNAL_ERROR_H |
1251 | + |
1252 | +#include <libxml++/exceptions/exception.h> |
1253 | + |
1254 | +namespace xmlpp { |
1255 | + |
1256 | +class internal_error : public exception |
1257 | +{ |
1258 | +public: |
1259 | + explicit internal_error(const Glib::ustring& message); |
1260 | + ~internal_error() noexcept override; |
1261 | + |
1262 | + void raise() const override; |
1263 | + exception* clone() const override; |
1264 | +}; |
1265 | + |
1266 | +} // namespace xmlpp |
1267 | + |
1268 | +#endif // __LIBXMLPP_INTERNAL_ERROR_H |
1269 | |
1270 | === added file 'src/libxml++/exceptions/parse_error.cc' |
1271 | --- src/libxml++/exceptions/parse_error.cc 1970-01-01 00:00:00 +0000 |
1272 | +++ src/libxml++/exceptions/parse_error.cc 2016-11-06 17:18:04 +0000 |
1273 | @@ -0,0 +1,23 @@ |
1274 | +#include "parse_error.h" |
1275 | + |
1276 | +namespace xmlpp { |
1277 | + |
1278 | +parse_error::parse_error(const Glib::ustring& message) |
1279 | +: exception(message) |
1280 | +{ |
1281 | +} |
1282 | + |
1283 | +parse_error::~parse_error() noexcept |
1284 | +{} |
1285 | + |
1286 | +void parse_error::raise() const |
1287 | +{ |
1288 | + throw *this; |
1289 | +} |
1290 | + |
1291 | +exception* parse_error::clone() const |
1292 | +{ |
1293 | + return new parse_error(*this); |
1294 | +} |
1295 | + |
1296 | +} //namespace xmlpp |
1297 | |
1298 | === added file 'src/libxml++/exceptions/parse_error.h' |
1299 | --- src/libxml++/exceptions/parse_error.h 1970-01-01 00:00:00 +0000 |
1300 | +++ src/libxml++/exceptions/parse_error.h 2016-11-06 17:18:04 +0000 |
1301 | @@ -0,0 +1,42 @@ |
1302 | +/* parse_error.h |
1303 | + * |
1304 | + * Copyright (C) 2002 The libxml++ development team |
1305 | + * |
1306 | + * This library is free software; you can redistribute it and/or |
1307 | + * modify it under the terms of the GNU Library General Public |
1308 | + * License as published by the Free Software Foundation; either |
1309 | + * version 2 of the License, or (at your option) any later version. |
1310 | + * |
1311 | + * This library is distributed in the hope that it will be useful, |
1312 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1313 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1314 | + * Library General Public License for more details. |
1315 | + * |
1316 | + * You should have received a copy of the GNU Library General Public |
1317 | + * License along with this library; if not, write to the Free |
1318 | + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
1319 | + */ |
1320 | + |
1321 | +#ifndef __LIBXMLPP_PARSE_ERROR_H |
1322 | +#define __LIBXMLPP_PARSE_ERROR_H |
1323 | + |
1324 | +#include <libxml++/exceptions/exception.h> |
1325 | + |
1326 | +namespace xmlpp |
1327 | +{ |
1328 | + |
1329 | +/** This exception will be thrown when the parser encounters an error in the XML document. |
1330 | + */ |
1331 | +class parse_error : public exception |
1332 | +{ |
1333 | +public: |
1334 | + explicit parse_error(const Glib::ustring& message); |
1335 | + ~parse_error() noexcept override; |
1336 | + |
1337 | + void raise() const override; |
1338 | + exception* clone() const override; |
1339 | +}; |
1340 | + |
1341 | +} // namespace xmlpp |
1342 | + |
1343 | +#endif // __LIBXMLPP_PARSE_ERROR_H |
1344 | |
1345 | === added file 'src/libxml++/exceptions/validity_error.cc' |
1346 | --- src/libxml++/exceptions/validity_error.cc 1970-01-01 00:00:00 +0000 |
1347 | +++ src/libxml++/exceptions/validity_error.cc 2016-11-06 17:18:04 +0000 |
1348 | @@ -0,0 +1,23 @@ |
1349 | +#include "validity_error.h" |
1350 | + |
1351 | +namespace xmlpp { |
1352 | + |
1353 | +validity_error::validity_error(const Glib::ustring& message) |
1354 | +: parse_error(message) |
1355 | +{ |
1356 | +} |
1357 | + |
1358 | +validity_error::~validity_error() noexcept |
1359 | +{} |
1360 | + |
1361 | +void validity_error::raise() const |
1362 | +{ |
1363 | + throw *this; |
1364 | +} |
1365 | + |
1366 | +exception* validity_error::clone() const |
1367 | +{ |
1368 | + return new validity_error(*this); |
1369 | +} |
1370 | + |
1371 | +} //namespace xmlpp |
1372 | |
1373 | === added file 'src/libxml++/exceptions/validity_error.h' |
1374 | --- src/libxml++/exceptions/validity_error.h 1970-01-01 00:00:00 +0000 |
1375 | +++ src/libxml++/exceptions/validity_error.h 2016-11-06 17:18:04 +0000 |
1376 | @@ -0,0 +1,42 @@ |
1377 | +/* validity_error.h |
1378 | + * |
1379 | + * Copyright (C) 2002 The libxml++ development team |
1380 | + * |
1381 | + * This library is free software; you can redistribute it and/or |
1382 | + * modify it under the terms of the GNU Library General Public |
1383 | + * License as published by the Free Software Foundation; either |
1384 | + * version 2 of the License, or (at your option) any later version. |
1385 | + * |
1386 | + * This library is distributed in the hope that it will be useful, |
1387 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1388 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1389 | + * Library General Public License for more details. |
1390 | + * |
1391 | + * You should have received a copy of the GNU Library General Public |
1392 | + * License along with this library; if not, write to the Free |
1393 | + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
1394 | + */ |
1395 | + |
1396 | +#ifndef __LIBXMLPP_VALIDITY_ERROR_H |
1397 | +#define __LIBXMLPP_VALIDITY_ERROR_H |
1398 | + |
1399 | +#include <libxml++/exceptions/parse_error.h> |
1400 | + |
1401 | +namespace xmlpp |
1402 | +{ |
1403 | + |
1404 | +/** This exception will be thrown when the parser encounters a validity error in the XML document. |
1405 | + */ |
1406 | +class validity_error : public parse_error |
1407 | +{ |
1408 | +public: |
1409 | + explicit validity_error(const Glib::ustring& message); |
1410 | + ~validity_error() noexcept override; |
1411 | + |
1412 | + void raise() const override; |
1413 | + exception* clone() const override; |
1414 | +}; |
1415 | + |
1416 | +} // namespace xmlpp |
1417 | + |
1418 | +#endif // __LIBXMLPP_VALIDITY_ERROR_H |
1419 | |
1420 | === added file 'src/libxml++/exceptions/wrapped_exception.cc' |
1421 | --- src/libxml++/exceptions/wrapped_exception.cc 1970-01-01 00:00:00 +0000 |
1422 | +++ src/libxml++/exceptions/wrapped_exception.cc 2016-11-06 17:18:04 +0000 |
1423 | @@ -0,0 +1,46 @@ |
1424 | +/* Copyright (C) 2015 The libxml++ development team |
1425 | + * |
1426 | + * This library is free software; you can redistribute it and/or |
1427 | + * modify it under the terms of the GNU Lesser General Public |
1428 | + * License as published by the Free Software Foundation; either |
1429 | + * version 2.1 of the License, or (at your option) any later version. |
1430 | + * |
1431 | + * This library is distributed in the hope that it will be useful, |
1432 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1433 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1434 | + * Lesser General Public License for more details. |
1435 | + * |
1436 | + * You should have received a copy of the GNU Lesser General Public |
1437 | + * License along with this library; if not, write to the Free Software |
1438 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1439 | + */ |
1440 | + |
1441 | +#include "wrapped_exception.h" |
1442 | + |
1443 | +namespace xmlpp |
1444 | +{ |
1445 | + |
1446 | +#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR |
1447 | + |
1448 | +wrapped_exception::wrapped_exception(std::exception_ptr exception_ptr) |
1449 | + : exception("Wrapped exception"), exception_ptr_(exception_ptr) |
1450 | +{ |
1451 | +} |
1452 | + |
1453 | +wrapped_exception::~wrapped_exception() noexcept |
1454 | +{ |
1455 | +} |
1456 | + |
1457 | +void wrapped_exception::raise() const |
1458 | +{ |
1459 | + std::rethrow_exception(exception_ptr_); |
1460 | +} |
1461 | + |
1462 | +exception* wrapped_exception::clone() const |
1463 | +{ |
1464 | + return new wrapped_exception(exception_ptr_); |
1465 | +} |
1466 | + |
1467 | +#endif // LIBXMLXX_HAVE_EXCEPTION_PTR |
1468 | + |
1469 | +} // namespace xmlpp |
1470 | |
1471 | === added file 'src/libxml++/exceptions/wrapped_exception.h' |
1472 | --- src/libxml++/exceptions/wrapped_exception.h 1970-01-01 00:00:00 +0000 |
1473 | +++ src/libxml++/exceptions/wrapped_exception.h 2016-11-06 17:18:04 +0000 |
1474 | @@ -0,0 +1,56 @@ |
1475 | +/* Copyright (C) 2015 The libxml++ development team |
1476 | + * |
1477 | + * This library is free software; you can redistribute it and/or |
1478 | + * modify it under the terms of the GNU Lesser General Public |
1479 | + * License as published by the Free Software Foundation; either |
1480 | + * version 2.1 of the License, or (at your option) any later version. |
1481 | + * |
1482 | + * This library is distributed in the hope that it will be useful, |
1483 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1484 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1485 | + * Lesser General Public License for more details. |
1486 | + * |
1487 | + * You should have received a copy of the GNU Lesser General Public |
1488 | + * License along with this library; if not, write to the Free Software |
1489 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1490 | + */ |
1491 | + |
1492 | +#ifndef __LIBXMLPP_WRAPPED_EXCEPTION_H |
1493 | +#define __LIBXMLPP_WRAPPED_EXCEPTION_H |
1494 | + |
1495 | +#include <exception> |
1496 | + |
1497 | +#include <libxml++/exceptions/exception.h> |
1498 | +#include <libxml++config.h> |
1499 | + |
1500 | +namespace xmlpp |
1501 | +{ |
1502 | + |
1503 | +#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR |
1504 | + |
1505 | +#ifndef DOXYGEN_SHOULD_SKIP_THIS |
1506 | +/** Helper class for propagating an exception through C code. |
1507 | + * Should not be used by applications. |
1508 | + * Does not exist in systems that don't support std::exception_ptr. |
1509 | + * |
1510 | + * @newin{2,40} |
1511 | + */ |
1512 | +class wrapped_exception : public exception |
1513 | +{ |
1514 | +public: |
1515 | + explicit wrapped_exception(std::exception_ptr exception_ptr); |
1516 | + ~wrapped_exception() noexcept override; |
1517 | + |
1518 | + void raise() const override; |
1519 | + exception* clone() const override; |
1520 | + |
1521 | +private: |
1522 | + std::exception_ptr exception_ptr_; |
1523 | +}; |
1524 | +#endif //DOXYGEN_SHOULD_SKIP_THIS |
1525 | + |
1526 | +#endif // LIBXMLXX_HAVE_EXCEPTION_PTR |
1527 | + |
1528 | +} // namespace xmlpp |
1529 | + |
1530 | +#endif // __LIBXMLPP_WRAPPED_EXCEPTION_H |
1531 | |
1532 | === added directory 'src/libxml++/io' |
1533 | === added file 'src/libxml++/io/istreamparserinputbuffer.cc' |
1534 | --- src/libxml++/io/istreamparserinputbuffer.cc 1970-01-01 00:00:00 +0000 |
1535 | +++ src/libxml++/io/istreamparserinputbuffer.cc 2016-11-06 17:18:04 +0000 |
1536 | @@ -0,0 +1,44 @@ |
1537 | +/* istreamparserinputbuffer |
1538 | + * this file is part of libxml++ |
1539 | + * |
1540 | + * copyright (C) 2003 by libxml++ developer's team |
1541 | + * |
1542 | + * this file is covered by the GNU Lesser General Public License, |
1543 | + * which should be included with libxml++ as the file COPYING. |
1544 | + */ |
1545 | + |
1546 | +#include <libxml++/io/istreamparserinputbuffer.h> |
1547 | + |
1548 | +namespace xmlpp |
1549 | +{ |
1550 | + IStreamParserInputBuffer::IStreamParserInputBuffer( |
1551 | + std::istream & input) |
1552 | + : ParserInputBuffer(), input_(input) |
1553 | + { |
1554 | + } |
1555 | + |
1556 | + IStreamParserInputBuffer::~IStreamParserInputBuffer() |
1557 | + { |
1558 | + } |
1559 | + |
1560 | + int IStreamParserInputBuffer::do_read( |
1561 | + char * buffer, |
1562 | + int len) |
1563 | + { |
1564 | + int l=0; |
1565 | + if(input_) |
1566 | + { |
1567 | + // This is the correct statement - but gcc 2.95.3 lacks this method |
1568 | + //l = input_.readsome(buffer, len); |
1569 | + input_.read(buffer, len); |
1570 | + l = input_.gcount(); |
1571 | + } |
1572 | + |
1573 | + return l; |
1574 | + } |
1575 | + |
1576 | + bool IStreamParserInputBuffer::do_close() |
1577 | + { |
1578 | + return input_.good(); |
1579 | + } |
1580 | +} |
1581 | |
1582 | === added file 'src/libxml++/io/istreamparserinputbuffer.h' |
1583 | --- src/libxml++/io/istreamparserinputbuffer.h 1970-01-01 00:00:00 +0000 |
1584 | +++ src/libxml++/io/istreamparserinputbuffer.h 2016-11-06 17:18:04 +0000 |
1585 | @@ -0,0 +1,36 @@ |
1586 | +/* inputstreamparserinputbuffer.h |
1587 | + * this file is part of libxml++ |
1588 | + * |
1589 | + * copyright (C) 2003 by libxml++ developer's team |
1590 | + * |
1591 | + * this file is covered by the GNU Lesser General Public License, |
1592 | + * which should be included with libxml++ as the file COPYING. |
1593 | + */ |
1594 | + |
1595 | +#ifndef __LIBXMLPP_ISTREAMPARSEROUTPUTBUFFER_H |
1596 | +#define __LIBXMLPP_ISTREAMPARSEROUTPUTBUFFER_H |
1597 | + |
1598 | +#include <libxml++/io/parserinputbuffer.h> |
1599 | + |
1600 | +#include <istream> |
1601 | + |
1602 | +namespace xmlpp |
1603 | +{ |
1604 | + class IStreamParserInputBuffer: public ParserInputBuffer |
1605 | + { |
1606 | + public: |
1607 | + /** |
1608 | + * @param input The istream datas will be read from |
1609 | + */ |
1610 | + IStreamParserInputBuffer(std::istream& input); |
1611 | + ~IStreamParserInputBuffer() override; |
1612 | + |
1613 | + private: |
1614 | + int do_read(char * buffer, int len) override; |
1615 | + bool do_close() override; |
1616 | + |
1617 | + std::istream& input_; |
1618 | + }; |
1619 | +} |
1620 | + |
1621 | +#endif |
1622 | |
1623 | === added file 'src/libxml++/io/parserinputbuffer.cc' |
1624 | --- src/libxml++/io/parserinputbuffer.cc 1970-01-01 00:00:00 +0000 |
1625 | +++ src/libxml++/io/parserinputbuffer.cc 2016-11-06 17:18:04 +0000 |
1626 | @@ -0,0 +1,84 @@ |
1627 | +/* parserinputbuffer.cc |
1628 | + * this file is part of libxml++ |
1629 | + * |
1630 | + * copyright (C) 2003 by libxml++ developer's team |
1631 | + * |
1632 | + * this file is covered by the GNU Lesser General Public License, |
1633 | + * which should be included with libxml++ as the file COPYING. |
1634 | + */ |
1635 | + |
1636 | +#include <libxml++/io/parserinputbuffer.h> |
1637 | +#include <libxml++/exceptions/internal_error.h> |
1638 | + |
1639 | +#include <libxml/globals.h> //Needed by libxml/xmlIO.h |
1640 | +#include <libxml/xmlIO.h> |
1641 | + |
1642 | +namespace xmlpp |
1643 | +{ |
1644 | + |
1645 | + struct ParserInputBufferCallback |
1646 | + { |
1647 | + static int on_read(void * context, char * buffer, int len) |
1648 | + { |
1649 | + auto tmp = static_cast<ParserInputBuffer*>(context); |
1650 | + return tmp->do_read(buffer, len); |
1651 | + } |
1652 | + |
1653 | + static int on_close(void * context) |
1654 | + { |
1655 | + auto tmp = static_cast<ParserInputBuffer*>(context); |
1656 | + return tmp->do_close(); |
1657 | + } |
1658 | + }; |
1659 | + |
1660 | + |
1661 | + ParserInputBuffer::ParserInputBuffer() |
1662 | + { |
1663 | + impl_ = xmlParserInputBufferCreateIO( |
1664 | + &ParserInputBufferCallback::on_read, |
1665 | + &ParserInputBufferCallback::on_close, |
1666 | + static_cast<void*>(this), |
1667 | + XML_CHAR_ENCODING_NONE); |
1668 | + if (!impl_) |
1669 | + { |
1670 | + throw internal_error("Cannot initialise underlying xmlParserInputBuffer"); |
1671 | + } |
1672 | + } |
1673 | + |
1674 | + ParserInputBuffer::~ParserInputBuffer() |
1675 | + { |
1676 | + } |
1677 | + |
1678 | + bool ParserInputBuffer::on_close() |
1679 | + { |
1680 | + bool result = do_close(); |
1681 | + // the underlying structure is being freed by libxml, the pointer will soon be |
1682 | + // invalid. |
1683 | + impl_ = nullptr; |
1684 | + |
1685 | + return result; |
1686 | + } |
1687 | + |
1688 | + int ParserInputBuffer::on_read( |
1689 | + char * buffer, |
1690 | + int len) |
1691 | + { |
1692 | + return do_read(buffer, len); |
1693 | + } |
1694 | + |
1695 | + bool ParserInputBuffer::do_close() |
1696 | + { |
1697 | + return true; |
1698 | + } |
1699 | + |
1700 | + _xmlParserInputBuffer* ParserInputBuffer::cobj() noexcept |
1701 | + { |
1702 | + return impl_; |
1703 | + } |
1704 | + |
1705 | + const _xmlParserInputBuffer* ParserInputBuffer::cobj() const noexcept |
1706 | + { |
1707 | + return impl_; |
1708 | + } |
1709 | + |
1710 | +} |
1711 | |
1712 | === added file 'src/libxml++/io/parserinputbuffer.h' |
1713 | --- src/libxml++/io/parserinputbuffer.h 1970-01-01 00:00:00 +0000 |
1714 | +++ src/libxml++/io/parserinputbuffer.h 2016-11-06 17:18:04 +0000 |
1715 | @@ -0,0 +1,75 @@ |
1716 | +/* parserinputbuffer.h |
1717 | + * this file is part of libxml++ |
1718 | + * |
1719 | + * copyright (C) 2003 by libxml++ developer's team |
1720 | + * |
1721 | + * this file is covered by the GNU Lesser General Public License, |
1722 | + * which should be included with libxml++ as the file COPYING. |
1723 | + */ |
1724 | + |
1725 | +#ifndef __LIBXMLPP_PARSERINPUTBUFFER_H |
1726 | +#define __LIBXMLPP_PARSERINPUTBUFFER_H |
1727 | + |
1728 | +#include <string> |
1729 | +#include <libxml++/noncopyable.h> |
1730 | + |
1731 | +extern "C" |
1732 | +{ |
1733 | + struct _xmlParserInputBuffer; |
1734 | +} |
1735 | + |
1736 | +namespace xmlpp |
1737 | +{ |
1738 | + struct ParserInputBufferCallback; |
1739 | + |
1740 | + /** Base class for xmlParserInputBuffer wrapper |
1741 | + * |
1742 | + * It can be derived from to create a new output buffer. |
1743 | + * A child class has to override do_write(), and possibly |
1744 | + * do_close() if some actions are required before buffer closing. |
1745 | + */ |
1746 | + class ParserInputBuffer: public NonCopyable |
1747 | + { |
1748 | + public: |
1749 | + ParserInputBuffer(); |
1750 | + ~ParserInputBuffer() override; |
1751 | + |
1752 | + public: |
1753 | + /** gives an access to the underlying libxml structure to the children |
1754 | + */ |
1755 | + _xmlParserInputBuffer* cobj() noexcept; |
1756 | + |
1757 | + /** gives an access to the underlying libxml structure to the children |
1758 | + */ |
1759 | + const _xmlParserInputBuffer* cobj() const noexcept; |
1760 | + |
1761 | + private: |
1762 | + int on_read(char * buffer, int len); |
1763 | + bool on_close(); |
1764 | + |
1765 | + /** Function called when some data are read from the buffer. |
1766 | + * @param buffer The datas encoded in the charset given to the constructor |
1767 | + * @param len bytes to read |
1768 | + * @return Number of bytes read |
1769 | + * |
1770 | + * This function MUST be overriden in derived classes. |
1771 | + */ |
1772 | + virtual int do_read(char * buffer, int len) = 0; |
1773 | + |
1774 | + /** Function called before closing the buffer. |
1775 | + * Derived classes should override it if some actions are required before |
1776 | + * closing the buffer, instead of doing them in the destructor. |
1777 | + */ |
1778 | + virtual bool do_close(); |
1779 | + |
1780 | + /** |
1781 | + * Underlying libxml2 structure. |
1782 | + */ |
1783 | + _xmlParserInputBuffer* impl_; |
1784 | + |
1785 | + friend struct ParserInputBufferCallback; |
1786 | + }; |
1787 | + |
1788 | +} |
1789 | + |
1790 | +#endif |
1791 | |
1792 | === added file 'src/libxml++/keepblanks.cc' |
1793 | --- src/libxml++/keepblanks.cc 1970-01-01 00:00:00 +0000 |
1794 | +++ src/libxml++/keepblanks.cc 2016-11-06 17:18:04 +0000 |
1795 | @@ -0,0 +1,29 @@ |
1796 | +/* keepblanks.cc |
1797 | + * libxml++ and this file are |
1798 | + * copyright (C) 2003 by The libxml++ Development Team, and |
1799 | + * are covered by the GNU Lesser General Public License, which should be |
1800 | + * included with libxml++ as the file COPYING. |
1801 | + */ |
1802 | + |
1803 | +#include <libxml++/keepblanks.h> |
1804 | + |
1805 | +#include <libxml/globals.h> |
1806 | + |
1807 | +namespace xmlpp |
1808 | +{ |
1809 | +#if _MSC_VER == 1200 // detect MSVC 6.0 |
1810 | + const bool KeepBlanks::Default = true; |
1811 | +#endif |
1812 | + |
1813 | + KeepBlanks::KeepBlanks(bool value) noexcept |
1814 | + { |
1815 | + oldIndentTreeOutput_ = xmlIndentTreeOutput; |
1816 | + oldKeepBlanksDefault_ = xmlKeepBlanksDefault( value?1:0 ); |
1817 | + } |
1818 | + |
1819 | + KeepBlanks::~KeepBlanks() noexcept |
1820 | + { |
1821 | + xmlKeepBlanksDefault(oldKeepBlanksDefault_); |
1822 | + xmlIndentTreeOutput = oldIndentTreeOutput_; |
1823 | + } |
1824 | +} |
1825 | |
1826 | === added file 'src/libxml++/keepblanks.h' |
1827 | --- src/libxml++/keepblanks.h 1970-01-01 00:00:00 +0000 |
1828 | +++ src/libxml++/keepblanks.h 2016-11-06 17:18:04 +0000 |
1829 | @@ -0,0 +1,35 @@ |
1830 | +/* keepblanks.h |
1831 | + * libxml++ and this file are |
1832 | + * copyright (C) 2003 by The libxml++ Development Team, and |
1833 | + * are covered by the GNU Lesser General Public License, which should be |
1834 | + * included with libxml++ as the file COPYING. |
1835 | + */ |
1836 | + |
1837 | +#ifndef __LIBXMLPP_KEEPBLANKS_H |
1838 | +#define __LIBXMLPP_KEEPBLANKS_H |
1839 | + |
1840 | +namespace xmlpp |
1841 | +{ |
1842 | + /** This class sets KeepBlanksDefault and IndentTreeOutput of libxmlpp |
1843 | + * and restores their initial values in its destructor. As a consequence |
1844 | + * the wanted setting is kept during instance lifetime. |
1845 | + */ |
1846 | + class KeepBlanks { |
1847 | + public: |
1848 | +#if _MSC_VER == 1200 // detect MSVC 6.0 |
1849 | + static const bool Default; |
1850 | +#else |
1851 | + static const bool Default = true; |
1852 | +#endif |
1853 | + |
1854 | + public: |
1855 | + KeepBlanks(bool value) noexcept; |
1856 | + ~KeepBlanks() noexcept; |
1857 | + |
1858 | + private: |
1859 | + int oldKeepBlanksDefault_; |
1860 | + int oldIndentTreeOutput_; |
1861 | + }; |
1862 | +} |
1863 | + |
1864 | +#endif // __LIBXMLPP_KEEPBLANKS_H |
1865 | |
1866 | === added file 'src/libxml++/libxml++config.h' |
1867 | --- src/libxml++/libxml++config.h 1970-01-01 00:00:00 +0000 |
1868 | +++ src/libxml++/libxml++config.h 2016-11-06 17:18:04 +0000 |
1869 | @@ -0,0 +1,26 @@ |
1870 | +/* libxml++config.h. Generated from libxml++config.h.in by configure. */ |
1871 | +#ifndef _LIBXMLPP_CONFIG_H |
1872 | +#define _LIBXMLPP_CONFIG_H |
1873 | + |
1874 | +#include <glibmmconfig.h> |
1875 | + |
1876 | +/* Define to omit deprecated API from the library. */ |
1877 | +/* #undef LIBXMLXX_DISABLE_DEPRECATED */ |
1878 | + |
1879 | +/* Defined if the C++ library supports std::exception_ptr. */ |
1880 | +#define LIBXMLXX_HAVE_EXCEPTION_PTR 1 |
1881 | + |
1882 | +/* Major version number of libxml++. */ |
1883 | +#define LIBXMLXX_MAJOR_VERSION 3 |
1884 | + |
1885 | +/* Minor version number of libxml++. */ |
1886 | +#define LIBXMLXX_MINOR_VERSION 0 |
1887 | + |
1888 | +/* Micro version number of libxml++. */ |
1889 | +#define LIBXMLXX_MICRO_VERSION 0 |
1890 | + |
1891 | +/* Create static library */ |
1892 | +#define LIBXMLPP_API |
1893 | + |
1894 | +#endif /* _LIBXMLPP_CONFIG_H */ |
1895 | + |
1896 | |
1897 | === added file 'src/libxml++/noncopyable.cc' |
1898 | --- src/libxml++/noncopyable.cc 1970-01-01 00:00:00 +0000 |
1899 | +++ src/libxml++/noncopyable.cc 2016-11-06 17:18:04 +0000 |
1900 | @@ -0,0 +1,21 @@ |
1901 | +/* noncopyable.cc |
1902 | + * libxml++ and this file are |
1903 | + * copyright (C) 2000 by The libxml++ Development Team, and |
1904 | + * are covered by the GNU Lesser General Public License, which should be |
1905 | + * included with libxml++ as the file COPYING. |
1906 | + */ |
1907 | + |
1908 | +#include <libxml++/noncopyable.h> |
1909 | + |
1910 | +namespace xmlpp |
1911 | +{ |
1912 | + |
1913 | +NonCopyable::NonCopyable() noexcept |
1914 | +{ |
1915 | +} |
1916 | + |
1917 | +NonCopyable::~NonCopyable() |
1918 | +{ |
1919 | +} |
1920 | + |
1921 | +} //namespace xmlpp |
1922 | |
1923 | === added file 'src/libxml++/noncopyable.h' |
1924 | --- src/libxml++/noncopyable.h 1970-01-01 00:00:00 +0000 |
1925 | +++ src/libxml++/noncopyable.h 2016-11-06 17:18:04 +0000 |
1926 | @@ -0,0 +1,31 @@ |
1927 | +/* noncopyable.h |
1928 | + * libxml++ and this file are |
1929 | + * copyright (C) 2000 by The libxml++ Development Team, and |
1930 | + * are covered by the GNU Lesser General Public License, which should be |
1931 | + * included with libxml++ as the file COPYING. |
1932 | + */ |
1933 | + |
1934 | +#ifndef __LIBXMLPP_NONCOPYABLE_H |
1935 | +#define __LIBXMLPP_NONCOPYABLE_H |
1936 | + |
1937 | +namespace xmlpp |
1938 | +{ |
1939 | + |
1940 | +/** A base for classes which cannot be copied or moved. |
1941 | + */ |
1942 | +class NonCopyable |
1943 | +{ |
1944 | +protected: |
1945 | + NonCopyable() noexcept; |
1946 | + virtual ~NonCopyable(); |
1947 | + |
1948 | + NonCopyable(const NonCopyable&) = delete; |
1949 | + NonCopyable& operator=(const NonCopyable&) = delete; |
1950 | + NonCopyable(NonCopyable&&) = delete; |
1951 | + NonCopyable& operator=(NonCopyable&&) = delete; |
1952 | +}; |
1953 | + |
1954 | +} // namespace xmlpp |
1955 | + |
1956 | +#endif //__LIBXMLPP_NONCOPYABLE_H |
1957 | + |
1958 | |
1959 | === added directory 'src/libxml++/parsers' |
1960 | === added file 'src/libxml++/parsers/parser.cc' |
1961 | --- src/libxml++/parsers/parser.cc 1970-01-01 00:00:00 +0000 |
1962 | +++ src/libxml++/parsers/parser.cc 2016-11-06 17:18:04 +0000 |
1963 | @@ -0,0 +1,365 @@ |
1964 | +/* parser.cc |
1965 | + * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and |
1966 | + * are covered by the GNU Lesser General Public License, which should be |
1967 | + * included with libxml++ as the file COPYING. |
1968 | + */ |
1969 | + |
1970 | +#include "libxml++/exceptions/wrapped_exception.h" |
1971 | +#include "libxml++/parsers/parser.h" |
1972 | + |
1973 | +#include <libxml/parser.h> |
1974 | + |
1975 | +namespace xmlpp |
1976 | +{ |
1977 | + |
1978 | +struct Parser::Impl |
1979 | +{ |
1980 | + Impl() |
1981 | + : |
1982 | + throw_messages_(true), validate_(false), substitute_entities_(false), |
1983 | + include_default_attributes_(false), set_options_(0), clear_options_(0) |
1984 | + {} |
1985 | + |
1986 | + // Built gradually - used in an exception at the end of parsing. |
1987 | + Glib::ustring parser_error_; |
1988 | + Glib::ustring parser_warning_; |
1989 | + Glib::ustring validate_error_; |
1990 | + Glib::ustring validate_warning_; |
1991 | + |
1992 | + bool throw_messages_; |
1993 | + bool validate_; |
1994 | + bool substitute_entities_; |
1995 | + bool include_default_attributes_; |
1996 | + int set_options_; |
1997 | + int clear_options_; |
1998 | +}; |
1999 | + |
2000 | +Parser::Parser() |
2001 | +: context_(nullptr), exception_(nullptr), pimpl_(new Impl) |
2002 | +{ |
2003 | +} |
2004 | + |
2005 | +Parser::~Parser() |
2006 | +{ |
2007 | + release_underlying(); |
2008 | +} |
2009 | + |
2010 | +void Parser::set_validate(bool val) noexcept |
2011 | +{ |
2012 | + pimpl_->validate_ = val; |
2013 | +} |
2014 | + |
2015 | +bool Parser::get_validate() const noexcept |
2016 | +{ |
2017 | + return pimpl_->validate_; |
2018 | +} |
2019 | + |
2020 | +void Parser::set_substitute_entities(bool val) noexcept |
2021 | +{ |
2022 | + pimpl_->substitute_entities_ = val; |
2023 | +} |
2024 | + |
2025 | +bool Parser::get_substitute_entities() const noexcept |
2026 | +{ |
2027 | + return pimpl_->substitute_entities_; |
2028 | +} |
2029 | + |
2030 | +void Parser::set_throw_messages(bool val) noexcept |
2031 | +{ |
2032 | + pimpl_->throw_messages_ = val; |
2033 | +} |
2034 | + |
2035 | +bool Parser::get_throw_messages() const noexcept |
2036 | +{ |
2037 | + return pimpl_->throw_messages_; |
2038 | +} |
2039 | + |
2040 | +void Parser::set_include_default_attributes(bool val) noexcept |
2041 | +{ |
2042 | + pimpl_->include_default_attributes_ = val; |
2043 | +} |
2044 | + |
2045 | +bool Parser::get_include_default_attributes() noexcept |
2046 | +{ |
2047 | + return pimpl_->include_default_attributes_; |
2048 | +} |
2049 | + |
2050 | +void Parser::set_parser_options(int set_options, int clear_options) noexcept |
2051 | +{ |
2052 | + pimpl_->set_options_ = set_options; |
2053 | + pimpl_->clear_options_ = clear_options; |
2054 | +} |
2055 | + |
2056 | +void Parser::get_parser_options(int& set_options, int& clear_options) noexcept |
2057 | +{ |
2058 | + set_options = pimpl_->set_options_; |
2059 | + clear_options = pimpl_->clear_options_; |
2060 | +} |
2061 | + |
2062 | +void Parser::initialize_context() |
2063 | +{ |
2064 | + //Clear these temporary buffers: |
2065 | + pimpl_->parser_error_.erase(); |
2066 | + pimpl_->parser_warning_.erase(); |
2067 | + pimpl_->validate_error_.erase(); |
2068 | + pimpl_->validate_warning_.erase(); |
2069 | + |
2070 | + //Disactivate any non-standards-compliant libxml1 features. |
2071 | + //These are disactivated by default, but if we don't deactivate them for each context |
2072 | + //then some other code which uses a global function, such as xmlKeepBlanksDefault(), |
2073 | + // could cause this to use the wrong settings: |
2074 | + context_->linenumbers = 1; // TRUE - This is the default anyway. |
2075 | + |
2076 | + //Turn on/off validation, entity substitution and default attribute inclusion. |
2077 | + int options = context_->options; |
2078 | + if (pimpl_->validate_) |
2079 | + options |= XML_PARSE_DTDVALID; |
2080 | + else |
2081 | + options &= ~XML_PARSE_DTDVALID; |
2082 | + |
2083 | + if (pimpl_->substitute_entities_) |
2084 | + options |= XML_PARSE_NOENT; |
2085 | + else |
2086 | + options &= ~XML_PARSE_NOENT; |
2087 | + |
2088 | + if (pimpl_->include_default_attributes_) |
2089 | + options |= XML_PARSE_DTDATTR; |
2090 | + else |
2091 | + options &= ~XML_PARSE_DTDATTR; |
2092 | + |
2093 | + //Turn on/off any parser options. |
2094 | + options |= pimpl_->set_options_; |
2095 | + options &= ~pimpl_->clear_options_; |
2096 | + |
2097 | + xmlCtxtUseOptions(context_, options); |
2098 | + |
2099 | + if (context_->sax && pimpl_->throw_messages_) |
2100 | + { |
2101 | + //Tell the parser context about the callbacks. |
2102 | + context_->sax->fatalError = &callback_parser_error; |
2103 | + context_->sax->error = &callback_parser_error; |
2104 | + context_->sax->warning = &callback_parser_warning; |
2105 | + } |
2106 | + |
2107 | + if (pimpl_->throw_messages_) |
2108 | + { |
2109 | + //Tell the validity context about the callbacks: |
2110 | + //(These are only called if validation is on - see above) |
2111 | + context_->vctxt.error = &callback_validity_error; |
2112 | + context_->vctxt.warning = &callback_validity_warning; |
2113 | + } |
2114 | + |
2115 | + //Allow callback_error_or_warning() to retrieve the C++ instance: |
2116 | + context_->_private = this; |
2117 | +} |
2118 | + |
2119 | +void Parser::release_underlying() |
2120 | +{ |
2121 | + if(context_) |
2122 | + { |
2123 | + context_->_private = nullptr; //Not really necessary. |
2124 | + |
2125 | + if( context_->myDoc != nullptr ) |
2126 | + { |
2127 | + xmlFreeDoc(context_->myDoc); |
2128 | + } |
2129 | + |
2130 | + xmlFreeParserCtxt(context_); |
2131 | + context_ = nullptr; |
2132 | + } |
2133 | +} |
2134 | + |
2135 | +void Parser::on_parser_error(const Glib::ustring& message) |
2136 | +{ |
2137 | + //Throw an exception later when the whole message has been received: |
2138 | + pimpl_->parser_error_ += message; |
2139 | +} |
2140 | + |
2141 | +void Parser::on_parser_warning(const Glib::ustring& message) |
2142 | +{ |
2143 | + //Throw an exception later when the whole message has been received: |
2144 | + pimpl_->parser_warning_ += message; |
2145 | +} |
2146 | +void Parser::on_validity_error(const Glib::ustring& message) |
2147 | +{ |
2148 | + //Throw an exception later when the whole message has been received: |
2149 | + pimpl_->validate_error_ += message; |
2150 | +} |
2151 | + |
2152 | +void Parser::on_validity_warning(const Glib::ustring& message) |
2153 | +{ |
2154 | + //Throw an exception later when the whole message has been received: |
2155 | + pimpl_->validate_warning_ += message; |
2156 | +} |
2157 | + |
2158 | +void Parser::check_for_error_and_warning_messages() |
2159 | +{ |
2160 | + Glib::ustring msg(exception_ ? exception_->what() : ""); |
2161 | + bool parser_msg = false; |
2162 | + bool validity_msg = false; |
2163 | + |
2164 | + if (!pimpl_->parser_error_.empty()) |
2165 | + { |
2166 | + parser_msg = true; |
2167 | + msg += "\nParser error:\n" + pimpl_->parser_error_; |
2168 | + pimpl_->parser_error_.erase(); |
2169 | + } |
2170 | + |
2171 | + if (!pimpl_->parser_warning_.empty()) |
2172 | + { |
2173 | + parser_msg = true; |
2174 | + msg += "\nParser warning:\n" + pimpl_->parser_warning_; |
2175 | + pimpl_->parser_warning_.erase(); |
2176 | + } |
2177 | + |
2178 | + if (!pimpl_->validate_error_.empty()) |
2179 | + { |
2180 | + validity_msg = true; |
2181 | + msg += "\nValidity error:\n" + pimpl_->validate_error_; |
2182 | + pimpl_->validate_error_.erase(); |
2183 | + } |
2184 | + |
2185 | + if (!pimpl_->validate_warning_.empty()) |
2186 | + { |
2187 | + validity_msg = true; |
2188 | + msg += "\nValidity warning:\n" + pimpl_->validate_warning_; |
2189 | + pimpl_->validate_warning_.erase(); |
2190 | + } |
2191 | + |
2192 | + if (validity_msg) |
2193 | + exception_.reset(new validity_error(msg)); |
2194 | + else if (parser_msg) |
2195 | + exception_.reset(new parse_error(msg)); |
2196 | +} |
2197 | + |
2198 | +//static |
2199 | +void Parser::callback_parser_error(void* ctx, const char* msg, ...) |
2200 | +{ |
2201 | + va_list var_args; |
2202 | + va_start(var_args, msg); |
2203 | + callback_error_or_warning(MsgType::ParserError, ctx, msg, var_args); |
2204 | + va_end(var_args); |
2205 | +} |
2206 | + |
2207 | +//static |
2208 | +void Parser::callback_parser_warning(void* ctx, const char* msg, ...) |
2209 | +{ |
2210 | + va_list var_args; |
2211 | + va_start(var_args, msg); |
2212 | + callback_error_or_warning(MsgType::ParserWarning, ctx, msg, var_args); |
2213 | + va_end(var_args); |
2214 | +} |
2215 | + |
2216 | +//static |
2217 | +void Parser::callback_validity_error(void* ctx, const char* msg, ...) |
2218 | +{ |
2219 | + va_list var_args; |
2220 | + va_start(var_args, msg); |
2221 | + callback_error_or_warning(MsgType::ValidityError, ctx, msg, var_args); |
2222 | + va_end(var_args); |
2223 | +} |
2224 | + |
2225 | +//static |
2226 | +void Parser::callback_validity_warning(void* ctx, const char* msg, ...) |
2227 | +{ |
2228 | + va_list var_args; |
2229 | + va_start(var_args, msg); |
2230 | + callback_error_or_warning(MsgType::ValidityWarning, ctx, msg, var_args); |
2231 | + va_end(var_args); |
2232 | +} |
2233 | + |
2234 | +//static |
2235 | +void Parser::callback_error_or_warning(MsgType msg_type, void* ctx, |
2236 | + const char* msg, va_list var_args) |
2237 | +{ |
2238 | + //See xmlHTMLValidityError() in xmllint.c in libxml for more about this: |
2239 | + |
2240 | + auto context = (xmlParserCtxtPtr)ctx; |
2241 | + if(context) |
2242 | + { |
2243 | + auto parser = static_cast<Parser*>(context->_private); |
2244 | + if(parser) |
2245 | + { |
2246 | + auto ubuff = format_xml_error(&context->lastError); |
2247 | + if (ubuff.empty()) |
2248 | + { |
2249 | + // Usually the result of formatting var_args with the format string msg |
2250 | + // is the same string as is stored in context->lastError.message. |
2251 | + // It's unnecessary to use msg and var_args, if format_xml_error() |
2252 | + // returns an error message (as it usually does). |
2253 | + |
2254 | + //Convert the ... to a string: |
2255 | + ubuff = format_printf_message(msg, var_args); |
2256 | + } |
2257 | + |
2258 | + try |
2259 | + { |
2260 | + switch (msg_type) |
2261 | + { |
2262 | + case MsgType::ParserError: |
2263 | + parser->on_parser_error(ubuff); |
2264 | + break; |
2265 | + case MsgType::ParserWarning: |
2266 | + parser->on_parser_warning(ubuff); |
2267 | + break; |
2268 | + case MsgType::ValidityError: |
2269 | + parser->on_validity_error(ubuff); |
2270 | + break; |
2271 | + case MsgType::ValidityWarning: |
2272 | + parser->on_validity_warning(ubuff); |
2273 | + break; |
2274 | + } |
2275 | + } |
2276 | + catch (...) |
2277 | + { |
2278 | + parser->handle_exception(); |
2279 | + } |
2280 | + } |
2281 | + } |
2282 | +} |
2283 | + |
2284 | +void Parser::handle_exception() |
2285 | +{ |
2286 | + try |
2287 | + { |
2288 | + throw; // Re-throw current exception |
2289 | + } |
2290 | + catch (const exception& e) |
2291 | + { |
2292 | + exception_.reset(e.clone()); |
2293 | + } |
2294 | +#ifdef LIBXMLXX_HAVE_EXCEPTION_PTR |
2295 | + catch (...) |
2296 | + { |
2297 | + exception_.reset(new wrapped_exception(std::current_exception())); |
2298 | + } |
2299 | +#else |
2300 | + catch (const std::exception& e) |
2301 | + { |
2302 | + exception_.reset(new exception(e.what())); |
2303 | + } |
2304 | + catch (...) |
2305 | + { |
2306 | + exception_.reset(new exception("An exception was thrown that is not derived from std::exception or xmlpp::exception.\n" |
2307 | + "It could not be caught and rethrown because this platform does not support std::exception_ptr.")); |
2308 | + } |
2309 | +#endif |
2310 | + |
2311 | + if (context_) |
2312 | + xmlStopParser(context_); |
2313 | + |
2314 | + //release_underlying(); |
2315 | +} |
2316 | + |
2317 | +void Parser::check_for_exception() |
2318 | +{ |
2319 | + check_for_error_and_warning_messages(); |
2320 | + |
2321 | + if (exception_) |
2322 | + { |
2323 | + std::unique_ptr<exception> tmp(std::move(exception_)); |
2324 | + tmp->raise(); |
2325 | + } |
2326 | +} |
2327 | + |
2328 | +} // namespace xmlpp |
2329 | |
2330 | === added file 'src/libxml++/parsers/parser.h' |
2331 | --- src/libxml++/parsers/parser.h 1970-01-01 00:00:00 +0000 |
2332 | +++ src/libxml++/parsers/parser.h 2016-11-06 17:18:04 +0000 |
2333 | @@ -0,0 +1,220 @@ |
2334 | +/* parser.h |
2335 | + * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and |
2336 | + * are covered by the GNU Lesser General Public License, which should be |
2337 | + * included with libxml++ as the file COPYING. |
2338 | + */ |
2339 | + |
2340 | +#ifndef __LIBXMLPP_PARSER_H |
2341 | +#define __LIBXMLPP_PARSER_H |
2342 | + |
2343 | +#ifdef _MSC_VER //Ignore warnings about the Visual C++ Bug, where we can not do anything |
2344 | +#pragma warning (disable : 4786) |
2345 | +#endif |
2346 | + |
2347 | +#include <libxml++/noncopyable.h> |
2348 | +#include <libxml++/exceptions/validity_error.h> |
2349 | +#include <libxml++/exceptions/internal_error.h> |
2350 | + |
2351 | +#include <string> |
2352 | +#include <istream> |
2353 | +#include <cstdarg> // va_list |
2354 | +#include <memory> // std::unique_ptr |
2355 | + |
2356 | +#ifndef DOXYGEN_SHOULD_SKIP_THIS |
2357 | +extern "C" { |
2358 | + struct _xmlParserCtxt; |
2359 | +} |
2360 | +#endif //DOXYGEN_SHOULD_SKIP_THIS |
2361 | + |
2362 | +namespace xmlpp { |
2363 | + |
2364 | +/** XML parser. |
2365 | + * |
2366 | + * Abstract base class for DOM parser and SAX parser. |
2367 | + */ |
2368 | +class Parser : public NonCopyable |
2369 | +{ |
2370 | +public: |
2371 | + Parser(); |
2372 | + ~Parser() override; |
2373 | + |
2374 | + using size_type = unsigned int; |
2375 | + |
2376 | + /** By default, the parser will not validate the XML file. |
2377 | + * @param val Whether the document should be validated. |
2378 | + */ |
2379 | + void set_validate(bool val = true) noexcept; |
2380 | + |
2381 | + /** See set_validate(). |
2382 | + * @returns Whether the parser will validate the XML file. |
2383 | + */ |
2384 | + bool get_validate() const noexcept; |
2385 | + |
2386 | + /** Set whether the parser will automatically substitute entity references with the text of the entities' definitions. |
2387 | + * For instance, this affects the text returned by ContentNode::get_content(). |
2388 | + * By default, the parser will not substitute entities, so that you do not lose the entity reference information. |
2389 | + * @param val Whether entities will be substitued. |
2390 | + */ |
2391 | + void set_substitute_entities(bool val = true) noexcept; |
2392 | + |
2393 | + /** See set_substitute_entities(). |
2394 | + * @returns Whether entities will be substituted during parsing. |
2395 | + */ |
2396 | + bool get_substitute_entities() const noexcept; |
2397 | + |
2398 | + /** Set whether the parser will collect and throw error and warning messages. |
2399 | + * |
2400 | + * If messages are collected, they are included in an exception thrown at the |
2401 | + * end of parsing. |
2402 | + * |
2403 | + * - DOM parser |
2404 | + * |
2405 | + * If the messages are not collected, they are written on stderr. |
2406 | + * The messages written on stderr are slightly different, and may be |
2407 | + * preferred in a program started from the command-line. The default, if |
2408 | + * set_throw_messages() is not called, is to collect and throw messages. |
2409 | + * |
2410 | + * - SAX parser |
2411 | + * |
2412 | + * If the messages are not collected, the error handling on_*() methods in |
2413 | + * the user's SAX parser subclass are called. This is the default, if |
2414 | + * set_throw_messages() is not called. |
2415 | + * |
2416 | + * @newin{2,36} |
2417 | + * |
2418 | + * @param val Whether messages will be collected and thrown in an exception. |
2419 | + */ |
2420 | + void set_throw_messages(bool val = true) noexcept; |
2421 | + |
2422 | + /** See set_throw_messages(). |
2423 | + * |
2424 | + * @newin{2,36} |
2425 | + * |
2426 | + * @returns Whether messages will be collected and thrown in an exception. |
2427 | + */ |
2428 | + bool get_throw_messages() const noexcept; |
2429 | + |
2430 | + /** Set whether default attribute values from the DTD shall be included in the node tree. |
2431 | + * If set, attributes not assigned a value in the XML file, but with a default value |
2432 | + * in the DTD file, will be included in the node tree that the parser creates. |
2433 | + * These attributes will be represented by AttributeNode instances (not AttributeDeclaration |
2434 | + * instances), just like attributes which are assigned a value in the XML file. |
2435 | + * |
2436 | + * @newin{2,38} |
2437 | + * |
2438 | + * @param val Whether attributes with default values will be included in the node tree. |
2439 | + */ |
2440 | + void set_include_default_attributes(bool val = true) noexcept; |
2441 | + |
2442 | + /** See set_include_default_attributes(). |
2443 | + * |
2444 | + * @newin{2,38} |
2445 | + * |
2446 | + * @returns Whether attributes with default values will be included in the node tree. |
2447 | + */ |
2448 | + bool get_include_default_attributes() noexcept; |
2449 | + |
2450 | + /** Set and/or clear parser option flags. |
2451 | + * See the libxml2 documentation, enum xmlParserOption, for a list of parser options. |
2452 | + * This method overrides other methods that set parser options, such as set_validate(), |
2453 | + * set_substitute_entities() and set_include_default_attributes(). Use set_parser_options() |
2454 | + * only if no other method can set the parser options you want. |
2455 | + * |
2456 | + * @newin{2,38} |
2457 | + * |
2458 | + * @param set_options Set bits correspond to flags that shall be set during parsing. |
2459 | + * @param clear_options Set bits correspond to flags that shall be cleared during parsing. |
2460 | + * Bits that are set in neither @a set_options nor @a clear_options are not affected. |
2461 | + */ |
2462 | + void set_parser_options(int set_options = 0, int clear_options = 0) noexcept; |
2463 | + |
2464 | + /** See set_parser_options(). |
2465 | + * |
2466 | + * @newin{2,38} |
2467 | + * |
2468 | + * @param [out] set_options Set bits correspond to flags that shall be set during parsing. |
2469 | + * @param [out] clear_options Set bits correspond to flags that shall be cleared during parsing. |
2470 | + * Bits that are set in neither @a set_options nor @a clear_options are not affected. |
2471 | + */ |
2472 | + void get_parser_options(int& set_options, int& clear_options) noexcept; |
2473 | + |
2474 | + /** Parse an XML document from a file. |
2475 | + * @throw exception |
2476 | + * @param filename The path to the file. |
2477 | + */ |
2478 | + virtual void parse_file(const std::string& filename) = 0; |
2479 | + |
2480 | + /** Parse an XML document from raw memory. |
2481 | + * @throw exception |
2482 | + * @param contents The XML document as an array of bytes. |
2483 | + * @param bytes_count The number of bytes in the @a contents array. |
2484 | + */ |
2485 | + virtual void parse_memory_raw(const unsigned char* contents, size_type bytes_count) = 0; |
2486 | + |
2487 | + /** Parse an XML document from a string. |
2488 | + * @throw exception |
2489 | + * @param contents The XML document as a string. |
2490 | + */ |
2491 | + virtual void parse_memory(const Glib::ustring& contents) = 0; |
2492 | + |
2493 | + /** Parse an XML document from a stream. |
2494 | + * @throw exception |
2495 | + * @param in The stream. |
2496 | + */ |
2497 | + virtual void parse_stream(std::istream& in) = 0; |
2498 | + |
2499 | + //TODO: Add stop_parser()/stop_parsing(), wrapping xmlStopParser()? |
2500 | + |
2501 | +protected: |
2502 | + virtual void initialize_context(); |
2503 | + virtual void release_underlying(); |
2504 | + |
2505 | + virtual void on_parser_error(const Glib::ustring& message); |
2506 | + virtual void on_parser_warning(const Glib::ustring& message); |
2507 | + virtual void on_validity_error(const Glib::ustring& message); |
2508 | + virtual void on_validity_warning(const Glib::ustring& message); |
2509 | + |
2510 | + /// To be called in an exception handler. |
2511 | + virtual void handle_exception(); |
2512 | + virtual void check_for_exception(); |
2513 | + |
2514 | + virtual void check_for_error_and_warning_messages(); |
2515 | + |
2516 | + static void callback_parser_error(void* ctx, const char* msg, ...); |
2517 | + static void callback_parser_warning(void* ctx, const char* msg, ...); |
2518 | + static void callback_validity_error(void* ctx, const char* msg, ...); |
2519 | + static void callback_validity_warning(void* ctx, const char* msg, ...); |
2520 | + |
2521 | + enum class MsgType |
2522 | + { |
2523 | + ParserError, |
2524 | + ParserWarning, |
2525 | + ValidityError, |
2526 | + ValidityWarning |
2527 | + }; |
2528 | + |
2529 | + static void callback_error_or_warning(MsgType msg_type, void* ctx, |
2530 | + const char* msg, va_list var_args); |
2531 | + |
2532 | + _xmlParserCtxt* context_; |
2533 | + std::unique_ptr<exception> exception_; |
2534 | + |
2535 | +private: |
2536 | + struct Impl; |
2537 | + std::unique_ptr<Impl> pimpl_; |
2538 | +}; |
2539 | + |
2540 | +/** Equivalent to Parser::parse_stream(). |
2541 | + * |
2542 | + * @newin{2,38} |
2543 | + */ |
2544 | +inline std::istream& operator>>(std::istream& in, Parser& parser) |
2545 | +{ |
2546 | + parser.parse_stream(in); |
2547 | + return in; |
2548 | +} |
2549 | + |
2550 | +} // namespace xmlpp |
2551 | + |
2552 | +#endif //__LIBXMLPP_PARSER_H |
2553 | + |
2554 | |
2555 | === added file 'src/libxml++/parsers/saxparser.cc' |
2556 | --- src/libxml++/parsers/saxparser.cc 1970-01-01 00:00:00 +0000 |
2557 | +++ src/libxml++/parsers/saxparser.cc 2016-11-06 17:18:04 +0000 |
2558 | @@ -0,0 +1,711 @@ |
2559 | +/* saxparser.cc |
2560 | + * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and |
2561 | + * are covered by the GNU Lesser General Public License, which should be |
2562 | + * included with libxml++ as the file COPYING. |
2563 | + * |
2564 | + * 2002/01/05 Valentin Rusu - fixed some potential buffer overruns |
2565 | + * 2002/01/21 Valentin Rusu - added CDATA handlers |
2566 | + */ |
2567 | + |
2568 | +#include "libxml++/parsers/saxparser.h" |
2569 | +#include "libxml++/keepblanks.h" |
2570 | + |
2571 | +#include <libxml/parser.h> |
2572 | +#include <libxml/parserInternals.h> // for xmlCreateFileParserCtxt |
2573 | + |
2574 | +#include <cstdarg> //For va_list. |
2575 | +#include <iostream> |
2576 | + |
2577 | +namespace xmlpp { |
2578 | + |
2579 | +struct SaxParserCallback |
2580 | +{ |
2581 | + static xmlEntityPtr get_entity(void* context, const xmlChar* name); |
2582 | + static void entity_decl(void* context, const xmlChar* name, int type, const xmlChar* publicId, const xmlChar* systemId, xmlChar* content); |
2583 | + static void start_document(void* context); |
2584 | + static void end_document(void* context); |
2585 | + static void start_element(void* context, const xmlChar* name, const xmlChar** p); |
2586 | + static void end_element(void* context, const xmlChar* name); |
2587 | + static void start_element_ns(void *context, const xmlChar *name, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, |
2588 | + const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes); |
2589 | + static void end_element_ns(void *context, const xmlChar *name, const xmlChar *prefix, const xmlChar *URI); |
2590 | + static void characters(void* context, const xmlChar* ch, int len); |
2591 | + static void comment(void* context, const xmlChar* value); |
2592 | + static void processing_instruction(void* context, const xmlChar* target, const xmlChar* data); |
2593 | + static void warning(void* context, const char* fmt, ...); |
2594 | + static void error(void* context, const char* fmt, ...); |
2595 | + static void fatal_error(void* context, const char* fmt, ...); |
2596 | + static void cdata_block(void* context, const xmlChar* value, int len); |
2597 | + static void internal_subset(void* context, const xmlChar* name, const xmlChar*publicId, const xmlChar*systemId); |
2598 | +}; |
2599 | + |
2600 | + |
2601 | + |
2602 | +SaxParser::SaxParser(bool use_get_entity) |
2603 | + : sax_handler_(new _xmlSAXHandler), entity_resolver_doc_(new Document) |
2604 | +{ |
2605 | + xmlSAXHandler temp = { |
2606 | + SaxParserCallback::internal_subset, |
2607 | + nullptr, // isStandalone |
2608 | + nullptr, // hasInternalSubset |
2609 | + nullptr, // hasExternalSubset |
2610 | + nullptr, // resolveEntity |
2611 | + use_get_entity ? SaxParserCallback::get_entity : nullptr, // getEntity |
2612 | + SaxParserCallback::entity_decl, // entityDecl |
2613 | + nullptr, // notationDecl |
2614 | + nullptr, // attributeDecl |
2615 | + nullptr, // elementDecl |
2616 | + nullptr, // unparsedEntityDecl |
2617 | + nullptr, // setDocumentLocator |
2618 | + SaxParserCallback::start_document, // startDocument |
2619 | + SaxParserCallback::end_document, // endDocument |
2620 | + SaxParserCallback::start_element, // startElement |
2621 | + SaxParserCallback::end_element, // endElement |
2622 | + nullptr, // reference |
2623 | + SaxParserCallback::characters, // characters |
2624 | + nullptr, // ignorableWhitespace |
2625 | + SaxParserCallback::processing_instruction, // processingInstruction |
2626 | + SaxParserCallback::comment, // comment |
2627 | + SaxParserCallback::warning, // warning |
2628 | + SaxParserCallback::error, // error |
2629 | + SaxParserCallback::fatal_error, // fatalError |
2630 | + nullptr, // getParameterEntity |
2631 | + SaxParserCallback::cdata_block, // cdataBlock |
2632 | + nullptr, // externalSubset |
2633 | + XML_SAX2_MAGIC, // initialized |
2634 | + nullptr, // private |
2635 | + SaxParserCallback::start_element_ns, // startElementNs |
2636 | + SaxParserCallback::end_element_ns, // endElementNs |
2637 | + nullptr, // serror |
2638 | + }; |
2639 | + *sax_handler_ = temp; |
2640 | + |
2641 | + // The default action is to call on_warning(), on_error(), on_fatal_error(). |
2642 | + set_throw_messages(false); |
2643 | +} |
2644 | + |
2645 | +SaxParser::~SaxParser() |
2646 | +{ |
2647 | + release_underlying(); |
2648 | +} |
2649 | + |
2650 | +xmlEntityPtr SaxParser::on_get_entity(const Glib::ustring& name) |
2651 | +{ |
2652 | + return entity_resolver_doc_->get_entity(name); |
2653 | +} |
2654 | + |
2655 | +void SaxParser::on_entity_declaration(const Glib::ustring& name, XmlEntityType type, const Glib::ustring& publicId, const Glib::ustring& systemId, const Glib::ustring& content) |
2656 | +{ |
2657 | + entity_resolver_doc_->set_entity_declaration(name, type, publicId, systemId, content); |
2658 | +} |
2659 | + |
2660 | +void SaxParser::on_start_document() |
2661 | +{ |
2662 | +} |
2663 | + |
2664 | +void SaxParser::on_end_document() |
2665 | +{ |
2666 | +} |
2667 | + |
2668 | +void SaxParser::on_start_element(const Glib::ustring& /* name */, const AttributeList& /* attributes */) |
2669 | +{ |
2670 | +} |
2671 | + |
2672 | +void SaxParser::on_end_element(const Glib::ustring& /* name */) |
2673 | +{ |
2674 | +} |
2675 | + |
2676 | +void SaxParser::on_start_element_ns(const Glib::ustring& /* name */, const Glib::ustring& /* prefix */, const Glib::ustring& /* uri */, const NamespaceList& /* namespaces */, const AttributeList& /* attributes */) |
2677 | +{ |
2678 | +} |
2679 | + |
2680 | +void SaxParser::on_end_element_ns(const Glib::ustring& /* name */, const Glib::ustring& /* prefix */, const Glib::ustring& /* uri */) |
2681 | +{ |
2682 | +} |
2683 | + |
2684 | +void SaxParser::on_characters(const Glib::ustring& /* text */) |
2685 | +{ |
2686 | +} |
2687 | + |
2688 | +void SaxParser::on_comment(const Glib::ustring& /* text */) |
2689 | +{ |
2690 | +} |
2691 | + |
2692 | +void SaxParser::on_processing_instruction(const Glib::ustring &target, const Glib::ustring &data) |
2693 | +{ |
2694 | +} |
2695 | + |
2696 | +void SaxParser::on_warning(const Glib::ustring& /* text */) |
2697 | +{ |
2698 | +} |
2699 | + |
2700 | +void SaxParser::on_error(const Glib::ustring& /* text */) |
2701 | +{ |
2702 | +} |
2703 | + |
2704 | +void SaxParser::on_fatal_error(const Glib::ustring& text) |
2705 | +{ |
2706 | + throw parse_error("Fatal error: " + text); |
2707 | +} |
2708 | + |
2709 | +void SaxParser::on_cdata_block(const Glib::ustring& /* text */) |
2710 | +{ |
2711 | +} |
2712 | + |
2713 | +void SaxParser::on_internal_subset(const Glib::ustring& name, |
2714 | + const Glib::ustring& publicId, |
2715 | + const Glib::ustring& systemId) |
2716 | +{ |
2717 | + entity_resolver_doc_->set_internal_subset(name, publicId, systemId); |
2718 | +} |
2719 | + |
2720 | +// implementation of this function is inspired by the SAX documentation by James Henstridge. |
2721 | +// (http://www.daa.com.au/~james/gnome/xml-sax/implementing.html) |
2722 | +void SaxParser::parse() |
2723 | +{ |
2724 | + if(!context_) |
2725 | + { |
2726 | + throw internal_error("Parser context not created."); |
2727 | + } |
2728 | + |
2729 | + auto old_sax = context_->sax; |
2730 | + context_->sax = sax_handler_.get(); |
2731 | + |
2732 | + xmlResetLastError(); |
2733 | + initialize_context(); |
2734 | + |
2735 | + const int parseError = xmlParseDocument(context_); |
2736 | + |
2737 | + context_->sax = old_sax; |
2738 | + |
2739 | + auto error_str = format_xml_parser_error(context_); |
2740 | + if (error_str.empty() && parseError == -1) |
2741 | + error_str = "xmlParseDocument() failed."; |
2742 | + |
2743 | + release_underlying(); // Free context_ |
2744 | + |
2745 | + check_for_exception(); |
2746 | + |
2747 | + if(!error_str.empty()) |
2748 | + { |
2749 | + throw parse_error(error_str); |
2750 | + } |
2751 | +} |
2752 | + |
2753 | +void SaxParser::parse_file(const std::string& filename) |
2754 | +{ |
2755 | + if(context_) |
2756 | + { |
2757 | + throw parse_error("Attempt to start a second parse while a parse is in progress."); |
2758 | + } |
2759 | + |
2760 | + KeepBlanks k(KeepBlanks::Default); |
2761 | + |
2762 | + context_ = xmlCreateFileParserCtxt(filename.c_str()); |
2763 | + parse(); |
2764 | +} |
2765 | + |
2766 | +void SaxParser::parse_memory_raw(const unsigned char* contents, size_type bytes_count) |
2767 | +{ |
2768 | + if(context_) |
2769 | + { |
2770 | + throw parse_error("Attempt to start a second parse while a parse is in progress."); |
2771 | + } |
2772 | + |
2773 | + KeepBlanks k(KeepBlanks::Default); |
2774 | + |
2775 | + context_ = xmlCreateMemoryParserCtxt((const char*)contents, bytes_count); |
2776 | + parse(); |
2777 | +} |
2778 | + |
2779 | +void SaxParser::parse_memory(const Glib::ustring& contents) |
2780 | +{ |
2781 | + parse_memory_raw((const unsigned char*)contents.c_str(), contents.bytes()); |
2782 | +} |
2783 | + |
2784 | +void SaxParser::parse_stream(std::istream& in) |
2785 | +{ |
2786 | + if(context_) |
2787 | + { |
2788 | + throw parse_error("Attempt to start a second parse while a parse is in progress."); |
2789 | + } |
2790 | + |
2791 | + KeepBlanks k(KeepBlanks::Default); |
2792 | + xmlResetLastError(); |
2793 | + |
2794 | + context_ = xmlCreatePushParserCtxt( |
2795 | + sax_handler_.get(), |
2796 | + nullptr, // user_data |
2797 | + nullptr, // chunk |
2798 | + 0, // size |
2799 | + nullptr); // no filename for fetching external entities |
2800 | + |
2801 | + if(!context_) |
2802 | + { |
2803 | + throw internal_error("Could not create parser context\n" + format_xml_error()); |
2804 | + } |
2805 | + |
2806 | + initialize_context(); |
2807 | + |
2808 | + // std::string or Glib::ustring? |
2809 | + // Output from the XML parser is UTF-8 encoded. |
2810 | + // But the istream "in" is input, i.e. an XML file. It can use any encoding. |
2811 | + // If it's not UTF-8, the file itself must contain information about which |
2812 | + // encoding it uses. See the XML specification. Thus use std::string. |
2813 | + int firstParseError = XML_ERR_OK; |
2814 | + std::string line; |
2815 | + while (!exception_ && std::getline(in, line)) |
2816 | + { |
2817 | + // since getline does not get the line separator, we have to add it since the parser care |
2818 | + // about layout in certain cases. |
2819 | + line += '\n'; |
2820 | + |
2821 | + const int parseError = xmlParseChunk(context_, line.c_str(), |
2822 | + line.size() /* This is a std::string, not a ustring, so this is the number of bytes. */, |
2823 | + 0 /* don't terminate */); |
2824 | + |
2825 | + // Save the first error code if any, but read on. |
2826 | + // More errors might be reported and then thrown by check_for_exception(). |
2827 | + if (parseError != XML_ERR_OK && firstParseError == XML_ERR_OK) |
2828 | + firstParseError = parseError; |
2829 | + } |
2830 | + |
2831 | + if (!exception_) |
2832 | + { |
2833 | + //This is called just to terminate parsing. |
2834 | + const int parseError = xmlParseChunk(context_, nullptr /* chunk */, 0 /* size */, 1 /* terminate (1 or 0) */); |
2835 | + |
2836 | + if (parseError != XML_ERR_OK && firstParseError == XML_ERR_OK) |
2837 | + firstParseError = parseError; |
2838 | + } |
2839 | + |
2840 | + auto error_str = format_xml_parser_error(context_); |
2841 | + if (error_str.empty() && firstParseError != XML_ERR_OK) |
2842 | + error_str = "Error code from xmlParseChunk(): " + Glib::ustring::format(firstParseError); |
2843 | + |
2844 | + release_underlying(); // Free context_ |
2845 | + |
2846 | + check_for_exception(); |
2847 | + |
2848 | + if(!error_str.empty()) |
2849 | + { |
2850 | + throw parse_error(error_str); |
2851 | + } |
2852 | +} |
2853 | + |
2854 | +void SaxParser::parse_chunk(const Glib::ustring& chunk) |
2855 | +{ |
2856 | + parse_chunk_raw((const unsigned char*)chunk.c_str(), chunk.bytes()); |
2857 | +} |
2858 | + |
2859 | +void SaxParser::parse_chunk_raw(const unsigned char* contents, size_type bytes_count) |
2860 | +{ |
2861 | + KeepBlanks k(KeepBlanks::Default); |
2862 | + xmlResetLastError(); |
2863 | + |
2864 | + if(!context_) |
2865 | + { |
2866 | + context_ = xmlCreatePushParserCtxt( |
2867 | + sax_handler_.get(), |
2868 | + nullptr, // user_data |
2869 | + nullptr, // chunk |
2870 | + 0, // size |
2871 | + nullptr); // no filename for fetching external entities |
2872 | + |
2873 | + if(!context_) |
2874 | + { |
2875 | + throw internal_error("Could not create parser context\n" + format_xml_error()); |
2876 | + } |
2877 | + initialize_context(); |
2878 | + } |
2879 | + else |
2880 | + xmlCtxtResetLastError(context_); |
2881 | + |
2882 | + int parseError = XML_ERR_OK; |
2883 | + if (!exception_) |
2884 | + parseError = xmlParseChunk(context_, (const char*)contents, bytes_count, 0 /* don't terminate */); |
2885 | + |
2886 | + check_for_exception(); |
2887 | + |
2888 | + auto error_str = format_xml_parser_error(context_); |
2889 | + if (error_str.empty() && parseError != XML_ERR_OK) |
2890 | + error_str = "Error code from xmlParseChunk(): " + Glib::ustring::format(parseError); |
2891 | + if(!error_str.empty()) |
2892 | + { |
2893 | + throw parse_error(error_str); |
2894 | + } |
2895 | +} |
2896 | + |
2897 | +void SaxParser::finish_chunk_parsing() |
2898 | +{ |
2899 | + xmlResetLastError(); |
2900 | + if(!context_) |
2901 | + { |
2902 | + context_ = xmlCreatePushParserCtxt( |
2903 | + sax_handler_.get(), |
2904 | + nullptr, // user_data |
2905 | + nullptr, // chunk |
2906 | + 0, // size |
2907 | + nullptr); // no filename for fetching external entities |
2908 | + |
2909 | + if(!context_) |
2910 | + { |
2911 | + throw internal_error("Could not create parser context\n" + format_xml_error()); |
2912 | + } |
2913 | + initialize_context(); |
2914 | + } |
2915 | + else |
2916 | + xmlCtxtResetLastError(context_); |
2917 | + |
2918 | + int parseError = XML_ERR_OK; |
2919 | + if (!exception_) |
2920 | + //This is called just to terminate parsing. |
2921 | + parseError = xmlParseChunk(context_, nullptr /* chunk */, 0 /* size */, 1 /* terminate (1 or 0) */); |
2922 | + |
2923 | + auto error_str = format_xml_parser_error(context_); |
2924 | + if (error_str.empty() && parseError != XML_ERR_OK) |
2925 | + error_str = "Error code from xmlParseChunk(): " + Glib::ustring::format(parseError); |
2926 | + |
2927 | + release_underlying(); // Free context_ |
2928 | + |
2929 | + check_for_exception(); |
2930 | + |
2931 | + if(!error_str.empty()) |
2932 | + { |
2933 | + throw parse_error(error_str); |
2934 | + } |
2935 | +} |
2936 | + |
2937 | +void SaxParser::release_underlying() |
2938 | +{ |
2939 | + Parser::release_underlying(); |
2940 | +} |
2941 | + |
2942 | +void SaxParser::initialize_context() |
2943 | +{ |
2944 | + Parser::initialize_context(); |
2945 | + // Start with an empty Document for entity resolution. |
2946 | + entity_resolver_doc_.reset(new Document); |
2947 | +} |
2948 | + |
2949 | +xmlEntityPtr SaxParserCallback::get_entity(void* context, const xmlChar* name) |
2950 | +{ |
2951 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
2952 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
2953 | + xmlEntityPtr result = nullptr; |
2954 | + |
2955 | + try |
2956 | + { |
2957 | + result = parser->on_get_entity((const char*)name); |
2958 | + } |
2959 | + catch (...) |
2960 | + { |
2961 | + parser->handle_exception(); |
2962 | + } |
2963 | + |
2964 | + return result; |
2965 | +} |
2966 | + |
2967 | +void SaxParserCallback::entity_decl(void* context, const xmlChar* name, int type, const xmlChar* publicId, const xmlChar* systemId, xmlChar* content) |
2968 | +{ |
2969 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
2970 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
2971 | + |
2972 | + try |
2973 | + { |
2974 | + parser->on_entity_declaration( |
2975 | + ( name ? Glib::ustring((const char*)name) : ""), |
2976 | + static_cast<XmlEntityType>(type), |
2977 | + ( publicId ? Glib::ustring((const char*)publicId) : ""), |
2978 | + ( systemId ? Glib::ustring((const char*)systemId) : ""), |
2979 | + ( content ? Glib::ustring((const char*)content) : "") ); |
2980 | + } |
2981 | + catch (...) |
2982 | + { |
2983 | + parser->handle_exception(); |
2984 | + } |
2985 | +} |
2986 | + |
2987 | +void SaxParserCallback::start_document(void* context) |
2988 | +{ |
2989 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
2990 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
2991 | + |
2992 | + try |
2993 | + { |
2994 | + parser->on_start_document(); |
2995 | + } |
2996 | + catch (...) |
2997 | + { |
2998 | + parser->handle_exception(); |
2999 | + } |
3000 | +} |
3001 | + |
3002 | +void SaxParserCallback::end_document(void* context) |
3003 | +{ |
3004 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3005 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3006 | + |
3007 | + if (parser->exception_) |
3008 | + return; |
3009 | + |
3010 | + try |
3011 | + { |
3012 | + parser->on_end_document(); |
3013 | + } |
3014 | + catch (...) |
3015 | + { |
3016 | + parser->handle_exception(); |
3017 | + } |
3018 | +} |
3019 | + |
3020 | +void SaxParserCallback::start_element(void* context, |
3021 | + const xmlChar* name, |
3022 | + const xmlChar** p) |
3023 | +{ |
3024 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3025 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3026 | + |
3027 | + SaxParser::AttributeList attributes; |
3028 | + |
3029 | + if(p) |
3030 | + for(const xmlChar** cur = p; cur && *cur; cur += 2) |
3031 | + attributes.push_back( |
3032 | + SaxParser::Attribute( (char*)*cur, (char*)*(cur + 1) )); |
3033 | + |
3034 | + try |
3035 | + { |
3036 | + parser->on_start_element(Glib::ustring((const char*) name), attributes); |
3037 | + } |
3038 | + catch (...) |
3039 | + { |
3040 | + parser->handle_exception(); |
3041 | + } |
3042 | +} |
3043 | + |
3044 | +void SaxParserCallback::end_element(void* context, const xmlChar* name) |
3045 | +{ |
3046 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3047 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3048 | + |
3049 | + try |
3050 | + { |
3051 | + parser->on_end_element(Glib::ustring((const char*) name)); |
3052 | + } |
3053 | + catch (...) |
3054 | + { |
3055 | + parser->handle_exception(); |
3056 | + } |
3057 | +} |
3058 | + |
3059 | +void SaxParserCallback::start_element_ns(void *context, const xmlChar *name, const xmlChar *prefix, const xmlChar *URI, |
3060 | + int nb_namespaces, const xmlChar **namespaces, int nb_attributes, |
3061 | + int nb_defaulted, const xmlChar **attributes) |
3062 | +{ |
3063 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3064 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3065 | + |
3066 | + SaxParser::AttributeList attrs; |
3067 | + SaxParser::NamespaceList nss; |
3068 | + try |
3069 | + { |
3070 | + const auto pref = prefix ? Glib::ustring((const char*) prefix) : ""; |
3071 | + const auto uri = URI ? Glib::ustring((const char*) URI) : ""; |
3072 | + for (int i = 0; i < nb_namespaces; ++i) |
3073 | + { |
3074 | + const auto p = namespaces[i * 2] ? Glib::ustring((const char*) namespaces[i * 2]) : ""; |
3075 | + const auto u = namespaces[i * 2 + 1] ? Glib::ustring((const char*) namespaces[i * 2 + 1]) : ""; |
3076 | + nss.push_back(SaxParser::Namespace(p, u)); |
3077 | + } |
3078 | + |
3079 | + unsigned int index = 0; |
3080 | + for (int ia = 0; ia < nb_attributes; ++ia, index += 5 ) |
3081 | + { |
3082 | + const auto attrName = attributes[index] ? Glib::ustring((const char*) attributes[index]) : ""; |
3083 | + const auto attrPrefix = attributes[index + 1] ? Glib::ustring((const char*) attributes[index + 1]) : ""; |
3084 | + const auto attrUri = attributes[index + 2] ? Glib::ustring((const char*) attributes[index + 2]) : ""; |
3085 | + const auto attrValueBegin = attributes[index + 3]; |
3086 | + const auto attrValueEnd = attributes[index + 4]; |
3087 | + Glib::ustring value((const char *)attrValueBegin, (const char *)attrValueEnd); |
3088 | + attrs.push_back(SaxParser::Attribute(attrName, value, attrPrefix, attrUri)); |
3089 | + } |
3090 | + parser->on_start_element_ns(Glib::ustring((const char *) name), pref, uri, nss, attrs); |
3091 | + } |
3092 | + catch (...) |
3093 | + { |
3094 | + parser->handle_exception(); |
3095 | + } |
3096 | +} |
3097 | + |
3098 | +void SaxParserCallback::end_element_ns(void *context, const xmlChar *name, const xmlChar *prefix, const xmlChar *URI) |
3099 | +{ |
3100 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3101 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3102 | + |
3103 | + try |
3104 | + { |
3105 | + const auto pref = prefix ? Glib::ustring((const char*) prefix) : ""; |
3106 | + const auto uri = URI ? Glib::ustring((const char*) URI) : ""; |
3107 | + |
3108 | + parser->on_end_element_ns(Glib::ustring((const char*) name), pref, uri); |
3109 | + } |
3110 | + catch (...) |
3111 | + { |
3112 | + parser->handle_exception(); |
3113 | + } |
3114 | +} |
3115 | + |
3116 | +void SaxParserCallback::characters(void * context, const xmlChar* ch, int len) |
3117 | +{ |
3118 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3119 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3120 | + |
3121 | + try |
3122 | + { |
3123 | + // Here we force the use of Glib::ustring::ustring( InputIterator begin, InputIterator end ) |
3124 | + // instead of Glib::ustring::ustring( const char*, size_type ) because it |
3125 | + // expects the length of the string in characters, not in bytes. |
3126 | + parser->on_characters( |
3127 | + Glib::ustring( |
3128 | + reinterpret_cast<const char *>(ch), |
3129 | + reinterpret_cast<const char *>(ch + len) ) ); |
3130 | + } |
3131 | + catch (...) |
3132 | + { |
3133 | + parser->handle_exception(); |
3134 | + } |
3135 | +} |
3136 | + |
3137 | +void SaxParserCallback::comment(void* context, const xmlChar* value) |
3138 | +{ |
3139 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3140 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3141 | + |
3142 | + try |
3143 | + { |
3144 | + parser->on_comment(Glib::ustring((const char*) value)); |
3145 | + } |
3146 | + catch (...) |
3147 | + { |
3148 | + parser->handle_exception(); |
3149 | + } |
3150 | +} |
3151 | + |
3152 | +void SaxParserCallback::warning(void* context, const char* fmt, ...) |
3153 | +{ |
3154 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3155 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3156 | + |
3157 | + va_list arg; |
3158 | + va_start(arg, fmt); |
3159 | + const Glib::ustring buff = format_printf_message(fmt, arg); |
3160 | + va_end(arg); |
3161 | + |
3162 | + try |
3163 | + { |
3164 | + parser->on_warning(buff); |
3165 | + } |
3166 | + catch (...) |
3167 | + { |
3168 | + parser->handle_exception(); |
3169 | + } |
3170 | +} |
3171 | + |
3172 | +void SaxParserCallback::error(void* context, const char* fmt, ...) |
3173 | +{ |
3174 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3175 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3176 | + |
3177 | + if (parser->exception_) |
3178 | + return; |
3179 | + |
3180 | + va_list arg; |
3181 | + va_start(arg, fmt); |
3182 | + const Glib::ustring buff = format_printf_message(fmt, arg); |
3183 | + va_end(arg); |
3184 | + |
3185 | + try |
3186 | + { |
3187 | + parser->on_error(buff); |
3188 | + } |
3189 | + catch (...) |
3190 | + { |
3191 | + parser->handle_exception(); |
3192 | + } |
3193 | +} |
3194 | + |
3195 | +void SaxParserCallback::fatal_error(void* context, const char* fmt, ...) |
3196 | +{ |
3197 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3198 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3199 | + |
3200 | + va_list arg; |
3201 | + va_start(arg, fmt); |
3202 | + const Glib::ustring buff = format_printf_message(fmt, arg); |
3203 | + va_end(arg); |
3204 | + |
3205 | + try |
3206 | + { |
3207 | + parser->on_fatal_error(buff); |
3208 | + } |
3209 | + catch (...) |
3210 | + { |
3211 | + parser->handle_exception(); |
3212 | + } |
3213 | +} |
3214 | + |
3215 | +void SaxParserCallback::cdata_block(void* context, const xmlChar* value, int len) |
3216 | +{ |
3217 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3218 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3219 | + |
3220 | + try |
3221 | + { |
3222 | + // Here we force the use of Glib::ustring::ustring( InputIterator begin, InputIterator end ) |
3223 | + // see comments in SaxParserCallback::characters |
3224 | + parser->on_cdata_block( |
3225 | + Glib::ustring( |
3226 | + reinterpret_cast<const char *>(value), |
3227 | + reinterpret_cast<const char *>(value + len) ) ); |
3228 | + } |
3229 | + catch (...) |
3230 | + { |
3231 | + parser->handle_exception(); |
3232 | + } |
3233 | +} |
3234 | + |
3235 | +void SaxParserCallback::internal_subset(void* context, const xmlChar* name, |
3236 | + const xmlChar* publicId, const xmlChar* systemId) |
3237 | +{ |
3238 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3239 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3240 | + |
3241 | + try |
3242 | + { |
3243 | + const auto pid = publicId ? Glib::ustring((const char*) publicId) : ""; |
3244 | + const auto sid = systemId ? Glib::ustring((const char*) systemId) : ""; |
3245 | + |
3246 | + parser->on_internal_subset( Glib::ustring((const char*) name), pid, sid); |
3247 | + } |
3248 | + catch (...) |
3249 | + { |
3250 | + parser->handle_exception(); |
3251 | + } |
3252 | +} |
3253 | + |
3254 | +void SaxParserCallback::processing_instruction(void *context, const xmlChar *target, const xmlChar *data) |
3255 | +{ |
3256 | + auto the_context = static_cast<_xmlParserCtxt*>(context); |
3257 | + auto parser = static_cast<SaxParser*>(the_context->_private); |
3258 | + |
3259 | + try |
3260 | + { |
3261 | + parser->on_processing_instruction(Glib::ustring((const char*) target), Glib::ustring((const char*) data)); |
3262 | + } |
3263 | + catch (...) |
3264 | + { |
3265 | + parser->handle_exception(); |
3266 | + } |
3267 | +} |
3268 | + |
3269 | +} // namespace xmlpp |
3270 | |
3271 | === added file 'src/libxml++/parsers/saxparser.h' |
3272 | --- src/libxml++/parsers/saxparser.h 1970-01-01 00:00:00 +0000 |
3273 | +++ src/libxml++/parsers/saxparser.h 2016-11-06 17:18:04 +0000 |
3274 | @@ -0,0 +1,261 @@ |
3275 | +/* saxparser.h |
3276 | + * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and |
3277 | + * are covered by the GNU Lesser General Public License, which should be |
3278 | + * included with libxml++ as the file COPYING. |
3279 | + */ |
3280 | + |
3281 | +#ifndef __LIBXMLPP_PARSERS_SAXPARSER_H |
3282 | +#define __LIBXMLPP_PARSERS_SAXPARSER_H |
3283 | + |
3284 | +#include <libxml++/parsers/parser.h> |
3285 | + |
3286 | +#include <deque> |
3287 | +#include <memory> |
3288 | +#include "libxml++/document.h" |
3289 | + |
3290 | +#ifndef DOXYGEN_SHOULD_SKIP_THIS |
3291 | +extern "C" { |
3292 | + struct _xmlSAXHandler; |
3293 | + struct _xmlEntity; |
3294 | +} |
3295 | +#endif //DOXYGEN_SHOULD_SKIP_THIS |
3296 | + |
3297 | +namespace xmlpp { |
3298 | + |
3299 | +/** SAX XML parser. |
3300 | + * Derive your own class and override the on_*() methods. |
3301 | + * SAX = Simple API for XML |
3302 | + * |
3303 | + * In a system that does not support std::exception_ptr: If an overridden on_*() |
3304 | + * method throws an exception which is not derived from xmlpp::exception, |
3305 | + * that exception is replaced by a xmlpp::exception before it is propagated |
3306 | + * out of the parse method, such as parse_file(). |
3307 | + */ |
3308 | +class SaxParser : public Parser |
3309 | +{ |
3310 | +public: |
3311 | + /** |
3312 | + * Simple structure used in the start_element callbacks, in which |
3313 | + * the namespaces are a list of prefix/uri pairs. |
3314 | + */ |
3315 | + struct Namespace |
3316 | + { |
3317 | + Glib::ustring prefix; |
3318 | + Glib::ustring uri; |
3319 | + |
3320 | + Namespace() |
3321 | + { |
3322 | + } |
3323 | + |
3324 | + Namespace(Glib::ustring const & p, Glib::ustring const & u) |
3325 | + : prefix(p), uri(u) |
3326 | + { |
3327 | + } |
3328 | + }; |
3329 | + /** |
3330 | + * Simple structure used in the start_element callbacks, in which |
3331 | + * the attributes are a list of name/value/namespace tuples. |
3332 | + */ |
3333 | + struct Attribute |
3334 | + { |
3335 | + Glib::ustring name; |
3336 | + Glib::ustring value; |
3337 | + Namespace ns; |
3338 | + |
3339 | + Attribute(Glib::ustring const & n, Glib::ustring const & v) |
3340 | + : name(n), value(v) |
3341 | + { |
3342 | + } |
3343 | + |
3344 | + Attribute(Glib::ustring const & n, Glib::ustring const & v, Glib::ustring const & p, Glib::ustring const & u) |
3345 | + : name(n), value(v), ns(Namespace(p, u)) |
3346 | + { |
3347 | + } |
3348 | + }; |
3349 | + |
3350 | + using AttributeList = std::deque<Attribute>; |
3351 | + using NamespaceList = std::deque<Namespace>; |
3352 | + |
3353 | + /** This functor is a helper to find an attribute by name in an |
3354 | + * AttributeList using the standard algorithm std::find_if |
3355 | + * |
3356 | + * Example:@n |
3357 | + * <code> |
3358 | + * Glib::ustring name = "foo";@n |
3359 | + * AttributeList::const_iterator attribute = std::find_if(attributes.begin(), attributes.end(), AttributeHasName(name)); |
3360 | + * </code> |
3361 | + */ |
3362 | + struct AttributeHasName |
3363 | + { |
3364 | + Glib::ustring const & name; |
3365 | + |
3366 | + AttributeHasName(Glib::ustring const & n) |
3367 | + : name(n) |
3368 | + { |
3369 | + } |
3370 | + |
3371 | + bool operator()(Attribute const & attribute) |
3372 | + { |
3373 | + return attribute.name == name; |
3374 | + } |
3375 | + }; |
3376 | + |
3377 | + /** |
3378 | + * @param use_get_entity Set this to true if you will override on_get_entity(). |
3379 | + * In theory, if you do not override on_get_entity() the parser should behave exactly the same |
3380 | + * whether you use true or false here. But the default implementation of on_get_entity(), needed |
3381 | + * if you override on_get_entity() might not have the same behaviour as the underlying default |
3382 | + * behaviour of libxml, so the libxml implementation is the default here. |
3383 | + */ |
3384 | + SaxParser(bool use_get_entity = false); |
3385 | + ~SaxParser() override; |
3386 | + |
3387 | + /** Parse an XML document from a file. |
3388 | + * @param filename The path to the file. |
3389 | + * @throws xmlpp::internal_error |
3390 | + * @throws xmlpp::parse_error |
3391 | + * @throws xmlpp::validity_error |
3392 | + */ |
3393 | + void parse_file(const std::string& filename) override; |
3394 | + |
3395 | + /** Parse an XML document from a string. |
3396 | + * @param contents The XML document as a string. |
3397 | + * @throws xmlpp::internal_error |
3398 | + * @throws xmlpp::parse_error |
3399 | + * @throws xmlpp::validity_error |
3400 | + */ |
3401 | + void parse_memory(const Glib::ustring& contents) override; |
3402 | + |
3403 | + /** Parse an XML document from raw memory. |
3404 | + * @param contents The XML document as an array of bytes. |
3405 | + * @param bytes_count The number of bytes in the @a contents array. |
3406 | + * @throws xmlpp::internal_error |
3407 | + * @throws xmlpp::parse_error |
3408 | + * @throws xmlpp::validity_error |
3409 | + */ |
3410 | + void parse_memory_raw(const unsigned char* contents, size_type bytes_count) override; |
3411 | + |
3412 | + /** Parse an XML document from a stream. |
3413 | + * @param in The stream. |
3414 | + * @throws xmlpp::internal_error |
3415 | + * @throws xmlpp::parse_error |
3416 | + * @throws xmlpp::validity_error |
3417 | + */ |
3418 | + void parse_stream(std::istream& in) override; |
3419 | + |
3420 | + /** Parse a chunk of data. |
3421 | + * |
3422 | + * This lets you pass a document in small chunks, e.g. from a network |
3423 | + * connection. The on_* virtual functions are called each time the chunks |
3424 | + * provide enough information to advance the parser. |
3425 | + * |
3426 | + * The first call to parse_chunk() will setup the parser. When the last chunk |
3427 | + * has been parsed, call finish_chunk_parsing() to finish the parse. |
3428 | + * |
3429 | + * @param chunk The next piece of the XML document. |
3430 | + * @throws xmlpp::internal_error |
3431 | + * @throws xmlpp::parse_error |
3432 | + * @throws xmlpp::validity_error |
3433 | + */ |
3434 | + void parse_chunk(const Glib::ustring& chunk); |
3435 | + |
3436 | + /** Parse a chunk of data. |
3437 | + * |
3438 | + * @newin{2,24} |
3439 | + * |
3440 | + * This lets you pass a document in small chunks, e.g. from a network |
3441 | + * connection. The on_* virtual functions are called each time the chunks |
3442 | + * provide enough information to advance the parser. |
3443 | + * |
3444 | + * The first call to parse_chunk_raw() will setup the parser. When the last chunk |
3445 | + * has been parsed, call finish_chunk_parsing() to finish the parse. |
3446 | + * |
3447 | + * @param contents The next piece of the XML document as an array of bytes. |
3448 | + * @param bytes_count The number of bytes in the @a contents array. |
3449 | + * @throws xmlpp::internal_error |
3450 | + * @throws xmlpp::parse_error |
3451 | + * @throws xmlpp::validity_error |
3452 | + */ |
3453 | + void parse_chunk_raw(const unsigned char* contents, size_type bytes_count); |
3454 | + |
3455 | + /** Finish a chunk-wise parse. |
3456 | + * |
3457 | + * Call this after the last call to parse_chunk() or parse_chunk_raw(). |
3458 | + * Don't use this function with the other parsing methods. |
3459 | + * @throws xmlpp::internal_error |
3460 | + * @throws xmlpp::parse_error |
3461 | + * @throws xmlpp::validity_error |
3462 | + */ |
3463 | + void finish_chunk_parsing(); |
3464 | + |
3465 | +protected: |
3466 | + |
3467 | + virtual void on_start_document(); |
3468 | + virtual void on_end_document(); |
3469 | + virtual void on_start_element(const Glib::ustring& name, const AttributeList& attributes); |
3470 | + virtual void on_end_element(const Glib::ustring& name); |
3471 | + virtual void on_start_element_ns(const Glib::ustring& name, const Glib::ustring& prefix, const Glib::ustring& uri, const NamespaceList& namespaces, const AttributeList& attributes); |
3472 | + virtual void on_end_element_ns(const Glib::ustring& name, const Glib::ustring& prefix, const Glib::ustring& uri); |
3473 | + virtual void on_characters(const Glib::ustring& characters); |
3474 | + virtual void on_comment(const Glib::ustring& text); |
3475 | + virtual void on_processing_instruction(const Glib::ustring& target, const Glib::ustring& data); |
3476 | + virtual void on_warning(const Glib::ustring& text); |
3477 | + virtual void on_error(const Glib::ustring& text); |
3478 | + |
3479 | + /** @throws xmlpp::parse_error |
3480 | + */ |
3481 | + virtual void on_fatal_error(const Glib::ustring& text); |
3482 | + virtual void on_cdata_block(const Glib::ustring& text); |
3483 | + |
3484 | + /** Override this to receive information about the document's DTD and any entity declarations. |
3485 | + */ |
3486 | + virtual void on_internal_subset(const Glib::ustring& name, const Glib::ustring& publicId, const Glib::ustring& systemId); |
3487 | + |
3488 | + /** Override this method to resolve entities references in your derived parser, instead of using the default entity resolution, |
3489 | + * or to be informed when entity references are encountered. |
3490 | + * |
3491 | + * If you override this function then you must also specify true for use_get_entity constructor parameter. |
3492 | + * You will probably need to override on_entity_declaration() as well so that you can use that information when |
3493 | + * resolving the entity reference. |
3494 | + * |
3495 | + * This is known to be difficult, because it requires both an understanding of the W3C specifications and knowledge of the |
3496 | + * libxml internals. Entity resolution is easier with the DomParser. |
3497 | + * |
3498 | + * Call this method in this base class for default processing. For instance, if you just want to know about the existence of |
3499 | + * an entity reference, without affecting the normal substitution, just override and call the base class. |
3500 | + * |
3501 | + * Unlike the DomParser, the SaxParser will also tell you about entity references for the 5 predefined entities. |
3502 | + * |
3503 | + * @param name The entity reference name. |
3504 | + * @returns The resolved xmlEntity for the entity reference, or <tt>nullptr</tt> if not found. |
3505 | + * You must include libxml/parser.h in order to use this C struct. |
3506 | + * This instance will not be freed by the caller. |
3507 | + */ |
3508 | + virtual _xmlEntity* on_get_entity(const Glib::ustring& name); |
3509 | + |
3510 | + /** Override this to receive information about every entity declaration. |
3511 | + * If you override this function, and you want normal entity substitution to work, then you must call the base class in your override. |
3512 | + * |
3513 | + * This would be useful when overriding on_get_entity(). |
3514 | + * @throws xmlpp::internal_error |
3515 | + */ |
3516 | + virtual void on_entity_declaration(const Glib::ustring& name, XmlEntityType type, const Glib::ustring& publicId, const Glib::ustring& systemId, const Glib::ustring& content); |
3517 | + |
3518 | + void release_underlying() override; |
3519 | + void initialize_context() override; |
3520 | + |
3521 | +private: |
3522 | + void parse(); |
3523 | + |
3524 | + std::unique_ptr<_xmlSAXHandler> sax_handler_; |
3525 | + |
3526 | + // A separate xmlpp::Document that is just used for entity resolution, |
3527 | + // and never seen in the API: |
3528 | + std::unique_ptr<Document> entity_resolver_doc_; |
3529 | + |
3530 | + friend struct SaxParserCallback; |
3531 | +}; |
3532 | + |
3533 | +} // namespace xmlpp |
3534 | + |
3535 | +#endif //__LIBXMLPP_PARSERS_SAXPARSER_H |
3536 | |
3537 | === modified file 'src/preferences.cpp' |
3538 | --- src/preferences.cpp 2016-09-20 11:19:44 +0000 |
3539 | +++ src/preferences.cpp 2016-11-06 17:18:04 +0000 |
3540 | @@ -17,6 +17,7 @@ |
3541 | #include <glibmm/i18n.h> |
3542 | #include <glib/gstdio.h> |
3543 | #include <gtk/gtk.h> |
3544 | +#include <xml/repr-io.h> |
3545 | #include "preferences.h" |
3546 | #include "preferences-skeleton.h" |
3547 | #include "inkscape.h" |
3548 | @@ -123,7 +124,7 @@ |
3549 | */ |
3550 | void Preferences::_loadDefaults() |
3551 | { |
3552 | - _prefs_doc = sp_repr_read_mem(preferences_skeleton, PREFERENCES_SKELETON_SIZE, NULL); |
3553 | + _prefs_doc = Inkscape::XML::read_svg_buffer(preferences_skeleton, true); |
3554 | } |
3555 | |
3556 | /** |
3557 | @@ -231,7 +232,8 @@ |
3558 | } |
3559 | |
3560 | // 4. Is it valid XML? |
3561 | - Inkscape::XML::Document *prefs_read = sp_repr_read_mem(prefs_xml, len, NULL); |
3562 | + Inkscape::XML::Document *prefs_read = Inkscape::XML::read_svg_buffer(prefs_xml, true); |
3563 | + |
3564 | g_free(prefs_xml); |
3565 | if (!prefs_read) { |
3566 | gchar *msg = g_strdup_printf(_("The preferences file %s is not a valid XML document."), |
3567 | @@ -281,7 +283,7 @@ |
3568 | // There are many other factors, so ask if you would like to learn them. - JAC |
3569 | Glib::ustring utf8name = Glib::filename_to_utf8(_prefs_filename); |
3570 | if (!utf8name.empty()) { |
3571 | - sp_repr_save_file(_prefs_doc, utf8name.c_str()); |
3572 | + Inkscape::XML::save_svg_file(_prefs_doc, utf8name); |
3573 | } |
3574 | } |
3575 | } |
3576 | |
3577 | === modified file 'src/shortcuts.cpp' |
3578 | --- src/shortcuts.cpp 2016-08-03 13:29:38 +0000 |
3579 | +++ src/shortcuts.cpp 2016-11-06 17:18:04 +0000 |
3580 | @@ -32,6 +32,7 @@ |
3581 | #include <glibmm/i18n.h> |
3582 | #include <glibmm/convert.h> |
3583 | #include <glibmm/miscutils.h> |
3584 | +#include <xml/repr-io.h> |
3585 | |
3586 | #include "helper/action.h" |
3587 | #include "io/sys.h" |
3588 | @@ -160,7 +161,7 @@ |
3589 | |
3590 | char const *filename = get_path(USER, KEYS, "default.xml"); |
3591 | |
3592 | - XML::Document *doc=sp_repr_read_file(filename, NULL); |
3593 | + XML::Document *doc = Inkscape::XML::read_svg_file(filename, true); |
3594 | if (!doc) { |
3595 | g_warning("Unable to read keys file %s", filename); |
3596 | return; |
3597 | @@ -183,8 +184,7 @@ |
3598 | iter=root->firstChild(); |
3599 | } |
3600 | |
3601 | - |
3602 | - sp_repr_save_file(doc, filename, NULL); |
3603 | + Inkscape::XML::save_svg_file(doc, filename); |
3604 | |
3605 | GC::release(doc); |
3606 | } |
3607 | @@ -196,10 +196,10 @@ |
3608 | "<keys name=\"My custom shortcuts\">" |
3609 | "</keys>"; |
3610 | |
3611 | - Inkscape::XML::Document *doc = sp_repr_read_mem(buffer, strlen(buffer), NULL); |
3612 | - sp_repr_save_file(doc, filename, NULL); |
3613 | + Inkscape::XML::Document *doc = Inkscape::XML::read_svg_buffer(buffer, true); |
3614 | + Inkscape::XML::save_svg_file(doc, filename); |
3615 | |
3616 | - return sp_repr_read_file(filename, NULL); |
3617 | + return Inkscape::XML::read_svg_file(filename, true); |
3618 | } |
3619 | |
3620 | /* |
3621 | @@ -242,7 +242,7 @@ |
3622 | if (!Inkscape::IO::file_test(full, G_FILE_TEST_IS_DIR)) { |
3623 | |
3624 | // Get the "key name" from the root element of each file |
3625 | - XML::Document *doc=sp_repr_read_file(full, NULL); |
3626 | + XML::Document *doc = Inkscape::XML::read_svg_file(full, true); |
3627 | if (!doc) { |
3628 | g_warning("Unable to read keyboard shortcut file %s", full); |
3629 | continue; |
3630 | @@ -385,15 +385,15 @@ |
3631 | } |
3632 | |
3633 | void sp_shortcut_file_import_do(char const *importname) { |
3634 | + XML::Document *doc = Inkscape::XML::read_svg_file(importname, true); |
3635 | |
3636 | - XML::Document *doc=sp_repr_read_file(importname, NULL); |
3637 | if (!doc) { |
3638 | g_warning("Unable to read keyboard shortcut file %s", importname); |
3639 | return; |
3640 | } |
3641 | |
3642 | char const *filename = get_path(USER, KEYS, "default.xml"); |
3643 | - sp_repr_save_file(doc, filename, NULL); |
3644 | + Inkscape::XML::save_svg_file(doc, filename); |
3645 | |
3646 | GC::release(doc); |
3647 | |
3648 | @@ -404,13 +404,13 @@ |
3649 | |
3650 | char const *filename = get_path(USER, KEYS, "default.xml"); |
3651 | |
3652 | - XML::Document *doc=sp_repr_read_file(filename, NULL); |
3653 | + XML::Document *doc = Inkscape::XML::read_svg_file(filename, true); |
3654 | if (!doc) { |
3655 | g_warning("Unable to read keyboard shortcut file %s", filename); |
3656 | return; |
3657 | } |
3658 | |
3659 | - sp_repr_save_file(doc, exportname, NULL); |
3660 | + Inkscape::XML::save_svg_file(doc, exportname); |
3661 | |
3662 | GC::release(doc); |
3663 | } |
3664 | @@ -428,7 +428,7 @@ |
3665 | |
3666 | char const *filename = get_path(USER, KEYS, "default.xml"); |
3667 | |
3668 | - XML::Document *doc=sp_repr_read_file(filename, NULL); |
3669 | + XML::Document *doc = Inkscape::XML::read_svg_file(filename, true); |
3670 | if (!doc) { |
3671 | g_warning("Unable to read keyboard shortcut file %s", filename); |
3672 | return; |
3673 | @@ -486,7 +486,7 @@ |
3674 | iter = iter->next(); |
3675 | } |
3676 | |
3677 | - sp_repr_save_file(doc, filename, NULL); |
3678 | + Inkscape::XML::save_svg_file(doc, filename); |
3679 | |
3680 | GC::release(doc); |
3681 | |
3682 | @@ -496,7 +496,7 @@ |
3683 | |
3684 | char const *filename = get_path(USER, KEYS, "default.xml"); |
3685 | |
3686 | - XML::Document *doc=sp_repr_read_file(filename, NULL); |
3687 | + XML::Document *doc = Inkscape::XML::read_svg_file(filename, true); |
3688 | if (!doc) { |
3689 | g_warning("Unable to read keyboard shortcut file %s, creating ....", filename); |
3690 | doc = sp_shortcut_create_template_file(filename); |
3691 | @@ -541,13 +541,13 @@ |
3692 | doc->root()->appendChild(newnode); |
3693 | } |
3694 | |
3695 | - sp_repr_save_file(doc, filename, NULL); |
3696 | + Inkscape::XML::save_svg_file(doc, filename); |
3697 | |
3698 | GC::release(doc); |
3699 | |
3700 | } |
3701 | static void read_shortcuts_file(char const *filename, bool const is_user_set) { |
3702 | - XML::Document *doc=sp_repr_read_file(filename, NULL); |
3703 | + XML::Document *doc = Inkscape::XML::read_svg_file(filename, true); |
3704 | if (!doc) { |
3705 | g_warning("Unable to read keys file %s", filename); |
3706 | return; |
3707 | |
3708 | === modified file 'src/ui/dialog/template-load-tab.cpp' |
3709 | --- src/ui/dialog/template-load-tab.cpp 2016-08-03 13:29:38 +0000 |
3710 | +++ src/ui/dialog/template-load-tab.cpp 2016-11-06 17:18:04 +0000 |
3711 | @@ -17,6 +17,7 @@ |
3712 | #include <gtkmm/messagedialog.h> |
3713 | #include <gtkmm/scrolledwindow.h> |
3714 | #include <iostream> |
3715 | +#include <xml/repr-io.h> |
3716 | |
3717 | #include "extension/db.h" |
3718 | #include "inkscape.h" |
3719 | @@ -234,7 +235,7 @@ |
3720 | n = result.display_name.rfind(".svg"); |
3721 | result.display_name.replace(n, 4, 1, ' '); |
3722 | |
3723 | - Inkscape::XML::Document *rdoc = sp_repr_read_file(path.data(), SP_SVG_NS_URI); |
3724 | + Inkscape::XML::Document *rdoc = Inkscape::XML::read_svg_file(path.data(), false, SP_SVG_NS_URI); |
3725 | if (rdoc){ |
3726 | Inkscape::XML::Node *myRoot = rdoc->root(); |
3727 | if (strcmp(myRoot->name(), "svg:svg") != 0){ // Wrong file format |
3728 | |
3729 | === modified file 'src/ui/interface.cpp' |
3730 | --- src/ui/interface.cpp 2016-10-24 22:58:43 +0000 |
3731 | +++ src/ui/interface.cpp 2016-11-06 17:18:04 +0000 |
3732 | @@ -29,6 +29,7 @@ |
3733 | #include <glibmm/miscutils.h> |
3734 | #include <gtkmm/imagemenuitem.h> |
3735 | #include <gtkmm/separatormenuitem.h> |
3736 | +#include <xml/repr-io.h> |
3737 | |
3738 | #include "inkscape.h" |
3739 | #include "extension/db.h" |
3740 | @@ -1174,7 +1175,7 @@ |
3741 | case SVG_XML_DATA: { |
3742 | gchar *svgdata = (gchar *)gtk_selection_data_get_data (data); |
3743 | |
3744 | - Inkscape::XML::Document *rnewdoc = sp_repr_read_mem(svgdata, gtk_selection_data_get_length (data), SP_SVG_NS_URI); |
3745 | + Inkscape::XML::Document *rnewdoc = Inkscape::XML::read_svg_buffer(svgdata, false, SP_SVG_NS_URI); |
3746 | |
3747 | if (rnewdoc == NULL) { |
3748 | sp_ui_error_dialog(_("Could not parse SVG data")); |
3749 | |
3750 | === modified file 'src/xml/CMakeLists.txt' |
3751 | --- src/xml/CMakeLists.txt 2011-10-08 06:34:23 +0000 |
3752 | +++ src/xml/CMakeLists.txt 2016-11-06 17:18:04 +0000 |
3753 | @@ -16,7 +16,7 @@ |
3754 | subtree.cpp |
3755 | helper-observer.cpp |
3756 | rebase-hrefs.cpp |
3757 | - |
3758 | + svg-parser.cpp |
3759 | |
3760 | # ------- |
3761 | # Headers |
3762 | @@ -42,12 +42,14 @@ |
3763 | rebase-hrefs-test.h |
3764 | rebase-hrefs.h |
3765 | repr-action-test.h |
3766 | + repr-io.h |
3767 | repr-sorting.h |
3768 | repr.h |
3769 | simple-document.h |
3770 | simple-node.h |
3771 | sp-css-attr.h |
3772 | subtree.h |
3773 | + svg-parser.h |
3774 | text-node.h |
3775 | ) |
3776 | |
3777 | |
3778 | === modified file 'src/xml/comment-node.h' |
3779 | --- src/xml/comment-node.h 2011-12-08 11:53:54 +0000 |
3780 | +++ src/xml/comment-node.h 2016-11-06 17:18:04 +0000 |
3781 | @@ -17,6 +17,7 @@ |
3782 | |
3783 | #include <glib.h> |
3784 | #include "xml/simple-node.h" |
3785 | +#include "io/inkscapestream.h" |
3786 | |
3787 | namespace Inkscape { |
3788 | |
3789 | @@ -37,6 +38,14 @@ |
3790 | |
3791 | Inkscape::XML::NodeType type() const { return Inkscape::XML::COMMENT_NODE; } |
3792 | |
3793 | + void serialize(Inkscape::IO::Writer& out, const Glib::ustring& defaultPrefix, int indent, int indent_level, bool inline_attributes, bool preserve_spaces) override { |
3794 | + Glib::ustring real_indentation((unsigned long) (indent * indent_level), ' '); |
3795 | + out.writeUString(real_indentation); |
3796 | + out.writeString("<!--"); |
3797 | + out.writeString(content()); |
3798 | + out.writeString("-->\n"); |
3799 | + } |
3800 | + |
3801 | protected: |
3802 | SimpleNode *_duplicate(Document* doc) const { return new CommentNode(*this, doc); } |
3803 | }; |
3804 | |
3805 | === modified file 'src/xml/node.h' |
3806 | --- src/xml/node.h 2014-12-16 14:05:47 +0000 |
3807 | +++ src/xml/node.h 2016-11-06 17:18:04 +0000 |
3808 | @@ -23,6 +23,11 @@ |
3809 | #include "util/list.h" |
3810 | |
3811 | namespace Inkscape { |
3812 | + |
3813 | +namespace IO { |
3814 | +class Writer; |
3815 | +} |
3816 | + |
3817 | namespace XML { |
3818 | |
3819 | struct AttributeRecord; |
3820 | @@ -193,8 +198,17 @@ |
3821 | * @param value The node's new content |
3822 | */ |
3823 | virtual void setContent(char const *value)=0; |
3824 | - |
3825 | - //@{ |
3826 | + |
3827 | + /** |
3828 | + * @brief Change a namespace of this node |
3829 | + * |
3830 | + * The strings passed to this method are copied, so you can free them after use. |
3831 | + * |
3832 | + * @param prefix namespace prefix |
3833 | + * @param uri namespace uri |
3834 | + */ |
3835 | + virtual void setNamespace(Glib::ustring const &prefix, Glib::ustring const &uri) = 0; |
3836 | + |
3837 | /** |
3838 | * @brief Change an attribute of this node |
3839 | * |
3840 | @@ -470,9 +484,18 @@ |
3841 | */ |
3842 | virtual void synthesizeEvents(NodeEventVector const *vector, void *data)=0; |
3843 | |
3844 | + /** |
3845 | + * @brief serialize node and all descendants into given stream |
3846 | + * @param out output writer |
3847 | + * @param indent size of indent in characters |
3848 | + * @param indent_level level of indent, every child should have indent_level of parent plus 1 |
3849 | + * @param inline_attributes whether attributes should be printed in one line |
3850 | + * @param preserve_spaces whether xml:space is set to 'preserve' |
3851 | + * @param defaultPrefix prefix for default namespace |
3852 | + */ |
3853 | + virtual void serialize(Inkscape::IO::Writer& out, const Glib::ustring& defaultPrefix, int indent, int indent_level, bool inline_attributes, bool preserve_spaces) = 0; |
3854 | + |
3855 | virtual void recursivePrintTree(unsigned level)=0; |
3856 | - |
3857 | - /*@}*/ |
3858 | |
3859 | protected: |
3860 | Node(Node const &) : Anchored() {} |
3861 | |
3862 | === modified file 'src/xml/pi-node.h' |
3863 | --- src/xml/pi-node.h 2014-10-08 02:22:03 +0000 |
3864 | +++ src/xml/pi-node.h 2016-11-06 17:18:04 +0000 |
3865 | @@ -15,6 +15,7 @@ |
3866 | #define SEEN_INKSCAPE_XML_PI_NODE_H |
3867 | |
3868 | #include "xml/simple-node.h" |
3869 | +#include "io/inkscapestream.h" |
3870 | |
3871 | namespace Inkscape { |
3872 | |
3873 | @@ -34,6 +35,11 @@ |
3874 | |
3875 | Inkscape::XML::NodeType type() const { return Inkscape::XML::PI_NODE; } |
3876 | |
3877 | + void serialize(Inkscape::IO::Writer& out, const Glib::ustring& defaultPrefix, int indent, int indent_level, bool inline_attributes, bool preserve_spaces) override { |
3878 | + out.printf("<?%s %s?>\n", name(), content()); |
3879 | + } |
3880 | + |
3881 | + |
3882 | protected: |
3883 | SimpleNode *_duplicate(Document* doc) const { return new PINode(*this, doc); } |
3884 | }; |
3885 | |
3886 | === modified file 'src/xml/repr-io.cpp' |
3887 | --- src/xml/repr-io.cpp 2016-08-03 13:29:38 +0000 |
3888 | +++ src/xml/repr-io.cpp 2016-11-06 17:18:04 +0000 |
3889 | @@ -1,1091 +1,200 @@ |
3890 | /* |
3891 | - * Dirty DOM-like tree |
3892 | + * IO functions for svg files. |
3893 | * |
3894 | * Authors: |
3895 | - * Lauris Kaplinski <lauris@kaplinski.com> |
3896 | - * bulia byak <buliabyak@users.sf.net> |
3897 | + * Adrian Boguszewski |
3898 | * |
3899 | - * Copyright (C) 1999-2002 Lauris Kaplinski |
3900 | + * Copyright (C) 2016 Adrian Boguszewski |
3901 | * |
3902 | * Released under GNU GPL, read the file 'COPYING' for more information |
3903 | */ |
3904 | |
3905 | -#ifdef HAVE_CONFIG_H |
3906 | -#include <config.h> |
3907 | -#endif |
3908 | - |
3909 | -#include <cstring> |
3910 | -#include <string> |
3911 | -#include <stdexcept> |
3912 | - |
3913 | -#include <libxml/parser.h> |
3914 | - |
3915 | -#include "xml/repr.h" |
3916 | -#include "xml/attribute-record.h" |
3917 | -#include "xml/rebase-hrefs.h" |
3918 | -#include "xml/simple-document.h" |
3919 | -#include "xml/text-node.h" |
3920 | - |
3921 | -#include "io/sys.h" |
3922 | #include "io/uristream.h" |
3923 | #include "io/stringstream.h" |
3924 | #include "io/gzipstream.h" |
3925 | - |
3926 | -#include "extension/extension.h" |
3927 | - |
3928 | #include "attribute-rel-util.h" |
3929 | #include "attribute-sort-util.h" |
3930 | - |
3931 | #include "preferences.h" |
3932 | - |
3933 | +#include "repr-io.h" |
3934 | +#include "rebase-hrefs.h" |
3935 | +#include "simple-node.h" |
3936 | +#include "util/list.h" |
3937 | +#include "svg-parser.h" |
3938 | +#include "xml/attribute-record.h" |
3939 | +#include <boost/algorithm/string.hpp> |
3940 | +#include <io/sys.h> |
3941 | #include <glibmm/miscutils.h> |
3942 | - |
3943 | -using Inkscape::IO::Writer; |
3944 | -using Inkscape::Util::List; |
3945 | -using Inkscape::Util::cons; |
3946 | -using Inkscape::XML::Document; |
3947 | -using Inkscape::XML::SimpleDocument; |
3948 | -using Inkscape::XML::Node; |
3949 | -using Inkscape::XML::AttributeRecord; |
3950 | -using Inkscape::XML::calc_abs_doc_base; |
3951 | -using Inkscape::XML::rebase_href_attrs; |
3952 | - |
3953 | -Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns); |
3954 | -static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, std::map<std::string, std::string> &prefix_map); |
3955 | -static gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar *default_ns, std::map<std::string, std::string> &prefix_map); |
3956 | -static void sp_repr_write_stream_root_element(Node *repr, Writer &out, |
3957 | - bool add_whitespace, gchar const *default_ns, |
3958 | - int inlineattrs, int indent, |
3959 | - gchar const *old_href_abs_base, |
3960 | - gchar const *new_href_abs_base); |
3961 | - |
3962 | -static void sp_repr_write_stream_element(Node *repr, Writer &out, |
3963 | - gint indent_level, bool add_whitespace, |
3964 | - Glib::QueryQuark elide_prefix, |
3965 | - List<AttributeRecord const> attributes, |
3966 | - int inlineattrs, int indent, |
3967 | - gchar const *old_href_abs_base, |
3968 | - gchar const *new_href_abs_base); |
3969 | - |
3970 | -#ifdef HAVE_LIBWMF |
3971 | -static xmlDocPtr sp_wmf_convert (const char * file_name); |
3972 | -static char * sp_wmf_image_name (void * context); |
3973 | -#endif /* HAVE_LIBWMF */ |
3974 | - |
3975 | - |
3976 | -class XmlSource |
3977 | -{ |
3978 | -public: |
3979 | - XmlSource() |
3980 | - : filename(0), |
3981 | - encoding(0), |
3982 | - fp(NULL), |
3983 | - firstFewLen(0), |
3984 | - LoadEntities(false), |
3985 | - cachedData(), |
3986 | - cachedPos(0), |
3987 | - dummy("x"), |
3988 | - instr(NULL), |
3989 | - gzin(NULL) |
3990 | - { |
3991 | - for (int k=0;k<4;k++) |
3992 | - { |
3993 | - firstFew[k]=0; |
3994 | - } |
3995 | - } |
3996 | - virtual ~XmlSource() |
3997 | - { |
3998 | - close(); |
3999 | - if ( encoding ) { |
4000 | - g_free(encoding); |
4001 | - encoding = 0; |
4002 | - } |
4003 | - } |
4004 | - |
4005 | - int setFile( char const * filename, bool load_entities ); |
4006 | - |
4007 | - xmlDocPtr readXml(); |
4008 | - |
4009 | - static int readCb( void * context, char * buffer, int len ); |
4010 | - static int closeCb( void * context ); |
4011 | - |
4012 | - char const* getEncoding() const { return encoding; } |
4013 | - int read( char * buffer, int len ); |
4014 | - int close(); |
4015 | -private: |
4016 | - const char* filename; |
4017 | - char* encoding; |
4018 | - FILE* fp; |
4019 | - unsigned char firstFew[4]; |
4020 | - int firstFewLen; |
4021 | - bool LoadEntities; // Checks for SYSTEM Entities (requires cached data) |
4022 | - std::string cachedData; |
4023 | - unsigned int cachedPos; |
4024 | - Inkscape::URI dummy; |
4025 | - Inkscape::IO::UriInputStream* instr; |
4026 | - Inkscape::IO::GzipInputStream* gzin; |
4027 | -}; |
4028 | - |
4029 | -int XmlSource::setFile(char const *filename, bool load_entities=false) |
4030 | -{ |
4031 | - int retVal = -1; |
4032 | - |
4033 | - this->filename = filename; |
4034 | - |
4035 | - fp = Inkscape::IO::fopen_utf8name(filename, "r"); |
4036 | - if ( fp ) { |
4037 | - // First peek in the file to see what it is |
4038 | - memset( firstFew, 0, sizeof(firstFew) ); |
4039 | - |
4040 | - size_t some = fread( firstFew, 1, 4, fp ); |
4041 | - if ( fp ) { |
4042 | - // first check for compression |
4043 | - if ( (some >= 2) && (firstFew[0] == 0x1f) && (firstFew[1] == 0x8b) ) { |
4044 | - //g_message(" the file being read is gzip'd. extract it"); |
4045 | - fclose(fp); |
4046 | - fp = 0; |
4047 | - fp = Inkscape::IO::fopen_utf8name(filename, "r"); |
4048 | - instr = new Inkscape::IO::UriInputStream(fp, dummy); |
4049 | - gzin = new Inkscape::IO::GzipInputStream(*instr); |
4050 | - |
4051 | - memset( firstFew, 0, sizeof(firstFew) ); |
4052 | - some = 0; |
4053 | - int single = 0; |
4054 | - while ( some < 4 && single >= 0 ) |
4055 | - { |
4056 | - single = gzin->get(); |
4057 | - if ( single >= 0 ) { |
4058 | - firstFew[some++] = 0x0ff & single; |
4059 | - } else { |
4060 | - break; |
4061 | - } |
4062 | - } |
4063 | - } |
4064 | - |
4065 | - int encSkip = 0; |
4066 | - if ( (some >= 2) &&(firstFew[0] == 0xfe) && (firstFew[1] == 0xff) ) { |
4067 | - encoding = g_strdup("UTF-16BE"); |
4068 | - encSkip = 2; |
4069 | - } else if ( (some >= 2) && (firstFew[0] == 0xff) && (firstFew[1] == 0xfe) ) { |
4070 | - encoding = g_strdup("UTF-16LE"); |
4071 | - encSkip = 2; |
4072 | - } else if ( (some >= 3) && (firstFew[0] == 0xef) && (firstFew[1] == 0xbb) && (firstFew[2] == 0xbf) ) { |
4073 | - encoding = g_strdup("UTF-8"); |
4074 | - encSkip = 3; |
4075 | - } |
4076 | - |
4077 | - if ( encSkip ) { |
4078 | - memmove( firstFew, firstFew + encSkip, (some - encSkip) ); |
4079 | - some -= encSkip; |
4080 | - } |
4081 | - |
4082 | - firstFewLen = some; |
4083 | - retVal = 0; // no error |
4084 | - } |
4085 | - } |
4086 | - if(load_entities) { |
4087 | - this->cachedData = std::string(""); |
4088 | - this->cachedPos = 0; |
4089 | - |
4090 | - // First get data from file in typical way (cache it all) |
4091 | - char *buffer = new char [4096]; |
4092 | - while(true) { |
4093 | - int len = this->read(buffer, 4096); |
4094 | - if(len <= 0) break; |
4095 | - buffer[len] = 0; |
4096 | - this->cachedData += buffer; |
4097 | - } |
4098 | - delete[] buffer; |
4099 | - |
4100 | - // Check for SYSTEM or PUBLIC entities and remove them from the cache |
4101 | - GMatchInfo *info; |
4102 | - gint start, end; |
4103 | - |
4104 | - GRegex *regex = g_regex_new( |
4105 | - "<!ENTITY\\s+[^>\\s]+\\s+(SYSTEM|PUBLIC\\s+\"[^>\"]+\")\\s+\"[^>\"]+\"\\s*>", |
4106 | - G_REGEX_CASELESS, G_REGEX_MATCH_NEWLINE_ANY, NULL); |
4107 | - |
4108 | - g_regex_match (regex, this->cachedData.c_str(), G_REGEX_MATCH_NEWLINE_ANY, &info); |
4109 | - |
4110 | - while (g_match_info_matches (info)) { |
4111 | - if (g_match_info_fetch_pos (info, 1, &start, &end)) |
4112 | - this->cachedData.erase(start, end - start); |
4113 | - g_match_info_next (info, NULL); |
4114 | - } |
4115 | - g_match_info_free(info); |
4116 | - g_regex_unref(regex); |
4117 | - } |
4118 | - // Do this after loading cache, so reads don't return cache to fill cache. |
4119 | - this->LoadEntities = load_entities; |
4120 | - return retVal; |
4121 | -} |
4122 | - |
4123 | -xmlDocPtr XmlSource::readXml() |
4124 | -{ |
4125 | - int parse_options = XML_PARSE_HUGE | XML_PARSE_RECOVER; |
4126 | - |
4127 | - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
4128 | - bool allowNetAccess = prefs->getBool("/options/externalresources/xml/allow_net_access", false); |
4129 | - if (!allowNetAccess) parse_options |= XML_PARSE_NONET; |
4130 | - |
4131 | - // Allow NOENT only if we're filtering out SYSTEM and PUBLIC entities |
4132 | - if (LoadEntities) parse_options |= XML_PARSE_NOENT; |
4133 | - |
4134 | - return xmlReadIO( readCb, closeCb, this, |
4135 | - filename, getEncoding(), parse_options); |
4136 | -} |
4137 | - |
4138 | -int XmlSource::readCb( void * context, char * buffer, int len ) |
4139 | -{ |
4140 | - int retVal = -1; |
4141 | - |
4142 | - if ( context ) { |
4143 | - XmlSource* self = static_cast<XmlSource*>(context); |
4144 | - retVal = self->read( buffer, len ); |
4145 | - } |
4146 | - return retVal; |
4147 | -} |
4148 | - |
4149 | -int XmlSource::closeCb(void * context) |
4150 | -{ |
4151 | - if ( context ) { |
4152 | - XmlSource* self = static_cast<XmlSource*>(context); |
4153 | - self->close(); |
4154 | - } |
4155 | - return 0; |
4156 | -} |
4157 | - |
4158 | -int XmlSource::read( char *buffer, int len ) |
4159 | -{ |
4160 | - int retVal = 0; |
4161 | - size_t got = 0; |
4162 | - |
4163 | - if ( LoadEntities ) { |
4164 | - if (cachedPos >= cachedData.length()) { |
4165 | - return -1; |
4166 | - } else { |
4167 | - retVal = cachedData.copy(buffer, len, cachedPos); |
4168 | - cachedPos += retVal; |
4169 | - return retVal; // Do NOT continue. |
4170 | - } |
4171 | - } else if ( firstFewLen > 0 ) { |
4172 | - int some = (len < firstFewLen) ? len : firstFewLen; |
4173 | - memcpy( buffer, firstFew, some ); |
4174 | - if ( len < firstFewLen ) { |
4175 | - memmove( firstFew, firstFew + some, (firstFewLen - some) ); |
4176 | - } |
4177 | - firstFewLen -= some; |
4178 | - got = some; |
4179 | - } else if ( gzin ) { |
4180 | - int single = 0; |
4181 | - while ( (static_cast<int>(got) < len) && (single >= 0) ) |
4182 | - { |
4183 | - single = gzin->get(); |
4184 | - if ( single >= 0 ) { |
4185 | - buffer[got++] = 0x0ff & single; |
4186 | - } else { |
4187 | - break; |
4188 | - } |
4189 | - } |
4190 | - } else { |
4191 | - got = fread( buffer, 1, len, fp ); |
4192 | - } |
4193 | - |
4194 | - if ( feof(fp) ) { |
4195 | - retVal = got; |
4196 | - } else if ( ferror(fp) ) { |
4197 | - retVal = -1; |
4198 | - } else { |
4199 | - retVal = got; |
4200 | - } |
4201 | - |
4202 | - return retVal; |
4203 | -} |
4204 | - |
4205 | -int XmlSource::close() |
4206 | -{ |
4207 | - if ( gzin ) { |
4208 | - gzin->close(); |
4209 | - delete gzin; |
4210 | - gzin = 0; |
4211 | - } |
4212 | - if ( instr ) { |
4213 | - instr->close(); |
4214 | - fp = 0; |
4215 | - delete instr; |
4216 | - instr = 0; |
4217 | - } |
4218 | - if ( fp ) { |
4219 | - fclose(fp); |
4220 | - fp = 0; |
4221 | - } |
4222 | - return 0; |
4223 | -} |
4224 | - |
4225 | -/** |
4226 | - * Reads XML from a file, including WMF files, and returns the Document. |
4227 | - * The default namespace can also be specified, if desired. |
4228 | - */ |
4229 | -Document *sp_repr_read_file (const gchar * filename, const gchar *default_ns) |
4230 | -{ |
4231 | - // g_warning( "Reading file: %s", filename ); |
4232 | - xmlDocPtr doc = 0; |
4233 | - Document * rdoc = 0; |
4234 | - |
4235 | - xmlSubstituteEntitiesDefault(1); |
4236 | - |
4237 | - g_return_val_if_fail (filename != NULL, NULL); |
4238 | - if (!Inkscape::IO::file_test( filename, G_FILE_TEST_EXISTS )) { |
4239 | - g_warning("Can't open file: %s (doesn't exist)", filename); |
4240 | - return NULL; |
4241 | - } |
4242 | - /* fixme: A file can disappear at any time, including between now and when we actually try to |
4243 | - * open it. Get rid of the above test once we're sure that we correctly handle |
4244 | - * non-existence. */ |
4245 | - |
4246 | - // TODO: bulia, please look over |
4247 | - gsize bytesRead = 0; |
4248 | - gsize bytesWritten = 0; |
4249 | - GError* error = NULL; |
4250 | - // TODO: need to replace with our own fopen and reading |
4251 | - gchar* localFilename = g_filename_from_utf8 ( filename, |
4252 | - -1, &bytesRead, &bytesWritten, &error); |
4253 | - g_return_val_if_fail( localFilename != NULL, NULL ); |
4254 | - |
4255 | - Inkscape::IO::dump_fopen_call( filename, "N" ); |
4256 | - |
4257 | -#ifdef HAVE_LIBWMF |
4258 | - if (strlen (localFilename) > 4) { |
4259 | - if ( (strcmp (localFilename + strlen (localFilename) - 4,".wmf") == 0) |
4260 | - || (strcmp (localFilename + strlen (localFilename) - 4,".WMF") == 0)) { |
4261 | - doc = sp_wmf_convert (localFilename); |
4262 | - } |
4263 | - } |
4264 | -#endif // !HAVE_LIBWMF |
4265 | - |
4266 | - if ( !doc ) { |
4267 | - XmlSource src; |
4268 | - |
4269 | - if ( (src.setFile(filename) == 0) ) { |
4270 | - doc = src.readXml(); |
4271 | - rdoc = sp_repr_do_read( doc, default_ns ); |
4272 | - // For some reason, failed ns loading results in this |
4273 | - // We try a system check version of load with NOENT for adobe |
4274 | - if(rdoc && strcmp(rdoc->root()->name(), "ns:svg") == 0) { |
4275 | - xmlFreeDoc( doc ); |
4276 | - src.setFile(filename, true); |
4277 | - doc = src.readXml(); |
4278 | - rdoc = sp_repr_do_read( doc, default_ns ); |
4279 | - } |
4280 | - } |
4281 | - } |
4282 | - |
4283 | - |
4284 | - if ( doc ) { |
4285 | - xmlFreeDoc( doc ); |
4286 | - } |
4287 | - |
4288 | - if ( localFilename ) { |
4289 | - g_free( localFilename ); |
4290 | - } |
4291 | - |
4292 | - return rdoc; |
4293 | -} |
4294 | - |
4295 | -/** |
4296 | - * Reads and parses XML from a buffer, returning it as an Document |
4297 | - */ |
4298 | -Document *sp_repr_read_mem (const gchar * buffer, gint length, const gchar *default_ns) |
4299 | -{ |
4300 | - xmlDocPtr doc; |
4301 | - Document * rdoc; |
4302 | - |
4303 | - xmlSubstituteEntitiesDefault(1); |
4304 | - |
4305 | - g_return_val_if_fail (buffer != NULL, NULL); |
4306 | - |
4307 | - doc = xmlParseMemory (const_cast<gchar *>(buffer), length); |
4308 | - |
4309 | - rdoc = sp_repr_do_read (doc, default_ns); |
4310 | - if (doc) { |
4311 | - xmlFreeDoc (doc); |
4312 | - } |
4313 | - return rdoc; |
4314 | -} |
4315 | - |
4316 | -/** |
4317 | - * Reads and parses XML from a buffer, returning it as an Document |
4318 | - */ |
4319 | -Document *sp_repr_read_buf (const Glib::ustring &buf, const gchar *default_ns) |
4320 | -{ |
4321 | - return sp_repr_read_mem(buf.c_str(), buf.size(), default_ns); |
4322 | -} |
4323 | - |
4324 | +#include <giomm/file.h> |
4325 | + |
4326 | +using namespace Inkscape::Util; |
4327 | |
4328 | namespace Inkscape { |
4329 | |
4330 | -struct compare_quark_ids { |
4331 | - bool operator()(Glib::QueryQuark const &a, Glib::QueryQuark const &b) const { |
4332 | - return a.id() < b.id(); |
4333 | - } |
4334 | -}; |
4335 | - |
4336 | -} |
4337 | - |
4338 | -namespace { |
4339 | - |
4340 | -typedef std::map<Glib::QueryQuark, Glib::QueryQuark, Inkscape::compare_quark_ids> PrefixMap; |
4341 | - |
4342 | -Glib::QueryQuark qname_prefix(Glib::QueryQuark qname) { |
4343 | - static PrefixMap prefix_map; |
4344 | - PrefixMap::iterator iter = prefix_map.find(qname); |
4345 | - if ( iter != prefix_map.end() ) { |
4346 | - return (*iter).second; |
4347 | - } else { |
4348 | - gchar const *name_string=g_quark_to_string(qname); |
4349 | - gchar const *prefix_end=strchr(name_string, ':'); |
4350 | - if (prefix_end) { |
4351 | - Glib::Quark prefix=Glib::ustring(name_string, prefix_end); |
4352 | - prefix_map.insert(PrefixMap::value_type(qname, prefix)); |
4353 | - return prefix; |
4354 | - } else { |
4355 | - return GQuark(0); |
4356 | - } |
4357 | - } |
4358 | -} |
4359 | - |
4360 | -} |
4361 | - |
4362 | -namespace { |
4363 | - |
4364 | -void promote_to_namespace(Node *repr, const gchar *prefix) { |
4365 | - if ( repr->type() == Inkscape::XML::ELEMENT_NODE ) { |
4366 | - GQuark code = repr->code(); |
4367 | - if (!qname_prefix(code).id()) { |
4368 | - gchar *svg_name = g_strconcat(prefix, ":", g_quark_to_string(code), NULL); |
4369 | - repr->setCodeUnsafe(g_quark_from_string(svg_name)); |
4370 | - g_free(svg_name); |
4371 | - } |
4372 | - for ( Node *child = repr->firstChild() ; child ; child = child->next() ) { |
4373 | - promote_to_namespace(child, prefix); |
4374 | - } |
4375 | - } |
4376 | -} |
4377 | - |
4378 | -} |
4379 | - |
4380 | -/** |
4381 | - * Reads in a XML file to create a Document |
4382 | - */ |
4383 | -Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns) |
4384 | -{ |
4385 | - if (doc == NULL) { |
4386 | - return NULL; |
4387 | - } |
4388 | - xmlNodePtr node=xmlDocGetRootElement (doc); |
4389 | - if (node == NULL) { |
4390 | - return NULL; |
4391 | - } |
4392 | - |
4393 | - std::map<std::string, std::string> prefix_map; |
4394 | - |
4395 | - Document *rdoc = new Inkscape::XML::SimpleDocument(); |
4396 | - |
4397 | - Node *root=NULL; |
4398 | - for ( node = doc->children ; node != NULL ; node = node->next ) { |
4399 | - if (node->type == XML_ELEMENT_NODE) { |
4400 | - Node *repr=sp_repr_svg_read_node(rdoc, node, default_ns, prefix_map); |
4401 | - rdoc->appendChild(repr); |
4402 | - Inkscape::GC::release(repr); |
4403 | - |
4404 | - if (!root) { |
4405 | - root = repr; |
4406 | - } else { |
4407 | - root = NULL; |
4408 | - break; |
4409 | - } |
4410 | - } else if ( node->type == XML_COMMENT_NODE || node->type == XML_PI_NODE ) { |
4411 | - Node *repr=sp_repr_svg_read_node(rdoc, node, default_ns, prefix_map); |
4412 | - rdoc->appendChild(repr); |
4413 | - Inkscape::GC::release(repr); |
4414 | - } |
4415 | - } |
4416 | - |
4417 | - if (root != NULL) { |
4418 | - /* promote elements of some XML documents that don't use namespaces |
4419 | - * into their default namespace */ |
4420 | - if ( default_ns && !strchr(root->name(), ':') ) { |
4421 | - if ( !strcmp(default_ns, SP_SVG_NS_URI) ) { |
4422 | - promote_to_namespace(root, "svg"); |
4423 | - } |
4424 | - if ( !strcmp(default_ns, INKSCAPE_EXTENSION_URI) ) { |
4425 | - promote_to_namespace(root, INKSCAPE_EXTENSION_NS_NC); |
4426 | - } |
4427 | - } |
4428 | - |
4429 | - |
4430 | - // Clean unnecessary attributes and style properties from SVG documents. (Controlled by |
4431 | - // preferences.) Note: internal Inkscape svg files will also be cleaned (filters.svg, |
4432 | - // icons.svg). How can one tell if a file is internal? |
4433 | - if ( !strcmp(root->name(), "svg:svg" ) ) { |
4434 | - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
4435 | - bool clean = prefs->getBool("/options/svgoutput/check_on_reading"); |
4436 | - if( clean ) { |
4437 | - sp_attribute_clean_tree( root ); |
4438 | - } |
4439 | - } |
4440 | - } |
4441 | - |
4442 | - return rdoc; |
4443 | -} |
4444 | - |
4445 | -gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar */*default_ns*/, std::map<std::string, std::string> &prefix_map) |
4446 | -{ |
4447 | - const xmlChar *prefix; |
4448 | - if (ns){ |
4449 | - if (ns->href ) { |
4450 | - prefix = reinterpret_cast<const xmlChar*>( sp_xml_ns_uri_prefix(reinterpret_cast<const gchar*>(ns->href), |
4451 | - reinterpret_cast<const char*>(ns->prefix)) ); |
4452 | - prefix_map[reinterpret_cast<const char*>(prefix)] = reinterpret_cast<const char*>(ns->href); |
4453 | - } |
4454 | - else { |
4455 | - prefix = NULL; |
4456 | - } |
4457 | - } |
4458 | - else { |
4459 | - prefix = NULL; |
4460 | - } |
4461 | - |
4462 | - if (prefix) { |
4463 | - return g_snprintf (p, len, "%s:%s", reinterpret_cast<const gchar*>(prefix), name); |
4464 | - } else { |
4465 | - return g_snprintf (p, len, "%s", name); |
4466 | - } |
4467 | -} |
4468 | - |
4469 | -static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, std::map<std::string, std::string> &prefix_map) |
4470 | -{ |
4471 | - xmlAttrPtr prop; |
4472 | - xmlNodePtr child; |
4473 | - gchar c[256]; |
4474 | - |
4475 | - if (node->type == XML_TEXT_NODE || node->type == XML_CDATA_SECTION_NODE) { |
4476 | - |
4477 | - if (node->content == NULL || *(node->content) == '\0') { |
4478 | - return NULL; // empty text node |
4479 | - } |
4480 | - |
4481 | - bool preserve = (xmlNodeGetSpacePreserve (node) == 1); |
4482 | - |
4483 | - xmlChar *p; |
4484 | - for (p = node->content; *p && g_ascii_isspace (*p) && !preserve; p++) |
4485 | - ; // skip all whitespace |
4486 | - |
4487 | - if (!(*p)) { // this is an all-whitespace node, and preserve == default |
4488 | - return NULL; // we do not preserve all-whitespace nodes unless we are asked to |
4489 | - } |
4490 | - |
4491 | - // We keep track of original node type so that CDATA sections are preserved on output. |
4492 | - return xml_doc->createTextNode(reinterpret_cast<gchar *>(node->content), |
4493 | - node->type == XML_CDATA_SECTION_NODE ); |
4494 | - } |
4495 | - |
4496 | - if (node->type == XML_COMMENT_NODE) { |
4497 | - return xml_doc->createComment(reinterpret_cast<gchar *>(node->content)); |
4498 | - } |
4499 | - |
4500 | - if (node->type == XML_PI_NODE) { |
4501 | - return xml_doc->createPI(reinterpret_cast<const gchar *>(node->name), |
4502 | - reinterpret_cast<const gchar *>(node->content)); |
4503 | - } |
4504 | - |
4505 | - if (node->type == XML_ENTITY_DECL) { |
4506 | - return NULL; |
4507 | - } |
4508 | - |
4509 | - sp_repr_qualified_name (c, 256, node->ns, node->name, default_ns, prefix_map); |
4510 | - Node *repr = xml_doc->createElement(c); |
4511 | - /* TODO remember node->ns->prefix if node->ns != NULL */ |
4512 | - |
4513 | - for (prop = node->properties; prop != NULL; prop = prop->next) { |
4514 | - if (prop->children) { |
4515 | - sp_repr_qualified_name (c, 256, prop->ns, prop->name, default_ns, prefix_map); |
4516 | - repr->setAttribute(c, reinterpret_cast<gchar*>(prop->children->content)); |
4517 | - /* TODO remember prop->ns->prefix if prop->ns != NULL */ |
4518 | - } |
4519 | - } |
4520 | - |
4521 | - if (node->content) { |
4522 | - repr->setContent(reinterpret_cast<gchar*>(node->content)); |
4523 | - } |
4524 | - |
4525 | - for (child = node->xmlChildrenNode; child != NULL; child = child->next) { |
4526 | - Node *crepr = sp_repr_svg_read_node (xml_doc, child, default_ns, prefix_map); |
4527 | - if (crepr) { |
4528 | - repr->appendChild(crepr); |
4529 | - Inkscape::GC::release(crepr); |
4530 | - } |
4531 | - } |
4532 | - |
4533 | - return repr; |
4534 | -} |
4535 | - |
4536 | - |
4537 | -static void sp_repr_save_writer(Document *doc, Inkscape::IO::Writer *out, |
4538 | - gchar const *default_ns, |
4539 | - gchar const *old_href_abs_base, |
4540 | - gchar const *new_href_abs_base) |
4541 | -{ |
4542 | +namespace XML { |
4543 | + |
4544 | +using namespace Inkscape::IO; |
4545 | + |
4546 | +static SVGParser _parser; |
4547 | + |
4548 | +static void clean_attributes(Document *doc) { |
4549 | + // Clean unnecessary attributes and style properties from SVG documents (controlled by preferences) |
4550 | Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
4551 | - bool inlineattrs = prefs->getBool("/options/svgoutput/inlineattrs"); |
4552 | - int indent = prefs->getInt("/options/svgoutput/indent", 2); |
4553 | - |
4554 | - /* fixme: do this The Right Way */ |
4555 | - out->writeString( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" ); |
4556 | - |
4557 | - const gchar *str = static_cast<Node *>(doc)->attribute("doctype"); |
4558 | - if (str) { |
4559 | - out->writeString( str ); |
4560 | - } |
4561 | - |
4562 | - for (Node *repr = sp_repr_document_first_child(doc); |
4563 | - repr; repr = repr->next()) |
4564 | - { |
4565 | - Inkscape::XML::NodeType const node_type = repr->type(); |
4566 | - if ( node_type == Inkscape::XML::ELEMENT_NODE ) { |
4567 | - sp_repr_write_stream_root_element(repr, *out, TRUE, default_ns, inlineattrs, indent, |
4568 | - old_href_abs_base, new_href_abs_base); |
4569 | - } else { |
4570 | - sp_repr_write_stream(repr, *out, 0, TRUE, GQuark(0), inlineattrs, indent, |
4571 | - old_href_abs_base, new_href_abs_base); |
4572 | - if ( node_type == Inkscape::XML::COMMENT_NODE ) { |
4573 | - out->writeChar('\n'); |
4574 | - } |
4575 | - } |
4576 | - } |
4577 | -} |
4578 | - |
4579 | - |
4580 | -Glib::ustring sp_repr_save_buf(Document *doc) |
4581 | -{ |
4582 | - Inkscape::IO::StringOutputStream souts; |
4583 | - Inkscape::IO::OutputStreamWriter outs(souts); |
4584 | - |
4585 | - sp_repr_save_writer(doc, &outs, SP_INKSCAPE_NS_URI, 0, 0); |
4586 | - |
4587 | - outs.close(); |
4588 | - Glib::ustring buf = souts.getString(); |
4589 | - |
4590 | - return buf; |
4591 | -} |
4592 | - |
4593 | - |
4594 | -void sp_repr_save_stream(Document *doc, FILE *fp, gchar const *default_ns, bool compress, |
4595 | - gchar const *const old_href_abs_base, |
4596 | - gchar const *const new_href_abs_base) |
4597 | -{ |
4598 | - Inkscape::URI dummy("x"); |
4599 | - Inkscape::IO::UriOutputStream bout(fp, dummy); |
4600 | - Inkscape::IO::GzipOutputStream *gout = compress ? new Inkscape::IO::GzipOutputStream(bout) : NULL; |
4601 | - Inkscape::IO::OutputStreamWriter *out = compress ? new Inkscape::IO::OutputStreamWriter( *gout ) : new Inkscape::IO::OutputStreamWriter( bout ); |
4602 | - |
4603 | - sp_repr_save_writer(doc, out, default_ns, old_href_abs_base, new_href_abs_base); |
4604 | - |
4605 | - delete out; |
4606 | - delete gout; |
4607 | -} |
4608 | - |
4609 | - |
4610 | - |
4611 | -/** |
4612 | - * Returns true if file successfully saved. |
4613 | - * |
4614 | - * \param filename The actual file to do I/O to, which might be a temp file. |
4615 | - * |
4616 | - * \param for_filename The base URI [actually filename] to assume for purposes of rewriting |
4617 | - * xlink:href attributes. |
4618 | - */ |
4619 | -bool sp_repr_save_rebased_file(Document *doc, gchar const *const filename, gchar const *default_ns, |
4620 | - gchar const *old_base, gchar const *for_filename) |
4621 | -{ |
4622 | - if (!filename) { |
4623 | - return false; |
4624 | - } |
4625 | - |
4626 | - bool compress; |
4627 | - { |
4628 | - size_t const filename_len = strlen(filename); |
4629 | - compress = ( filename_len > 5 |
4630 | - && strcasecmp(".svgz", filename + filename_len - 5) == 0 ); |
4631 | - } |
4632 | - |
4633 | - Inkscape::IO::dump_fopen_call( filename, "B" ); |
4634 | - FILE *file = Inkscape::IO::fopen_utf8name(filename, "w"); |
4635 | - if (file == NULL) { |
4636 | - return false; |
4637 | - } |
4638 | - |
4639 | - Glib::ustring old_href_abs_base; |
4640 | - Glib::ustring new_href_abs_base; |
4641 | - if (for_filename) { |
4642 | - old_href_abs_base = calc_abs_doc_base(old_base); |
4643 | - if (Glib::path_is_absolute(for_filename)) { |
4644 | - new_href_abs_base = Glib::path_get_dirname(for_filename); |
4645 | + bool clean = prefs->getBool("/options/svgoutput/check_on_reading"); |
4646 | + if(clean) { |
4647 | + sp_attribute_clean_tree(doc->root()); |
4648 | + } |
4649 | +} |
4650 | + |
4651 | +Document* read_svg_file(const Glib::ustring& filename, const bool& is_internal, const Glib::ustring& default_ns) { |
4652 | + if (!Inkscape::IO::file_test(filename.c_str(), G_FILE_TEST_EXISTS)) { |
4653 | + g_warning("Can't open file: %s (doesn't exist)", filename.c_str()); |
4654 | + return nullptr; |
4655 | + } |
4656 | + |
4657 | + Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(filename); |
4658 | + Glib::RefPtr<Gio::FileInfo> info = file->query_info(); |
4659 | + std::string content_type = info->get_content_type(); |
4660 | + |
4661 | + Document *doc; |
4662 | + if(content_type == "image/svg+xml" || content_type == "application/xml" || content_type == "text/html" |
4663 | + // Windows doesn't support mime type |
4664 | + || content_type == ".svg" || content_type == ".xml" || content_type == ".inx" || content_type == ".htm" || content_type == ".html") { |
4665 | + doc = _parser.parseFile(filename, default_ns); |
4666 | + } else if (content_type == "image/svg+xml-compressed" || content_type == "application/x-gzip" |
4667 | + // the same as above |
4668 | + || content_type == ".svgz") { |
4669 | + doc = _parser.parseCompressedFile(filename, default_ns); |
4670 | + } else { |
4671 | + g_warning("Unrecognized content type: %s.", content_type.c_str()); |
4672 | + return nullptr; |
4673 | + } |
4674 | + |
4675 | + if(!is_internal) { |
4676 | + clean_attributes(doc); |
4677 | + } |
4678 | + return doc; |
4679 | +} |
4680 | + |
4681 | +Document* read_svg_buffer(const Glib::ustring& source, const bool& is_internal, const Glib::ustring& default_ns) { |
4682 | + Document *doc = _parser.parseBuffer(source, default_ns); |
4683 | + if(!is_internal) { |
4684 | + clean_attributes(doc); |
4685 | + } |
4686 | + return doc; |
4687 | +} |
4688 | + |
4689 | +static void rebase_attributes(Node* node, const Glib::ustring& old_href_base, const Glib::ustring& new_href_base) { |
4690 | + for(auto iter = rebase_href_attrs(old_href_base.c_str(), new_href_base.c_str(), node->attributeList()); iter; ++iter) { |
4691 | + node->setAttribute(g_quark_to_string(iter->key), iter->value); |
4692 | + } |
4693 | + |
4694 | + for (Node *child = node->firstChild(); child != nullptr; child = child->next()) { |
4695 | + if (child->type() == ELEMENT_NODE) { |
4696 | + rebase_attributes(child, old_href_base, new_href_base); |
4697 | + } |
4698 | + } |
4699 | +} |
4700 | + |
4701 | +static void add_namespace_to_doc(Document* doc, const Glib::ustring& node_name) { |
4702 | + if (node_name.find(":") != Glib::ustring::npos) { |
4703 | + Glib::ustring prefix = node_name.substr(0, node_name.find(":")); |
4704 | + Glib::ustring extendedPrefix = "xmlns:" + prefix; |
4705 | + SimpleNode* root = dynamic_cast<SimpleNode*>(doc->root()); |
4706 | + if (root->namespaces().find(g_quark_from_string(extendedPrefix.c_str())) == root->namespaces().end() |
4707 | + && prefix != "xml") { |
4708 | + root->setNamespace(extendedPrefix, sp_xml_ns_prefix_uri(prefix.c_str())); |
4709 | + } |
4710 | + } |
4711 | +} |
4712 | + |
4713 | +static void find_all_prefixes(Document* doc, Node* node) { |
4714 | + add_namespace_to_doc(doc, node->name()); |
4715 | + for (List<AttributeRecord const> iter = node->attributeList(); iter; ++iter) { |
4716 | + add_namespace_to_doc(doc, g_quark_to_string(iter->key)); |
4717 | + } |
4718 | + for (Node *child = node->firstChild(); child != nullptr; child = child->next()) { |
4719 | + if (child->type() == ELEMENT_NODE) { |
4720 | + find_all_prefixes(doc, child); |
4721 | + } |
4722 | + } |
4723 | +} |
4724 | + |
4725 | +static void serialize(Writer& writer, Document* doc, const Glib::ustring& default_ns, const Glib::ustring& old_base, const Glib::ustring& new_base) { |
4726 | + if (old_base != "") { |
4727 | + Glib::ustring old_href_abs_base = calc_abs_doc_base(old_base.c_str()); |
4728 | + Glib::ustring new_href_abs_base; |
4729 | + if (Glib::path_is_absolute(new_base)) { |
4730 | + new_href_abs_base = Glib::path_get_dirname(new_base); |
4731 | } else { |
4732 | Glib::ustring const cwd = Glib::get_current_dir(); |
4733 | - Glib::ustring const for_abs_filename = Glib::build_filename(cwd, for_filename); |
4734 | + Glib::ustring const for_abs_filename = Glib::build_filename(cwd, new_base); |
4735 | new_href_abs_base = Glib::path_get_dirname(for_abs_filename); |
4736 | } |
4737 | - |
4738 | - /* effic: Once we're confident that we never need (or never want) to resort |
4739 | - * to using sodipodi:absref instead of the xlink:href value, |
4740 | - * then we should do `if streq() { free them and set both to NULL; }'. */ |
4741 | - } |
4742 | - sp_repr_save_stream(doc, file, default_ns, compress, old_href_abs_base.c_str(), new_href_abs_base.c_str()); |
4743 | - |
4744 | - if (fclose (file) != 0) { |
4745 | - return false; |
4746 | - } |
4747 | - |
4748 | - return true; |
4749 | -} |
4750 | - |
4751 | -/** |
4752 | - * Returns true iff file successfully saved. |
4753 | - */ |
4754 | -bool sp_repr_save_file(Document *doc, gchar const *const filename, gchar const *default_ns) |
4755 | -{ |
4756 | - return sp_repr_save_rebased_file(doc, filename, default_ns, NULL, NULL); |
4757 | -} |
4758 | - |
4759 | - |
4760 | -/* (No doubt this function already exists elsewhere.) */ |
4761 | -static void repr_quote_write (Writer &out, const gchar * val) |
4762 | -{ |
4763 | - if (val) { |
4764 | - for (; *val != '\0'; val++) { |
4765 | - switch (*val) { |
4766 | - case '"': out.writeString( """ ); break; |
4767 | - case '&': out.writeString( "&" ); break; |
4768 | - case '<': out.writeString( "<" ); break; |
4769 | - case '>': out.writeString( ">" ); break; |
4770 | - default: out.writeChar( *val ); break; |
4771 | - } |
4772 | - } |
4773 | - } |
4774 | -} |
4775 | - |
4776 | -static void repr_write_comment( Writer &out, const gchar * val, bool addWhitespace, gint indentLevel, int indent ) |
4777 | -{ |
4778 | - if ( indentLevel > 16 ) { |
4779 | - indentLevel = 16; |
4780 | - } |
4781 | - if (addWhitespace && indent) { |
4782 | - for (gint i = 0; i < indentLevel; i++) { |
4783 | - for (gint j = 0; j < indent; j++) { |
4784 | - out.writeString(" "); |
4785 | - } |
4786 | - } |
4787 | - } |
4788 | - |
4789 | - out.writeString("<!--"); |
4790 | - // WARNING out.printf() and out.writeString() are *NOT* non-ASCII friendly. |
4791 | - if (val) { |
4792 | - for (const gchar* cur = val; *cur; cur++ ) { |
4793 | - out.writeChar(*cur); |
4794 | - } |
4795 | - } else { |
4796 | - out.writeString(" "); |
4797 | - } |
4798 | - out.writeString("-->"); |
4799 | - |
4800 | - if (addWhitespace) { |
4801 | - out.writeString("\n"); |
4802 | - } |
4803 | -} |
4804 | - |
4805 | -namespace { |
4806 | - |
4807 | -typedef std::map<Glib::QueryQuark, gchar const *, Inkscape::compare_quark_ids> LocalNameMap; |
4808 | -typedef std::map<Glib::QueryQuark, Inkscape::Util::ptr_shared<char>, Inkscape::compare_quark_ids> NSMap; |
4809 | - |
4810 | -gchar const *qname_local_name(Glib::QueryQuark qname) { |
4811 | - static LocalNameMap local_name_map; |
4812 | - LocalNameMap::iterator iter = local_name_map.find(qname); |
4813 | - if ( iter != local_name_map.end() ) { |
4814 | - return (*iter).second; |
4815 | - } else { |
4816 | - gchar const *name_string=g_quark_to_string(qname); |
4817 | - gchar const *prefix_end=strchr(name_string, ':'); |
4818 | - if (prefix_end) { |
4819 | - return prefix_end + 1; |
4820 | - } else { |
4821 | - return name_string; |
4822 | - } |
4823 | - } |
4824 | -} |
4825 | - |
4826 | -void add_ns_map_entry(NSMap &ns_map, Glib::QueryQuark prefix) { |
4827 | - using Inkscape::Util::ptr_shared; |
4828 | - using Inkscape::Util::share_unsafe; |
4829 | - |
4830 | - static const Glib::QueryQuark xml_prefix("xml"); |
4831 | - |
4832 | - NSMap::iterator iter=ns_map.find(prefix); |
4833 | - if ( iter == ns_map.end() ) { |
4834 | - if (prefix.id()) { |
4835 | - gchar const *uri=sp_xml_ns_prefix_uri(g_quark_to_string(prefix)); |
4836 | - if (uri) { |
4837 | - ns_map.insert(NSMap::value_type(prefix, share_unsafe(uri))); |
4838 | - } else if ( prefix != xml_prefix ) { |
4839 | - g_warning("No namespace known for normalized prefix %s", g_quark_to_string(prefix)); |
4840 | - } |
4841 | - } else { |
4842 | - ns_map.insert(NSMap::value_type(prefix, ptr_shared<char>())); |
4843 | - } |
4844 | - } |
4845 | -} |
4846 | - |
4847 | -void populate_ns_map(NSMap &ns_map, Node &repr) { |
4848 | - if ( repr.type() == Inkscape::XML::ELEMENT_NODE ) { |
4849 | - add_ns_map_entry(ns_map, qname_prefix(repr.code())); |
4850 | - for ( List<AttributeRecord const> iter=repr.attributeList() ; |
4851 | - iter ; ++iter ) |
4852 | - { |
4853 | - Glib::QueryQuark prefix=qname_prefix(iter->key); |
4854 | - if (prefix.id()) { |
4855 | - add_ns_map_entry(ns_map, prefix); |
4856 | - } |
4857 | - } |
4858 | - for ( Node *child=repr.firstChild() ; |
4859 | - child ; child = child->next() ) |
4860 | - { |
4861 | - populate_ns_map(ns_map, *child); |
4862 | - } |
4863 | - } |
4864 | -} |
4865 | - |
4866 | -} |
4867 | - |
4868 | -static void sp_repr_write_stream_root_element(Node *repr, Writer &out, |
4869 | - bool add_whitespace, gchar const *default_ns, |
4870 | - int inlineattrs, int indent, |
4871 | - gchar const *const old_href_base, |
4872 | - gchar const *const new_href_base) |
4873 | -{ |
4874 | - using Inkscape::Util::ptr_shared; |
4875 | - |
4876 | - g_assert(repr != NULL); |
4877 | - |
4878 | + rebase_attributes(doc->root(), old_href_abs_base, new_href_abs_base); |
4879 | + } |
4880 | + |
4881 | + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
4882 | // Clean unnecessary attributes and stype properties. (Controlled by preferences.) |
4883 | - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); |
4884 | bool clean = prefs->getBool("/options/svgoutput/check_on_writing"); |
4885 | - if (clean) sp_attribute_clean_tree( repr ); |
4886 | + if (clean) { |
4887 | + sp_attribute_clean_tree(doc->root()); |
4888 | + } |
4889 | + |
4890 | + // find all used prefixes |
4891 | + find_all_prefixes(doc, doc->root()); |
4892 | + if (default_ns != "") { |
4893 | + doc->root()->setNamespace("xmlns", default_ns); |
4894 | + } |
4895 | + Glib::ustring defaultPrefix = sp_xml_ns_uri_prefix(default_ns.c_str(), ""); |
4896 | + |
4897 | + bool inlineAttributes = prefs->getBool("/options/svgoutput/inlineattrs"); |
4898 | + int indent = prefs->getInt("/options/svgoutput/indent", 2); |
4899 | |
4900 | // Sort attributes in a canonical order (helps with "diffing" SVG files). |
4901 | bool sort = prefs->getBool("/options/svgoutput/sort_attributes"); |
4902 | - if (sort) sp_attribute_sort_tree( repr ); |
4903 | - |
4904 | - Glib::QueryQuark xml_prefix=g_quark_from_static_string("xml"); |
4905 | - |
4906 | - NSMap ns_map; |
4907 | - populate_ns_map(ns_map, *repr); |
4908 | - |
4909 | - Glib::QueryQuark elide_prefix=GQuark(0); |
4910 | - if ( default_ns && ns_map.find(GQuark(0)) == ns_map.end() ) { |
4911 | - elide_prefix = g_quark_from_string(sp_xml_ns_uri_prefix(default_ns, NULL)); |
4912 | - } |
4913 | - |
4914 | - List<AttributeRecord const> attributes=repr->attributeList(); |
4915 | - for ( NSMap::iterator iter=ns_map.begin() ; iter != ns_map.end() ; ++iter ) |
4916 | - { |
4917 | - Glib::QueryQuark prefix=(*iter).first; |
4918 | - ptr_shared<char> ns_uri=(*iter).second; |
4919 | - |
4920 | - if (prefix.id()) { |
4921 | - if ( prefix != xml_prefix ) { |
4922 | - if ( elide_prefix == prefix ) { |
4923 | - attributes = cons(AttributeRecord(g_quark_from_static_string("xmlns"), ns_uri), attributes); |
4924 | - } |
4925 | - |
4926 | - Glib::ustring attr_name="xmlns:"; |
4927 | - attr_name.append(g_quark_to_string(prefix)); |
4928 | - GQuark key = g_quark_from_string(attr_name.c_str()); |
4929 | - attributes = cons(AttributeRecord(key, ns_uri), attributes); |
4930 | - } |
4931 | - } else { |
4932 | - // if there are non-namespaced elements, we can't globally |
4933 | - // use a default namespace |
4934 | - elide_prefix = GQuark(0); |
4935 | - } |
4936 | - } |
4937 | - |
4938 | - return sp_repr_write_stream_element(repr, out, 0, add_whitespace, elide_prefix, attributes, |
4939 | - inlineattrs, indent, old_href_base, new_href_base); |
4940 | -} |
4941 | - |
4942 | -void sp_repr_write_stream( Node *repr, Writer &out, gint indent_level, |
4943 | - bool add_whitespace, Glib::QueryQuark elide_prefix, |
4944 | - int inlineattrs, int indent, |
4945 | - gchar const *const old_href_base, |
4946 | - gchar const *const new_href_base) |
4947 | -{ |
4948 | - switch (repr->type()) { |
4949 | - case Inkscape::XML::TEXT_NODE: { |
4950 | - if( dynamic_cast<const Inkscape::XML::TextNode *>(repr)->is_CData() ) { |
4951 | - // Preserve CDATA sections, not converting '&' to &, etc. |
4952 | - out.printf( "<![CDATA[%s]]>", repr->content() ); |
4953 | - } else { |
4954 | - repr_quote_write( out, repr->content() ); |
4955 | - } |
4956 | - break; |
4957 | - } |
4958 | - case Inkscape::XML::COMMENT_NODE: { |
4959 | - repr_write_comment( out, repr->content(), add_whitespace, indent_level, indent ); |
4960 | - break; |
4961 | - } |
4962 | - case Inkscape::XML::PI_NODE: { |
4963 | - out.printf( "<?%s %s?>", repr->name(), repr->content() ); |
4964 | - break; |
4965 | - } |
4966 | - case Inkscape::XML::ELEMENT_NODE: { |
4967 | - sp_repr_write_stream_element( repr, out, indent_level, |
4968 | - add_whitespace, elide_prefix, |
4969 | - repr->attributeList(), |
4970 | - inlineattrs, indent, |
4971 | - old_href_base, new_href_base); |
4972 | - break; |
4973 | - } |
4974 | - case Inkscape::XML::DOCUMENT_NODE: { |
4975 | - g_assert_not_reached(); |
4976 | - break; |
4977 | - } |
4978 | - default: { |
4979 | - g_assert_not_reached(); |
4980 | - } |
4981 | - } |
4982 | -} |
4983 | - |
4984 | - |
4985 | -void sp_repr_write_stream_element( Node * repr, Writer & out, |
4986 | - gint indent_level, bool add_whitespace, |
4987 | - Glib::QueryQuark elide_prefix, |
4988 | - List<AttributeRecord const> attributes, |
4989 | - int inlineattrs, int indent, |
4990 | - gchar const *old_href_base, |
4991 | - gchar const *new_href_base ) |
4992 | -{ |
4993 | - Node *child = 0; |
4994 | - bool loose = false; |
4995 | - |
4996 | - g_return_if_fail (repr != NULL); |
4997 | - |
4998 | - if ( indent_level > 16 ) { |
4999 | - indent_level = 16; |
5000 | - } |
The diff has been truncated for viewing.