1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2016-2018, Torsten Paul <torsten.paul@gmx.de>,
5 * Marius Kintel <marius@kintel.net>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25 #include <map>
26 #include <stack>
27 #include <vector>
28 #include <Eigen/Core>
29 #include <Eigen/Geometry>
30 #include <boost/filesystem.hpp>
31 #include <boost/format.hpp>
32 #include <libxml/xmlreader.h>
33
34 #include "libsvg.h"
35
36 #include "shape.h"
37 #include "circle.h"
38 #include "ellipse.h"
39 #include "line.h"
40 #include "polygon.h"
41 #include "polyline.h"
42 #include "rect.h"
43
44 namespace fs = boost::filesystem;
45
46 namespace libsvg {
47
48 #define SVG_DEBUG 0
49
50 static bool in_defs = false;
51 static shapes_list_t stack;
52 static shapes_list_t *shape_list;
53
54 #if SVG_DEBUG
dump_stack()55 static std::string dump_stack() {
56 bool first = true;
57 std::stringstream s;
58 s << "[";
59 for (const auto &shape : stack) {
60 s << (first ? "" : "|") << shape->get_name();
61 first = false;
62 }
63 return s.str() + "]";
64 }
65 #endif
66
read_attributes(xmlTextReaderPtr reader)67 attr_map_t read_attributes(xmlTextReaderPtr reader)
68 {
69 attr_map_t attrs;
70 int attr_count = xmlTextReaderAttributeCount(reader);
71 for (int idx = 0; idx < attr_count; ++idx) {
72 xmlTextReaderMoveToAttributeNo(reader, idx);
73 const char *name = reinterpret_cast<const char *> (xmlTextReaderName(reader));
74 const char *value = reinterpret_cast<const char *> (xmlTextReaderValue(reader));
75 attrs[name] = value;
76 }
77 return attrs;
78 }
79
processNode(xmlTextReaderPtr reader)80 void processNode(xmlTextReaderPtr reader)
81 {
82 const char *name = reinterpret_cast<const char *> (xmlTextReaderName(reader));
83 if (name == nullptr) name = reinterpret_cast<const char *> (xmlStrdup(BAD_CAST "--"));
84
85 bool isEmpty;
86 xmlChar *value = xmlTextReaderValue(reader);
87 int node_type = xmlTextReaderNodeType(reader);
88 switch (node_type) {
89 case XML_READER_TYPE_ELEMENT:
90 isEmpty = xmlTextReaderIsEmptyElement(reader);
91 {
92 #if SVG_DEBUG
93 printf("XML_READER_TYPE_ELEMENT (%s %s): %d %d %s\n",
94 dump_stack().c_str(), name,
95 xmlTextReaderDepth(reader),
96 xmlTextReaderNodeType(reader),
97 value);
98 #endif
99
100 if (std::string("defs") == name) {
101 in_defs = true;
102 }
103
104 auto s = shared_ptr<shape>(shape::create_from_name(name));
105 if (!in_defs && s) {
106 attr_map_t attrs = read_attributes(reader);
107 s->set_attrs(attrs);
108 shape_list->push_back(s);
109 if (!stack.empty()) {
110 stack.back()->add_child(s.get());
111 }
112 if (s->is_container()) {
113 stack.push_back(s);
114 }
115 s->apply_transform();
116 }
117 }
118 if (!isEmpty) {
119 break;
120 }
121 /* fall through */
122 case XML_READER_TYPE_END_ELEMENT:
123 {
124 if (std::string("defs") == name) {
125 in_defs = false;
126 }
127 if (in_defs) {
128 return;
129 }
130
131 if (std::string("g") == name) {
132 stack.pop_back();
133 } else if (std::string("tspan") == name) {
134 stack.pop_back();
135 } else if (std::string("text") == name) {
136 stack.pop_back();
137 }
138 #if SVG_DEBUG
139 printf("XML_READER_TYPE_END_ELEMENT (%s %s): %d %d %s\n",
140 dump_stack().c_str(), name,
141 xmlTextReaderDepth(reader),
142 xmlTextReaderNodeType(reader),
143 value);
144 #endif
145 }
146 break;
147 case XML_READER_TYPE_TEXT:
148 {
149 attr_map_t attrs;
150 attrs["text"] = reinterpret_cast<const char *>(value);
151 auto s = shared_ptr<shape>(shape::create_from_name("data"));
152 s->set_attrs(attrs);
153 shape_list->push_back(s);
154 if (!stack.empty()) {
155 stack.back()->add_child(s.get());
156 }
157 }
158 break;
159 }
160
161 xmlFree(value);
162 xmlFree((void *) (name));
163 }
164
streamFile(const char * filename)165 int streamFile(const char *filename)
166 {
167 xmlTextReaderPtr reader;
168
169 in_defs = false;
170 reader = xmlNewTextReaderFilename(filename);
171 xmlTextReaderSetParserProp(reader, XML_PARSER_SUBST_ENTITIES, 1);
172 if (reader != nullptr) {
173 int ret = xmlTextReaderRead(reader);
174 while (ret == 1) {
175 processNode(reader);
176 ret = xmlTextReaderRead(reader);
177 }
178 xmlFreeTextReader(reader);
179 if (ret != 0) {
180 throw SvgException((boost::format("Error parsing file '%1%'") % filename).str());
181 }
182 } else {
183 throw SvgException((boost::format("Can't open file '%1%'") % filename).str());
184 }
185 return 0;
186 }
187
dump(int idx,shape * s)188 void dump(int idx, shape *s) {
189 for (int a = 0; a < idx; ++a) {
190 std::cout << " ";
191 }
192 std::cout << "=> " << s->dump() << std::endl;
193 for (const auto& c : s->get_children()) {
194 dump(idx + 1, c);
195 }
196 }
197
198 shapes_list_t *
libsvg_read_file(const char * filename)199 libsvg_read_file(const char *filename)
200 {
201 shape_list = new shapes_list_t();
202 streamFile(filename);
203
204 //#ifdef DEBUG
205 // if (!shape_list->empty()) {
206 // dump(0, shape_list->front().get());
207 // }
208 //#endif
209
210 return shape_list;
211 }
212
213 void
libsvg_free(shapes_list_t * shapes)214 libsvg_free(shapes_list_t *shapes)
215 {
216 delete shapes;
217 }
218
219 }
220