diff --git a/simgear/hla/HLAPropertyDataElement.cxx b/simgear/hla/HLAPropertyDataElement.cxx index 121eddda..e8a931ee 100644 --- a/simgear/hla/HLAPropertyDataElement.cxx +++ b/simgear/hla/HLAPropertyDataElement.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2009 - 2010 Mathias Froehlich - Mathias.Froehlich@web.de +// Copyright (C) 2009 - 2011 Mathias Froehlich - Mathias.Froehlich@web.de // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -17,16 +17,21 @@ #include "HLAPropertyDataElement.hxx" +#include "HLAArrayDataElement.hxx" #include "HLADataTypeVisitor.hxx" +#include "HLAFixedRecordDataElement.hxx" +#include "HLAVariantDataElement.hxx" namespace simgear { -class HLAPropertyDataElement::DecodeVisitor : public HLADataTypeDecodeVisitor { +class HLAPropertyDataElement::ScalarDecodeVisitor : public HLADataTypeDecodeVisitor { public: - DecodeVisitor(HLADecodeStream& stream, SGPropertyNode& propertyNode) : + ScalarDecodeVisitor(HLADecodeStream& stream, SGPropertyNode& propertyNode) : HLADataTypeDecodeVisitor(stream), _propertyNode(propertyNode) { } + virtual ~ScalarDecodeVisitor() + { } virtual void apply(const HLAInt8DataType& dataType) { @@ -89,43 +94,18 @@ public: _propertyNode.setDoubleValue(value); } - virtual void apply(const HLAFixedArrayDataType& dataType) - { - unsigned numElements = dataType.getNumElements(); - std::string value; - value.reserve(numElements); - for (unsigned i = 0; i < numElements; ++i) { - HLATemplateDecodeVisitor visitor(_stream); - dataType.getElementDataType()->accept(visitor); - value.push_back(visitor.getValue()); - } - _propertyNode.setStringValue(value); - } - virtual void apply(const HLAVariableArrayDataType& dataType) - { - HLATemplateDecodeVisitor numElementsVisitor(_stream); - dataType.getSizeDataType()->accept(numElementsVisitor); - unsigned numElements = numElementsVisitor.getValue(); - std::string value; - value.reserve(numElements); - for (unsigned i = 0; i < numElements; ++i) { - HLATemplateDecodeVisitor visitor(_stream); - dataType.getElementDataType()->accept(visitor); - value.push_back(visitor.getValue()); - } - _propertyNode.setStringValue(value); - } - protected: SGPropertyNode& _propertyNode; }; -class HLAPropertyDataElement::EncodeVisitor : public HLADataTypeEncodeVisitor { +class HLAPropertyDataElement::ScalarEncodeVisitor : public HLADataTypeEncodeVisitor { public: - EncodeVisitor(HLAEncodeStream& stream, const SGPropertyNode& propertyNode) : + ScalarEncodeVisitor(HLAEncodeStream& stream, const SGPropertyNode& propertyNode) : HLADataTypeEncodeVisitor(stream), _propertyNode(propertyNode) { } + virtual ~ScalarEncodeVisitor() + { } virtual void apply(const HLAInt8DataType& dataType) { @@ -168,6 +148,116 @@ public: dataType.encode(_stream, _propertyNode.getDoubleValue()); } +protected: + const SGPropertyNode& _propertyNode; +}; + +class HLAPropertyDataElement::ScalarDataElement : public HLADataElement { +public: + ScalarDataElement(const HLABasicDataType* dataType, SGPropertyNode* propertyNode); + virtual ~ScalarDataElement(); + + virtual bool encode(HLAEncodeStream& stream) const; + virtual bool decode(HLADecodeStream& stream); + + virtual const HLADataType* getDataType() const; + virtual bool setDataType(const HLADataType* dataType); + +private: + SGSharedPtr _dataType; + SGSharedPtr _propertyNode; +}; + +HLAPropertyDataElement::ScalarDataElement::ScalarDataElement(const HLABasicDataType* dataType, SGPropertyNode* propertyNode) : + _dataType(dataType), + _propertyNode(propertyNode) +{ +} + +HLAPropertyDataElement::ScalarDataElement::~ScalarDataElement() +{ +} + +bool +HLAPropertyDataElement::ScalarDataElement::encode(HLAEncodeStream& stream) const +{ + ScalarEncodeVisitor visitor(stream, *_propertyNode); + _dataType->accept(visitor); + return true; +} + +bool +HLAPropertyDataElement::ScalarDataElement::decode(HLADecodeStream& stream) +{ + ScalarDecodeVisitor visitor(stream, *_propertyNode); + _dataType->accept(visitor); + return true; +} + +const HLADataType* +HLAPropertyDataElement::ScalarDataElement::getDataType() const +{ + return _dataType.get(); +} + +bool +HLAPropertyDataElement::ScalarDataElement::setDataType(const HLADataType* dataType) +{ + if (!dataType) + return false; + const HLABasicDataType* basicDataType = dataType->toBasicDataType(); + if (!basicDataType) + return false; + _dataType = basicDataType; + return true; +} + + +class HLAPropertyDataElement::StringDecodeVisitor : public HLADataTypeDecodeVisitor { +public: + StringDecodeVisitor(HLADecodeStream& stream, SGPropertyNode& propertyNode) : + HLADataTypeDecodeVisitor(stream), + _propertyNode(propertyNode) + { } + + virtual void apply(const HLAFixedArrayDataType& dataType) + { + unsigned numElements = dataType.getNumElements(); + std::string value; + value.reserve(numElements); + for (unsigned i = 0; i < numElements; ++i) { + HLATemplateDecodeVisitor visitor(_stream); + dataType.getElementDataType()->accept(visitor); + value.push_back(visitor.getValue()); + } + _propertyNode.setStringValue(value); + } + virtual void apply(const HLAVariableArrayDataType& dataType) + { + HLATemplateDecodeVisitor numElementsVisitor(_stream); + dataType.getSizeDataType()->accept(numElementsVisitor); + std::string::size_type numElements = numElementsVisitor.getValue(); + std::string value; + value.reserve(numElements); + for (std::string::size_type i = 0; i < numElements; ++i) { + HLATemplateDecodeVisitor visitor(_stream); + dataType.getElementDataType()->accept(visitor); + value.push_back(visitor.getValue()); + } + _propertyNode.setStringValue(value); + } + +protected: + SGPropertyNode& _propertyNode; +}; + +class HLAPropertyDataElement::StringEncodeVisitor : public HLADataTypeEncodeVisitor { +public: + StringEncodeVisitor(HLAEncodeStream& stream, const SGPropertyNode& propertyNode) : + HLADataTypeEncodeVisitor(stream), + _propertyNode(propertyNode) + { } + virtual void apply(const HLAFixedArrayDataType& dataType) { unsigned numElements = dataType.getNumElements(); @@ -198,6 +288,228 @@ protected: const SGPropertyNode& _propertyNode; }; +class HLAPropertyDataElement::StringDataElement : public HLADataElement { +public: + StringDataElement(const HLAArrayDataType* dataType, SGPropertyNode* propertyNode); + virtual ~StringDataElement(); + + virtual bool encode(HLAEncodeStream& stream) const; + virtual bool decode(HLADecodeStream& stream); + + virtual const HLADataType* getDataType() const; + virtual bool setDataType(const HLADataType* dataType); + +private: + SGSharedPtr _dataType; + SGSharedPtr _propertyNode; +}; + +HLAPropertyDataElement::StringDataElement::StringDataElement(const HLAArrayDataType* dataType, SGPropertyNode* propertyNode) : + _dataType(dataType), + _propertyNode(propertyNode) +{ +} + +HLAPropertyDataElement::StringDataElement::~StringDataElement() +{ +} + +bool +HLAPropertyDataElement::StringDataElement::encode(HLAEncodeStream& stream) const +{ + StringEncodeVisitor visitor(stream, *_propertyNode); + _dataType->accept(visitor); + return true; +} + +bool +HLAPropertyDataElement::StringDataElement::decode(HLADecodeStream& stream) +{ + StringDecodeVisitor visitor(stream, *_propertyNode); + _dataType->accept(visitor); + return true; +} + +const HLADataType* +HLAPropertyDataElement::StringDataElement::getDataType() const +{ + return _dataType.get(); +} + +bool +HLAPropertyDataElement::StringDataElement::setDataType(const HLADataType* dataType) +{ + if (!dataType) + return false; + const HLAArrayDataType* arrayDataType = dataType->toArrayDataType(); + if (!arrayDataType) + return false; + const HLADataType* elementDataType = arrayDataType->getElementDataType(); + if (!elementDataType) + return false; + if (!elementDataType->toBasicDataType()) + return false; + _dataType = arrayDataType; + return true; +} + +class HLAPropertyDataElement::DataElementFactoryVisitor : public HLADataTypeVisitor { +public: + DataElementFactoryVisitor(SGPropertyNode* propertyNode) : + _propertyNode(propertyNode) + { } + virtual ~DataElementFactoryVisitor() + { } + + virtual void apply(const HLADataType& dataType) + { + SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Can not find a suitable data element for data type \"" + << dataType.getName() << "\""); + } + + virtual void apply(const HLAInt8DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAUInt8DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAInt16DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAUInt16DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAInt32DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAUInt32DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAInt64DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAUInt64DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAFloat32DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + virtual void apply(const HLAFloat64DataType& dataType) + { + _dataElement = new ScalarDataElement(&dataType, _propertyNode.get()); + } + + class ArrayDataElementFactory : public HLAArrayDataElement::DataElementFactory { + public: + ArrayDataElementFactory(SGPropertyNode* propertyNode) : + _propertyNode(propertyNode) + { } + virtual HLADataElement* createElement(const HLAArrayDataElement& element, unsigned index) + { + const HLADataType* dataType = element.getElementDataType(); + if (!dataType) + return 0; + + SGPropertyNode* parent = _propertyNode->getParent(); + DataElementFactoryVisitor visitor(parent->getChild(_propertyNode->getNameString(), index, true)); + dataType->accept(visitor); + return visitor.getDataElement(); + } + private: + SGSharedPtr _propertyNode; + }; + + virtual void apply(const HLAFixedArrayDataType& dataType) + { + if (dataType.getIsString()) { + _dataElement = new StringDataElement(&dataType, _propertyNode.get()); + } else { + SGSharedPtr arrayDataElement; + arrayDataElement = new HLAArrayDataElement(&dataType); + arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_propertyNode.get())); + arrayDataElement->setNumElements(dataType.getNumElements()); + _dataElement = arrayDataElement; + } + } + + virtual void apply(const HLAVariableArrayDataType& dataType) + { + if (dataType.getIsString()) { + _dataElement = new StringDataElement(&dataType, _propertyNode.get()); + } else { + SGSharedPtr arrayDataElement; + arrayDataElement = new HLAArrayDataElement(&dataType); + arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_propertyNode.get())); + _dataElement = arrayDataElement; + } + } + + virtual void apply(const HLAEnumeratedDataType& dataType) + { + _dataElement = new ScalarDataElement(dataType.getRepresentation(), _propertyNode.get()); + } + + virtual void apply(const HLAFixedRecordDataType& dataType) + { + SGSharedPtr recordDataElement; + recordDataElement = new HLAFixedRecordDataElement(&dataType); + + unsigned numFields = dataType.getNumFields(); + for (unsigned i = 0; i < numFields; ++i) { + DataElementFactoryVisitor visitor(_propertyNode->getChild(dataType.getFieldName(i), 0, true)); + dataType.getFieldDataType(i)->accept(visitor); + recordDataElement->setField(i, visitor._dataElement.get()); + } + + _dataElement = recordDataElement; + } + + class VariantDataElementFactory : public HLAVariantDataElement::DataElementFactory { + public: + VariantDataElementFactory(SGPropertyNode* propertyNode) : + _propertyNode(propertyNode) + { } + virtual HLADataElement* createElement(const HLAVariantDataElement& element, unsigned index) + { + const HLAVariantDataType* dataType = element.getDataType(); + if (!dataType) + return 0; + const HLADataType* alternativeDataType = element.getAlternativeDataType(); + if (!alternativeDataType) + return 0; + DataElementFactoryVisitor visitor(_propertyNode->getChild(dataType->getAlternativeName(index), 0, true)); + alternativeDataType->accept(visitor); + return visitor.getDataElement(); + } + private: + SGSharedPtr _propertyNode; + }; + + virtual void apply(const HLAVariantDataType& dataType) + { + SGSharedPtr variantDataElement; + variantDataElement = new HLAVariantDataElement(&dataType); + variantDataElement->setDataElementFactory(new VariantDataElementFactory(_propertyNode.get())); + _dataElement = variantDataElement; + } + + HLADataElement* getDataElement() + { return _dataElement.release(); } + +private: + SGSharedPtr _propertyNode; + SGSharedPtr _dataElement; +}; + HLAPropertyDataElement::HLAPropertyDataElement() { } @@ -225,31 +537,37 @@ HLAPropertyDataElement::~HLAPropertyDataElement() bool HLAPropertyDataElement::encode(HLAEncodeStream& stream) const { - if (!_dataType.valid()) - return false; - if (const SGPropertyNode* propertyNode = getPropertyNode()) { - EncodeVisitor visitor(stream, *propertyNode); - _dataType->accept(visitor); + if (_dataElement.valid()) { + return _dataElement->encode(stream); } else { + if (!_dataType.valid()) + return false; HLADataTypeEncodeVisitor visitor(stream); _dataType->accept(visitor); + return true; } - return true; } bool HLAPropertyDataElement::decode(HLADecodeStream& stream) { - if (!_dataType.valid()) + if (_dataElement.valid()) { + return _dataElement->decode(stream); + } else if (!_dataType.valid()) { + // We cant do anything if the data type is not valid return false; - if (SGPropertyNode* propertyNode = getPropertyNode()) { - DecodeVisitor visitor(stream, *propertyNode); - _dataType->accept(visitor); } else { - HLADataTypeDecodeVisitor visitor(stream); + HLADataElementFactoryVisitor visitor; _dataType->accept(visitor); + _dataElement = visitor.getDataElement(); + if (_dataElement.valid()) { + return _dataElement->decode(stream); + } else { + HLADataTypeDecodeVisitor visitor(stream); + _dataType->accept(visitor); + return true; + } } - return true; } const HLADataType* @@ -261,24 +579,18 @@ HLAPropertyDataElement::getDataType() const bool HLAPropertyDataElement::setDataType(const HLADataType* dataType) { - if (dataType->toBasicDataType()) { - _dataType = dataType; - return true; - } else { - const HLAArrayDataType* arrayDataType = dataType->toArrayDataType(); - if (arrayDataType && arrayDataType->getElementDataType() && - arrayDataType->getElementDataType()->toBasicDataType()) { - _dataType = dataType; - return true; - } - } - return false; + _dataType = dataType; + if (_dataType.valid() && _propertyNode.valid()) + _dataElement = createDataElement(_dataType, _propertyNode); + return true; } void HLAPropertyDataElement::setPropertyNode(SGPropertyNode* propertyNode) { _propertyNode = propertyNode; + if (_dataType.valid() && _propertyNode.valid()) + _dataElement = createDataElement(_dataType, _propertyNode); } SGPropertyNode* @@ -293,4 +605,26 @@ HLAPropertyDataElement::getPropertyNode() const return _propertyNode.get(); } +HLADataElement* +HLAPropertyDataElement::createDataElement(const SGSharedPtr& dataType, + const SGSharedPtr& propertyNode) +{ + DataElementFactoryVisitor visitor(propertyNode); + dataType->accept(visitor); + SGSharedPtr dataElement = visitor.getDataElement(); + + // Copy over the content of the previous data element if there is any. + if (_dataElement.valid()) { + // FIXME is encode/decode the right tool here?? + RTIData data; + HLAEncodeStream encodeStream(data); + if (_dataElement->encode(encodeStream)) { + HLADecodeStream decodeStream(data); + dataElement->decode(decodeStream); + } + } + + return dataElement.release(); +} + } // namespace simgear diff --git a/simgear/hla/HLAPropertyDataElement.hxx b/simgear/hla/HLAPropertyDataElement.hxx index 076d85ba..4354a1d9 100644 --- a/simgear/hla/HLAPropertyDataElement.hxx +++ b/simgear/hla/HLAPropertyDataElement.hxx @@ -1,4 +1,4 @@ -// Copyright (C) 2009 - 2010 Mathias Froehlich - Mathias.Froehlich@web.de +// Copyright (C) 2009 - 2011 Mathias Froehlich - Mathias.Froehlich@web.de // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -42,10 +42,19 @@ public: const SGPropertyNode* getPropertyNode() const; private: - class DecodeVisitor; - class EncodeVisitor; + HLADataElement* + createDataElement(const SGSharedPtr& dataType, const SGSharedPtr& propertyNode); + + class ScalarDecodeVisitor; + class ScalarEncodeVisitor; + class ScalarDataElement; + class StringDecodeVisitor; + class StringEncodeVisitor; + class StringDataElement; + class DataElementFactoryVisitor; SGSharedPtr _dataType; + SGSharedPtr _dataElement; SGSharedPtr _propertyNode; };