]> git.mxchange.org Git - simgear.git/blob - simgear/hla/RTIData.hxx
Windows versionhelpers.h support.
[simgear.git] / simgear / hla / RTIData.hxx
1 // Copyright (C) 2009 - 2010  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 #ifndef RTIData_hxx
19 #define RTIData_hxx
20
21 #include <cstring>
22 #include <list>
23 #include <simgear/misc/stdint.hxx>
24
25 namespace simgear {
26
27 /// Sigh, this is std::vector<char>, except that
28 /// you could feed that with external pointers without copying ...
29 /// Note on alignment: the c++ standard garantees (5.3.4.10) that
30 /// new (unsigned) char returns sufficiently aligned memory
31 /// for all relevant cases
32 class RTIData {
33 public:
34     RTIData() :
35         _data(0),
36         _size(0),
37         _capacity(0)
38     { }
39     RTIData(unsigned size) :
40         _data(0),
41         _size(0),
42         _capacity(0)
43     { resize(size); }
44     RTIData(char* data, unsigned size) :
45         _data(data),
46         _size(size),
47         _capacity(0)
48     { }
49     RTIData(const char* data, unsigned size) :
50         _data(0),
51         _size(0),
52         _capacity(0)
53     { setData(data, size); }
54     RTIData(const char* data) :
55         _data(0),
56         _size(0),
57         _capacity(0)
58     { setData(data); }
59     RTIData(const RTIData& data) :
60         _data(0),
61         _size(0),
62         _capacity(0)
63     {
64         unsigned size = data.size();
65         if (size) {
66             resize(size);
67             memcpy(_data, data.data(), size);
68         }
69     }
70     ~RTIData()
71     {
72         if (_capacity)
73             delete [] _data;
74         _data = 0;
75     }
76
77     const char* data() const
78     { return _data; }
79     char* data()
80     { return _data; }
81
82     unsigned size() const
83     { return _size; }
84
85     bool empty() const
86     { return _size == 0; }
87
88     void clear()
89     {
90         if (_capacity == 0) {
91             _data = 0;
92             _size = 0;
93         } else
94             resize(0);
95     }
96
97     void resize(unsigned size)
98     {
99         if (size == _size)
100             return;
101         if (_capacity < size) {
102             unsigned capacity = 2*_capacity;
103             if (size < capacity)
104                 ensureCapacity(capacity);
105             else
106                 ensureCapacity(size);
107         }
108         _size = size;
109     }
110
111     void reserve(unsigned capacity)
112     {
113         if (capacity <= _capacity)
114             return;
115         ensureCapacity(capacity);
116     }
117
118     void swap(RTIData& data)
119     {
120         std::swap(_data, data._data);
121         std::swap(_size, data._size);
122         std::swap(_capacity, data._capacity);
123     }
124
125     void setData(char* data, unsigned size)
126     {
127         if (_capacity)
128             delete [] _data;
129         _data = data;
130         _size = size;
131         _capacity = 0;
132     }
133     void setData(const char* data, unsigned size)
134     {
135         resize(size);
136         if (!size)
137             return;
138         memcpy(_data, data, size);
139     }
140     void setData(const char* data)
141     {
142         if (!data) {
143             setData("", 1);
144         } else {
145             size_t size = strlen(data) + 1;
146             setData(data, size);
147         }
148     }
149
150     RTIData& operator=(const RTIData& data)
151     {
152         unsigned size = data.size();
153         if (size) {
154             resize(size);
155             memcpy(_data, data.data(), size);
156         }
157         return *this;
158     }
159
160     void getData8(char data[1], unsigned offset = 0) const
161     {
162         data[0] = _data[offset];
163     }
164
165     void setData8(const char data[1], unsigned offset = 0)
166     {
167         _data[offset] = data[0];
168     }
169
170     void getData16LE(char data[2], unsigned offset = 0) const
171     {
172         if (hostIsLittleEndian()) {
173             data[0] = _data[offset];
174             data[1] = _data[offset+1];
175         } else {
176             data[1] = _data[offset];
177             data[0] = _data[offset+1];
178         }
179     }
180     void setData16LE(const char data[2], unsigned offset = 0)
181     {
182         if (hostIsLittleEndian()) {
183             _data[offset] = data[0];
184             _data[offset+1] = data[1];
185         } else {
186             _data[offset] = data[1];
187             _data[offset+1] = data[0];
188         }
189     }
190
191     void getData16BE(char data[2], unsigned offset = 0) const
192     {
193         if (hostIsLittleEndian()) {
194             data[1] = _data[offset];
195             data[0] = _data[offset+1];
196         } else {
197             data[0] = _data[offset];
198             data[1] = _data[offset+1];
199         }
200     }
201     void setData16BE(const char data[2], unsigned offset = 0)
202     {
203         if (hostIsLittleEndian()) {
204             _data[offset] = data[1];
205             _data[offset+1] = data[0];
206         } else {
207             _data[offset] = data[0];
208             _data[offset+1] = data[1];
209         }
210     }
211
212
213     void getData32LE(char data[4], unsigned offset = 0) const
214     {
215         if (hostIsLittleEndian()) {
216             data[0] = _data[offset];
217             data[1] = _data[offset+1];
218             data[2] = _data[offset+2];
219             data[3] = _data[offset+3];
220         } else {
221             data[3] = _data[offset];
222             data[2] = _data[offset+1];
223             data[1] = _data[offset+2];
224             data[0] = _data[offset+3];
225         }
226     }
227     void setData32LE(const char data[4], unsigned offset = 0)
228     {
229         if (hostIsLittleEndian()) {
230             _data[offset] = data[0];
231             _data[offset+1] = data[1];
232             _data[offset+2] = data[2];
233             _data[offset+3] = data[3];
234         } else {
235             _data[offset] = data[3];
236             _data[offset+1] = data[2];
237             _data[offset+2] = data[1];
238             _data[offset+3] = data[0];
239         }
240     }
241
242     void getData32BE(char data[4], unsigned offset = 0) const
243     {
244         if (hostIsLittleEndian()) {
245             data[3] = _data[offset];
246             data[2] = _data[offset+1];
247             data[1] = _data[offset+2];
248             data[0] = _data[offset+3];
249         } else {
250             data[0] = _data[offset];
251             data[1] = _data[offset+1];
252             data[2] = _data[offset+2];
253             data[3] = _data[offset+3];
254         }
255     }
256     void setData32BE(const char data[4], unsigned offset = 0)
257     {
258         if (hostIsLittleEndian()) {
259             _data[offset] = data[3];
260             _data[offset+1] = data[2];
261             _data[offset+2] = data[1];
262             _data[offset+3] = data[0];
263         } else {
264             _data[offset] = data[0];
265             _data[offset+1] = data[1];
266             _data[offset+2] = data[2];
267             _data[offset+3] = data[3];
268         }
269     }
270
271
272     void getData64LE(char data[8], unsigned offset = 0) const
273     {
274         if (hostIsLittleEndian()) {
275             data[0] = _data[offset];
276             data[1] = _data[offset+1];
277             data[2] = _data[offset+2];
278             data[3] = _data[offset+3];
279             data[4] = _data[offset+4];
280             data[5] = _data[offset+5];
281             data[6] = _data[offset+6];
282             data[7] = _data[offset+7];
283         } else {
284             data[7] = _data[offset];
285             data[6] = _data[offset+1];
286             data[5] = _data[offset+2];
287             data[4] = _data[offset+3];
288             data[3] = _data[offset+4];
289             data[2] = _data[offset+5];
290             data[1] = _data[offset+6];
291             data[0] = _data[offset+7];
292         }
293     }
294     void setData64LE(const char data[8], unsigned offset = 0)
295     {
296         if (hostIsLittleEndian()) {
297             _data[offset] = data[0];
298             _data[offset+1] = data[1];
299             _data[offset+2] = data[2];
300             _data[offset+3] = data[3];
301             _data[offset+4] = data[4];
302             _data[offset+5] = data[5];
303             _data[offset+6] = data[6];
304             _data[offset+7] = data[7];
305         } else {
306             _data[offset] = data[7];
307             _data[offset+1] = data[6];
308             _data[offset+2] = data[5];
309             _data[offset+3] = data[4];
310             _data[offset+4] = data[3];
311             _data[offset+5] = data[2];
312             _data[offset+6] = data[1];
313             _data[offset+7] = data[0];
314         }
315     }
316
317     void getData64BE(char data[8], unsigned offset = 0) const
318     {
319         if (hostIsLittleEndian()) {
320             data[7] = _data[offset];
321             data[6] = _data[offset+1];
322             data[5] = _data[offset+2];
323             data[4] = _data[offset+3];
324             data[3] = _data[offset+4];
325             data[2] = _data[offset+5];
326             data[1] = _data[offset+6];
327             data[0] = _data[offset+7];
328         } else {
329             data[0] = _data[offset];
330             data[1] = _data[offset+1];
331             data[2] = _data[offset+2];
332             data[3] = _data[offset+3];
333             data[4] = _data[offset+4];
334             data[5] = _data[offset+5];
335             data[6] = _data[offset+6];
336             data[7] = _data[offset+7];
337         }
338     }
339     void setData64BE(const char data[8], unsigned offset = 0)
340     {
341         if (hostIsLittleEndian()) {
342             _data[offset] = data[7];
343             _data[offset+1] = data[6];
344             _data[offset+2] = data[5];
345             _data[offset+3] = data[4];
346             _data[offset+4] = data[3];
347             _data[offset+5] = data[2];
348             _data[offset+6] = data[1];
349             _data[offset+7] = data[0];
350         } else {
351             _data[offset] = data[0];
352             _data[offset+1] = data[1];
353             _data[offset+2] = data[2];
354             _data[offset+3] = data[3];
355             _data[offset+4] = data[4];
356             _data[offset+5] = data[5];
357             _data[offset+6] = data[6];
358             _data[offset+7] = data[7];
359         }
360     }
361
362
363 #define TYPED_GETSET_IMPLEMENTATION(type, base, suffix)         \
364     type get##base##suffix(unsigned offset = 0) const           \
365     {                                                           \
366         union {                                                 \
367             type t;                                             \
368             char u8[sizeof(type)];                              \
369         } u;                                                    \
370         getData##suffix(u.u8, offset);                          \
371         return u.t;                                             \
372     }                                                           \
373     void set##base##suffix(type value, unsigned offset = 0)     \
374     {                                                           \
375         union {                                                 \
376             type t;                                             \
377             char u8[sizeof(type)];                              \
378         } u;                                                    \
379         u.t = value;                                            \
380         setData##suffix(u.u8, offset);                          \
381     }
382
383     TYPED_GETSET_IMPLEMENTATION(uint8_t, UInt, 8)
384     TYPED_GETSET_IMPLEMENTATION(int8_t, Int, 8)
385     TYPED_GETSET_IMPLEMENTATION(uint16_t, UInt, 16LE)
386     TYPED_GETSET_IMPLEMENTATION(uint16_t, UInt, 16BE)
387     TYPED_GETSET_IMPLEMENTATION(int16_t, Int, 16LE)
388     TYPED_GETSET_IMPLEMENTATION(int16_t, Int, 16BE)
389     TYPED_GETSET_IMPLEMENTATION(uint32_t, UInt, 32LE)
390     TYPED_GETSET_IMPLEMENTATION(uint32_t, UInt, 32BE)
391     TYPED_GETSET_IMPLEMENTATION(int32_t, Int, 32LE)
392     TYPED_GETSET_IMPLEMENTATION(int32_t, Int, 32BE)
393     TYPED_GETSET_IMPLEMENTATION(uint64_t, UInt, 64LE)
394     TYPED_GETSET_IMPLEMENTATION(uint64_t, UInt, 64BE)
395     TYPED_GETSET_IMPLEMENTATION(int64_t, Int, 64LE)
396     TYPED_GETSET_IMPLEMENTATION(int64_t, Int, 64BE)
397
398     TYPED_GETSET_IMPLEMENTATION(float, Float, 32LE)
399     TYPED_GETSET_IMPLEMENTATION(float, Float, 32BE)
400     TYPED_GETSET_IMPLEMENTATION(double, Float, 64LE)
401     TYPED_GETSET_IMPLEMENTATION(double, Float, 64BE)
402
403 #undef TYPED_GETSET_IMPLEMENTATION
404
405 private:
406     static inline bool hostIsLittleEndian()
407     {
408         union {
409             uint16_t u16;
410             uint8_t u8[2];
411         } u;
412         u.u16 = 1;
413         return u.u8[0] == 1;
414     }
415
416     void ensureCapacity(unsigned capacity)
417     {
418         if (capacity < 32)
419             capacity = 32;
420         char* data = new char[capacity];
421         if (_size)
422             memcpy(data, _data, _size);
423         if (_capacity)
424             delete [] _data;
425         _data = data;
426         _capacity = capacity;
427     }
428
429     char* _data;
430     unsigned _size;
431     unsigned _capacity;
432 };
433
434 /// Gets an own header at some time
435
436 class RTIBasicDataStream {
437 public:
438     RTIBasicDataStream() : _offset(0) {}
439
440     /// Get aligned offset that aligns to a multiple of size
441     static inline unsigned getAlignedOffset(unsigned offset, unsigned size)
442     {
443         return ((offset + size - 1)/size) * size;
444     }
445
446 protected:
447     unsigned _offset;
448 };
449
450 class HLADecodeStream : public RTIBasicDataStream {
451 public:
452     HLADecodeStream(const RTIData& value) :
453         _value(value)
454     { }
455
456     bool alignOffsetForSize(unsigned size)
457     {
458         _offset = getAlignedOffset(_offset, size);
459         return _offset <= _value.size();
460     }
461
462     bool skip(unsigned size)
463     {
464         _offset += size;
465         return _offset <= _value.size();
466     }
467
468     bool eof() const
469     { return _value.size() <= _offset; }
470
471     const RTIData& getData() const
472     { return _value; }
473
474 #define TYPED_READ_IMPLEMENTATION(type, base, suffix)           \
475     bool decode##base##suffix(type& value)                      \
476     {                                                           \
477         if (_value.size() < _offset + sizeof(type))             \
478             return false;                                       \
479         value = _value.get##base##suffix(_offset);              \
480         _offset += sizeof(type);                                \
481         return true;                                            \
482     }
483
484     TYPED_READ_IMPLEMENTATION(uint8_t, UInt, 8)
485     TYPED_READ_IMPLEMENTATION(int8_t, Int, 8)
486     TYPED_READ_IMPLEMENTATION(uint16_t, UInt, 16LE)
487     TYPED_READ_IMPLEMENTATION(uint16_t, UInt, 16BE)
488     TYPED_READ_IMPLEMENTATION(int16_t, Int, 16LE)
489     TYPED_READ_IMPLEMENTATION(int16_t, Int, 16BE)
490     TYPED_READ_IMPLEMENTATION(uint32_t, UInt, 32LE)
491     TYPED_READ_IMPLEMENTATION(uint32_t, UInt, 32BE)
492     TYPED_READ_IMPLEMENTATION(int32_t, Int, 32LE)
493     TYPED_READ_IMPLEMENTATION(int32_t, Int, 32BE)
494     TYPED_READ_IMPLEMENTATION(uint64_t, UInt, 64LE)
495     TYPED_READ_IMPLEMENTATION(uint64_t, UInt, 64BE)
496     TYPED_READ_IMPLEMENTATION(int64_t, Int, 64LE)
497     TYPED_READ_IMPLEMENTATION(int64_t, Int, 64BE)
498
499     TYPED_READ_IMPLEMENTATION(float, Float, 32LE)
500     TYPED_READ_IMPLEMENTATION(float, Float, 32BE)
501     TYPED_READ_IMPLEMENTATION(double, Float, 64LE)
502     TYPED_READ_IMPLEMENTATION(double, Float, 64BE)
503
504 #undef TYPED_READ_IMPLEMENTATION
505
506 private:
507     const RTIData& _value;
508 };
509
510 class HLAEncodeStream : public RTIBasicDataStream {
511 public:
512     HLAEncodeStream(RTIData& value) :
513         _value(value)
514     { }
515
516     bool alignOffsetForSize(unsigned size)
517     {
518         _offset = getAlignedOffset(_offset, size);
519         _value.resize(_offset);
520         return true;
521     }
522
523     bool skip(unsigned size)
524     {
525         _offset += size;
526         _value.resize(_offset);
527         return true;
528     }
529
530     bool eof() const
531     { return _value.size() <= _offset; }
532
533     void setData(const RTIData& data)
534     { _value = data; }
535
536 #define TYPED_WRITE_IMPLEMENTATION(type, base, suffix)                  \
537     bool encode##base##suffix(type value)                               \
538     {                                                                   \
539         unsigned nextOffset = _offset + sizeof(type);                   \
540         _value.resize(nextOffset);                                      \
541         _value.set##base##suffix(value, _offset);                       \
542         _offset = nextOffset;                                           \
543         return true;                                                    \
544     }
545
546     TYPED_WRITE_IMPLEMENTATION(uint8_t, UInt, 8)
547     TYPED_WRITE_IMPLEMENTATION(int8_t, Int, 8)
548     TYPED_WRITE_IMPLEMENTATION(uint16_t, UInt, 16LE)
549     TYPED_WRITE_IMPLEMENTATION(uint16_t, UInt, 16BE)
550     TYPED_WRITE_IMPLEMENTATION(int16_t, Int, 16LE)
551     TYPED_WRITE_IMPLEMENTATION(int16_t, Int, 16BE)
552     TYPED_WRITE_IMPLEMENTATION(uint32_t, UInt, 32LE)
553     TYPED_WRITE_IMPLEMENTATION(uint32_t, UInt, 32BE)
554     TYPED_WRITE_IMPLEMENTATION(int32_t, Int, 32LE)
555     TYPED_WRITE_IMPLEMENTATION(int32_t, Int, 32BE)
556     TYPED_WRITE_IMPLEMENTATION(uint64_t, UInt, 64LE)
557     TYPED_WRITE_IMPLEMENTATION(uint64_t, UInt, 64BE)
558     TYPED_WRITE_IMPLEMENTATION(int64_t, Int, 64LE)
559     TYPED_WRITE_IMPLEMENTATION(int64_t, Int, 64BE)
560
561     TYPED_WRITE_IMPLEMENTATION(float, Float, 32LE)
562     TYPED_WRITE_IMPLEMENTATION(float, Float, 32BE)
563     TYPED_WRITE_IMPLEMENTATION(double, Float, 64LE)
564     TYPED_WRITE_IMPLEMENTATION(double, Float, 64BE)
565
566 #undef TYPED_WRITE_IMPLEMENTATION
567
568 private:
569     RTIData& _value;
570 };
571
572 } // namespace simgear
573
574 #endif