]> git.mxchange.org Git - simgear.git/blobdiff - simgear/hla/HLAPropertyDataElement.cxx
Fix a typo breaking HTTP unit-test.
[simgear.git] / simgear / hla / HLAPropertyDataElement.cxx
index db4f00ba84a571a3f6330dd6650435caa80b9f8b..0b9e354ea0ab496a24b786833ddb14e6331a82fe 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2009 - 2010  Mathias Froehlich - Mathias.Froehlich@web.de
+// Copyright (C) 2009 - 2012  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
 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //
 
+#ifdef HAVE_CONFIG_H
+#  include <simgear_config.h>
+#endif
+
+#include <simgear/compiler.h>
+
 #include "HLAPropertyDataElement.hxx"
 
+#include "HLAArrayDataElement.hxx"
+#include "HLABasicDataElement.hxx"
+#include "HLADataElementVisitor.hxx"
 #include "HLADataTypeVisitor.hxx"
+#include "HLAFixedRecordDataElement.hxx"
+#include "HLAVariantRecordDataElement.hxx"
 
 namespace simgear {
 
-class HLAPropertyDataElement::DecodeVisitor : public HLADataTypeDecodeVisitor {
+class HLAPropertyDataElement::ScalarDecodeVisitor : public HLADataTypeDecodeVisitor {
 public:
-    DecodeVisitor(HLADecodeStream& stream, HLAPropertyReference& propertyReference) :
+    ScalarDecodeVisitor(HLADecodeStream& stream, SGPropertyNode& propertyNode) :
         HLADataTypeDecodeVisitor(stream),
-        _propertyReference(propertyReference)
+        _propertyNode(propertyNode)
+    { }
+    virtual ~ScalarDecodeVisitor()
     { }
 
     virtual void apply(const HLAInt8DataType& dataType)
     {
         int8_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setIntValue(value);
+        _propertyNode.setIntValue(value);
     }
     virtual void apply(const HLAUInt8DataType& dataType)
     {
         uint8_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setIntValue(value);
+        _propertyNode.setIntValue(value);
     }
     virtual void apply(const HLAInt16DataType& dataType)
     {
         int16_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setIntValue(value);
+        _propertyNode.setIntValue(value);
     }
     virtual void apply(const HLAUInt16DataType& dataType)
     {
         uint16_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setIntValue(value);
+        _propertyNode.setIntValue(value);
     }
     virtual void apply(const HLAInt32DataType& dataType)
     {
         int32_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setIntValue(value);
+        _propertyNode.setIntValue(value);
     }
     virtual void apply(const HLAUInt32DataType& dataType)
     {
         uint32_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setIntValue(value);
+        _propertyNode.setIntValue(value);
     }
     virtual void apply(const HLAInt64DataType& dataType)
     {
         int64_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setLongValue(value);
+        _propertyNode.setLongValue(value);
     }
     virtual void apply(const HLAUInt64DataType& dataType)
     {
         uint64_t value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setLongValue(value);
+        _propertyNode.setLongValue(value);
     }
     virtual void apply(const HLAFloat32DataType& dataType)
     {
         float value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setFloatValue(value);
+        _propertyNode.setFloatValue(value);
     }
     virtual void apply(const HLAFloat64DataType& dataType)
     {
         double value = 0;
         dataType.decode(_stream, value);
-        _propertyReference.setDoubleValue(value);
+        _propertyNode.setDoubleValue(value);
     }
 
-    virtual void apply(const HLAFixedArrayDataType& dataType)
+protected:
+    SGPropertyNode& _propertyNode;
+};
+
+class HLAPropertyDataElement::ScalarEncodeVisitor : public HLADataTypeEncodeVisitor {
+public:
+    ScalarEncodeVisitor(HLAEncodeStream& stream, const SGPropertyNode& propertyNode) :
+        HLADataTypeEncodeVisitor(stream),
+        _propertyNode(propertyNode)
+    { }
+    virtual ~ScalarEncodeVisitor()
+    { }
+
+    virtual void apply(const HLAInt8DataType& dataType)
     {
-        unsigned numElements = dataType.getNumElements();
-        std::string value;
-        value.reserve(numElements);
-        for (unsigned i = 0; i < numElements; ++i) {
-            HLATemplateDecodeVisitor<char> visitor(_stream);
-            dataType.getElementDataType()->accept(visitor);
-            value.push_back(visitor.getValue());
-        }
-        _propertyReference.setStringValue(value);
+        dataType.encode(_stream, _propertyNode.getIntValue());
     }
-    virtual void apply(const HLAVariableArrayDataType& dataType)
+    virtual void apply(const HLAUInt8DataType& dataType)
     {
-        HLATemplateDecodeVisitor<unsigned> numElementsVisitor(_stream);
-        dataType.getSizeDataType()->accept(numElementsVisitor);
-        unsigned numElements = numElementsVisitor.getValue();
-        std::string value;
-        value.reserve(numElements);
-        for (unsigned i = 0; i < numElements; ++i) {
-            HLATemplateDecodeVisitor<char> visitor(_stream);
-            dataType.getElementDataType()->accept(visitor);
-            value.push_back(visitor.getValue());
-        }
-        _propertyReference.setStringValue(value);
+        dataType.encode(_stream, _propertyNode.getIntValue());
+    }
+    virtual void apply(const HLAInt16DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getIntValue());
+    }
+    virtual void apply(const HLAUInt16DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getIntValue());
+    }
+    virtual void apply(const HLAInt32DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getIntValue());
+    }
+    virtual void apply(const HLAUInt32DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getIntValue());
+    }
+    virtual void apply(const HLAInt64DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getLongValue());
+    }
+    virtual void apply(const HLAUInt64DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getLongValue());
+    }
+    virtual void apply(const HLAFloat32DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getFloatValue());
+    }
+    virtual void apply(const HLAFloat64DataType& dataType)
+    {
+        dataType.encode(_stream, _propertyNode.getDoubleValue());
     }
 
 protected:
