]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/mapxml/xmlparse.cpp
- Fix: Added missing xml-writer pop-calls
[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 #define 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   {
55     return GlobalBrushCreator().createBrush();
56   }
57   else if(string_equal(name, "patch"))
58   {
59     return GlobalPatchCreator().createPatch();
60   }
61
62   ASSERT_MESSAGE(0, PARSE_ERROR << ": primitive type not supported: \"" << name << "\"\n");
63   scene::Node* node = 0;
64   return *node;
65 }
66
67 class TreeXMLImporter : public XMLImporter
68 {
69 public:
70   virtual TreeXMLImporter& child() = 0;
71 };
72
73 class SubPrimitiveImporter : public TreeXMLImporter
74 {
75   XMLImporter* m_importer;
76 public:
77   SubPrimitiveImporter(XMLImporter* importer) : m_importer(importer)
78   {
79   }
80   void pushElement(const XMLElement& element)
81   {
82     m_importer->pushElement(element);
83   }
84   void popElement(const char* name)
85   {
86     m_importer->popElement(name);
87   }
88   std::size_t write(const char* buffer, std::size_t length)
89   {
90     return m_importer->write(buffer, length);
91   }
92   SubPrimitiveImporter& child()
93   {
94     return *this;
95   }
96 };
97
98 class PrimitiveImporter : public TreeXMLImporter
99 {
100   scene::Node& m_parent;
101   XMLImporter* m_importer;
102   char m_child[sizeof(SubPrimitiveImporter)];
103
104   SubPrimitiveImporter& subprimitive()
105   {
106     return *reinterpret_cast<SubPrimitiveImporter*>(m_child);
107   }
108 public:
109   PrimitiveImporter(scene::Node& parent) : m_parent(parent), m_importer(0)
110   {
111   }
112   void pushElement(const XMLElement& element)
113   {
114     if(string_equal(element.name(), "epair"))
115     {
116       ASSERT_MESSAGE(string_equal(element.name(), "epair"), PARSE_ERROR);
117       Node_getEntity(m_parent)->setKeyValue(element.attribute("key"), element.attribute("value"));
118     }
119     else
120     {
121       NodeSmartReference node(createPrimitive(element.name()));
122
123       m_importer = Node_getXMLImporter(node);
124
125       constructor(subprimitive(), m_importer);
126
127       m_importer->pushElement(element);
128
129       Node_getTraversable(m_parent)->insert(node);
130     }
131   }
132   void popElement(const char* name)
133   {
134     if(string_equal(name, "epair"))
135     {
136     }
137     else
138     {
139       m_importer->popElement(name);
140
141       destructor(subprimitive());
142       m_importer = 0;
143     }
144   }
145   std::size_t write(const char* buffer, std::size_t length)
146   {
147     return m_importer->write(buffer, length);
148   }
149   TreeXMLImporter& child()
150   {
151     return subprimitive();
152   }
153 };
154
155 class EntityImporter : public TreeXMLImporter
156 {
157   scene::Node& m_parent;
158   char m_node[sizeof(NodeSmartReference)];
159   char m_child[sizeof(PrimitiveImporter)];
160   EntityCreator& m_entityTable;
161
162   NodeSmartReference& node()
163   {
164     return *reinterpret_cast<NodeSmartReference*>(m_node);
165   }
166   PrimitiveImporter& primitive()
167   {
168     return *reinterpret_cast<PrimitiveImporter*>(m_child);
169   }
170
171 public:
172   EntityImporter(scene::Node& parent, EntityCreator& entityTable) : m_parent(parent), m_entityTable(entityTable)
173   {
174   }
175   void pushElement(const XMLElement& element)
176   {
177     ASSERT_MESSAGE(string_equal(element.name(), "entity"), PARSE_ERROR);
178     constructor(node(), NodeSmartReference(m_entityTable.createEntity(GlobalEntityClassManager().findOrInsert("", true))));
179     constructor(primitive(), makeReference(node().get()));
180   }
181   void popElement(const char* name)
182   {
183     ASSERT_MESSAGE(string_equal(name, "entity"), PARSE_ERROR);
184     NodeSmartReference entity(m_entityTable.createEntity(GlobalEntityClassManager().findOrInsert(Node_getEntity(node())->getKeyValue("classname"), node_is_group(node()))));
185
186     {
187       EntityCopyingVisitor visitor(*Node_getEntity(entity));
188       Node_getEntity(node())->forEachKeyValue(visitor);
189     }
190
191     if(Node_getTraversable(entity) != 0 && !Node_getEntity(entity)->getEntityClass().fixedsize)
192     {
193       parentBrushes(node(), entity);
194     }
195
196     Node_getTraversable(m_parent)->insert(entity);
197
198     destructor(primitive());
199     destructor(node());
200   }
201   std::size_t write(const char* buffer, std::size_t length)
202   {
203     return length;
204   }
205   TreeXMLImporter& child()
206   {
207     return primitive();
208   }
209 };
210
211 class MapDoom3Importer : public TreeXMLImporter
212 {
213   scene::Node& m_root;
214   char m_child[sizeof(EntityImporter)];
215   EntityCreator& m_entityTable;
216
217   EntityImporter& getEntity()
218   {
219     return *reinterpret_cast<EntityImporter*>(m_child);
220   }
221 public:
222   MapDoom3Importer(scene::Node& root, EntityCreator& entityTable) : m_root(root), m_entityTable(entityTable)
223   {
224   }
225   void pushElement(const XMLElement& element)
226   {
227     ASSERT_MESSAGE(string_equal(element.name(), "mapdoom3"), PARSE_ERROR);
228     constructor(getEntity(), makeReference(m_root), makeReference(m_entityTable));
229   }
230   void popElement(const char* name)
231   {
232     ASSERT_MESSAGE(string_equal(name, "mapdoom3"), PARSE_ERROR);
233     destructor(getEntity());
234   }
235   std::size_t write(const char* data, std::size_t length)
236   {
237     return length;
238   }
239   TreeXMLImporter& child()
240   {
241     return getEntity();
242   }
243 };
244
245 class TreeXMLImporterStack : public XMLImporter
246 {
247   std::vector< Reference<TreeXMLImporter> > m_importers;
248 public:
249   TreeXMLImporterStack(TreeXMLImporter& importer)
250   {
251     m_importers.push_back(makeReference(importer));
252   }
253   void pushElement(const XMLElement& element)
254   {
255     m_importers.back().get().pushElement(element);
256     m_importers.push_back(makeReference(m_importers.back().get().child()));
257   }
258   void popElement(const char* name)
259   {
260     m_importers.pop_back();
261     m_importers.back().get().popElement(name);
262   }
263   std::size_t write(const char* buffer, std::size_t length)
264   {
265     return (*(m_importers.end() - 2)).get().write(buffer, length);
266   }
267 };
268
269
270 void Map_Read(scene::Node& root, TextInputStream& in, EntityCreator& entityTable)
271 {
272   XMLStreamParser parser(in);
273
274   MapDoom3Importer importer(root, entityTable);
275   TreeXMLImporterStack stack(importer);
276   parser.exportXML(stack);
277 }