Merge lp:~adrianboguszewski/inkscape/sax-parser into lp:~inkscape.dev/inkscape/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
Reviewer Review Type Date Requested Status
Mc Pending
Review via email: mp+310142@code.launchpad.net

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( "&quot;" ); break;
4767- case '&': out.writeString( "&amp;" ); break;
4768- case '<': out.writeString( "&lt;" ); break;
4769- case '>': out.writeString( "&gt;" ); 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 &amp;, 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.