]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/mapxml/xmlparse.cpp
Merge branch 'transfilterfix' into 'master'
[xonotic/netradiant.git] / plugins / mapxml / xmlparse.cpp
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 //
23 // parses xml tree format into internal objects
24 //
25
26 #include "xmlparse.h"
27
28 #include <vector>
29
30 #include "ientity.h"
31 #include "ibrush.h"
32 #include "ipatch.h"
33 #include "ieclass.h"
34 #include "eclasslib.h"
35
36 #include "xml/xmlparser.h"
37 #include "scenelib.h"
38 #include "generic/reference.h"
39 #include "generic/object.h"
40
41
42 const char *PARSE_ERROR = "XML PARSE ERROR";
43
44
45 inline XMLImporter *Node_getXMLImporter(scene::Node &node)
46 {
47     return NodeTypeCast<XMLImporter>::cast(node);
48 }
49
50
51 scene::Node &createPrimitive(const char *name)
52 {
53     if (string_equal(name, "brush")) {
54         return GlobalBrushCreator().createBrush();
55     } else if (string_equal(name, "patch")) {
56         return GlobalPatchCreator().createPatch();
57     }
58
59     ASSERT_MESSAGE(0, PARSE_ERROR << ": primitive type not supported: \"" << name << "\"\n");
60     scene::Node *node = 0;
61     return *node;
62 }
63
64 class TreeXMLImporter : public XMLImporter {
65 public:
66     virtual TreeXMLImporter &child() = 0;
67 };
68
69 class SubPrimitiveImporter : public TreeXMLImporter {
70     XMLImporter *m_importer;
71 public:
72     SubPrimitiveImporter(XMLImporter *importer) : m_importer(importer)
73     {
74     }
75
76     void pushElement(const XMLElement &element)
77     {
78         m_importer->pushElement(element);
79     }
80
81     void popElement(const char *name)
82     {
83         m_importer->popElement(name);
84     }
85
86     std::size_t write(const char *buffer, std::size_t length)
87     {
88         return m_importer->write(buffer, length);
89     }
90
91     SubPrimitiveImporter &child()
92     {
93         return *this;
94     }
95 };
96
97 class PrimitiveImporter : public TreeXMLImporter {
98     scene::Node &m_parent;
99     XMLImporter *m_importer;
100     char m_child[sizeof(SubPrimitiveImporter)];
101
102     SubPrimitiveImporter &subprimitive()
103     {
104         return *reinterpret_cast<SubPrimitiveImporter *>( m_child );
105     }
106
107 public:
108     PrimitiveImporter(scene::Node &parent) : m_parent(parent), m_importer(0)
109     {
110     }
111
112     void pushElement(const XMLElement &element)
113     {
114         if (string_equal(element.name(), "epair")) {
115             ASSERT_MESSAGE(string_equal(element.name(), "epair"), PARSE_ERROR);
116             Node_getEntity(m_parent)->setKeyValue(element.attribute("key"), element.attribute("value"));
117         } else {
118             NodeSmartReference node(createPrimitive(element.name()));
119
120             m_importer = Node_getXMLImporter(node);
121
122             constructor(subprimitive(), m_importer);
123
124             m_importer->pushElement(element);
125
126             Node_getTraversable(m_parent)->insert(node);
127         }
128     }
129
130     void popElement(const char *name)
131     {
132         if (string_equal(name, "epair")) {
133         } else {
134             m_importer->popElement(name);
135
136             destructor(subprimitive());
137             m_importer = 0;
138         }
139     }
140
141     std::size_t write(const char *buffer, std::size_t length)
142     {
143         return m_importer->write(buffer, length);
144     }
145
146     TreeXMLImporter &child()
147     {
148         return subprimitive();
149     }
150 };
151
152 class EntityImporter : public TreeXMLImporter {
153     scene::Node &m_parent;
154     char m_node[sizeof(NodeSmartReference)];
155     char m_child[sizeof(PrimitiveImporter)];
156     EntityCreator &m_entityTable;
157
158     NodeSmartReference &node()
159     {
160         return *reinterpret_cast<NodeSmartReference *>( m_node );
161     }
162
163     PrimitiveImporter &primitive()
164     {
165         return *reinterpret_cast<PrimitiveImporter *>( m_child );
166     }
167
168 public:
169     EntityImporter(scene::Node &parent, EntityCreator &entityTable) : m_parent(parent), m_entityTable(entityTable)
170     {
171     }
172
173     void pushElement(const XMLElement &element)
174     {
175         ASSERT_MESSAGE(string_equal(element.name(), "entity"), PARSE_ERROR);
176         constructor(node(),
177                     NodeSmartReference(m_entityTable.createEntity(GlobalEntityClassManager().findOrInsert("", true))));
178         constructor(primitive(), makeReference(node().get()));
179     }
180
181     void popElement(const char *name)
182     {
183         ASSERT_MESSAGE(string_equal(name, "entity"), PARSE_ERROR);
184         NodeSmartReference entity(m_entityTable.createEntity(
185                 GlobalEntityClassManager().findOrInsert(Node_getEntity(node())->getKeyValue("classname"),
186                                                         node_is_group(node()))));
187
188         {
189             EntityCopyingVisitor visitor(*Node_getEntity(entity));
190             Node_getEntity(node())->forEachKeyValue(visitor);
191         }
192
193         if (Node_getTraversable(entity) != 0 && !Node_getEntity(entity)->getEntityClass().fixedsize) {
194             parentBrushes(node(), entity);
195         }
196
197         Node_getTraversable(m_parent)->insert(entity);
198
199         destructor(primitive());
200         destructor(node());
201     }
202
203     std::size_t write(const char *buffer, std::size_t length)
204     {
205         return length;
206     }
207
208     TreeXMLImporter &child()
209     {
210         return primitive();
211     }
212 };
213
214 class MapDoom3Importer : public TreeXMLImporter {
215     scene::Node &m_root;
216     char m_child[sizeof(EntityImporter)];
217     EntityCreator &m_entityTable;
218
219     EntityImporter &getEntity()
220     {
221         return *reinterpret_cast<EntityImporter *>( m_child );
222     }
223
224 public:
225     MapDoom3Importer(scene::Node &root, EntityCreator &entityTable) : m_root(root), m_entityTable(entityTable)
226     {
227     }
228
229     void pushElement(const XMLElement &element)
230     {
231         ASSERT_MESSAGE(string_equal(element.name(), "mapdoom3"), PARSE_ERROR);
232         constructor(getEntity(), makeReference(m_root), makeReference(m_entityTable));
233     }
234
235     void popElement(const char *name)
236     {
237         ASSERT_MESSAGE(string_equal(name, "mapdoom3"), PARSE_ERROR);
238         destructor(getEntity());
239     }
240
241     std::size_t write(const char *data, std::size_t length)
242     {
243         return length;
244     }
245
246     TreeXMLImporter &child()
247     {
248         return getEntity();
249     }
250 };
251
252 class TreeXMLImporterStack : public XMLImporter {
253     std::vector<Reference<TreeXMLImporter> > m_importers;
254 public:
255     TreeXMLImporterStack(TreeXMLImporter &importer)
256     {
257         m_importers.push_back(makeReference(importer));
258     }
259
260     void pushElement(const XMLElement &element)
261     {
262         m_importers.back().get().pushElement(element);
263         m_importers.push_back(makeReference(m_importers.back().get().child()));
264     }
265
266     void popElement(const char *name)
267     {
268         m_importers.pop_back();
269         m_importers.back().get().popElement(name);
270     }
271
272     std::size_t write(const char *buffer, std::size_t length)
273     {
274         return (*(m_importers.end() - 2)).get().write(buffer, length);
275     }
276 };
277
278
279 void Map_Read(scene::Node &root, TextInputStream &in, EntityCreator &entityTable)
280 {
281     XMLStreamParser parser(in);
282
283     MapDoom3Importer importer(root, entityTable);
284     TreeXMLImporterStack stack(importer);
285     parser.exportXML(stack);
286 }