X-Plane Remote Access Plugin and Client Library
MultiBuffer.cc
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 
45 
46 using xplra::Protocol;
47 
48 using std::vector;
49 using std::string;
50 using std::min;
51 
52 //------------------------------------------------------------------------------
53 
54 inline 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 
73 inline 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 
95 inline 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 
114 bool 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 
124 inline size_t
125 MultiBuffer::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 
136 inline void MultiBuffer::unfinalize() noexcept
137 {
138  delete data; data = 0;
139 }
140 
141 //------------------------------------------------------------------------------
142 
144 {
145  registeredID = -1;
146 }
147 
148 //------------------------------------------------------------------------------
149 
150 inline const MultiBuffer::DataRef* MultiBuffer::getLastDataRef() const noexcept
151 {
152  return dataRefs.empty() ? 0 : &(dataRefs.back());
153 }
154 
155 //------------------------------------------------------------------------------
156 
157 inline 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 
167 inline 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 
176 inline 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 
185 template <typename T, uint8_t type> size_t
186 inline 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 
204 template <typename T, uint8_t type>
205 inline 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 
223 template <typename T, uint8_t type>
224 inline 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 
235 MultiBuffer::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 
248 {
250  delete[] data;
251 }
252 
253 //------------------------------------------------------------------------------
254 
255 size_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 
264 size_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 
273 size_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 
282 size_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 
293 size_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 
304 size_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 
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 
331 {
332  if (finalize() && registeredID<0) {
334 
336 
337  uint32_t id = xplane.stream->readU32();
339 
340  registeredID = static_cast<int>(id);
341  }
342 }
343 
344 //------------------------------------------------------------------------------
345 
347 {
348  if (registeredID>=0) {
349  xplane.stream->writeU8(unregisterCommand);
350  xplane.stream->writeU32(static_cast<uint32_t>(registeredID));
351  xplane.stream->flush();
353  registeredID = -1;
354  }
355 }
356 
357 //------------------------------------------------------------------------------
358 
360 {
361  try {
363  return true;
364  } catch(...) {
365  registeredID = -1;
366  return false;
367  }
368 }
369 
370 //------------------------------------------------------------------------------
371 
373 {
374  if (data==0 && registeredID>=0) {
377  } else {
378  finalize();
379  }
380 
381  if (registeredID>=0) {
382  doExecute();
383  } else {
385  }
386 }
387 
388 //------------------------------------------------------------------------------
389 
390 void MultiBuffer::setInt(size_t id, int value)
391 {
392  *reinterpret_cast<int32_t*>(getData(id, Protocol::TYPE_INT)) = value;
393 }
394 
395 //------------------------------------------------------------------------------
396 
397 int MultiBuffer::getInt(size_t id) const
398 {
399  return *reinterpret_cast<const int32_t*>(getData(id, Protocol::TYPE_INT));
400 }
401 
402 //------------------------------------------------------------------------------
403 
404 const 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 
411 int32_t& MultiBuffer::getIntRef(size_t id)
412 {
413  return *reinterpret_cast<int32_t*>(getData(id, Protocol::TYPE_INT));
414 }
415 
416 //------------------------------------------------------------------------------
417 
418 void MultiBuffer::setFloat(size_t id, float value)
419 {
420  *reinterpret_cast<float*>(getData(id, Protocol::TYPE_FLOAT)) = value;
421 }
422 
423 //------------------------------------------------------------------------------
424 
425 float MultiBuffer::getFloat(size_t id) const
426 {
427  return *reinterpret_cast<const float*>(getData(id, Protocol::TYPE_FLOAT));
428 }
429 
430 //------------------------------------------------------------------------------
431 
432 const float& MultiBuffer::getFloatRef(size_t id) const
433 {
434  return *reinterpret_cast<const float*>(getData(id, Protocol::TYPE_FLOAT));
435 }
436 
437 //------------------------------------------------------------------------------
438 
439 float& MultiBuffer::getFloatRef(size_t id)
440 {
441  return *reinterpret_cast<float*>(getData(id, Protocol::TYPE_FLOAT));
442 }
443 
444 //------------------------------------------------------------------------------
445 
446 void MultiBuffer::setDouble(size_t id, double value)
447 {
448  *reinterpret_cast<double*>(getData(id, Protocol::TYPE_DOUBLE)) = value;
449 }
450 
451 //------------------------------------------------------------------------------
452 
453 double MultiBuffer::getDouble(size_t id) const
454 {
455  return *reinterpret_cast<const double*>(getData(id, Protocol::TYPE_DOUBLE));
456 }
457 
458 //------------------------------------------------------------------------------
459 
460 const double& MultiBuffer::getDoubleRef(size_t id) const
461 {
462  return *reinterpret_cast<const double*>(getData(id, Protocol::TYPE_DOUBLE));
463 }
464 
465 //------------------------------------------------------------------------------
466 
467 double& MultiBuffer::getDoubleRef(size_t id)
468 {
469  return *reinterpret_cast<double*>(getData(id, Protocol::TYPE_DOUBLE));
470 }
471 
472 //------------------------------------------------------------------------------
473 
474 size_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 
482 size_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 
490 const 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 
497 size_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 
506 size_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 
514 const 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 
521 size_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 
529 size_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 
537 const 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 
544 size_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 
553 string 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 
571 const char* MultiBuffer::getStringPtr(size_t id, size_t offset) const
572 {
573  return reinterpret_cast<const char*>(getByteArray(id, offset));
574 }
575 
576 //------------------------------------------------------------------------------
577 
578 void 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 
602 {
603  if (registeredID>=0) {
604  int origRegisteredID = registeredID;
605  try {
606  registeredID = -1;
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:
size_t getCopyLength(size_t userLength, size_t userOffset) const noexcept
Definition: MultiBuffer.cc:125
double getDouble(size_t id) const
Definition: MultiBuffer.cc:453
size_t setIntArray(size_t id, const int32_t *value, size_t length=0, size_t offset=0)
Definition: MultiBuffer.cc:497
const DataRef & getDataRef(size_t id, uint8_t type) const
Definition: MultiBuffer.cc:157
void writeSpec(uint8_t command) const
Definition: MultiBuffer.cc:578
std::vector< DataRef > dataRefs
Definition: MultiBuffer.h:122
size_t getByteArray(size_t id, uint8_t *value, size_t length=0, size_t offset=0) const
Definition: MultiBuffer.cc:529
std::string getString(size_t id, size_t offset=0) const
Definition: MultiBuffer.cc:553
const int32_t & getIntRef(size_t id) const
Definition: MultiBuffer.cc:404
void * getData(size_t id, uint8_t type)
Definition: MultiBuffer.cc:167
size_t addIntArray(const std::string &name, size_t length, size_t offset=0) noexcept
Definition: MultiBuffer.cc:293
size_t addByteArray(const std::string &name, size_t length, size_t offset=0) noexcept
Definition: MultiBuffer.cc:304
size_t setByteArray(size_t id, const uint8_t *value, size_t length=0, size_t offset=0)
Definition: MultiBuffer.cc:521
void setInt(size_t id, int value)
Definition: MultiBuffer.cc:390
size_t addDouble(const std::string &name) noexcept
Definition: MultiBuffer.cc:273
const char * getStringPtr(size_t id, size_t offset=0) const
Definition: MultiBuffer.cc:571
const double & getDoubleRef(size_t id) const
Definition: MultiBuffer.cc:460
size_t getIntArray(size_t id, int32_t *value, size_t length=0, size_t offset=0) const
Definition: MultiBuffer.cc:506
void setDouble(size_t id, double value)
Definition: MultiBuffer.cc:446
MultiBuffer(XPlane &xplane, uint8_t registerCommand, uint8_t unregisterCommand) noexcept
Definition: MultiBuffer.cc:235
size_t getFloatArray(size_t id, float *value, size_t length=0, size_t offset=0) const
Definition: MultiBuffer.cc:482
const float & getFloatRef(size_t id) const
Definition: MultiBuffer.cc:432
const DataRef * getLastDataRef() const noexcept
Definition: MultiBuffer.cc:150
size_t setArray(size_t id, const T *value, size_t length, size_t offset)
Definition: MultiBuffer.cc:186
size_t addFloat(const std::string &name) noexcept
Definition: MultiBuffer.cc:264
size_t setString(size_t id, const std::string &value, size_t offset=0)
Definition: MultiBuffer.cc:544
size_t setFloatArray(size_t id, const float *value, size_t length=0, size_t offset=0)
Definition: MultiBuffer.cc:474
size_t addInt(const std::string &name) noexcept
Definition: MultiBuffer.cc:255
size_t addFloatArray(const std::string &name, size_t length, size_t offset=0) noexcept
Definition: MultiBuffer.cc:282
size_t getArray(size_t id, T *value, size_t length, size_t offset) const
Definition: MultiBuffer.cc:205
float getFloat(size_t id) const
Definition: MultiBuffer.cc:425
void setFloat(size_t id, float value)
Definition: MultiBuffer.cc:418
scpl::io::DataStream * stream
Definition: XPlane.h:94
void checkResult(uint8_t result, bool hasParameter=false, long parameter=0)
Definition: XPlane.cc:113