-    HLAPropertyReference& _propertyReference;
+    const SGPropertyNode& _propertyNode;
 };
 
-class HLAPropertyDataElement::EncodeVisitor : public HLADataTypeEncodeVisitor {
+class HLAPropertyDataElement::ScalarDataElement : public HLABasicDataElement {
 public:
-    EncodeVisitor(HLAEncodeStream& stream, const HLAPropertyReference& propertyReference) :
-        HLADataTypeEncodeVisitor(stream),
-        _propertyReference(propertyReference)
+    ScalarDataElement(const HLABasicDataType* dataType, SGPropertyNode* propertyNode);
+    virtual ~ScalarDataElement();
+
+    virtual bool encode(HLAEncodeStream& stream) const;
+    virtual bool decode(HLADecodeStream& stream);
+
+private:
+    SGSharedPtr<SGPropertyNode> _propertyNode;
+};
+
+HLAPropertyDataElement::ScalarDataElement::ScalarDataElement(const HLABasicDataType* dataType, SGPropertyNode* propertyNode) :
+    HLABasicDataElement(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;
+}
+
+class HLAPropertyDataElement::StringDataElement : public HLAStringDataElement {
+public:
+    StringDataElement(const HLAArrayDataType* dataType, SGPropertyNode* propertyNode);
+    virtual ~StringDataElement();
+
+    virtual bool decodeElement(HLADecodeStream& stream, unsigned i);
+
+    class Listener : public SGPropertyChangeListener {
+    public:
+        Listener(StringDataElement* stringDataElement);
+        virtual ~Listener();
+        virtual void valueChanged (SGPropertyNode * node);
+    private:
+        StringDataElement* _stringDataElement;
+    };
+
+private:
+    SGSharedPtr<SGPropertyNode> _propertyNode;
+    Listener* _listener;
+};
+
+HLAPropertyDataElement::StringDataElement::Listener::Listener(StringDataElement* stringDataElement) :
+            _stringDataElement(stringDataElement)
+{
+}
+
+HLAPropertyDataElement::StringDataElement::Listener::~Listener()
+{
+}
+
+void
+HLAPropertyDataElement::StringDataElement::Listener::valueChanged (SGPropertyNode * node)
+{
+    _stringDataElement->setValue(node->getStringValue());
+}
+
+HLAPropertyDataElement::StringDataElement::StringDataElement(const HLAArrayDataType* dataType, SGPropertyNode* propertyNode) :
+    HLAStringDataElement(dataType),
+    _propertyNode(propertyNode),
+    _listener(new Listener(this))
+{
+    _propertyNode->addChangeListener(_listener, true);
+}
+
+HLAPropertyDataElement::StringDataElement::~StringDataElement()
+{
+    _propertyNode->removeChangeListener(_listener);
+    delete _listener;
+    _listener = 0;
+}
+
+bool
+HLAPropertyDataElement::StringDataElement::decodeElement(HLADecodeStream& stream, unsigned i)
+{
+    if (!HLAStringDataElement::decodeElement(stream, i))
+        return false;
+    if (i + 1 == getValue().size())
+        _propertyNode->setStringValue(getValue());
+    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)
     {
-        dataType.encode(_stream, _propertyReference.getIntValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAUInt8DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getIntValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAInt16DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getIntValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAUInt16DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getIntValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAInt32DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getIntValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAUInt32DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getIntValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAInt64DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getLongValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAUInt64DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getLongValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAFloat32DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getFloatValue());
+        _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
     }
     virtual void apply(const HLAFloat64DataType& dataType)
     {
-        dataType.encode(_stream, _propertyReference.getDoubleValue());
+        _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<SGPropertyNode> _propertyNode;
+    };
+
     virtual void apply(const HLAFixedArrayDataType& dataType)
     {
-        unsigned numElements = dataType.getNumElements();
-        std::string value = _propertyReference.getStringValue();
-        for (unsigned i = 0; i < numElements; ++i) {
-            if (i < value.size()) {
-                HLATemplateEncodeVisitor<char> visitor(_stream, value[i]);
-                dataType.getElementDataType()->accept(visitor);
-            } else {
-                HLADataTypeEncodeVisitor visitor(_stream);
-                dataType.getElementDataType()->accept(visitor);
-            }
+        if (dataType.getIsString()) {
+            _dataElement = new StringDataElement(&dataType, _propertyNode.get());
+        } else {
+            SGSharedPtr<HLAArrayDataElement> arrayDataElement;
+            arrayDataElement = new HLAArrayDataElement(&dataType);
+            arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_propertyNode.get()));
+            arrayDataElement->setNumElements(dataType.getNumElements());
+            _dataElement = arrayDataElement;
         }
     }
 
     virtual void apply(const HLAVariableArrayDataType& dataType)
     {
-        std::string value = _propertyReference.getStringValue();
-        HLATemplateEncodeVisitor<std::string::size_type> numElementsVisitor(_stream, value.size());
-        dataType.getSizeDataType()->accept(numElementsVisitor);
-        for (unsigned i = 0; i < value.size(); ++i) {
-            HLATemplateEncodeVisitor<char> visitor(_stream, value[i]);
-            dataType.getElementDataType()->accept(visitor);
+        if (dataType.getIsString()) {
+            _dataElement = new StringDataElement(&dataType, _propertyNode.get());
+        } else {
+            SGSharedPtr<HLAArrayDataElement> arrayDataElement;
+            arrayDataElement = new HLAArrayDataElement(&dataType);
+            arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_propertyNode.get()));
+            _dataElement = arrayDataElement;
         }
     }
 
