NanoOcp
Minimal AES70 / OCP.1 TCP client/server library for d&b Soundscape devices
Loading...
Searching...
No Matches
Variant.cpp
Go to the documentation of this file.
1/* Copyright (c) 2024, Bernardo Escalona
2 *
3 * This file is part of NanoOcp <https://github.com/ChristianAhrens/NanoOcp>
4 *
5 * This library is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU Lesser General Public License version 3.0 as published
7 * by the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 * details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include "Variant.h"
20#include <assert.h>
21#include <sstream>
22
23
24namespace NanoOcp1
25{
26
27Variant::Variant(bool v) { m_value = v; }
28Variant::Variant(std::int32_t v) { m_value = v; }
29Variant::Variant(std::uint8_t v) { m_value = v; }
30Variant::Variant(std::uint16_t v) { m_value = v; }
31Variant::Variant(std::uint32_t v) { m_value = v; }
32Variant::Variant(std::uint64_t v) { m_value = v; }
33Variant::Variant(std::float_t v) { m_value = v; }
34Variant::Variant(std::double_t v) { m_value = v; }
35Variant::Variant(const std::string& v) { m_value = v; }
36Variant::Variant(const char* v) : Variant(std::string(v)) { } // Allow Variant("test") to become of TypeString.
37
38Variant::Variant(std::float_t x, std::float_t y, std::float_t z)
39{
40 assert(sizeof(std::uint32_t) == sizeof(std::float_t)); // Required for pointer cast to work below
41 std::uint32_t xInt = *(std::uint32_t*)&x;
42 std::uint32_t yInt = *(std::uint32_t*)&y;
43 std::uint32_t zInt = *(std::uint32_t*)&z;
44
45 m_value = ByteVector
46 ({
47 static_cast<std::uint8_t>(xInt >> 24),
48 static_cast<std::uint8_t>(xInt >> 16),
49 static_cast<std::uint8_t>(xInt >> 8),
50 static_cast<std::uint8_t>(xInt),
51 static_cast<std::uint8_t>(yInt >> 24),
52 static_cast<std::uint8_t>(yInt >> 16),
53 static_cast<std::uint8_t>(yInt >> 8),
54 static_cast<std::uint8_t>(yInt),
55 static_cast<std::uint8_t>(zInt >> 24),
56 static_cast<std::uint8_t>(zInt >> 16),
57 static_cast<std::uint8_t>(zInt >> 8),
58 static_cast<std::uint8_t>(zInt),
59 });
60}
61
63{
64 bool ok(false);
65 switch (type)
66 {
68 m_value = NanoOcp1::DataToBool(data, &ok);
69 break;
71 m_value = NanoOcp1::DataToInt32(data, &ok);
72 break;
74 m_value = NanoOcp1::DataToUint8(data, &ok);
75 break;
77 m_value = NanoOcp1::DataToUint16(data, &ok);
78 break;
80 m_value = NanoOcp1::DataToUint32(data, &ok);
81 break;
83 m_value = NanoOcp1::DataToUint64(data, &ok);
84 break;
86 m_value = NanoOcp1::DataToFloat(data, &ok);
87 break;
89 m_value = NanoOcp1::DataToDouble(data, &ok);
90 break;
92 m_value = NanoOcp1::DataToString(data, &ok);
93 break;
95 ok = (data.size() >= 2); // OcaBlob size is 2 bytes
96 if (ok)
97 {
98 // TODO: include 2 initial bytes?
99 m_value = data;
100 }
101 break;
103 ok = (data.size() == 12) || // Notification contains 3 floats: x, y, z.
104 (data.size() == 24) || // Notification contains 6 floats: x, y, z, hor, vert, rot.
105 (data.size() == 36); // Response contains 9 floats: current, min, and max x, y, z.
106 if (ok)
107 {
108 m_value = data;
109 }
110 break;
118 default:
119 break;
120 }
121
122 assert(ok); // Conversion not possible or not yet implemented!
123}
124
125bool Variant::operator==(const Variant& other) const
126{
127 return m_value == other.m_value;
128}
129
130bool Variant::operator!=(const Variant& other) const
131{
132 return m_value != other.m_value;
133}
134
136{
137 return (m_value.index() != TypeNone);
138}
139
141{
142 switch (m_value.index())
143 {
144 case TypeBool: return OCP1DATATYPE_BOOLEAN;
145 case TypeInt32: return OCP1DATATYPE_INT32;
146 case TypeUInt8: return OCP1DATATYPE_UINT8;
147 case TypeUInt16: return OCP1DATATYPE_UINT16;
148 case TypeUInt32: return OCP1DATATYPE_UINT32;
149 case TypeUInt64: return OCP1DATATYPE_UINT64;
150 case TypeFloat: return OCP1DATATYPE_FLOAT32;
151 case TypeDouble: return OCP1DATATYPE_FLOAT64;
152 case TypeString: return OCP1DATATYPE_STRING;
154 default:
155 break;
156 }
157
158 return OCP1DATATYPE_NONE;
159}
160
161bool Variant::ToBool(bool* pOk) const
162{
163 if (pOk != nullptr) *pOk = true;
164
165 switch (m_value.index())
166 {
167 case TypeBool:
168 return std::get<bool>(m_value);
169 case TypeInt32:
170 return (std::get<std::int32_t>(m_value) > std::int32_t(0));
171 case TypeUInt8:
172 return (std::get<std::uint8_t>(m_value) > std::uint8_t(0));
173 case TypeUInt16:
174 return (std::get<std::uint16_t>(m_value) > std::uint16_t(0));
175 case TypeUInt32:
176 return (std::get<std::uint32_t>(m_value) > std::uint32_t(0));
177 case TypeUInt64:
178 return (std::get<std::uint64_t>(m_value) > std::uint64_t(0));
179 case TypeFloat:
180 return (std::get<std::float_t>(m_value) > std::float_t(0.0f));
181 case TypeDouble:
182 return (std::get<std::double_t>(m_value) > std::double_t(0.0));
183 case TypeString:
184 return (std::get<std::string>(m_value) == "true");
185 case TypeByteVector:
186 return DataToBool(std::get<ByteVector>(m_value), pOk);
187 default:
188 break;
189 }
190
191 // Conversion not possible or not yet implemented!
192 if (pOk != nullptr) *pOk = false;
193
194 return false;
195}
196
197std::int32_t Variant::ToInt32(bool* pOk) const
198{
199 if (pOk != nullptr) *pOk = true;
200
201 switch (m_value.index())
202 {
203 case TypeBool:
204 return std::get<bool>(m_value) ? 1 : 0;
205 case TypeInt32:
206 return std::get<std::int32_t>(m_value);
207 case TypeUInt8:
208 return static_cast<std::int32_t>(std::get<std::uint8_t>(m_value));
209 case TypeUInt16:
210 return static_cast<std::int32_t>(std::get<std::uint16_t>(m_value));
211 case TypeUInt32:
212 return static_cast<std::int32_t>(std::get<std::uint32_t>(m_value));
213 case TypeUInt64:
214 return static_cast<std::int32_t>(std::get<std::uint64_t>(m_value));
215 case TypeFloat:
216 return std::lround(std::get<std::float_t>(m_value));
217 case TypeDouble:
218 return std::lround(std::get<std::double_t>(m_value));
219 case TypeString:
220 try
221 {
222 return std::stol(std::get<std::string>(m_value));
223 }
224 catch (...)
225 {
226 break;
227 }
228 case TypeByteVector:
229 return DataToInt32(std::get<ByteVector>(m_value), pOk);
230 default:
231 break;
232 }
233
234 // Conversion not possible or not yet implemented!
235 if (pOk != nullptr) *pOk = false;
236
237 return std::int32_t(0);
238}
239
240std::uint8_t Variant::ToUInt8(bool* pOk) const
241{
242 if (pOk != nullptr) *pOk = true;
243
244 switch (m_value.index())
245 {
246 case TypeBool:
247 return std::get<bool>(m_value) ? std::uint8_t(1) : std::uint8_t(0);
248 case TypeInt32:
249 return static_cast<std::uint8_t>(std::get<std::int32_t>(m_value));
250 case TypeUInt8:
251 return std::get<std::uint8_t>(m_value);
252 case TypeUInt16:
253 return static_cast<std::uint8_t>(std::get<std::uint16_t>(m_value));
254 case TypeUInt32:
255 return static_cast<std::uint8_t>(std::get<std::uint32_t>(m_value));
256 case TypeUInt64:
257 return static_cast<std::uint8_t>(std::get<std::uint64_t>(m_value));
258 case TypeFloat:
259 return static_cast<std::uint8_t>(std::lround(std::get<std::float_t>(m_value)));
260 case TypeDouble:
261 return static_cast<std::uint8_t>(std::lround(std::get<std::double_t>(m_value)));
262 case TypeString:
263 try
264 {
265 return static_cast<std::uint8_t>(std::stol(std::get<std::string>(m_value)));
266 }
267 catch (...)
268 {
269 break;
270 }
271 case TypeByteVector:
272 return DataToUint8(std::get<ByteVector>(m_value), pOk);
273 default:
274 break;
275 }
276
277 // Conversion not possible or not yet implemented!
278 if (pOk != nullptr) *pOk = false;
279
280 return std::uint8_t(0);
281}
282
283std::uint16_t Variant::ToUInt16(bool* pOk) const
284{
285 if (pOk != nullptr) *pOk = true;
286
287 switch (m_value.index())
288 {
289 case TypeBool:
290 return std::get<bool>(m_value) ? std::uint16_t(1) : std::uint16_t(0);
291 case TypeInt32:
292 return static_cast<std::uint16_t>(std::get<std::int32_t>(m_value));
293 case TypeUInt8:
294 return static_cast<std::uint16_t>(std::get<std::uint8_t>(m_value));
295 case TypeUInt16:
296 return std::get<std::uint16_t>(m_value);
297 case TypeUInt32:
298 return static_cast<std::uint16_t>(std::get<std::uint32_t>(m_value));
299 case TypeUInt64:
300 return static_cast<std::uint16_t>(std::get<std::uint64_t>(m_value));
301 case TypeFloat:
302 return static_cast<std::uint16_t>(std::lround(std::get<std::float_t>(m_value)));
303 case TypeDouble:
304 return static_cast<std::uint16_t>(std::lround(std::get<std::double_t>(m_value)));
305 case TypeString:
306 try
307 {
308 return static_cast<std::uint16_t>(std::stoi(std::get<std::string>(m_value)));
309 }
310 catch (...)
311 {
312 break;
313 }
314 case TypeByteVector:
315 return DataToUint16(std::get<ByteVector>(m_value), pOk);
316 default:
317 break;
318 }
319
320 // Conversion not possible or not yet implemented!
321 if (pOk != nullptr) *pOk = false;
322
323 return std::uint16_t(0);
324}
325
326std::uint32_t Variant::ToUInt32(bool* pOk) const
327{
328 if (pOk != nullptr) *pOk = true;
329
330 switch (m_value.index())
331 {
332 case TypeBool:
333 return std::get<bool>(m_value) ? std::uint32_t(1) : std::uint32_t(0);
334 case TypeInt32:
335 return static_cast<std::uint32_t>(std::get<std::int32_t>(m_value));
336 case TypeUInt8:
337 return static_cast<std::uint32_t>(std::get<std::uint8_t>(m_value));
338 case TypeUInt16:
339 return static_cast<std::uint32_t>(std::get<std::uint16_t>(m_value));
340 case TypeUInt32:
341 return static_cast<std::uint32_t>(std::get<std::uint32_t>(m_value));
342 case TypeUInt64:
343 return static_cast<std::uint32_t>(std::get<std::uint64_t>(m_value));
344 case TypeFloat:
345 return static_cast<std::uint32_t>(std::lround(std::get<std::float_t>(m_value)));
346 case TypeDouble:
347 return static_cast<std::uint32_t>(std::lround(std::get<std::double_t>(m_value)));
348 case TypeString:
349 try
350 {
351 return static_cast<std::uint32_t>(std::stoi(std::get<std::string>(m_value)));
352 }
353 catch (...)
354 {
355 break;
356 }
357 case TypeByteVector:
358 return DataToUint32(std::get<ByteVector>(m_value), pOk);
359 default:
360 break;
361 }
362
363 // Conversion not possible or not yet implemented!
364 if (pOk != nullptr) *pOk = false;
365
366 return std::uint32_t(0);
367}
368
369std::uint64_t Variant::ToUInt64(bool* pOk) const
370{
371 if (pOk != nullptr) *pOk = true;
372
373 switch (m_value.index())
374 {
375 case TypeBool:
376 return std::get<bool>(m_value) ? std::uint64_t(1) : std::uint64_t(0);
377 case TypeInt32:
378 return static_cast<std::uint64_t>(std::get<std::int32_t>(m_value));
379 case TypeUInt8:
380 return static_cast<std::uint64_t>(std::get<std::uint8_t>(m_value));
381 case TypeUInt16:
382 return static_cast<std::uint64_t>(std::get<std::uint16_t>(m_value));
383 case TypeUInt32:
384 return static_cast<std::uint64_t>(std::get<std::uint32_t>(m_value));
385 case TypeUInt64:
386 return static_cast<std::uint64_t>(std::get<std::uint64_t>(m_value));
387 case TypeFloat:
388 return static_cast<std::uint64_t>(std::llround(std::get<std::float_t>(m_value)));
389 case TypeDouble:
390 return static_cast<std::uint64_t>(std::llround(std::get<std::double_t>(m_value)));
391 case TypeString:
392 try
393 {
394 return static_cast<std::uint64_t>(std::stoll(std::get<std::string>(m_value)));
395 }
396 catch (...)
397 {
398 break;
399 }
400 case TypeByteVector:
401 return DataToUint64(std::get<ByteVector>(m_value), pOk);
402 default:
403 break;
404 }
405
406 // Conversion not possible or not yet implemented!
407 if (pOk != nullptr) *pOk = false;
408
409 return std::uint64_t(0);
410}
411
412std::double_t Variant::ToDouble(bool* pOk) const
413{
414 if (pOk != nullptr) *pOk = true;
415
416 switch (m_value.index())
417 {
418 case TypeBool:
419 return std::get<bool>(m_value) ? std::double_t(1.0) : std::double_t(0.0);
420 case TypeInt32:
421 return static_cast<std::double_t>(std::get<std::int32_t>(m_value));
422 case TypeUInt8:
423 return static_cast<std::double_t>(std::get<std::uint8_t>(m_value));
424 case TypeUInt16:
425 return static_cast<std::double_t>(std::get<std::uint16_t>(m_value));
426 case TypeUInt32:
427 return static_cast<std::double_t>(std::get<std::uint32_t>(m_value));
428 case TypeUInt64:
429 return static_cast<std::double_t>(std::get<std::uint64_t>(m_value));
430 case TypeFloat:
431 return static_cast<std::double_t>(std::get<std::float_t>(m_value));
432 case TypeDouble:
433 return std::get<std::double_t>(m_value);
434 case TypeString:
435 try
436 {
437 return std::stod(std::get<std::string>(m_value));
438 }
439 catch (...)
440 {
441 break;
442 }
443 case TypeByteVector:
444 return DataToDouble(std::get<ByteVector>(m_value), pOk);
445 default:
446 break;
447 }
448
449 // Conversion not possible or not yet implemented!
450 if (pOk != nullptr) *pOk = false;
451
452 return std::double_t(0.0);
453}
454
455std::float_t Variant::ToFloat(bool* pOk) const
456{
457 if (pOk != nullptr) *pOk = true;
458
459 switch (m_value.index())
460 {
461 case TypeBool:
462 return std::get<bool>(m_value) ? std::float_t(1.0f) : std::float_t(0.0f);
463 case TypeInt32:
464 return static_cast<std::float_t>(std::get<std::int32_t>(m_value));
465 case TypeUInt8:
466 return static_cast<std::float_t>(std::get<std::uint8_t>(m_value));
467 case TypeUInt16:
468 return static_cast<std::float_t>(std::get<std::uint16_t>(m_value));
469 case TypeUInt32:
470 return static_cast<std::float_t>(std::get<std::uint32_t>(m_value));
471 case TypeUInt64:
472 return static_cast<std::float_t>(std::get<std::uint64_t>(m_value));
473 case TypeFloat:
474 return std::get<std::float_t>(m_value);
475 case TypeDouble:
476 return static_cast<std::float_t>(std::get<std::double_t>(m_value));
477 case TypeString:
478 try
479 {
480 return static_cast<std::float_t>(std::stof(std::get<std::string>(m_value)));
481 }
482 catch (...)
483 {
484 break;
485 }
486 case TypeByteVector:
487 return DataToFloat(std::get<ByteVector>(m_value), pOk);
488 default:
489 break;
490 }
491
492 // Conversion not possible or not yet implemented!
493 if (pOk != nullptr) *pOk = false;
494
495 return std::float_t(0.0f);
496}
497
498std::string Variant::ToString(bool* pOk) const
499{
500 if (pOk != nullptr) *pOk = true;
501
502 switch (m_value.index())
503 {
504 case TypeBool:
505 return (std::get<bool>(m_value) ? "true" : "false");
506 case TypeInt32:
507 return std::to_string(std::get<std::int32_t>(m_value));
508 case TypeUInt8:
509 return std::to_string(std::get<std::uint8_t>(m_value));
510 case TypeUInt16:
511 return std::to_string(std::get<std::uint16_t>(m_value));
512 case TypeUInt32:
513 return std::to_string(std::get<std::uint32_t>(m_value));
514 case TypeUInt64:
515 return std::to_string(std::get<std::uint64_t>(m_value));
516 case TypeFloat:
517 return std::to_string(std::get<std::float_t>(m_value));
518 case TypeDouble:
519 return std::to_string(std::get<std::double_t>(m_value));
520 case TypeString:
521 return std::get<std::string>(m_value);
522 case TypeByteVector:
523 return DataToString(std::get<ByteVector>(m_value), pOk);
524 default:
525 break;
526 }
527
528 // Conversion not possible or not yet implemented!
529 if (pOk != nullptr) *pOk = false;
530
531 return std::string{};
532}
533
535{
536 if (pOk != nullptr) *pOk = true;
537
538 switch (m_value.index())
539 {
540 case TypeBool:
541 return DataFromBool(std::get<bool>(m_value));
542 case TypeInt32:
543 return DataFromInt32(std::get<std::int32_t>(m_value));
544 case TypeUInt8:
545 return DataFromUint8(std::get<std::uint8_t>(m_value));
546 case TypeUInt16:
547 return DataFromUint16(std::get<std::uint16_t>(m_value));
548 case TypeUInt32:
549 return DataFromUint32(std::get<std::uint32_t>(m_value));
550 case TypeUInt64:
551 return DataFromUint64(std::get<std::uint64_t>(m_value));
552 case TypeFloat:
553 return DataFromFloat(std::get<std::float_t>(m_value));
554 case TypeDouble:
555 return DataFromDouble(std::get<std::double_t>(m_value));
556 case TypeString:
557 return DataFromString(std::get<std::string>(m_value));
558 case TypeByteVector:
559 return std::get<ByteVector>(m_value);
560 default:
561 break;
562 }
563
564 // Conversion not possible or not yet implemented!
565 if (pOk != nullptr) *pOk = false;
566
567 return ByteVector{};
568}
569
570ByteVector Variant::ToParamData(Ocp1DataType type /* = OCP1DATATYPE_NONE */, bool* pOk) const
571{
572 if (pOk != nullptr) *pOk = true;
573
574 Ocp1DataType nativeType(type);
575 if (type == OCP1DATATYPE_NONE)
576 nativeType = GetDataType();
577
578 switch (nativeType)
579 {
581 return DataFromBool(ToBool(pOk));
583 return DataFromInt32(ToInt32(pOk));
585 return DataFromUint8(ToUInt8(pOk));
587 return DataFromUint16(ToUInt16(pOk));
589 return DataFromUint32(ToUInt32(pOk));
591 return DataFromUint64(ToUInt64(pOk));
593 return DataFromFloat(ToFloat(pOk));
595 return DataFromDouble(ToDouble(pOk));
597 return DataFromString(ToString(pOk));
599 return ToByteVector(pOk);
601 return ToByteVector(pOk);
609 default:
610 break;
611 }
612
613 // Conversion not possible or not yet implemented!
614 if (pOk != nullptr) *pOk = false;
615
616 return ByteVector{};
617}
618
619std::array<std::float_t, 3> Variant::ToPosition(bool* pOk) const
620{
621 std::array<std::float_t, 3> ret{ 0.0f };
622
623 if (m_value.index() != TypeByteVector)
624 {
625 if (pOk != nullptr)
626 *pOk = false;
627
628 return ret;
629 }
630
631 const auto& data = std::get<ByteVector>(m_value);
632 bool ok = ((data.size() == 12) || // Value contains 3 floats: x, y, z.
633 (data.size() == 36)); // Value contains 9 floats: x, y, z, plus min and max each on top.
634
635 if (ok)
636 ret[0] = NanoOcp1::DataToFloat(data, &ok); // x
637
638 if (ok)
639 ret[1] = NanoOcp1::DataToFloat(ByteVector(data.data() + 4, data.data() + 8), &ok); // y
640
641 if (ok)
642 ret[2] = NanoOcp1::DataToFloat(ByteVector(data.data() + 8, data.data() + 12), &ok); // z
643
644 if (pOk != nullptr)
645 *pOk = ok;
646
647 return ret;
648}
649
650std::string Variant::ToPositionString(bool* pOk) const
651{
652 bool ok;
653 std::string ret;
654
655 auto pos = ToPosition(&ok);
656 if (ok)
657 {
658 std::stringstream ss;
659 ss << pos[0] << ", " << pos[1] << ", " << pos[2];
660
661 ret = std::string(ss.str());
662 }
663
664 if (pOk != nullptr)
665 *pOk = ok;
666
667 return ret;
668}
669
670std::array<std::float_t, 6> Variant::ToPositionAndRotation(bool* pOk) const
671{
672 return ToAimingAndPosition(pOk);
673}
674
675std::array<std::float_t, 6> Variant::ToAimingAndPosition(bool* pOk) const
676{
677 std::array<std::float_t, 6> ret{ 0.0f };
678
679 if (m_value.index() != TypeByteVector)
680 {
681 if (pOk != nullptr)
682 *pOk = false;
683
684 return ret;
685 }
686
687 const auto& data = std::get<ByteVector>(m_value);
688 bool ok = (data.size() == 24); // Value contains 6 floats: horAngle, vertAngle, rotAngle, x, y, z.
689
690 if (ok)
691 ret[0] = NanoOcp1::DataToFloat(data, &ok); // hor
692
693 if (ok)
694 ret[1] = NanoOcp1::DataToFloat(ByteVector(data.data() + 4, data.data() + 8), &ok); // ver
695
696 if (ok)
697 ret[2] = NanoOcp1::DataToFloat(ByteVector(data.data() + 8, data.data() + 12), &ok); // rot
698
699 if (ok)
700 ret[3] = NanoOcp1::DataToFloat(ByteVector(data.data() + 12, data.data() + 16), &ok); // x
701
702 if (ok)
703 ret[4] = NanoOcp1::DataToFloat(ByteVector(data.data() + 16, data.data() + 20), &ok); // y
704
705 if (ok)
706 ret[5] = NanoOcp1::DataToFloat(ByteVector(data.data() + 20, data.data() + 24), &ok); // z
707
708 if (pOk != nullptr)
709 *pOk = ok;
710
711 return ret;
712}
713
714std::string Variant::ToAimingAndPositionString(bool* pOk) const
715{
716 bool ok;
717 std::string ret;
718
719 auto pos = ToAimingAndPosition(&ok);
720 if (ok)
721 {
722 std::stringstream ss;
723 ss << pos[0] << ", " << pos[1] << ", " << pos[2] << ", " <<
724 pos[3] << ", " << pos[4] << ", " << pos[5];
725
726 ret = std::string(ss.str());
727 }
728
729 if (pOk != nullptr)
730 *pOk = ok;
731
732 return ret;
733}
734
735std::vector<bool> Variant::ToBoolVector(bool* pOk) const
736{
737 std::vector<bool> boolVector;
738
739 if (m_value.index() != TypeByteVector)
740 {
741 if (pOk != nullptr)
742 *pOk = false;
743
744 return boolVector;
745 }
746
747 const auto& data = std::get<ByteVector>(m_value);
748 bool ok = (data.size() >= 2); // OcaList size takes up the first 2 bytes.
749
750 std::uint16_t listSize(0);
751 if (ok)
752 listSize = NanoOcp1::DataToUint16(data, &ok);
753
754 ok = ok && (data.size() == listSize + 2);
755 if (ok && listSize > 0)
756 {
757 boolVector.reserve(listSize);
758 std::size_t readPos(2); // Start after the OcaList size bytes
759 while (readPos < data.size() && ok)
760 {
761 ByteVector tmpData(data.data() + readPos, data.data() + readPos + 1);
762 boolVector.push_back(NanoOcp1::DataToBool(tmpData, &ok));
763 readPos++;
764 }
765 }
766
767 ok = ok && (boolVector.size() == listSize);
768
769 if (pOk != nullptr)
770 *pOk = ok;
771
772 return boolVector;
773}
774
775std::vector<std::string> Variant::ToStringVector(bool* pOk) const
776{
777 std::vector<std::string> stringVector;
778
779 if (m_value.index() != TypeByteVector)
780 {
781 if (pOk != nullptr)
782 *pOk = false;
783
784 return stringVector;
785 }
786
787 const auto& data = std::get<ByteVector>(m_value);
788 bool ok = (data.size() >= 2); // OcaList size takes up the first 2 bytes.
789
790 std::uint16_t listSize(0);
791 if (ok)
792 listSize = NanoOcp1::DataToUint16(data, &ok);
793
794 // Byte vector has the right size even assuming empty strings (min 2 bytes per string + 2 bytes for list size).
795 ok = ok && (data.size() >= ((listSize * 2) + 2));
796 if (ok && listSize > 0)
797 {
798 stringVector.reserve(static_cast<size_t>(listSize));
799 std::size_t readPos(2); // Start after the OcaList size bytes
800 while (readPos + 2 <= data.size() && ok)
801 {
802 ByteVector stringLenData(data.data() + readPos, data.data() + readPos + 2);
803 auto stringLen = NanoOcp1::DataToUint16(stringLenData, &ok);
804 readPos += 2;
805
806 ok = ok && (readPos + stringLen <= data.size());
807 if (ok)
808 {
809 stringVector.push_back(std::string(data.data() + readPos, data.data() + readPos + stringLen));
810 readPos += stringLen;
811 }
812 }
813 }
814
815 ok = ok && (stringVector.size() == listSize);
816
817 if (pOk != nullptr)
818 *pOk = ok;
819
820 return stringVector;
821}
822
823}
Type-erased OCA parameter value with built-in marshal/unmarshal support.
Definition Variant.h:102
std::array< std::float_t, 6 > ToAimingAndPosition(bool *pOk=nullptr) const
Definition Variant.cpp:675
@ TypeFloat
std::float_t (32-bit IEEE 754)
Definition Variant.h:305
@ TypeInt32
std::int32_t
Definition Variant.h:300
@ TypeByteVector
std::vector<uint8_t> — used for blobs and multi-float spatial types
Definition Variant.h:308
@ TypeUInt64
std::uint64_t
Definition Variant.h:304
@ TypeUInt8
std::uint8_t
Definition Variant.h:301
@ TypeDouble
std::double_t (64-bit IEEE 754)
Definition Variant.h:306
@ TypeString
std::string (OCA string: 2-byte length prefix + UTF-8 bytes)
Definition Variant.h:307
@ TypeNone
Default / unset state (std::monostate). IsValid() returns false.
Definition Variant.h:298
@ TypeUInt32
std::uint32_t
Definition Variant.h:303
@ TypeUInt16
std::uint16_t
Definition Variant.h:302
std::array< std::float_t, 6 > ToPositionAndRotation(bool *pOk=nullptr) const
Definition Variant.cpp:670
std::vector< bool > ToBoolVector(bool *pOk=nullptr) const
Definition Variant.cpp:735
bool IsValid() const
Definition Variant.cpp:135
bool ToBool(bool *pOk=nullptr) const
Returns the value as bool. Numeric types: non-zero = true.
Definition Variant.cpp:161
std::float_t ToFloat(bool *pOk=nullptr) const
Returns the value as float_t (32-bit). Conversion from double loses precision.
Definition Variant.cpp:455
std::string ToPositionString(bool *pOk=nullptr) const
Definition Variant.cpp:650
Ocp1DataType GetDataType() const
Definition Variant.cpp:140
std::vector< std::uint8_t > ToByteVector(bool *pOk=nullptr) const
Definition Variant.cpp:534
std::double_t ToDouble(bool *pOk=nullptr) const
Returns the value as double_t (64-bit).
Definition Variant.cpp:412
std::uint64_t ToUInt64(bool *pOk=nullptr) const
Returns the value as uint64_t.
Definition Variant.cpp:369
std::vector< std::uint8_t > ToParamData(Ocp1DataType type=OCP1DATATYPE_NONE, bool *pOk=nullptr) const
Definition Variant.cpp:570
std::uint8_t ToUInt8(bool *pOk=nullptr) const
Returns the value as uint8_t. Values outside [0, 255] are clamped/truncated.
Definition Variant.cpp:240
bool operator==(const Variant &other) const
Returns true if both Variants hold the same type and value.
Definition Variant.cpp:125
std::uint16_t ToUInt16(bool *pOk=nullptr) const
Returns the value as uint16_t.
Definition Variant.cpp:283
bool operator!=(const Variant &other) const
Returns true if the Variants differ in type or value.
Definition Variant.cpp:130
std::array< std::float_t, 3 > ToPosition(bool *pOk=nullptr) const
Definition Variant.cpp:619
std::uint32_t ToUInt32(bool *pOk=nullptr) const
Returns the value as uint32_t.
Definition Variant.cpp:326
std::string ToAimingAndPositionString(bool *pOk=nullptr) const
Definition Variant.cpp:714
std::int32_t ToInt32(bool *pOk=nullptr) const
Returns the value as int32_t. Numeric widening/narrowing applied as needed.
Definition Variant.cpp:197
std::string ToString(bool *pOk=nullptr) const
Returns the value as a std::string. Only succeeds if the internal type is TypeString; numeric types a...
Definition Variant.cpp:498
std::vector< std::string > ToStringVector(bool *pOk=nullptr) const
Definition Variant.cpp:775
Minimal AES70 / OCP.1 TCP client/server library built on JUCE.
Definition NanoOcp1.cpp:23
std::int32_t DataToInt32(const ByteVector &parameterData, bool *pOk)
std::string DataToString(const ByteVector &parameterData, bool *pOk)
std::vector< std::uint8_t > ByteVector
Binary buffer type used throughout NanoOcp for all serialized OCP.1 data.
std::float_t DataToFloat(const ByteVector &parameterData, bool *pOk)
Ocp1DataType
OCA base data type codes, matching OcaBaseDataType in the AES70 specification.
@ OCP1DATATYPE_BOOLEAN
Single byte: 0 = false, non-zero = true.
@ OCP1DATATYPE_CUSTOM
User-defined / vendor-specific type.
@ OCP1DATATYPE_FLOAT64
IEEE 754 double-precision float, big-endian (8 bytes).
@ OCP1DATATYPE_DB_POSITION
d&b-specific 3D position blob (3 × float32); used by deprecated position agent.
@ OCP1DATATYPE_NONE
No type; used as "not set" sentinel.
@ OCP1DATATYPE_INT16
Signed 16-bit integer, big-endian.
@ OCP1DATATYPE_STRING
OCA string: 2-byte big-endian length prefix followed by UTF-8 bytes.
@ OCP1DATATYPE_UINT16
Unsigned 16-bit integer, big-endian.
@ OCP1DATATYPE_INT8
Signed 8-bit integer.
@ OCP1DATATYPE_UINT64
Unsigned 64-bit integer, big-endian.
@ OCP1DATATYPE_UINT32
Unsigned 32-bit integer, big-endian.
@ OCP1DATATYPE_FLOAT32
IEEE 754 single-precision float, big-endian (4 bytes).
@ OCP1DATATYPE_BLOB
Variable-length binary blob; layout is property-specific.
@ OCP1DATATYPE_BLOB_FIXED_LEN
Fixed-length binary blob; size determined by the property definition.
@ OCP1DATATYPE_UINT8
Unsigned 8-bit integer.
@ OCP1DATATYPE_INT64
Signed 64-bit integer, big-endian.
@ OCP1DATATYPE_BIT_STRING
Packed bit string.
@ OCP1DATATYPE_INT32
Signed 32-bit integer, big-endian.
ByteVector DataFromUint64(std::uint64_t intValue)
ByteVector DataFromUint32(std::uint32_t intValue)
ByteVector DataFromFloat(std::float_t floatValue)
ByteVector DataFromBool(bool boolValue)
Convenience helper method to convert a bool into a byte vector.
std::uint8_t DataToUint8(const ByteVector &parameterData, bool *pOk)
std::uint32_t DataToUint32(const ByteVector &parameterData, bool *pOk)
ByteVector DataFromUint16(std::uint16_t value)
std::uint16_t DataToUint16(const ByteVector &parameterData, bool *pOk)
ByteVector DataFromString(const std::string &string)
ByteVector DataFromDouble(std::double_t doubleValue)
ByteVector DataFromUint8(std::uint8_t value)
ByteVector DataFromInt32(std::int32_t intValue)
std::double_t DataToDouble(const ByteVector &parameterData, bool *pOk)
std::uint64_t DataToUint64(const ByteVector &parameterData, bool *pOk)
bool DataToBool(const ByteVector &parameterData, bool *pOk)
Convenience helper method to convert a byte vector into a bool.