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 "HLAPropertyDataElement.hxx"
25 
26 #include "HLAArrayDataElement.hxx"
27 #include "HLABasicDataElement.hxx"
28 #include "HLADataElementVisitor.hxx"
29 #include "HLADataTypeVisitor.hxx"
30 #include "HLAFixedRecordDataElement.hxx"
31 #include "HLAVariantRecordDataElement.hxx"
32 
33 namespace simgear {
34 
35 class HLAPropertyDataElement::ScalarDecodeVisitor : public HLADataTypeDecodeVisitor {
36 public:
ScalarDecodeVisitor(HLADecodeStream & stream,SGPropertyNode & propertyNode)37     ScalarDecodeVisitor(HLADecodeStream& stream, SGPropertyNode& propertyNode) :
38         HLADataTypeDecodeVisitor(stream),
39         _propertyNode(propertyNode)
40     { }
~ScalarDecodeVisitor()41     virtual ~ScalarDecodeVisitor()
42     { }
43 
apply(const HLAInt8DataType & dataType)44     virtual void apply(const HLAInt8DataType& dataType)
45     {
46         int8_t value = 0;
47         dataType.decode(_stream, value);
48         _propertyNode.setIntValue(value);
49     }
apply(const HLAUInt8DataType & dataType)50     virtual void apply(const HLAUInt8DataType& dataType)
51     {
52         uint8_t value = 0;
53         dataType.decode(_stream, value);
54         _propertyNode.setIntValue(value);
55     }
apply(const HLAInt16DataType & dataType)56     virtual void apply(const HLAInt16DataType& dataType)
57     {
58         int16_t value = 0;
59         dataType.decode(_stream, value);
60         _propertyNode.setIntValue(value);
61     }
apply(const HLAUInt16DataType & dataType)62     virtual void apply(const HLAUInt16DataType& dataType)
63     {
64         uint16_t value = 0;
65         dataType.decode(_stream, value);
66         _propertyNode.setIntValue(value);
67     }
apply(const HLAInt32DataType & dataType)68     virtual void apply(const HLAInt32DataType& dataType)
69     {
70         int32_t value = 0;
71         dataType.decode(_stream, value);
72         _propertyNode.setIntValue(value);
73     }
apply(const HLAUInt32DataType & dataType)74     virtual void apply(const HLAUInt32DataType& dataType)
75     {
76         uint32_t value = 0;
77         dataType.decode(_stream, value);
78         _propertyNode.setIntValue(value);
79     }
apply(const HLAInt64DataType & dataType)80     virtual void apply(const HLAInt64DataType& dataType)
81     {
82         int64_t value = 0;
83         dataType.decode(_stream, value);
84         _propertyNode.setLongValue(value);
85     }
apply(const HLAUInt64DataType & dataType)86     virtual void apply(const HLAUInt64DataType& dataType)
87     {
88         uint64_t value = 0;
89         dataType.decode(_stream, value);
90         _propertyNode.setLongValue(value);
91     }
apply(const HLAFloat32DataType & dataType)92     virtual void apply(const HLAFloat32DataType& dataType)
93     {
94         float value = 0;
95         dataType.decode(_stream, value);
96         _propertyNode.setFloatValue(value);
97     }
apply(const HLAFloat64DataType & dataType)98     virtual void apply(const HLAFloat64DataType& dataType)
99     {
100         double value = 0;
101         dataType.decode(_stream, value);
102         _propertyNode.setDoubleValue(value);
103     }
104 
105 protected:
106     SGPropertyNode& _propertyNode;
107 };
108 
109 class HLAPropertyDataElement::ScalarEncodeVisitor : public HLADataTypeEncodeVisitor {
110 public:
ScalarEncodeVisitor(HLAEncodeStream & stream,const SGPropertyNode & propertyNode)111     ScalarEncodeVisitor(HLAEncodeStream& stream, const SGPropertyNode& propertyNode) :
112         HLADataTypeEncodeVisitor(stream),
113         _propertyNode(propertyNode)
114     { }
~ScalarEncodeVisitor()115     virtual ~ScalarEncodeVisitor()
116     { }
117 
apply(const HLAInt8DataType & dataType)118     virtual void apply(const HLAInt8DataType& dataType)
119     {
120         dataType.encode(_stream, _propertyNode.getIntValue());
121     }
apply(const HLAUInt8DataType & dataType)122     virtual void apply(const HLAUInt8DataType& dataType)
123     {
124         dataType.encode(_stream, _propertyNode.getIntValue());
125     }
apply(const HLAInt16DataType & dataType)126     virtual void apply(const HLAInt16DataType& dataType)
127     {
128         dataType.encode(_stream, _propertyNode.getIntValue());
129     }
apply(const HLAUInt16DataType & dataType)130     virtual void apply(const HLAUInt16DataType& dataType)
131     {
132         dataType.encode(_stream, _propertyNode.getIntValue());
133     }
apply(const HLAInt32DataType & dataType)134     virtual void apply(const HLAInt32DataType& dataType)
135     {
136         dataType.encode(_stream, _propertyNode.getIntValue());
137     }
apply(const HLAUInt32DataType & dataType)138     virtual void apply(const HLAUInt32DataType& dataType)
139     {
140         dataType.encode(_stream, _propertyNode.getIntValue());
141     }
apply(const HLAInt64DataType & dataType)142     virtual void apply(const HLAInt64DataType& dataType)
143     {
144         dataType.encode(_stream, _propertyNode.getLongValue());
145     }
apply(const HLAUInt64DataType & dataType)146     virtual void apply(const HLAUInt64DataType& dataType)
147     {
148         dataType.encode(_stream, _propertyNode.getLongValue());
149     }
apply(const HLAFloat32DataType & dataType)150     virtual void apply(const HLAFloat32DataType& dataType)
151     {
152         dataType.encode(_stream, _propertyNode.getFloatValue());
153     }
apply(const HLAFloat64DataType & dataType)154     virtual void apply(const HLAFloat64DataType& dataType)
155     {
156         dataType.encode(_stream, _propertyNode.getDoubleValue());
157     }
158 
159 protected:
160     const SGPropertyNode& _propertyNode;
161 };
162 
163 class HLAPropertyDataElement::ScalarDataElement : public HLABasicDataElement {
164 public:
165     ScalarDataElement(const HLABasicDataType* dataType, SGPropertyNode* propertyNode);
166     virtual ~ScalarDataElement();
167 
168     virtual bool encode(HLAEncodeStream& stream) const;
169     virtual bool decode(HLADecodeStream& stream);
170 
171 private:
172     SGSharedPtr<SGPropertyNode> _propertyNode;
173 };
174 
ScalarDataElement(const HLABasicDataType * dataType,SGPropertyNode * propertyNode)175 HLAPropertyDataElement::ScalarDataElement::ScalarDataElement(const HLABasicDataType* dataType, SGPropertyNode* propertyNode) :
176     HLABasicDataElement(dataType),
177     _propertyNode(propertyNode)
178 {
179 }
180 
~ScalarDataElement()181 HLAPropertyDataElement::ScalarDataElement::~ScalarDataElement()
182 {
183 }
184 
185 bool
encode(HLAEncodeStream & stream) const186 HLAPropertyDataElement::ScalarDataElement::encode(HLAEncodeStream& stream) const
187 {
188     ScalarEncodeVisitor visitor(stream, *_propertyNode);
189     _dataType->accept(visitor);
190     return true;
191 }
192 
193 bool
decode(HLADecodeStream & stream)194 HLAPropertyDataElement::ScalarDataElement::decode(HLADecodeStream& stream)
195 {
196     ScalarDecodeVisitor visitor(stream, *_propertyNode);
197     _dataType->accept(visitor);
198     return true;
199 }
200 
201 class HLAPropertyDataElement::StringDataElement : public HLAStringDataElement {
202 public:
203     StringDataElement(const HLAArrayDataType* dataType, SGPropertyNode* propertyNode);
204     virtual ~StringDataElement();
205 
206     virtual bool decodeElement(HLADecodeStream& stream, unsigned i);
207 
208     class Listener : public SGPropertyChangeListener {
209     public:
210         Listener(StringDataElement* stringDataElement);
211         virtual ~Listener();
212         virtual void valueChanged (SGPropertyNode * node);
213     private:
214         StringDataElement* _stringDataElement;
215     };
216 
217 private:
218     SGSharedPtr<SGPropertyNode> _propertyNode;
219     Listener* _listener;
220 };
221 
Listener(StringDataElement * stringDataElement)222 HLAPropertyDataElement::StringDataElement::Listener::Listener(StringDataElement* stringDataElement) :
223             _stringDataElement(stringDataElement)
224 {
225 }
226 
~Listener()227 HLAPropertyDataElement::StringDataElement::Listener::~Listener()
228 {
229 }
230 
231 void
valueChanged(SGPropertyNode * node)232 HLAPropertyDataElement::StringDataElement::Listener::valueChanged (SGPropertyNode * node)
233 {
234     _stringDataElement->setValue(node->getStringValue());
235 }
236 
StringDataElement(const HLAArrayDataType * dataType,SGPropertyNode * propertyNode)237 HLAPropertyDataElement::StringDataElement::StringDataElement(const HLAArrayDataType* dataType, SGPropertyNode* propertyNode) :
238     HLAStringDataElement(dataType),
239     _propertyNode(propertyNode),
240     _listener(new Listener(this))
241 {
242     _propertyNode->addChangeListener(_listener, true);
243 }
244 
~StringDataElement()245 HLAPropertyDataElement::StringDataElement::~StringDataElement()
246 {
247     _propertyNode->removeChangeListener(_listener);
248     delete _listener;
249     _listener = 0;
250 }
251 
252 bool
decodeElement(HLADecodeStream & stream,unsigned i)253 HLAPropertyDataElement::StringDataElement::decodeElement(HLADecodeStream& stream, unsigned i)
254 {
255     if (!HLAStringDataElement::decodeElement(stream, i))
256         return false;
257     if (i + 1 == getValue().size())
258         _propertyNode->setStringValue(getValue());
259     return true;
260 }
261 
262 class HLAPropertyDataElement::DataElementFactoryVisitor : public HLADataTypeVisitor {
263 public:
DataElementFactoryVisitor(SGPropertyNode * propertyNode)264     DataElementFactoryVisitor(SGPropertyNode* propertyNode) :
265         _propertyNode(propertyNode)
266     { }
~DataElementFactoryVisitor()267     virtual ~DataElementFactoryVisitor()
268     { }
269 
apply(const HLADataType & dataType)270     virtual void apply(const HLADataType& dataType)
271     {
272         SG_LOG(SG_NETWORK, SG_ALERT, "HLA: Can not find a suitable data element for data type \""
273                << dataType.getName() << "\"");
274     }
275 
apply(const HLAInt8DataType & dataType)276     virtual void apply(const HLAInt8DataType& dataType)
277     {
278         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
279     }
apply(const HLAUInt8DataType & dataType)280     virtual void apply(const HLAUInt8DataType& dataType)
281     {
282         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
283     }
apply(const HLAInt16DataType & dataType)284     virtual void apply(const HLAInt16DataType& dataType)
285     {
286         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
287     }
apply(const HLAUInt16DataType & dataType)288     virtual void apply(const HLAUInt16DataType& dataType)
289     {
290         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
291     }
apply(const HLAInt32DataType & dataType)292     virtual void apply(const HLAInt32DataType& dataType)
293     {
294         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
295     }
apply(const HLAUInt32DataType & dataType)296     virtual void apply(const HLAUInt32DataType& dataType)
297     {
298         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
299     }
apply(const HLAInt64DataType & dataType)300     virtual void apply(const HLAInt64DataType& dataType)
301     {
302         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
303     }
apply(const HLAUInt64DataType & dataType)304     virtual void apply(const HLAUInt64DataType& dataType)
305     {
306         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
307     }
apply(const HLAFloat32DataType & dataType)308     virtual void apply(const HLAFloat32DataType& dataType)
309     {
310         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
311     }
apply(const HLAFloat64DataType & dataType)312     virtual void apply(const HLAFloat64DataType& dataType)
313     {
314         _dataElement = new ScalarDataElement(&dataType, _propertyNode.get());
315     }
316 
317     class ArrayDataElementFactory : public HLAArrayDataElement::DataElementFactory {
318     public:
ArrayDataElementFactory(SGPropertyNode * propertyNode)319         ArrayDataElementFactory(SGPropertyNode* propertyNode) :
320             _propertyNode(propertyNode)
321         { }
createElement(const HLAArrayDataElement & element,unsigned index)322         virtual HLADataElement* createElement(const HLAArrayDataElement& element, unsigned index)
323         {
324             const HLADataType* dataType = element.getElementDataType();
325             if (!dataType)
326                 return 0;
327 
328             SGPropertyNode* parent = _propertyNode->getParent();
329             DataElementFactoryVisitor visitor(parent->getChild(_propertyNode->getNameString(), index, true));
330             dataType->accept(visitor);
331             return visitor.getDataElement();
332         }
333     private:
334         SGSharedPtr<SGPropertyNode> _propertyNode;
335     };
336 
apply(const HLAFixedArrayDataType & dataType)337     virtual void apply(const HLAFixedArrayDataType& dataType)
338     {
339         if (dataType.getIsString()) {
340             _dataElement = new StringDataElement(&dataType, _propertyNode.get());
341         } else {
342             SGSharedPtr<HLAArrayDataElement> arrayDataElement;
343             arrayDataElement = new HLAArrayDataElement(&dataType);
344             arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_propertyNode.get()));
345             arrayDataElement->setNumElements(dataType.getNumElements());
346             _dataElement = arrayDataElement;
347         }
348     }
349 
apply(const HLAVariableArrayDataType & dataType)350     virtual void apply(const HLAVariableArrayDataType& dataType)
351     {
352         if (dataType.getIsString()) {
353             _dataElement = new StringDataElement(&dataType, _propertyNode.get());
354         } else {
355             SGSharedPtr<HLAArrayDataElement> arrayDataElement;
356             arrayDataElement = new HLAArrayDataElement(&dataType);
357             arrayDataElement->setDataElementFactory(new ArrayDataElementFactory(_propertyNode.get()));
358             _dataElement = arrayDataElement;
359         }
360     }
361 
apply(const HLAEnumeratedDataType & dataType)362     virtual void apply(const HLAEnumeratedDataType& dataType)
363     {
364         _dataElement = new ScalarDataElement(dataType.getRepresentation(), _propertyNode.get());
365     }
366 
apply(const HLAFixedRecordDataType & dataType)367     virtual void apply(const HLAFixedRecordDataType& dataType)
368     {
369         SGSharedPtr<HLAFixedRecordDataElement> recordDataElement;
370         recordDataElement = new HLAFixedRecordDataElement(&dataType);
371 
372         unsigned numFields = dataType.getNumFields();
373         for (unsigned i = 0; i < numFields; ++i) {
374             DataElementFactoryVisitor visitor(_propertyNode->getChild(dataType.getFieldName(i), 0, true));
375             dataType.getFieldDataType(i)->accept(visitor);
376             recordDataElement->setField(i, visitor._dataElement.get());
377         }
378 
379         _dataElement = recordDataElement;
380     }
381 
382     class VariantRecordDataElementFactory : public HLAVariantRecordDataElement::DataElementFactory {
383     public:
VariantRecordDataElementFactory(SGPropertyNode * propertyNode)384         VariantRecordDataElementFactory(SGPropertyNode* propertyNode) :
385             _propertyNode(propertyNode)
386         { }
createElement(const HLAVariantRecordDataElement & element,unsigned index)387         virtual HLADataElement* createElement(const HLAVariantRecordDataElement& element, unsigned index)
388         {
389             const HLAVariantRecordDataType* dataType = element.getDataType();
390             if (!dataType)
391                 return 0;
392             const HLADataType* alternativeDataType = element.getAlternativeDataType();
393             if (!alternativeDataType)
394                 return 0;
395             DataElementFactoryVisitor visitor(_propertyNode->getChild(dataType->getAlternativeName(index), 0, true));
396             alternativeDataType->accept(visitor);
397             return visitor.getDataElement();
398         }
399     private:
400         SGSharedPtr<SGPropertyNode> _propertyNode;
401     };
402 
apply(const HLAVariantRecordDataType & dataType)403     virtual void apply(const HLAVariantRecordDataType& dataType)
404     {
405         SGSharedPtr<HLAVariantRecordDataElement> variantRecordDataElement;
406         variantRecordDataElement = new HLAVariantRecordDataElement(&dataType);
407         variantRecordDataElement->setDataElementFactory(new VariantRecordDataElementFactory(_propertyNode.get()));
408         _dataElement = variantRecordDataElement;
409     }
410 
getDataElement()411     HLADataElement* getDataElement()
412     { return _dataElement.release(); }
413 
414 private:
415     SGSharedPtr<SGPropertyNode> _propertyNode;
416     SGSharedPtr<HLADataElement> _dataElement;
417 };
418 
HLAPropertyDataElement()419 HLAPropertyDataElement::HLAPropertyDataElement()
420 {
421 }
422 
HLAPropertyDataElement(SGPropertyNode * propertyNode)423 HLAPropertyDataElement::HLAPropertyDataElement(SGPropertyNode* propertyNode)
424 {
425     setPropertyNode(propertyNode);
426 }
427 
HLAPropertyDataElement(const HLADataType * dataType,SGPropertyNode * propertyNode)428 HLAPropertyDataElement::HLAPropertyDataElement(const HLADataType* dataType, SGPropertyNode* propertyNode) :
429     _dataType(dataType)
430 {
431     setPropertyNode(propertyNode);
432 }
433 
HLAPropertyDataElement(const HLADataType * dataType)434 HLAPropertyDataElement::HLAPropertyDataElement(const HLADataType* dataType) :
435     _dataType(dataType)
436 {
437 }
438 
~HLAPropertyDataElement()439 HLAPropertyDataElement::~HLAPropertyDataElement()
440 {
441 }
442 
443 void
accept(HLADataElementVisitor & visitor)444 HLAPropertyDataElement::accept(HLADataElementVisitor& visitor)
445 {
446     if (_dataElement.valid()) {
447         visitor.apply(*_dataElement);
448     } else {
449         // We cant do anything if the data type is not valid
450         if (_dataType.valid()) {
451             HLADataElementFactoryVisitor factoryVisitor;
452             _dataType->accept(factoryVisitor);
453             _dataElement = factoryVisitor.getDataElement();
454             if (_dataElement.valid()) {
455                 visitor.apply(*_dataElement);
456             } else {
457                 HLADataElement::accept(visitor);
458             }
459         } else {
460             HLADataElement::accept(visitor);
461         }
462     }
463 }
464 
465 void
accept(HLAConstDataElementVisitor & visitor) const466 HLAPropertyDataElement::accept(HLAConstDataElementVisitor& visitor) const
467 {
468     if (_dataElement.valid()) {
469         visitor.apply(*_dataElement);
470     } else {
471         HLADataElement::accept(visitor);
472     }
473 }
474 
475 bool
encode(HLAEncodeStream & stream) const476 HLAPropertyDataElement::encode(HLAEncodeStream& stream) const
477 {
478     if (_dataElement.valid()) {
479         return _dataElement->encode(stream);
480     } else {
481         if (!_dataType.valid())
482             return false;
483         HLADataTypeEncodeVisitor visitor(stream);
484         _dataType->accept(visitor);
485         return true;
486     }
487 }
488 
489 bool
decode(HLADecodeStream & stream)490 HLAPropertyDataElement::decode(HLADecodeStream& stream)
491 {
492     if (_dataElement.valid()) {
493         return _dataElement->decode(stream);
494     } else if (!_dataType.valid()) {
495         // We cant do anything if the data type is not valid
496         return false;
497     } else {
498         HLADataElementFactoryVisitor visitor;
499         _dataType->accept(visitor);
500         _dataElement = visitor.getDataElement();
501         if (_dataElement.valid()) {
502             return _dataElement->decode(stream);
503         } else {
504             HLADataTypeDecodeVisitor visitor(stream);
505             _dataType->accept(visitor);
506             return true;
507         }
508     }
509 }
510 
511 const HLADataType*
getDataType() const512 HLAPropertyDataElement::getDataType() const
513 {
514     return _dataType.get();
515 }
516 
517 bool
setDataType(const HLADataType * dataType)518 HLAPropertyDataElement::setDataType(const HLADataType* dataType)
519 {
520     _dataType = dataType;
521     if (_dataType.valid() && _propertyNode.valid())
522         _dataElement = createDataElement(_dataType, _propertyNode);
523     return true;
524 }
525 
526 void
setPropertyNode(SGPropertyNode * propertyNode)527 HLAPropertyDataElement::setPropertyNode(SGPropertyNode* propertyNode)
528 {
529     _propertyNode = propertyNode;
530     if (_dataType.valid() && _propertyNode.valid())
531         _dataElement = createDataElement(_dataType, _propertyNode);
532 }
533 
534 SGPropertyNode*
getPropertyNode()535 HLAPropertyDataElement::getPropertyNode()
536 {
537     return _propertyNode.get();
538 }
539 
540 const SGPropertyNode*
getPropertyNode() const541 HLAPropertyDataElement::getPropertyNode() const
542 {
543     return _propertyNode.get();
544 }
545 
546 HLADataElement*
createDataElement(const SGSharedPtr<const HLADataType> & dataType,const SGSharedPtr<SGPropertyNode> & propertyNode)547 HLAPropertyDataElement::createDataElement(const SGSharedPtr<const HLADataType>& dataType,
548                                           const SGSharedPtr<SGPropertyNode>& propertyNode)
549 {
550     DataElementFactoryVisitor visitor(propertyNode);
551     dataType->accept(visitor);
552     SGSharedPtr<HLADataElement> dataElement = visitor.getDataElement();
553 
554     // Copy over the content of the previous data element if there is any.
555     if (_dataElement.valid()) {
556         // FIXME is encode/decode the right tool here??
557         RTIData data;
558         HLAEncodeStream encodeStream(data);
559         if (_dataElement->encode(encodeStream)) {
560             HLADecodeStream decodeStream(data);
561             dataElement->decode(decodeStream);
562         }
563     }
564 
565     return dataElement.release();
566 }
567 
568 } // namespace simgear
569