-protected:
-    const HLAPropertyReference& _propertyReference;
+    virtual void apply(const HLAEnumeratedDataType& dataType)
+    {
+        _dataElement = new ScalarDataElement(dataType.getRepresentation(), _propertyNode.get());
+    }
+
+    virtual void apply(const HLAFixedRecordDataType& dataType)
+    {
+        SGSharedPtr<HLAFixedRecordDataElement> 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 VariantRecordDataElementFactory : public HLAVariantRecordDataElement::DataElementFactory {
+    public:
+        VariantRecordDataElementFactory(SGPropertyNode* propertyNode) :
+            _propertyNode(propertyNode)
+        { }
+        virtual HLADataElement* createElement(const HLAVariantRecordDataElement& element, unsigned index)
+        {
+            const HLAVariantRecordDataType* 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<SGPropertyNode> _propertyNode;
+    };
+
+    virtual void apply(const HLAVariantRecordDataType& dataType)
+    {
+        SGSharedPtr<HLAVariantRecordDataElement> variantRecordDataElement;
+        variantRecordDataElement = new HLAVariantRecordDataElement(&dataType);
+        variantRecordDataElement->setDataElementFactory(new VariantRecordDataElementFactory(_propertyNode.get()));
+        _dataElement = variantRecordDataElement;
+    }
+
+    HLADataElement* getDataElement()
+    { return _dataElement.release(); }
+
+private:
+    SGSharedPtr<SGPropertyNode> _propertyNode;
+    SGSharedPtr<HLADataElement> _dataElement;
 };
 
-HLAPropertyDataElement::HLAPropertyDataElement(HLAPropertyReference* propertyReference) :
-    _propertyReference(propertyReference)
+HLAPropertyDataElement::HLAPropertyDataElement()
+{
+}
+
+HLAPropertyDataElement::HLAPropertyDataElement(SGPropertyNode* propertyNode)
+{
+    setPropertyNode(propertyNode);
+}
+
+HLAPropertyDataElement::HLAPropertyDataElement(const HLADataType* dataType, SGPropertyNode* propertyNode) :
+    _dataType(dataType)
 {
+    setPropertyNode(propertyNode);
 }
 
-HLAPropertyDataElement::HLAPropertyDataElement(const simgear::HLADataType* dataType, HLAPropertyReference* propertyReference) :
-    _dataType(dataType),
-    _propertyReference(propertyReference)
+HLAPropertyDataElement::HLAPropertyDataElement(const HLADataType* dataType) :
+    _dataType(dataType)
 {
 }
 
@@ -213,34 +440,72 @@ HLAPropertyDataElement::~HLAPropertyDataElement()
 {
 }
 
+void
+HLAPropertyDataElement::accept(HLADataElementVisitor& visitor)
+{
+    if (_dataElement.valid()) {
+        visitor.apply(*_dataElement);
+    } else {
+        // We cant do anything if the data type is not valid
+        if (_dataType.valid()) {
+            HLADataElementFactoryVisitor factoryVisitor;
+            _dataType->accept(factoryVisitor);
+            _dataElement = factoryVisitor.getDataElement();
+            if (_dataElement.valid()) {
+                visitor.apply(*_dataElement);
+            } else {
+                HLADataElement::accept(visitor);
+            }
+        } else {
+            HLADataElement::accept(visitor);
+        }
+    }
+}
+
+void
+HLAPropertyDataElement::accept(HLAConstDataElementVisitor& visitor) const
+{
+    if (_dataElement.valid()) {
+        visitor.apply(*_dataElement);
+    } else {
+        HLADataElement::accept(visitor);
+    }
+}
+
 bool
 HLAPropertyDataElement::encode(HLAEncodeStream& stream) const
 {
-    if (!_dataType.valid())
-        return false;
-    if (_propertyReference.valid()) {
-        EncodeVisitor visitor(stream, *_propertyReference);
-        _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 (_propertyReference.valid()) {
-        DecodeVisitor visitor(stream, *_propertyReference);
-        _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*
@@ -252,18 +517,52 @@ 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;
+    _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*
+HLAPropertyDataElement::getPropertyNode()
+{
+    return _propertyNode.get();
+}
+
+const SGPropertyNode*
+HLAPropertyDataElement::getPropertyNode() const
+{
+    return _propertyNode.get();
+}
+
+HLADataElement*
+HLAPropertyDataElement::createDataElement(const SGSharedPtr<const HLADataType>& dataType,
+                                          const SGSharedPtr<SGPropertyNode>& propertyNode)
+{
+    DataElementFactoryVisitor visitor(propertyNode);
+    dataType->accept(visitor);
+    SGSharedPtr<HLADataElement> 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 false;
+
+    return dataElement.release();
 }
 
 } // namespace simgear