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 #define PARSE_ERROR "XML PARSE ERROR"
45 inline XMLImporter* Node_getXMLImporter( scene::Node& node ){
46 return NodeTypeCast<XMLImporter>::cast( node );
50 scene::Node& createPrimitive( const char* name ){
51 if ( string_equal( name, "brush" ) ) {
52 return GlobalBrushCreator().createBrush();
54 else if ( string_equal( name, "patch" ) ) {
55 return GlobalPatchCreator().createPatch();
58 ASSERT_MESSAGE( 0, PARSE_ERROR << ": primitive type not supported: \"" << name << "\"\n" );
59 scene::Node* node = 0;
63 class TreeXMLImporter : public XMLImporter
66 virtual TreeXMLImporter& child() = 0;
69 class SubPrimitiveImporter : public TreeXMLImporter
71 XMLImporter* m_importer;
73 SubPrimitiveImporter( XMLImporter* importer ) : m_importer( importer ){
75 void pushElement( const XMLElement& element ){
76 m_importer->pushElement( element );
78 void popElement( const char* name ){
79 m_importer->popElement( name );
81 std::size_t write( const char* buffer, std::size_t length ){
82 return m_importer->write( buffer, length );
84 SubPrimitiveImporter& child(){
89 class PrimitiveImporter : public TreeXMLImporter
91 scene::Node& m_parent;
92 XMLImporter* m_importer;
93 char m_child[sizeof( SubPrimitiveImporter )];
95 SubPrimitiveImporter& subprimitive(){
96 return *reinterpret_cast<SubPrimitiveImporter*>( m_child );
99 PrimitiveImporter( scene::Node& parent ) : m_parent( parent ), m_importer( 0 ){
101 void pushElement( const XMLElement& element ){
102 if ( string_equal( element.name(), "epair" ) ) {
103 ASSERT_MESSAGE( string_equal( element.name(), "epair" ), PARSE_ERROR );
104 Node_getEntity( m_parent )->setKeyValue( element.attribute( "key" ), element.attribute( "value" ) );
108 NodeSmartReference node( createPrimitive( element.name() ) );
110 m_importer = Node_getXMLImporter( node );
112 constructor( subprimitive(), m_importer );
114 m_importer->pushElement( element );
116 Node_getTraversable( m_parent )->insert( node );
119 void popElement( const char* name ){
120 if ( string_equal( name, "epair" ) ) {
124 m_importer->popElement( name );
126 destructor( subprimitive() );
130 std::size_t write( const char* buffer, std::size_t length ){
131 return m_importer->write( buffer, length );
133 TreeXMLImporter& child(){
134 return subprimitive();
138 class EntityImporter : public TreeXMLImporter
140 scene::Node& m_parent;
141 char m_node[sizeof( NodeSmartReference )];
142 char m_child[sizeof( PrimitiveImporter )];
143 EntityCreator& m_entityTable;
145 NodeSmartReference& node(){
146 return *reinterpret_cast<NodeSmartReference*>( m_node );
148 PrimitiveImporter& primitive(){
149 return *reinterpret_cast<PrimitiveImporter*>( m_child );
153 EntityImporter( scene::Node& parent, EntityCreator& entityTable ) : m_parent( parent ), m_entityTable( entityTable ){
155 void pushElement( const XMLElement& element ){
156 ASSERT_MESSAGE( string_equal( element.name(), "entity" ), PARSE_ERROR );
157 constructor( node(), NodeSmartReference( m_entityTable.createEntity( GlobalEntityClassManager().findOrInsert( "", true ) ) ) );
158 constructor( primitive(), makeReference( node().get() ) );
160 void popElement( const char* name ){
161 ASSERT_MESSAGE( string_equal( name, "entity" ), PARSE_ERROR );
162 NodeSmartReference entity( m_entityTable.createEntity( GlobalEntityClassManager().findOrInsert( Node_getEntity( node() )->getKeyValue( "classname" ), node_is_group( node() ) ) ) );
165 EntityCopyingVisitor visitor( *Node_getEntity( entity ) );
166 Node_getEntity( node() )->forEachKeyValue( visitor );
169 if ( Node_getTraversable( entity ) != 0 && !Node_getEntity( entity )->getEntityClass().fixedsize ) {
170 parentBrushes( node(), entity );
173 Node_getTraversable( m_parent )->insert( entity );
175 destructor( primitive() );
176 destructor( node() );
178 std::size_t write( const char* buffer, std::size_t length ){
181 TreeXMLImporter& child(){
186 class MapDoom3Importer : public TreeXMLImporter
189 char m_child[sizeof( EntityImporter )];
190 EntityCreator& m_entityTable;
192 EntityImporter& getEntity(){
193 return *reinterpret_cast<EntityImporter*>( m_child );
196 MapDoom3Importer( scene::Node& root, EntityCreator& entityTable ) : m_root( root ), m_entityTable( entityTable ){
198 void pushElement( const XMLElement& element ){
199 ASSERT_MESSAGE( string_equal( element.name(), "mapdoom3" ), PARSE_ERROR );
200 constructor( getEntity(), makeReference( m_root ), makeReference( m_entityTable ) );
202 void popElement( const char* name ){
203 ASSERT_MESSAGE( string_equal( name, "mapdoom3" ), PARSE_ERROR );
204 destructor( getEntity() );
206 std::size_t write( const char* data, std::size_t length ){
209 TreeXMLImporter& child(){
214 class TreeXMLImporterStack : public XMLImporter
216 std::vector< Reference<TreeXMLImporter> > m_importers;
218 TreeXMLImporterStack( TreeXMLImporter& importer ){
219 m_importers.push_back( makeReference( importer ) );
221 void pushElement( const XMLElement& element ){
222 m_importers.back().get().pushElement( element );
223 m_importers.push_back( makeReference( m_importers.back().get().child() ) );
225 void popElement( const char* name ){
226 m_importers.pop_back();
227 m_importers.back().get().popElement( name );
229 std::size_t write( const char* buffer, std::size_t length ){
230 return ( *( m_importers.end() - 2 ) ).get().write( buffer, length );
235 void Map_Read( scene::Node& root, TextInputStream& in, EntityCreator& entityTable ){
236 XMLStreamParser parser( in );
238 MapDoom3Importer importer( root, entityTable );
239 TreeXMLImporterStack stack( importer );
240 parser.exportXML( stack );