source: xplra/src/client/c/hu/varadiistvan/xplra/MultiBuffer.cc@ 107:614b9ff033c1

Last change on this file since 107:614b9ff033c1 was 107:614b9ff033c1, checked in by István Váradi <ivaradi@…>, 17 months ago

Modernized the exception specifications in the C++ client

File size: 18.7 KB
Line 
1// Copyright (c) 2013 by István Váradi
2
3// This file is part of XPLRA, a remote-access plugin for X-Plane
4
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7
8// 1. Redistributions of source code must retain the above copyright notice, this
9// list of conditions and the following disclaimer.
10// 2. Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13
14// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
25// The views and conclusions contained in the software and documentation are those
26// of the authors and should not be interpreted as representing official policies,
27// either expressed or implied, of the FreeBSD Project.
28
29//------------------------------------------------------------------------------
30
31#include "MultiBuffer.h"
32
33#include "XPlane.h"
34
35#include <xplra/Protocol.h>
36
37#include <hu/varadiistvan/scpl/io/DataStream.h>
38
39#include <cstring>
40#include <cstdio>
41
42//------------------------------------------------------------------------------
43
44using hu::varadiistvan::xplra::MultiBuffer;
45
46using xplra::Protocol;
47
48using std::vector;
49using std::string;
50using std::min;
51
52//------------------------------------------------------------------------------
53
54inline MultiBuffer::DataRef::DataRef(const string& name, uint8_t type,
55 const DataRef* previous,
56 size_t length, size_t offset) noexcept :
57 name(name),
58 type(type),
59 length(length),
60 offset(offset),
61 dataOffset(0)
62{
63 if (previous!=0) {
64 size_t alignment = getAlignment();
65 dataOffset = previous->dataOffset + previous->getSize();
66 dataOffset += alignment - 1;
67 dataOffset &= ~(alignment-1);
68 }
69}
70
71//------------------------------------------------------------------------------
72
73inline size_t MultiBuffer::DataRef::getSize() const noexcept
74{
75 switch (type) {
76 case Protocol::TYPE_INT:
77 return sizeof(int32_t);
78 case Protocol::TYPE_FLOAT:
79 return sizeof(float);
80 case Protocol::TYPE_DOUBLE:
81 return sizeof(double);
82 case Protocol::TYPE_FLOAT_ARRAY:
83 return sizeof(float) * length;
84 case Protocol::TYPE_INT_ARRAY:
85 return sizeof(int32_t) * length;
86 case Protocol::TYPE_BYTE_ARRAY:
87 return sizeof(uint8_t) * length;
88 default:
89 return 0;
90 }
91}
92
93//------------------------------------------------------------------------------
94
95inline size_t MultiBuffer::DataRef::getAlignment() const noexcept
96{
97 switch (type) {
98 case Protocol::TYPE_INT:
99 case Protocol::TYPE_INT_ARRAY:
100 return sizeof(int32_t);
101 case Protocol::TYPE_FLOAT:
102 case Protocol::TYPE_FLOAT_ARRAY:
103 return sizeof(float);
104 case Protocol::TYPE_DOUBLE:
105 return sizeof(double);
106 case Protocol::TYPE_BYTE_ARRAY:
107 default:
108 return sizeof(uint8_t);
109 }
110}
111
112//------------------------------------------------------------------------------
113
114bool MultiBuffer::DataRef::isArray() const noexcept
115{
116 return
117 type==Protocol::TYPE_FLOAT_ARRAY ||
118 type==Protocol::TYPE_INT_ARRAY ||
119 type==Protocol::TYPE_BYTE_ARRAY;
120}
121
122//------------------------------------------------------------------------------
123
124inline size_t
125MultiBuffer::DataRef::getCopyLength(size_t userLength, size_t userOffset)
126 const noexcept
127{
128 size_t maxLength =
129 (userOffset>length) ? 0 : (length - userOffset);
130 return (userLength==0) ? maxLength : min(userLength, maxLength);
131}
132
133//------------------------------------------------------------------------------
134//------------------------------------------------------------------------------
135
136inline void MultiBuffer::unfinalize() noexcept
137{
138 delete data; data = 0;
139}
140
141//------------------------------------------------------------------------------
142
143void MultiBuffer::forgetRegistration() noexcept
144{
145 registeredID = -1;
146}
147
148//------------------------------------------------------------------------------
149
150inline const MultiBuffer::DataRef* MultiBuffer::getLastDataRef() const noexcept
151{
152 return dataRefs.empty() ? 0 : &(dataRefs.back());
153}
154
155//------------------------------------------------------------------------------
156
157inline const MultiBuffer::DataRef& MultiBuffer::getDataRef(size_t id, uint8_t type) const
158{
159 if (id>=dataRefs.size()) throw InvalidIDException();
160 const DataRef& dataRef = dataRefs[id];
161 if (dataRef.type!=type) throw TypeMismatchException();
162 return dataRef;
163}
164
165//------------------------------------------------------------------------------
166
167inline void* MultiBuffer::getData(size_t id, uint8_t type)
168{
169 const DataRef& dataRef = getDataRef(id, type);
170 finalize();
171 return data + dataRef.dataOffset;
172}
173
174//------------------------------------------------------------------------------
175
176inline const void* MultiBuffer::getData(size_t id, uint8_t type) const
177{
178 const DataRef& dataRef = getDataRef(id, type);
179 finalize();
180 return data + dataRef.dataOffset;
181}
182
183//------------------------------------------------------------------------------
184
185template <typename T, uint8_t type> size_t
186inline MultiBuffer::setArray(size_t id, const T* value,
187 size_t length, size_t offset)
188{
189 const DataRef& dataRef = getDataRef(id, type);
190 finalize();
191
192 size_t toCopy = dataRef.getCopyLength(length, offset);
193
194 if (toCopy>0) {
195 memcpy( data + dataRef.dataOffset + offset * sizeof(T),
196 value, toCopy * sizeof(T) );
197 }
198
199 return toCopy;
200}
201
202//------------------------------------------------------------------------------
203
204template <typename T, uint8_t type>
205inline size_t MultiBuffer::getArray(size_t id, T* value,
206 size_t length, size_t offset) const
207{
208 const DataRef& dataRef = getDataRef(id, type);
209 finalize();
210
211 size_t toCopy = dataRef.getCopyLength(length, offset);
212
213 if (toCopy>0) {
214 memcpy( value, data + dataRef.dataOffset + offset * sizeof(T),
215 toCopy * sizeof(T) );
216 }
217
218 return toCopy;
219}
220
221//------------------------------------------------------------------------------
222
223template <typename T, uint8_t type>
224inline const T* MultiBuffer::getArray(size_t id, size_t offset) const
225{
226 const DataRef& dataRef = getDataRef(id, type);
227 finalize();
228 return (offset<dataRef.length) ?
229 reinterpret_cast<const T*>(data + dataRef.dataOffset +
230 offset * sizeof(T)) : 0;
231}
232
233//------------------------------------------------------------------------------
234
235MultiBuffer::MultiBuffer(XPlane& xplane, uint8_t registerCommand,
236 uint8_t unregisterCommand) noexcept :
237 data(0),
238 xplane(xplane),
239 registerCommand(registerCommand),
240 unregisterCommand(unregisterCommand),
241 registeredID(-1)
242{
243}
244
245//------------------------------------------------------------------------------
246
247MultiBuffer::~MultiBuffer() noexcept
248{
249 unregisterSafelyFromXPlane();
250 delete[] data;
251}
252
253//------------------------------------------------------------------------------
254
255size_t MultiBuffer::addInt(const std::string& name) noexcept
256{
257 unfinalize();
258 dataRefs.push_back(DataRef(name, Protocol::TYPE_INT, getLastDataRef()));
259 return dataRefs.size() - 1;
260}
261
262//------------------------------------------------------------------------------
263
264size_t MultiBuffer::addFloat(const std::string& name) noexcept
265{
266 unfinalize();
267 dataRefs.push_back(DataRef(name, Protocol::TYPE_FLOAT, getLastDataRef()));
268 return dataRefs.size() - 1;
269}
270
271//------------------------------------------------------------------------------
272
273size_t MultiBuffer::addDouble(const std::string& name) noexcept
274{
275 unfinalize();
276 dataRefs.push_back(DataRef(name, Protocol::TYPE_DOUBLE, getLastDataRef()));
277 return dataRefs.size() - 1;
278}
279
280//------------------------------------------------------------------------------
281
282size_t MultiBuffer::addFloatArray(const std::string& name, size_t length,
283 size_t offset) noexcept
284{
285 unfinalize();
286 dataRefs.push_back(DataRef(name, Protocol::TYPE_FLOAT_ARRAY,
287 getLastDataRef(), length, offset));
288 return dataRefs.size() - 1;
289}
290
291//------------------------------------------------------------------------------
292
293size_t MultiBuffer::addIntArray(const std::string& name, size_t length,
294 size_t offset) noexcept
295{
296 unfinalize();
297 dataRefs.push_back(DataRef(name, Protocol::TYPE_INT_ARRAY,
298 getLastDataRef(), length, offset));
299 return dataRefs.size() - 1;
300}
301
302//------------------------------------------------------------------------------
303
304size_t MultiBuffer::addByteArray(const std::string& name, size_t length,
305 size_t offset) noexcept
306{
307 unfinalize();
308 dataRefs.push_back(DataRef(name, Protocol::TYPE_BYTE_ARRAY,
309 getLastDataRef(), length, offset));
310 return dataRefs.size() - 1;
311}
312
313//------------------------------------------------------------------------------
314
315bool MultiBuffer::finalize() const
316{
317 if (data==0 && !dataRefs.empty()) {
318 const DataRef* lastDataRef = getLastDataRef();
319 size_t dataSize = lastDataRef->dataOffset + lastDataRef->getSize();
320 data = new unsigned char[dataSize];
321 memset(data, 0, dataSize);
322 return true;
323 } else {
324 return data!=0;
325 }
326}
327
328//------------------------------------------------------------------------------
329
330void MultiBuffer::registerInXPlane()
331{
332 if (finalize() && registeredID<0) {
333 xplane.checkStream();
334
335 writeSpec(registerCommand);
336
337 uint32_t id = xplane.stream->readU32();
338 xplane.checkStream();
339
340 registeredID = static_cast<int>(id);
341 }
342}
343
344//------------------------------------------------------------------------------
345
346void MultiBuffer::unregisterFromXPlane()
347{
348 if (registeredID>=0) {
349 xplane.stream->writeU8(unregisterCommand);
350 xplane.stream->writeU32(static_cast<uint32_t>(registeredID));
351 xplane.stream->flush();
352 xplane.checkResult();
353 registeredID = -1;
354 }
355}
356
357//------------------------------------------------------------------------------
358
359bool MultiBuffer::unregisterSafelyFromXPlane() noexcept
360{
361 try {
362 unregisterFromXPlane();
363 return true;
364 } catch(...) {
365 registeredID = -1;
366 return false;
367 }
368}
369
370//------------------------------------------------------------------------------
371
372void MultiBuffer::execute()
373{
374 if (data==0 && registeredID>=0) {
375 unregisterFromXPlane();
376 registerInXPlane();
377 } else {
378 finalize();
379 }
380
381 if (registeredID>=0) {
382 doExecute();
383 } else {
384 doExecuteUnregistered();
385 }
386}
387
388//------------------------------------------------------------------------------
389
390void MultiBuffer::setInt(size_t id, int value)
391{
392 *reinterpret_cast<int32_t*>(getData(id, Protocol::TYPE_INT)) = value;
393}
394
395//------------------------------------------------------------------------------
396
397int MultiBuffer::getInt(size_t id) const
398{
399 return *reinterpret_cast<const int32_t*>(getData(id, Protocol::TYPE_INT));
400}
401
402//------------------------------------------------------------------------------
403
404const int32_t& MultiBuffer::getIntRef(size_t id) const
405{
406 return *reinterpret_cast<const int32_t*>(getData(id, Protocol::TYPE_INT));
407}
408
409//------------------------------------------------------------------------------
410
411int32_t& MultiBuffer::getIntRef(size_t id)
412{
413 return *reinterpret_cast<int32_t*>(getData(id, Protocol::TYPE_INT));
414}
415
416//------------------------------------------------------------------------------
417
418void MultiBuffer::setFloat(size_t id, float value)
419{
420 *reinterpret_cast<float*>(getData(id, Protocol::TYPE_FLOAT)) = value;
421}
422
423//------------------------------------------------------------------------------
424
425float MultiBuffer::getFloat(size_t id) const
426{
427 return *reinterpret_cast<const float*>(getData(id, Protocol::TYPE_FLOAT));
428}
429
430//------------------------------------------------------------------------------
431
432const float& MultiBuffer::getFloatRef(size_t id) const
433{
434 return *reinterpret_cast<const float*>(getData(id, Protocol::TYPE_FLOAT));
435}
436
437//------------------------------------------------------------------------------
438
439float& MultiBuffer::getFloatRef(size_t id)
440{
441 return *reinterpret_cast<float*>(getData(id, Protocol::TYPE_FLOAT));
442}
443
444//------------------------------------------------------------------------------
445
446void MultiBuffer::setDouble(size_t id, double value)
447{
448 *reinterpret_cast<double*>(getData(id, Protocol::TYPE_DOUBLE)) = value;
449}
450
451//------------------------------------------------------------------------------
452
453double MultiBuffer::getDouble(size_t id) const
454{
455 return *reinterpret_cast<const double*>(getData(id, Protocol::TYPE_DOUBLE));
456}
457
458//------------------------------------------------------------------------------
459
460const double& MultiBuffer::getDoubleRef(size_t id) const
461{
462 return *reinterpret_cast<const double*>(getData(id, Protocol::TYPE_DOUBLE));
463}
464
465//------------------------------------------------------------------------------
466
467double& MultiBuffer::getDoubleRef(size_t id)
468{
469 return *reinterpret_cast<double*>(getData(id, Protocol::TYPE_DOUBLE));
470}
471
472//------------------------------------------------------------------------------
473
474size_t MultiBuffer::setFloatArray(size_t id, const float* value,
475 size_t length, size_t offset)
476{
477 return setArray<float, Protocol::TYPE_FLOAT_ARRAY>(id, value, length, offset);
478}
479
480//------------------------------------------------------------------------------
481
482size_t MultiBuffer::getFloatArray(size_t id, float* value,
483 size_t length, size_t offset) const
484{
485 return getArray<float, Protocol::TYPE_FLOAT_ARRAY>(id, value, length, offset);
486}
487
488//------------------------------------------------------------------------------
489
490const float* MultiBuffer::getFloatArray(size_t id, size_t offset) const
491{
492 return getArray<float, Protocol::TYPE_FLOAT_ARRAY>(id, offset);
493}
494
495//------------------------------------------------------------------------------
496
497size_t MultiBuffer::setIntArray(size_t id, const int32_t* value,
498 size_t length, size_t offset)
499
500{
501 return setArray<int32_t, Protocol::TYPE_INT_ARRAY>(id, value, length, offset);
502}
503
504//------------------------------------------------------------------------------
505
506size_t MultiBuffer::getIntArray(size_t id, int32_t* value,
507 size_t length, size_t offset) const
508{
509 return getArray<int32_t, Protocol::TYPE_INT_ARRAY>(id, value, length, offset);
510}
511
512//------------------------------------------------------------------------------
513
514const int32_t* MultiBuffer::getIntArray(size_t id, size_t offset) const
515{
516 return getArray<int32_t, Protocol::TYPE_INT_ARRAY>(id, offset);
517}
518
519//------------------------------------------------------------------------------
520
521size_t MultiBuffer::setByteArray(size_t id, const uint8_t* value,
522 size_t length, size_t offset)
523{
524 return setArray<uint8_t, Protocol::TYPE_BYTE_ARRAY>(id, value, length, offset);
525}
526
527//------------------------------------------------------------------------------
528
529size_t MultiBuffer::getByteArray(size_t id, uint8_t* value,
530 size_t length, size_t offset) const
531{
532 return getArray<uint8_t, Protocol::TYPE_BYTE_ARRAY>(id, value, length, offset);
533}
534
535//------------------------------------------------------------------------------
536
537const uint8_t* MultiBuffer::getByteArray(size_t id, size_t offset) const
538{
539 return getArray<uint8_t, Protocol::TYPE_BYTE_ARRAY>(id, offset);
540}
541
542//------------------------------------------------------------------------------
543
544size_t MultiBuffer::setString(size_t id, const string& value,
545 size_t offset)
546{
547 return setByteArray(id, reinterpret_cast<const uint8_t*>(value.c_str()),
548 value.length(), offset);
549}
550
551//------------------------------------------------------------------------------
552
553string MultiBuffer::getString(size_t id, size_t offset) const
554{
555 const DataRef& dataRef = getDataRef(id, Protocol::TYPE_BYTE_ARRAY);
556 finalize();
557
558 size_t toCopy = dataRef.getCopyLength(0, offset);
559 const uint8_t* str = data + dataRef.dataOffset + offset;
560
561 size_t length = 0;
562 if (toCopy!=0) {
563 while(length<toCopy && str[length]!=0) ++length;
564 }
565
566 return string(reinterpret_cast<const char*>(str), length);
567}
568
569//------------------------------------------------------------------------------
570
571const char* MultiBuffer::getStringPtr(size_t id, size_t offset) const
572{
573 return reinterpret_cast<const char*>(getByteArray(id, offset));
574}
575
576//------------------------------------------------------------------------------
577
578void MultiBuffer::writeSpec(uint8_t command) const
579{
580 xplane.stream->writeU8(command);
581 xplane.stream->writeU32(dataRefs.size());
582
583 for(vector<DataRef>::const_iterator i = dataRefs.begin();
584 i!=dataRefs.end(); ++i)
585 {
586 const DataRef& dataRef = *i;
587 xplane.stream->writeString(dataRef.name);
588 xplane.stream->writeU8(dataRef.type);
589 if (dataRef.isArray()) {
590 xplane.stream->writeS32(dataRef.length);
591 xplane.stream->writeS32(dataRef.offset);
592 }
593 }
594
595 xplane.stream->flush();
596 xplane.checkResult(true);
597}
598
599//------------------------------------------------------------------------------
600
601void MultiBuffer::reregisterInXPlane()
602{
603 if (registeredID>=0) {
604 int origRegisteredID = registeredID;
605 try {
606 registeredID = -1;
607 registerInXPlane();
608 } catch(...) {
609 registeredID = origRegisteredID;
610 throw;
611 }
612 }
613}
614
615//------------------------------------------------------------------------------
616
617// Local Variables:
618// mode: C++
619// c-basic-offset: 4
620// indent-tabs-mode: nil
621// End:
Note: See TracBrowser for help on using the repository browser.