1 // Copyright (C) 2009 - 2012  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17 
18 #ifdef HAVE_CONFIG_H
19 #  include <simgear_config.h>
20 #endif
21 
22 #include <simgear/compiler.h>
23 
24 #include "HLAOMTXmlVisitor.hxx"
25 
26 #include <map>
27 #include <string>
28 #include <sstream>
29 
30 #include <simgear/structure/exception.hxx>
31 #include <simgear/xml/easyxml.hxx>
32 #include "HLAArrayDataType.hxx"
33 #include "HLABasicDataType.hxx"
34 #include "HLADataTypeVisitor.hxx"
35 #include "HLAEnumeratedDataType.hxx"
36 #include "HLAFederate.hxx"
37 #include "HLAFixedRecordDataType.hxx"
38 #include "HLAVariantRecordDataType.hxx"
39 
40 namespace simgear {
41 
ObjectClass(const std::string & name,const std::string & sharing)42 HLAOMTXmlVisitor::ObjectClass::ObjectClass(const std::string& name, const std::string& sharing) :
43     _name(name),
44     _sharing(sharing)
45 {
46 }
47 
~ObjectClass()48 HLAOMTXmlVisitor::ObjectClass::~ObjectClass()
49 {
50 }
51 
52 const std::string&
getName() const53 HLAOMTXmlVisitor::ObjectClass::getName() const
54 {
55     return _name;
56 }
57 
58 const std::string&
getSharing() const59 HLAOMTXmlVisitor::ObjectClass::getSharing() const
60 {
61     return _sharing;
62 }
63 
64 unsigned
getNumAttributes() const65 HLAOMTXmlVisitor::ObjectClass::getNumAttributes() const
66 {
67     return _attributes.size();
68 }
69 
70 const HLAOMTXmlVisitor::Attribute*
getAttribute(unsigned index) const71 HLAOMTXmlVisitor::ObjectClass::getAttribute(unsigned index) const
72 {
73     if (_attributes.size() <= index)
74         return 0;
75     return _attributes[index];
76 }
77 
78 const HLAOMTXmlVisitor::ObjectClass*
getParentObjectClass() const79 HLAOMTXmlVisitor::ObjectClass::getParentObjectClass() const
80 {
81     return _parentObjectClass.get();
82 }
83 
InteractionClass(const std::string & name)84 HLAOMTXmlVisitor::InteractionClass::InteractionClass(const std::string& name) :
85     _name(name)
86 {
87 }
88 
~InteractionClass()89 HLAOMTXmlVisitor::InteractionClass::~InteractionClass()
90 {
91 }
92 
93 const std::string&
getName() const94 HLAOMTXmlVisitor::InteractionClass::getName() const
95 {
96     return _name;
97 }
98 
99 const std::string&
getDimensions() const100 HLAOMTXmlVisitor::InteractionClass::getDimensions() const
101 {
102     return _dimensions;
103 }
104 
105 const std::string&
getSharing() const106 HLAOMTXmlVisitor::InteractionClass::getSharing() const
107 {
108     return _sharing;
109 }
110 
111 const std::string&
getTransportation() const112 HLAOMTXmlVisitor::InteractionClass::getTransportation() const
113 {
114     return _transportation;
115 }
116 
117 const std::string&
getOrder() const118 HLAOMTXmlVisitor::InteractionClass::getOrder() const
119 {
120     return _order;
121 }
122 
123 unsigned
getNumParameters() const124 HLAOMTXmlVisitor::InteractionClass::getNumParameters() const
125 {
126     return _parameters.size();
127 }
128 
129 const HLAOMTXmlVisitor::Parameter*
getParameter(unsigned index) const130 HLAOMTXmlVisitor::InteractionClass::getParameter(unsigned index) const
131 {
132     if (_parameters.size() <= index)
133         return 0;
134     return _parameters[index];
135 }
136 
137 const HLAOMTXmlVisitor::InteractionClass*
getParentInteractionClass() const138 HLAOMTXmlVisitor::InteractionClass::getParentInteractionClass() const
139 {
140     return _parentInteractionClass.get();
141 }
142 
HLAOMTXmlVisitor()143 HLAOMTXmlVisitor::HLAOMTXmlVisitor()
144 {
145 }
146 
~HLAOMTXmlVisitor()147 HLAOMTXmlVisitor::~HLAOMTXmlVisitor()
148 {
149 }
150 
151 void
setDataTypesToFederate(HLAFederate & federate)152 HLAOMTXmlVisitor::setDataTypesToFederate(HLAFederate& federate)
153 {
154     // Provide all the data types
155     for (BasicDataMap::iterator i = _basicDataMap.begin(); i != _basicDataMap.end(); ++i)
156         federate.insertDataType(i->first, getDataType(i->first));
157     for (SimpleDataMap::iterator i = _simpleDataMap.begin(); i != _simpleDataMap.end(); ++i)
158         federate.insertDataType(i->first, getDataType(i->first));
159     for (EnumeratedDataMap::iterator i = _enumeratedDataMap.begin(); i != _enumeratedDataMap.end(); ++i)
160         federate.insertDataType(i->first, getDataType(i->first));
161     for (ArrayDataMap::iterator i = _arrayDataMap.begin(); i != _arrayDataMap.end(); ++i)
162         federate.insertDataType(i->first, getDataType(i->first));
163     for (FixedRecordDataMap::iterator i = _fixedRecordDataMap.begin(); i != _fixedRecordDataMap.end(); ++i)
164         federate.insertDataType(i->first, getDataType(i->first));
165     for (VariantRecordDataMap::iterator i = _variantRecordDataMap.begin(); i != _variantRecordDataMap.end(); ++i)
166         federate.insertDataType(i->first, getDataType(i->first));
167 
168     // Finish alignment computations
169     federate.recomputeDataTypeAlignment();
170 }
171 
172 void
setToFederate(HLAFederate & federate)173 HLAOMTXmlVisitor::setToFederate(HLAFederate& federate)
174 {
175     setDataTypesToFederate(federate);
176 
177     // Provide all interaction classes
178     unsigned numInteractionClasses = getNumInteractionClasses();
179     for (unsigned i = 0; i < numInteractionClasses; ++i) {
180         const InteractionClass* interactionClass = getInteractionClass(i);
181         if (federate.getInteractionClass(interactionClass->getName())) {
182             SG_LOG(SG_IO, SG_ALERT, "Not creating Interaction class \"" << interactionClass->getName() << "\" twice!.");
183             continue;
184         }
185 
186         SGSharedPtr<HLAInteractionClass> hlaInteractionClass;
187         hlaInteractionClass = federate.createInteractionClass(interactionClass->getName());
188         if (!hlaInteractionClass.valid()) {
189             SG_LOG(SG_IO, SG_INFO, "Ignoring Interaction class \"" << interactionClass->getName() << "\".");
190             continue;
191         }
192 
193         hlaInteractionClass->setSubscriptionType(interactionClass->getSubscriptionType());
194         hlaInteractionClass->setPublicationType(interactionClass->getPublicationType());
195 
196         // process the parameters
197         for (unsigned j = 0; j < interactionClass->getNumParameters(); ++j) {
198             const Parameter* parameter = interactionClass->getParameter(j);
199             unsigned index = hlaInteractionClass->addParameter(parameter->getName());
200             hlaInteractionClass->setParameterDataType(index, federate.getDataType(parameter->getDataType()));
201         }
202     }
203 
204     // Provide all object classes
205     unsigned numObjectClasses = getNumObjectClasses();
206     for (unsigned i = 0; i < numObjectClasses; ++i) {
207         const ObjectClass* objectClass = getObjectClass(i);
208         if (federate.getObjectClass(objectClass->getName())) {
209             SG_LOG(SG_IO, SG_ALERT, "Not creating Object class \"" << objectClass->getName() << "\" twice!.");
210             continue;
211         }
212 
213         SGSharedPtr<HLAObjectClass> hlaObjectClass;
214         hlaObjectClass = federate.createObjectClass(objectClass->getName());
215         if (!hlaObjectClass.valid()) {
216             SG_LOG(SG_IO, SG_INFO, "Ignoring Object class \"" << objectClass->getName() << "\".");
217             continue;
218         }
219 
220         // process the attributes
221         for (unsigned j = 0; j < objectClass->getNumAttributes(); ++j) {
222             const Attribute* attribute = objectClass->getAttribute(j);
223 
224             unsigned index = hlaObjectClass->addAttribute(attribute->getName());
225             hlaObjectClass->setAttributeDataType(index, federate.getDataType(attribute->getDataType()));
226 
227             hlaObjectClass->setAttributeSubscriptionType(index, attribute->getSubscriptionType());
228             hlaObjectClass->setAttributePublicationType(index, attribute->getPublicationType());
229             hlaObjectClass->setAttributeUpdateType(index, attribute->getUpdateType());
230         }
231     }
232 }
233 
234 unsigned
getNumObjectClasses() const235 HLAOMTXmlVisitor::getNumObjectClasses() const
236 {
237     return _objectClassList.size();
238 }
239 
240 const HLAOMTXmlVisitor::ObjectClass*
getObjectClass(unsigned i) const241 HLAOMTXmlVisitor::getObjectClass(unsigned i) const
242 {
243     if (_objectClassList.size() <= i)
244         return 0;
245     return _objectClassList[i];
246 }
247 
248 unsigned
getNumInteractionClasses() const249 HLAOMTXmlVisitor::getNumInteractionClasses() const
250 {
251     return _interactionClassList.size();
252 }
253 
254 const HLAOMTXmlVisitor::InteractionClass*
getInteractionClass(unsigned i) const255 HLAOMTXmlVisitor::getInteractionClass(unsigned i) const
256 {
257     if (_interactionClassList.size() <= i)
258         return 0;
259     return _interactionClassList[i];
260 }
261 
262 SGSharedPtr<HLADataType>
getDataType(const std::string & dataTypeName)263 HLAOMTXmlVisitor::getDataType(const std::string& dataTypeName)
264 {
265     StringDataTypeMap::const_iterator i = _dataTypeMap.find(dataTypeName);
266     if (i != _dataTypeMap.end())
267         return i->second;
268 
269     SGSharedPtr<HLADataType> dataType;
270     dataType = getBasicDataType(dataTypeName);
271     if (dataType.valid()) {
272         _dataTypeMap[dataTypeName] = dataType;
273         return dataType;
274     }
275 
276     dataType = getSimpleDataType(dataTypeName);
277     if (dataType.valid())
278         return dataType;
279 
280     dataType = getEnumeratedDataType(dataTypeName);
281     if (dataType.valid())
282         return dataType;
283 
284     dataType = getArrayDataType(dataTypeName);
285     if (dataType.valid())
286         return dataType;
287 
288     dataType = getFixedRecordDataType(dataTypeName);
289     if (dataType.valid())
290         return dataType;
291 
292     dataType = getVariantRecordDataType(dataTypeName);
293     if (dataType.valid())
294         return dataType;
295 
296     SG_LOG(SG_IO, SG_WARN, "Could not resolve dataType \"" << dataTypeName << "\".");
297     return 0;
298 }
299 
300 SGSharedPtr<HLABasicDataType>
getBasicDataType(const std::string & dataTypeName)301 HLAOMTXmlVisitor::getBasicDataType(const std::string& dataTypeName)
302 {
303     BasicDataMap::const_iterator i = _basicDataMap.find(dataTypeName);
304     if (i == _basicDataMap.end())
305         return 0;
306     if (i->second._size == "8") {
307         return new HLAUInt8DataType(dataTypeName);
308     } else if (i->second._size == "16") {
309         if (i->first.find("Unsigned") != std::string::npos) {
310             if (i->second._endian == "Little") {
311                 return new HLAUInt16LEDataType(dataTypeName);
312             } else {
313                 return new HLAUInt16BEDataType(dataTypeName);
314             }
315         } else if (i->first.find("octetPair") != std::string::npos) {
316             if (i->second._endian == "Little") {
317                 return new HLAUInt16LEDataType(dataTypeName);
318             } else {
319                 return new HLAUInt16BEDataType(dataTypeName);
320             }
321         } else {
322             if (i->second._endian == "Little") {
323                 return new HLAInt16LEDataType(dataTypeName);
324             } else {
325                 return new HLAInt16BEDataType(dataTypeName);
326             }
327         }
328     } else if (i->second._size == "32") {
329         if (i->first.find("Unsigned") != std::string::npos) {
330             if (i->second._endian == "Little") {
331                 return new HLAUInt32LEDataType(dataTypeName);
332             } else {
333                 return new HLAUInt32BEDataType(dataTypeName);
334             }
335         } else if (i->first.find("float") != std::string::npos) {
336             if (i->second._endian == "Little") {
337                 return new HLAFloat32LEDataType(dataTypeName);
338             } else {
339                 return new HLAFloat32BEDataType(dataTypeName);
340             }
341         } else {
342             if (i->second._endian == "Little") {
343                 return new HLAInt32LEDataType(dataTypeName);
344             } else {
345                 return new HLAInt32BEDataType(dataTypeName);
346             }
347         }
348     } else if (i->second._size == "64") {
349         if (i->first.find("Unsigned") != std::string::npos) {
350             if (i->second._endian == "Little") {
351                 return new HLAUInt64LEDataType(dataTypeName);
352             } else {
353                 return new HLAUInt64BEDataType(dataTypeName);
354             }
355         } else if (i->first.find("float") != std::string::npos) {
356             if (i->second._endian == "Little") {
357                 return new HLAFloat64LEDataType(dataTypeName);
358             } else {
359                 return new HLAFloat64BEDataType(dataTypeName);
360             }
361         } else {
362             if (i->second._endian == "Little") {
363                 return new HLAInt64LEDataType(dataTypeName);
364             } else {
365                 return new HLAInt64BEDataType(dataTypeName);
366             }
367         }
368     }
369 
370     return 0;
371 }
372 
373 SGSharedPtr<HLADataType>
getSimpleDataType(const std::string & dataTypeName)374 HLAOMTXmlVisitor::getSimpleDataType(const std::string& dataTypeName)
375 {
376     SimpleDataMap::const_iterator i = _simpleDataMap.find(dataTypeName);
377     if (i == _simpleDataMap.end())
378         return 0;
379     return getDataType(i->second._representation);
380 }
381 
382 SGSharedPtr<HLAEnumeratedDataType>
getEnumeratedDataType(const std::string & dataTypeName)383 HLAOMTXmlVisitor::getEnumeratedDataType(const std::string& dataTypeName)
384 {
385     EnumeratedDataMap::const_iterator i = _enumeratedDataMap.find(dataTypeName);
386     if (i == _enumeratedDataMap.end())
387         return 0;
388 
389     SGSharedPtr<HLAEnumeratedDataType> enumeratedDataType = new HLAEnumeratedDataType(dataTypeName);
390     _dataTypeMap[dataTypeName] = enumeratedDataType;
391     enumeratedDataType->setRepresentation(getBasicDataType(i->second._representation));
392 
393     for (EnumeratorList::const_iterator j = i->second._enumeratorList.begin();
394          j != i->second._enumeratorList.end(); ++j) {
395         if (!enumeratedDataType->addEnumerator(j->_name, j->_values)) {
396             SG_LOG(SG_IO, SG_ALERT, "Could not add enumerator \"" << j->_name
397                    << "\" to find enumerated data type \"" << dataTypeName << "\".");
398             return 0;
399         }
400     }
401 
402     return enumeratedDataType;
403 }
404 
405 SGSharedPtr<HLADataType>
getArrayDataType(const std::string & dataTypeName)406 HLAOMTXmlVisitor::getArrayDataType(const std::string& dataTypeName)
407 {
408     ArrayDataMap::const_iterator i = _arrayDataMap.find(dataTypeName);
409     if (i == _arrayDataMap.end())
410         return 0;
411     SGSharedPtr<HLAArrayDataType> arrayDataType;
412     if (i->second._encoding == "HLAvariableArray") {
413         arrayDataType = new HLAVariableArrayDataType(dataTypeName);
414     } else if (i->second._encoding == "HLAfixedArray") {
415         std::stringstream ss(i->second._cardinality);
416         unsigned cardinality;
417         ss >> cardinality;
418         if (ss.fail()) {
419             SG_LOG(SG_IO, SG_ALERT, "Could not interpret cardinality \""
420                    << i->second._cardinality << "\" for dataType \""
421                    << dataTypeName << "\".");
422             return 0;
423         }
424         SGSharedPtr<HLAFixedArrayDataType> dataType = new HLAFixedArrayDataType(dataTypeName);
425         dataType->setNumElements(cardinality);
426         arrayDataType = dataType;
427     } else {
428         SG_LOG(SG_IO, SG_ALERT, "Can not interpret encoding \""
429                << i->second._encoding << "\" for dataType \""
430                << dataTypeName << "\".");
431         return 0;
432     }
433 
434     _dataTypeMap[dataTypeName] = arrayDataType;
435     SGSharedPtr<HLADataType> elementDataType = getDataType(i->second._dataType);
436     if (!elementDataType.valid()) {
437         SG_LOG(SG_IO, SG_ALERT, "Could not interpret dataType \""
438                << i->second._dataType << "\" for array data type \""
439                << dataTypeName << "\".");
440         _dataTypeMap.erase(dataTypeName);
441         return 0;
442     }
443     arrayDataType->setElementDataType(elementDataType.get());
444 
445     // Check if this should be a string data type
446     if (elementDataType->toBasicDataType()) {
447         if (dataTypeName == "HLAopaqueData") {
448             arrayDataType->setIsOpaque(true);
449         } else if (dataTypeName.find("String") != std::string::npos || dataTypeName.find("string") != std::string::npos) {
450             arrayDataType->setIsString(true);
451         }
452     }
453 
454     return arrayDataType;
455 }
456 
457 SGSharedPtr<HLAFixedRecordDataType>
getFixedRecordDataType(const std::string & dataTypeName)458 HLAOMTXmlVisitor::getFixedRecordDataType(const std::string& dataTypeName)
459 {
460     FixedRecordDataMap::const_iterator i = _fixedRecordDataMap.find(dataTypeName);
461     if (i == _fixedRecordDataMap.end())
462         return 0;
463 
464     SGSharedPtr<HLAFixedRecordDataType> dataType = new HLAFixedRecordDataType(dataTypeName);
465     _dataTypeMap[dataTypeName] = dataType;
466     for (FieldList::size_type j = 0; j < i->second._fieldList.size(); ++j) {
467         SGSharedPtr<HLADataType> fieldDataType = getDataType(i->second._fieldList[j]._dataType);
468         if (!fieldDataType.valid()) {
469             SG_LOG(SG_IO, SG_ALERT, "Could not get data type \"" << i->second._fieldList[j]._dataType
470                    << "\" for field " << j << "of fixed record data type \"" << dataTypeName << "\".");
471             _dataTypeMap.erase(dataTypeName);
472             return 0;
473         }
474         dataType->addField(i->second._fieldList[j]._name, fieldDataType.get());
475     }
476     return dataType;
477 }
478 
479 SGSharedPtr<HLAVariantRecordDataType>
getVariantRecordDataType(const std::string & dataTypeName)480 HLAOMTXmlVisitor::getVariantRecordDataType(const std::string& dataTypeName)
481 {
482     VariantRecordDataMap::const_iterator i = _variantRecordDataMap.find(dataTypeName);
483     if (i == _variantRecordDataMap.end())
484         return 0;
485     SGSharedPtr<HLAVariantRecordDataType> dataType = new HLAVariantRecordDataType(dataTypeName);
486     _dataTypeMap[dataTypeName] = dataType;
487 
488     SGSharedPtr<HLAEnumeratedDataType> enumeratedDataType = getEnumeratedDataType(i->second._dataType);
489     if (!enumeratedDataType.valid()) {
490         SG_LOG(SG_IO, SG_ALERT, "Could not find enumerted data type \"" << i->second._dataType
491                << "\" for variant data type \"" << dataTypeName << "\".");
492         return 0;
493     }
494     dataType->setEnumeratedDataType(enumeratedDataType);
495 
496     for (AlternativeList::const_iterator j = i->second._alternativeList.begin();
497          j != i->second._alternativeList.end(); ++j) {
498         SGSharedPtr<HLADataType> alternativeDataType = getDataType(j->_dataType);
499         if (!alternativeDataType.valid()) {
500             SG_LOG(SG_IO, SG_ALERT, "Could not resolve alternative dataType \"" << j->_dataType
501                    << "\" for alternative \"" << j->_name << "\".");
502             _dataTypeMap.erase(dataTypeName);
503             return 0;
504         }
505         if (!dataType->addAlternative(j->_name, j->_enumerator, alternativeDataType.get(), j->_semantics)) {
506             SG_LOG(SG_IO, SG_ALERT, "Could not add alternative \"" << j->_name << "\".");
507             return 0;
508         }
509     }
510     return dataType;
511 }
512 
513 HLAOMTXmlVisitor::Mode
getCurrentMode()514 HLAOMTXmlVisitor::getCurrentMode()
515 {
516     if (_modeStack.empty())
517         return UnknownMode;
518     return _modeStack.back();
519 }
520 
521 void
pushMode(HLAOMTXmlVisitor::Mode mode)522 HLAOMTXmlVisitor::pushMode(HLAOMTXmlVisitor::Mode mode)
523 {
524     _modeStack.push_back(mode);
525 }
526 
527 void
popMode()528 HLAOMTXmlVisitor::popMode()
529 {
530     _modeStack.pop_back();
531 }
532 
533 void
startXML()534 HLAOMTXmlVisitor::startXML()
535 {
536     _modeStack.clear();
537 }
538 
539 void
endXML()540 HLAOMTXmlVisitor::endXML()
541 {
542     if (!_modeStack.empty())
543         throw sg_exception("Internal parse error!");
544 
545     // propagate parent attributes to the derived classes
546     // Note that this preserves the order of the attributes starting from the root object
547     for (ObjectClassList::const_iterator i = _objectClassList.begin(); i != _objectClassList.end(); ++i) {
548         SGSharedPtr<const ObjectClass> objectClass = (*i)->_parentObjectClass;
549         if (!objectClass.valid())
550             continue;
551         for (AttributeList::const_reverse_iterator j = objectClass->_attributes.rbegin();
552              j != objectClass->_attributes.rend(); ++j) {
553             (*i)->_attributes.insert((*i)->_attributes.begin(), *j);
554         }
555     }
556 
557     // propagate parent parameter to the derived interactions
558     // Note that this preserves the order of the parameters starting from the root object
559     for (InteractionClassList::const_iterator i = _interactionClassList.begin(); i != _interactionClassList.end(); ++i) {
560         SGSharedPtr<const InteractionClass> interactionClass = (*i)->_parentInteractionClass;
561         if (!interactionClass.valid())
562             continue;
563         for (ParameterList::const_reverse_iterator j = interactionClass->_parameters.rbegin();
564              j != interactionClass->_parameters.rend(); ++j) {
565             (*i)->_parameters.insert((*i)->_parameters.begin(), *j);
566         }
567     }
568 }
569 
570 void
startElement(const char * name,const XMLAttributes & atts)571 HLAOMTXmlVisitor::startElement(const char* name, const XMLAttributes& atts)
572 {
573     if (strcmp(name, "attribute") == 0) {
574         if (getCurrentMode() != ObjectClassMode)
575             throw sg_exception("attribute tag outside objectClass!");
576         pushMode(AttributeMode);
577 
578         if (_objectClassList.empty())
579             throw sg_exception("attribute tag outside of an objectClass");
580 
581         std::string name = getAttribute("name", atts);
582         if (name.empty())
583             throw sg_exception("attribute tag without name attribute");
584 
585         SGSharedPtr<Attribute> attribute = new Attribute(name);
586 
587         attribute->_dataType = getAttribute("dataType", atts);
588         attribute->_updateType = getAttribute("updateType", atts);
589         attribute->_updateCondition = getAttribute("updateCondition", atts);
590         attribute->_ownership = getAttribute("ownership", atts);
591         attribute->_sharing = getAttribute("sharing", atts);
592         attribute->_dimensions = getAttribute("dimensions", atts);
593         attribute->_transportation = getAttribute("transportation", atts);
594         attribute->_order = getAttribute("order", atts);
595 
596         _objectClassStack.back()->_attributes.push_back(attribute);
597 
598     } else if (strcmp(name, "objectClass") == 0) {
599         if (getCurrentMode() != ObjectsMode && getCurrentMode() != ObjectClassMode)
600             throw sg_exception("objectClass tag outside objectClass or objects!");
601         pushMode(ObjectClassMode);
602 
603         std::string name = getAttribute("name", atts);
604         if (name.empty())
605             throw sg_exception("objectClass tag without name attribute");
606 
607         std::string sharing = getAttribute("sharing", atts);
608 
609         // The new ObjectClass
610         ObjectClass* objectClass = new ObjectClass(name, sharing);
611 
612         // Inherit all previous attributes
613         if (!_objectClassStack.empty())
614             objectClass->_parentObjectClass = _objectClassStack.back();
615 
616         _objectClassStack.push_back(objectClass);
617         _objectClassList.push_back(objectClass);
618 
619     } else if (strcmp(name, "objects") == 0) {
620         if (getCurrentMode() != ObjectModelMode)
621             throw sg_exception("objects tag outside objectModel!");
622         pushMode(ObjectsMode);
623 
624     } else if (strcmp(name, "parameter") == 0) {
625         if (getCurrentMode() != InteractionClassMode)
626             throw sg_exception("parameter tag outside interactionClass!");
627         pushMode(ParameterMode);
628 
629         if (_interactionClassList.empty())
630             throw sg_exception("parameter tag outside of an interactionClass");
631 
632         std::string name = getAttribute("name", atts);
633         if (name.empty())
634             throw sg_exception("parameter tag without name parameter");
635 
636         SGSharedPtr<Parameter> parameter = new Parameter(name);
637         parameter->_dataType = getAttribute("dataType", atts);
638 
639         _interactionClassStack.back()->_parameters.push_back(parameter);
640 
641     } else if (strcmp(name, "interactionClass") == 0) {
642         if (getCurrentMode() != InteractionsMode && getCurrentMode() != InteractionClassMode)
643             throw sg_exception("interactionClass tag outside interactions or interactionClass!");
644         pushMode(InteractionClassMode);
645 
646         std::string name = getAttribute("name", atts);
647         if (name.empty())
648             throw sg_exception("interactionClass tag without name attribute");
649 
650         // The new ObjectClass
651         InteractionClass* interactionClass = new InteractionClass(name);
652         interactionClass->_dimensions = getAttribute("dimensions", atts);
653         interactionClass->_transportation = getAttribute("transportation", atts);
654         interactionClass->_order = getAttribute("order", atts);
655 
656         // Inherit all previous attributes
657         if (!_interactionClassStack.empty())
658             interactionClass->_parentInteractionClass = _interactionClassStack.back();
659 
660         _interactionClassStack.push_back(interactionClass);
661         _interactionClassList.push_back(interactionClass);
662 
663     } else if (strcmp(name, "interactions") == 0) {
664         if (getCurrentMode() != ObjectModelMode)
665             throw sg_exception("interactions tag outside objectModel!");
666         pushMode(InteractionsMode);
667 
668     } else if (strcmp(name, "basicData") == 0) {
669         if (getCurrentMode() != BasicDataRepresentationsMode)
670             throw sg_exception("basicData tag outside basicDataRepresentations!");
671         pushMode(BasicDataMode);
672 
673         std::string name = getAttribute("name", atts);
674         if (name.empty())
675             throw sg_exception("basicData tag without name attribute");
676 
677         _basicDataMap[name]._size = getAttribute("size", atts);
678         _basicDataMap[name]._endian = getAttribute("endian", atts);
679 
680     } else if (strcmp(name, "basicDataRepresentations") == 0) {
681         if (getCurrentMode() != DataTypesMode)
682             throw sg_exception("basicDataRepresentations tag outside dataTypes!");
683         pushMode(BasicDataRepresentationsMode);
684 
685     } else if (strcmp(name, "simpleData") == 0) {
686         if (getCurrentMode() != SimpleDataTypesMode)
687             throw sg_exception("simpleData tag outside simpleDataTypes!");
688         pushMode(SimpleDataMode);
689 
690         std::string name = getAttribute("name", atts);
691         if (name.empty())
692             throw sg_exception("simpleData tag without name attribute");
693 
694         _simpleDataMap[name]._representation = getAttribute("representation", atts);
695         _simpleDataMap[name]._units = getAttribute("units", atts);
696         _simpleDataMap[name]._resolution = getAttribute("resolution", atts);
697         _simpleDataMap[name]._accuracy = getAttribute("accuracy", atts);
698 
699     } else if (strcmp(name, "simpleDataTypes") == 0) {
700         if (getCurrentMode() != DataTypesMode)
701             throw sg_exception("simpleDataTypes tag outside dataTypes!");
702         pushMode(SimpleDataTypesMode);
703 
704     } else if (strcmp(name, "enumerator") == 0) {
705         if (getCurrentMode() != EnumeratedDataMode)
706             throw sg_exception("enumerator tag outside enumeratedData!");
707         pushMode(EnumeratorMode);
708 
709         std::string name = getAttribute("name", atts);
710         if (name.empty())
711             throw sg_exception("enumerator tag without name attribute");
712 
713         Enumerator enumerator;
714         enumerator._name = name;
715         enumerator._values = getAttribute("values", atts);
716         _enumeratedDataMap[_enumeratedDataName]._enumeratorList.push_back(enumerator);
717 
718     } else if (strcmp(name, "enumeratedData") == 0) {
719         if (getCurrentMode() != EnumeratedDataTypesMode)
720             throw sg_exception("enumeratedData tag outside enumeratedDataTypes!");
721         pushMode(EnumeratedDataMode);
722 
723         std::string name = getAttribute("name", atts);
724         if (name.empty())
725             throw sg_exception("enumeratedData tag without name attribute");
726 
727         _enumeratedDataName = name;
728         _enumeratedDataMap[_enumeratedDataName]._representation = getAttribute("representation", atts);
729 
730     } else if (strcmp(name, "enumeratedDataTypes") == 0) {
731         if (getCurrentMode() != DataTypesMode)
732             throw sg_exception("enumeratedDataTypes tag outside dataTypes!");
733         pushMode(EnumeratedDataTypesMode);
734 
735     } else if (strcmp(name, "arrayData") == 0) {
736         if (getCurrentMode() != ArrayDataTypesMode)
737             throw sg_exception("arrayData tag outside arrayDataTypes!");
738         pushMode(ArrayDataMode);
739 
740         std::string name = getAttribute("name", atts);
741         if (name.empty())
742             throw sg_exception("arrayData tag without name attribute");
743 
744         _arrayDataMap[name]._dataType = getAttribute("dataType", atts);
745         _arrayDataMap[name]._cardinality = getAttribute("cardinality", atts);
746         _arrayDataMap[name]._encoding = getAttribute("encoding", atts);
747 
748     } else if (strcmp(name, "arrayDataTypes") == 0) {
749         if (getCurrentMode() != DataTypesMode)
750             throw sg_exception("arrayDataTypes tag outside dataTypes!");
751         pushMode(ArrayDataTypesMode);
752 
753     } else if (strcmp(name, "field") == 0) {
754         if (getCurrentMode() != FixedRecordDataMode)
755             throw sg_exception("field tag outside fixedRecordData!");
756         pushMode(FieldMode);
757 
758         std::string name = getAttribute("name", atts);
759         if (name.empty())
760             throw sg_exception("field tag without name attribute");
761 
762         Field field;
763         field._name = name;
764         field._dataType = getAttribute("dataType", atts);
765         _fixedRecordDataMap[_fixedRecordDataName]._fieldList.push_back(field);
766 
767     } else if (strcmp(name, "fixedRecordData") == 0) {
768         if (getCurrentMode() != FixedRecordDataTypesMode)
769             throw sg_exception("fixedRecordData tag outside fixedRecordDataTypes!");
770         pushMode(FixedRecordDataMode);
771 
772         std::string name = getAttribute("name", atts);
773         if (name.empty())
774             throw sg_exception("fixedRecordData tag without name attribute");
775 
776         _fixedRecordDataName = name;
777         _fixedRecordDataMap[name]._encoding = getAttribute("encoding", atts);
778 
779     } else if (strcmp(name, "fixedRecordDataTypes") == 0) {
780         if (getCurrentMode() != DataTypesMode)
781             throw sg_exception("fixedRecordDataTypes tag outside dataTypes!");
782         pushMode(FixedRecordDataTypesMode);
783 
784     } else if (strcmp(name, "alternative") == 0) {
785 
786         if (getCurrentMode() != VariantRecordDataMode)
787             throw sg_exception("alternative tag outside variantRecordData!");
788         pushMode(AlternativeDataMode);
789 
790         std::string name = getAttribute("name", atts);
791         if (name.empty())
792             throw sg_exception("alternative tag without name attribute");
793 
794         Alternative alternative;
795         alternative._name = name;
796         alternative._dataType = getAttribute("dataType", atts);
797         alternative._semantics = getAttribute("semantics", atts);
798         alternative._enumerator = getAttribute("enumerator", atts);
799         _variantRecordDataMap[_variantRecordDataName]._alternativeList.push_back(alternative);
800 
801     } else if (strcmp(name, "variantRecordData") == 0) {
802         if (getCurrentMode() != VariantRecordDataTypesMode)
803             throw sg_exception("variantRecordData tag outside variantRecordDataTypes!");
804         pushMode(VariantRecordDataMode);
805 
806         std::string name = getAttribute("name", atts);
807         if (name.empty())
808             throw sg_exception("fixedRecordData tag without name attribute");
809 
810         _variantRecordDataName = name;
811         _variantRecordDataMap[name]._encoding = getAttribute("encoding", atts);
812         _variantRecordDataMap[name]._dataType = getAttribute("dataType", atts);
813         _variantRecordDataMap[name]._semantics = getAttribute("semantics", atts);
814         _variantRecordDataMap[name]._discriminant = getAttribute("discriminant", atts);
815 
816     } else if (strcmp(name, "variantRecordDataTypes") == 0) {
817         if (getCurrentMode() != DataTypesMode)
818             throw sg_exception("variantRecordDataTypes tag outside dataTypes!");
819         pushMode(VariantRecordDataTypesMode);
820 
821     } else if (strcmp(name, "dataTypes") == 0) {
822         if (getCurrentMode() != ObjectModelMode)
823             throw sg_exception("dataTypes tag outside objectModel!");
824         pushMode(DataTypesMode);
825 
826     } else if (strcmp(name, "objectModel") == 0) {
827         if (!_modeStack.empty())
828             throw sg_exception("objectModel tag not at top level!");
829         pushMode(ObjectModelMode);
830 
831     } else {
832         _modeStack.push_back(UnknownMode);
833     }
834 }
835 
836 void
endElement(const char * name)837 HLAOMTXmlVisitor::endElement(const char* name)
838 {
839     if (strcmp(name, "objectClass") == 0) {
840         _objectClassStack.pop_back();
841     } else if (strcmp(name, "interactionClass") == 0) {
842         _interactionClassStack.pop_back();
843     } else if (strcmp(name, "enumeratedData") == 0) {
844         _enumeratedDataName.clear();
845     } else if (strcmp(name, "fixedRecordData") == 0) {
846         _fixedRecordDataName.clear();
847     } else if (strcmp(name, "variantRecordData") == 0) {
848         _variantRecordDataName.clear();
849     }
850 
851     _modeStack.pop_back();
852 }
853 
854 std::string
getAttribute(const char * name,const XMLAttributes & atts)855 HLAOMTXmlVisitor::getAttribute(const char* name, const XMLAttributes& atts)
856 {
857     int index = atts.findAttribute(name);
858     if (index < 0 || atts.size() <= index)
859         return std::string();
860     return std::string(atts.getValue(index));
861 }
862 
863 std::string
getAttribute(const std::string & name,const XMLAttributes & atts)864 HLAOMTXmlVisitor::getAttribute(const std::string& name, const XMLAttributes& atts)
865 {
866     int index = atts.findAttribute(name.c_str());
867     if (index < 0 || atts.size() <= index)
868         return std::string();
869     return std::string(atts.getValue(index));
870 }
871 
872 } // namespace simgear
873