2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
23 // parses xml tree format into internal objects
34 #include "eclasslib.h"
36 #include "xml/xmlparser.h"
38 #include "generic/reference.h"
39 #include "generic/object.h"
42 const char *PARSE_ERROR = "XML PARSE ERROR";
45 inline XMLImporter *Node_getXMLImporter(scene::Node &node)
47 return NodeTypeCast<XMLImporter>::cast(node);
51 scene::Node &createPrimitive(const char *name)
53 if (string_equal(name, "brush")) {
54 return GlobalBrushCreator().createBrush();
55 } else if (string_equal(name, "patch")) {
56 return GlobalPatchCreator().createPatch();
59 ASSERT_MESSAGE(0, PARSE_ERROR << ": primitive type not supported: \"" << name << "\"\n");
60 scene::Node *node = 0;
64 class TreeXMLImporter : public XMLImporter {
66 virtual TreeXMLImporter &child() = 0;
69 class SubPrimitiveImporter : public TreeXMLImporter {
70 XMLImporter *m_importer;
72 SubPrimitiveImporter(XMLImporter *importer) : m_importer(importer)
76 void pushElement(const XMLElement &element)
78 m_importer->pushElement(element);
81 void popElement(const char *name)
83 m_importer->popElement(name);
86 std::size_t write(const char *buffer, std::size_t length)
88 return m_importer->write(buffer, length);
91 SubPrimitiveImporter &child()
97 class PrimitiveImporter : public TreeXMLImporter {
98 scene::Node &m_parent;
99 XMLImporter *m_importer;
100 char m_child[sizeof(SubPrimitiveImporter)];
102 SubPrimitiveImporter &subprimitive()
104 return *reinterpret_cast<SubPrimitiveImporter *>( m_child );
108 PrimitiveImporter(scene::Node &parent) : m_parent(parent), m_importer(0)
112 void pushElement(const XMLElement &element)
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"));
118 NodeSmartReference node(createPrimitive(element.name()));
120 m_importer = Node_getXMLImporter(node);
122 constructor(subprimitive(), m_importer);
124 m_importer->pushElement(element);
126 Node_getTraversable(m_parent)->insert(node);
130 void popElement(const char *name)
132 if (string_equal(name, "epair")) {
134 m_importer->popElement(name);
136 destructor(subprimitive());
141 std::size_t write(const char *buffer, std::size_t length)
143 return m_importer->write(buffer, length);
146 TreeXMLImporter &child()
148 return subprimitive();
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;
158 NodeSmartReference &node()
160 return *reinterpret_cast<NodeSmartReference *>( m_node );
163 PrimitiveImporter &primitive()
165 return *reinterpret_cast<PrimitiveImporter *>( m_child );
169 EntityImporter(scene::Node &parent, EntityCreator &entityTable) : m_parent(parent), m_entityTable(entityTable)
173 void pushElement(const XMLElement &element)
175 ASSERT_MESSAGE(string_equal(element.name(), "entity"), PARSE_ERROR);
177 NodeSmartReference(m_entityTable.createEntity(GlobalEntityClassManager().findOrInsert("", true))));
178 constructor(primitive(), makeReference(node().get()));
181 void popElement(const char *name)
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()))));
189 EntityCopyingVisitor visitor(*Node_getEntity(entity));
190 Node_getEntity(node())->forEachKeyValue(visitor);
193 if (Node_getTraversable(entity) != 0 && !Node_getEntity(entity)->getEntityClass().fixedsize) {
194 parentBrushes(node(), entity);
197 Node_getTraversable(m_parent)->insert(entity);
199 destructor(primitive());
203 std::size_t write(const char *buffer, std::size_t length)
208 TreeXMLImporter &child()
214 class MapDoom3Importer : public TreeXMLImporter {
216 char m_child[sizeof(EntityImporter)];
217 EntityCreator &m_entityTable;
219 EntityImporter &getEntity()
221 return *reinterpret_cast<EntityImporter *>( m_child );
225 MapDoom3Importer(scene::Node &root, EntityCreator &entityTable) : m_root(root), m_entityTable(entityTable)
229 void pushElement(const XMLElement &element)
231 ASSERT_MESSAGE(string_equal(element.name(), "mapdoom3"), PARSE_ERROR);
232 constructor(getEntity(), makeReference(m_root), makeReference(m_entityTable));
235 void popElement(const char *name)
237 ASSERT_MESSAGE(string_equal(name, "mapdoom3"), PARSE_ERROR);
238 destructor(getEntity());
241 std::size_t write(const char *data, std::size_t length)
246 TreeXMLImporter &child()
252 class TreeXMLImporterStack : public XMLImporter {
253 std::vector<Reference<TreeXMLImporter> > m_importers;
255 TreeXMLImporterStack(TreeXMLImporter &importer)
257 m_importers.push_back(makeReference(importer));
260 void pushElement(const XMLElement &element)
262 m_importers.back().get().pushElement(element);
263 m_importers.push_back(makeReference(m_importers.back().get().child()));
266 void popElement(const char *name)
268 m_importers.pop_back();
269 m_importers.back().get().popElement(name);
272 std::size_t write(const char *buffer, std::size_t length)
274 return (*(m_importers.end() - 2)).get().write(buffer, length);
279 void Map_Read(scene::Node &root, TextInputStream &in, EntityCreator &entityTable)
281 XMLStreamParser parser(in);
283 MapDoom3Importer importer(root, entityTable);
284 TreeXMLImporterStack stack(importer);
285 parser.exportXML(stack);