97 return "GUID: " + stubGUID;
99 return '#' + std::to_string(index);
106 return std::format(
"{}",
static_cast<int>(this->
getValue<bool>()));
110 std::stringstream hex;
111 hex << std::hex << std::setfill(
'0');
113 hex << std::setw(2) << static_cast<unsigned char>(
byte);
118 std::stringstream hex;
119 hex << std::hex << std::setfill(
'0');
121 hex << std::setw(2) << static_cast<unsigned char>(
byte);
129 return "rgba(" + std::to_string(r) +
", " + std::to_string(g) +
", " + std::to_string(b) +
", " + std::to_string(a) +
')';
133 return '[' + std::to_string(vec2[0]) +
", " + std::to_string(vec2[1]) +
']';
137 return '[' + std::to_string(vec3[0]) +
", " + std::to_string(vec3[1]) +
", " + std::to_string(vec3[2]) +
']';
141 return '[' + std::to_string(vec4[0]) +
", " + std::to_string(vec4[1]) +
", " + std::to_string(vec4[2]) +
", " + std::to_string(vec4[3]) +
']';
145 return '[' + std::to_string(angles[0]) +
", " + std::to_string(angles[1]) +
", " + std::to_string(angles[2]) +
']';
149 return '[' + std::to_string(quat[0]) +
", " + std::to_string(quat[1]) +
", " + std::to_string(quat[2]) +
", " + std::to_string(quat[3]) +
']';
154 for (
int i = 0; i < 4; i++) {
155 out += i == 0 ?
'[' :
' ';
156 for (
int j = 0; j < 4; j++) {
157 out += std::to_string(mat4[i][j]);
173 case ARRAY_ELEMENT: {
175 std::string out =
"[";
176 for (
int i = 0; i < elements.size(); i++) {
177 if (elements[i].index == -2) {
178 out += (i == 0 ?
"" :
" ") + std::string{
"GUID: "} + elements[i].externalGUID + (i == elements.size() - 1 ?
"" :
",");
180 out += (i == 0 ?
"" :
" ") + std::string{
"#"} + std::to_string(elements[i].index) + (i == elements.size() - 1 ?
"" :
",");
187 std::string out =
"[";
188 for (
int i = 0; i < ints.size(); i++) {
189 out += (i == 0 ?
"" :
" ") + std::to_string(ints[i]) + (i == ints.size() - 1 ?
"" :
",");
195 std::string out =
"[";
196 for (
int i = 0; i < floats.size(); i++) {
197 out += (i == 0 ?
"" :
" ") + std::to_string(floats[i]) + (i == floats.size() - 1 ?
"" :
",");
203 std::string out =
"[";
204 for (
int i = 0; i < bools.size(); i++) {
205 out += (i == 0 ?
"" :
" ") + std::string{bools[i] ?
"true" :
"false"} + (i == bools.size() - 1 ?
"" :
",");
211 std::string out =
"[";
212 for (
int i = 0; i < strings.size(); i++) {
213 out += (i == 0 ?
"" :
" ") + strings[i] + (i == strings.size() - 1 ?
"" :
",\n");
217 case ARRAY_BYTEARRAY: {
219 std::string out =
"[";
220 for (
int i = 0; i < bytearrays.size(); i++) {
221 std::stringstream hex;
222 hex << std::hex << std::setfill(
'0');
223 for (
auto byte : bytearrays[i]) {
224 hex << std::setw(2) << static_cast<unsigned char>(
byte);
226 out += (i == 0 ?
"" :
" ") + hex.str() + (i == bytearrays.size() - 1 ?
"" :
",\n");
232 std::string out =
"[";
233 for (
int i = 0; i < uuids.size(); i++) {
234 std::stringstream hex;
235 hex << std::hex << std::setfill(
'0');
236 for (
auto byte : uuids[i]) {
237 hex << std::setw(2) << static_cast<unsigned char>(
byte);
239 out += (i == 0 ?
"" :
" ") + hex.str() + (i == uuids.size() - 1 ?
"" :
",\n");
245 std::string out =
"[";
246 for (
int i = 0; i < times.size(); i++) {
247 out += (i == 0 ?
"" :
" ") + std::to_string(times[i]) + (i == times.size() - 1 ?
"" :
",");
253 std::string out =
"[";
254 for (
int i = 0; i < colors.size(); i++) {
255 out += (i == 0 ?
"" :
" ") + std::string{
"rgba("} + std::to_string(colors[i].r) +
", " + std::to_string(colors[i].g) +
", " + std::to_string(colors[i].b) +
", " + std::to_string(colors[i].a) +
')' + (i == colors.size() - 1 ?
"" :
",\n");
259 case ARRAY_VECTOR2: {
261 std::string out =
"[";
262 for (
int i = 0; i < vecs.size(); i++) {
263 out += (i == 0 ?
"" :
" ") + std::string{
"["} + std::to_string(vecs[i][0]) +
", " + std::to_string(vecs[i][1]) +
']' + (i == vecs.size() - 1 ?
"" :
",\n");
267 case ARRAY_VECTOR3: {
269 std::string out =
"[";
270 for (
int i = 0; i < vecs.size(); i++) {
271 out += (i == 0 ?
"" :
" ") + std::string{
"["} + std::to_string(vecs[i][0]) +
", " + std::to_string(vecs[i][1]) +
", " + std::to_string(vecs[i][2]) +
']' + (i == vecs.size() - 1 ?
"" :
",\n");
275 case ARRAY_VECTOR4: {
277 std::string out =
"[";
278 for (
int i = 0; i < vecs.size(); i++) {
279 out += (i == 0 ?
"" :
" ") + std::string{
"["} + std::to_string(vecs[i][0]) +
", " + std::to_string(vecs[i][1]) +
", " + std::to_string(vecs[i][2]) +
']' +
", " + std::to_string(vecs[i][3]) +
']' + (i == vecs.size() - 1 ?
"" :
",\n");
283 case ARRAY_EULER_ANGLES: {
285 std::string out =
"[";
286 for (
int i = 0; i < angles.size(); i++) {
287 out += (i == 0 ?
"" :
" ") + std::string{
"["} + std::to_string(angles[i][0]) +
", " + std::to_string(angles[i][1]) +
", " + std::to_string(angles[i][2]) +
']' + (i == angles.size() - 1 ?
"" :
",\n");
291 case ARRAY_QUATERNION: {
293 std::string out =
"[";
294 for (
int i = 0; i < quats.size(); i++) {
295 out += (i == 0 ?
"" :
" ") + std::string{
"["} + std::to_string(quats[i][0]) +
", " + std::to_string(quats[i][1]) +
", " + std::to_string(quats[i][2]) +
']' +
", " + std::to_string(quats[i][3]) +
']' + (i == quats.size() - 1 ?
"" :
",\n");
299 case ARRAY_MATRIX_4X4: {
301 std::string out =
"[";
302 for (
int m = 0; m < matrices.size(); m++) {
303 out += m == 0 ?
"[" :
" [";
304 for (
int i = 0; i < 4; i++) {
305 out += i == 0 ?
"" :
" ";
306 for (
int j = 0; j < 4; j++) {
307 out += std::to_string(matrices[m][i][j]);
317 if (m < matrices.size() - 1) {
325 std::string out =
"[";
326 for (
int i = 0; i < ints.size(); i++) {
327 out += (i == 0 ?
"" :
" ") + std::to_string(ints[i]) + (i == ints.size() - 1 ?
"" :
",");
333 std::string out =
"[";
334 for (
int i = 0; i < ints.size(); i++) {
335 out += (i == 0 ?
"" :
" ") + std::to_string(ints[i]) + (i == ints.size() - 1 ?
"" :
",");
511 BufferStreamReadOnly stream{dmxData};
514 static constexpr int MAX_FORMAT_LENGTH = 64;
515 static constexpr int MAX_HEADER_LENGTH = 40 + MAX_FORMAT_LENGTH * 2;
518 while (header.length() < MAX_HEADER_LENGTH) {
519 const char temp = stream.read<
char>();
520 if (temp ==
'\0' || temp ==
'\n') {
526 std::array<char, MAX_FORMAT_LENGTH> encodingTypeData{};
527 std::array<char, MAX_FORMAT_LENGTH> formatTypeData{};
529 static constexpr std::string_view HEADER_FORMAT =
"<!-- dmx encoding %63s %i format %63s %i -->";
530 static constexpr std::string_view HEADER_FORMAT_OLD =
"<!-- DMXVersion %63s_v%i -->";
533 bool headerParsed = sscanf_s(header.c_str(), HEADER_FORMAT.data(), encodingTypeData.data(), MAX_FORMAT_LENGTH, &this->encodingVersion, formatTypeData.data(), MAX_FORMAT_LENGTH, &this->formatVersion);
535 bool headerParsed = std::sscanf(header.c_str(), HEADER_FORMAT.data(), encodingTypeData.data(), &this->encodingVersion, formatTypeData.data(), &this->formatVersion);
540 headerParsed = sscanf_s(header.c_str(), HEADER_FORMAT_OLD.data(), encodingTypeData.data(), MAX_FORMAT_LENGTH, &this->encodingVersion);
542 headerParsed = std::sscanf(header.c_str(), HEADER_FORMAT_OLD.data(), encodingTypeData.data(), &this->encodingVersion);
551 std::string_view encodingTypeStr = encodingTypeData.data();
552 if (encodingTypeStr.starts_with(
"unicode_")) {
554 encodingTypeStr = encodingTypeStr.substr(8);
557 if (encodingTypeStr ==
"binary") {
559 }
else if (encodingTypeStr ==
"sfm") {
563 }
else if (encodingTypeStr ==
"keyvalues2") {
565 }
else if (encodingTypeStr ==
"keyvalues2_flat") {
574 std::string_view encodingTypeStr = encodingTypeData.data();
575 if (encodingTypeStr.starts_with(
"unicode_")) {
577 encodingTypeStr = encodingTypeStr.substr(8);
580 if (encodingTypeStr ==
"binary") {
582 }
else if (encodingTypeStr ==
"binary_seqids") {
584 }
else if (encodingTypeStr ==
"keyvalues2") {
586 }
else if (encodingTypeStr ==
"keyvalues2_flat") {
588 }
else if (encodingTypeStr ==
"keyvalues2_noids") {
601 const auto readBinary = [
this, &stream] {
605 const bool stringListExists = !isLegacyEncoding && this->
encodingVersion > 1;
606 const bool elementNamesAndStringValuesAreStoredInStringList = !isLegacyEncoding && this->encodingVersion > 3;
607 const bool stringListLengthIsShort = this->encodingVersion < 4;
608 const bool stringListIndicesAreShort = this->encodingVersion < 5;
609 const bool preloadAttributeListExists = !isLegacyEncoding && this->encodingVersion > 5;
612 if (stream.read<
char>() != 0) {
617 std::vector<std::string> stringList;
618 const auto readStringFromIndex = [stringListExists, stringListIndicesAreShort, &stringList](BufferStream& stream_) -> std::string {
619 if (!stringListExists) {
620 return stream_.read_string();
623 if (stringListIndicesAreShort) {
624 index = stream_.read<uint16_t>();
626 index = stream_.read<uint32_t>();
628 if (index >= stringList.size()) {
632 return stringList.at(index);
638 const auto readArrayValue = [&stream, &readValue]<
typename T>(
DMXValue::ID type_) {
640 auto size = stream.read<uint32_t>();
642 for (
int i = 0; i < size; i++) {
651 return std::monostate{};
654 value.
index = stream.read<int32_t>();
655 if (value.
index == -2) {
662 return stream.read<int32_t>();
664 return stream.read<
float>();
666 return stream.read<
bool>();
668 return useStringList ? readStringFromIndex(stream) : stream.read_string();
670 return stream.read_bytes(stream.read<uint32_t>());
672 return stream.read_bytes<16>();
674 return DMXValue::Time{
static_cast<float>(
static_cast<double>(stream.read<int32_t>()) / 10000.0)};
677 stream >> value.
r >> value.
g >> value.
b >> value.
a;
682 stream >> value[0] >> value[1];
687 stream >> value[0] >> value[1] >> value[2];
692 stream >> value[0] >> value[1] >> value[2] >> value[3];
697 stream >> value[0] >> value[1] >> value[2];
702 stream >> value[0] >> value[1] >> value[2] >> value[3];
708 >> value[0][0] >> value[0][1] >> value[0][2] >> value[0][3]
709 >> value[1][0] >> value[1][1] >> value[1][2] >> value[1][3]
710 >> value[2][0] >> value[2][1] >> value[2][2] >> value[2][3]
711 >> value[3][0] >> value[3][1] >> value[3][2] >> value[3][3];
715 return stream.read<uint64_t>();
717 return stream.read<uint8_t>();
721 return readArrayValue.operator()<int32_t>(
type);
723 return readArrayValue.operator()<
float>(
type);
725 return readArrayValue.operator()<
bool>(
type);
727 return readArrayValue.operator()<std::string>(
type);
728 case ARRAY_BYTEARRAY:
729 return readArrayValue.operator()<std::vector<std::byte>>(
type);
742 case ARRAY_EULER_ANGLES:
744 case ARRAY_QUATERNION:
746 case ARRAY_MATRIX_4X4:
749 return readArrayValue.operator()<uint64_t>(
type);
751 return readArrayValue.operator()<uint8_t>(
type);
753 return std::monostate{};
757 const auto readAttributes = [&stream, attributeIDVersion, &readStringFromIndex, &readValue](
DMXElement& element,
bool useStringList) {
758 const auto attributeCount = stream.read<int32_t>();
759 element.attributes.reserve(attributeCount);
761 for (
int i = 0; i < attributeCount; i++) {
763 auto& attribute = element.attributes.back();
765 attribute.setKey(readStringFromIndex(stream));
768 switch (attributeIDVersion) {
774 attribute.setValue(readValue(attributeID, useStringList));
779 if (preloadAttributeListExists) {
780 if (
const auto preloadElementCount = stream.read<uint32_t>()) {
782 for (uint32_t i = 0; i < preloadElementCount; i++) {
784 readAttributes(element,
false);
790 if (stringListExists) {
791 uint32_t stringCount;
792 if (stringListLengthIsShort) {
793 stringCount = stream.read<uint16_t>();
795 stringCount = stream.read<uint32_t>();
797 stringList.reserve(stringCount);
798 for (
int i = 0; i < stringCount; i++) {
799 stringList.push_back(stream.read_string());
804 const auto elementCount = stream.read<int32_t>();
805 this->
elements.reserve(elementCount);
807 for (
int i = 0; i < elementCount; i++) {
809 auto& element = this->
elements.back();
811 element.setType(readStringFromIndex(stream));
812 if (elementNamesAndStringValuesAreStoredInStringList) {
813 element.setKey(readStringFromIndex(stream));
815 element.setKey(stream.read_string());
817 element.setUUID(stream.read_bytes<16>());
821 for (
auto& element : this->
elements) {
822 readAttributes(element, elementNamesAndStringValuesAreStoredInStringList);
828 bool parseSuccess =
false;
836 parseSuccess = readBinary();
std::variant< std::monostate, Element, int32_t, float, bool, std::string, std::vector< std::byte >, UUID, Time, Color, Vector2, Vector3, Vector4, EulerAngles, Quaternion, Matrix4x4, uint64_t, uint8_t, std::vector< Element >, std::vector< int32_t >, std::vector< float >, std::vector< bool >, std::vector< std::string >, std::vector< std::vector< std::byte > >, std::vector< UUID >, std::vector< Time >, std::vector< Color >, std::vector< Vector2 >, std::vector< Vector3 >, std::vector< Vector4 >, std::vector< EulerAngles >, std::vector< Quaternion >, std::vector< Matrix4x4 >, std::vector< uint64_t >, std::vector< uint8_t > > Generic