96 return std::format(
"{}{}", index == -2 ?
"GUID: " :
"#", index);
103 return std::format(
"{}",
static_cast<int>(this->
getValue<bool>()));
107 std::stringstream hex;
108 hex << std::hex << std::setfill(
'0');
110 hex << std::setw(2) << static_cast<unsigned char>(
byte);
115 std::stringstream hex;
116 hex << std::hex << std::setfill(
'0');
118 hex << std::setw(2) << static_cast<unsigned char>(
byte);
126 return std::format(
"rgba({}, {}, {}, {})", r, g, b, a);
130 return std::format(
"[{}, {}]", vec2[0], vec2[1]);
134 return std::format(
"[{}, {}, {}]", vec3[0], vec3[1], vec3[2]);
138 return std::format(
"[{}, {}, {}, {}]", vec4[0], vec4[1], vec4[2], vec4[3]);
142 return std::format(
"[{}, {}, {}]", angles[0], angles[1], angles[2]);
146 return std::format(
"[{}, {}, {}, {}]", quat[0], quat[1], quat[2], quat[3]);
151 for (
int i = 0; i < 4; i++) {
152 out += i == 0 ?
'[' :
' ';
153 for (
int j = 0; j < 4; j++) {
154 out += std::format(
"{}{}", mat4[i][j], j < 3 ?
", " : i < 3 ?
",\n" :
"]");
163 case ARRAY_ELEMENT: {
165 std::string out =
"[";
166 for (
int i = 0; i < elements.size(); i++) {
167 if (elements[i].index == -2) {
168 out += std::format(
"{}GUID: {}{}", i == 0 ?
"" :
" ", elements[i].externalGUID, i == elements.size() - 1 ?
"" :
",");
170 out += std::format(
"{}#{}{}", i == 0 ?
"" :
" ", elements[i].index, i == elements.size() - 1 ?
"" :
",");
177 std::string out =
"[";
178 for (
int i = 0; i < ints.size(); i++) {
179 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", ints[i], i == ints.size() - 1 ?
"" :
",");
185 std::string out =
"[";
186 for (
int i = 0; i < floats.size(); i++) {
187 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", floats[i], i == floats.size() - 1 ?
"" :
",");
193 std::string out =
"[";
194 for (
int i = 0; i < bools.size(); i++) {
196 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ",
static_cast<bool>(bools[i]), i == bools.size() - 1 ?
"" :
",");
202 std::string out =
"[";
203 for (
int i = 0; i < strings.size(); i++) {
204 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", strings[i], i == strings.size() - 1 ?
"" :
",\n");
208 case ARRAY_BYTEARRAY: {
210 std::string out =
"[";
211 for (
int i = 0; i < bytearrays.size(); i++) {
212 std::stringstream hex;
213 hex << std::hex << std::setfill(
'0');
214 for (
auto byte : bytearrays[i]) {
215 hex << std::setw(2) << static_cast<unsigned char>(
byte);
217 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", hex.str(), i == bytearrays.size() - 1 ?
"" :
",\n");
223 std::string out =
"[";
224 for (
int i = 0; i < uuids.size(); i++) {
225 std::stringstream hex;
226 hex << std::hex << std::setfill(
'0');
227 for (
auto byte : uuids[i]) {
228 hex << std::setw(2) << static_cast<unsigned char>(
byte);
230 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", hex.str(), i == uuids.size() - 1 ?
"" :
",\n");
236 std::string out =
"[";
237 for (
int i = 0; i < times.size(); i++) {
238 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", times[i].seconds, i == times.size() - 1 ?
"" :
",");
244 std::string out =
"[";
245 for (
int i = 0; i < colors.size(); i++) {
246 out += std::format(
"{}rgba({}, {}, {}, {}){}", i == 0 ?
"" :
" ", colors[i].r, colors[i].g, colors[i].b, colors[i].a, i == colors.size() - 1 ?
"" :
",\n");
250 case ARRAY_VECTOR2: {
252 std::string out =
"[";
253 for (
int i = 0; i < vecs.size(); i++) {
254 out += std::format(
"{}[{}, {}]{}", i == 0 ?
"" :
" ", vecs[i][0], vecs[i][1], i == vecs.size() - 1 ?
"" :
",\n");
258 case ARRAY_VECTOR3: {
260 std::string out =
"[";
261 for (
int i = 0; i < vecs.size(); i++) {
262 out += std::format(
"{}[{}, {}, {}]{}", i == 0 ?
"" :
" ", vecs[i][0], vecs[i][1], vecs[i][2], i == vecs.size() - 1 ?
"" :
",\n");
266 case ARRAY_VECTOR4: {
268 std::string out =
"[";
269 for (
int i = 0; i < vecs.size(); i++) {
270 out += std::format(
"{}[{}, {}, {}, {}]{}", i == 0 ?
"" :
" ", vecs[i][0], vecs[i][1], vecs[i][2], vecs[i][3], i == vecs.size() - 1 ?
"" :
",\n");
274 case ARRAY_EULER_ANGLES: {
276 std::string out =
"[";
277 for (
int i = 0; i < angles.size(); i++) {
278 out += std::format(
"{}[{}, {}, {}]{}", i == 0 ?
"" :
" ", angles[i][0], angles[i][1], angles[i][2], i == angles.size() - 1 ?
"" :
",\n");
282 case ARRAY_QUATERNION: {
284 std::string out =
"[";
285 for (
int i = 0; i < quats.size(); i++) {
286 out += std::format(
"{}[{}, {}, {}, {}]{}", i == 0 ?
"" :
" ", quats[i][0], quats[i][1], quats[i][2], quats[i][3], i == quats.size() - 1 ?
"" :
",\n");
290 case ARRAY_MATRIX_4X4: {
292 std::string out =
"[";
293 for (
int m = 0; m < matrices.size(); m++) {
294 out += m == 0 ?
"[" :
" [";
295 for (
int i = 0; i < 4; i++) {
296 out += i == 0 ?
"" :
" ";
297 for (
int j = 0; j < 4; j++) {
298 out += std::format(
"{}{}", matrices[m][i][j], j < 3 ?
", " : i < 3 ?
",\n" :
"]");
301 if (m < matrices.size() - 1) {
309 std::string out =
"[";
310 for (
int i = 0; i < ints.size(); i++) {
311 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", ints[i], i == ints.size() - 1 ?
"" :
",");
317 std::string out =
"[";
318 for (
int i = 0; i < ints.size(); i++) {
319 out += std::format(
"{}{}{}", i == 0 ?
"" :
" ", ints[i], i == ints.size() - 1 ?
"" :
",");
495 BufferStreamReadOnly stream{dmxData};
498 static constexpr int MAX_FORMAT_LENGTH = 64;
499 static constexpr int MAX_HEADER_LENGTH = 40 + MAX_FORMAT_LENGTH * 2;
502 while (header.length() < MAX_HEADER_LENGTH) {
503 const char temp = stream.read<
char>();
504 if (temp ==
'\0' || temp ==
'\n') {
510 std::array<char, MAX_FORMAT_LENGTH> encodingTypeData{};
511 std::array<char, MAX_FORMAT_LENGTH> formatTypeData{};
513 static constexpr std::string_view HEADER_FORMAT =
"<!-- dmx encoding %63s %i format %63s %i -->";
514 static constexpr std::string_view HEADER_FORMAT_OLD =
"<!-- DMXVersion %63s_v%i -->";
517 bool headerParsed = sscanf_s(header.c_str(), HEADER_FORMAT.data(), encodingTypeData.data(), MAX_FORMAT_LENGTH, &this->encodingVersion, formatTypeData.data(), MAX_FORMAT_LENGTH, &this->formatVersion);
519 bool headerParsed = std::sscanf(header.c_str(), HEADER_FORMAT.data(), encodingTypeData.data(), &this->encodingVersion, formatTypeData.data(), &this->formatVersion);
524 headerParsed = sscanf_s(header.c_str(), HEADER_FORMAT_OLD.data(), encodingTypeData.data(), MAX_FORMAT_LENGTH, &this->encodingVersion);
526 headerParsed = std::sscanf(header.c_str(), HEADER_FORMAT_OLD.data(), encodingTypeData.data(), &this->encodingVersion);
535 std::string_view encodingTypeStr = encodingTypeData.data();
536 if (encodingTypeStr.starts_with(
"unicode_")) {
538 encodingTypeStr = encodingTypeStr.substr(8);
541 if (encodingTypeStr ==
"binary") {
543 }
else if (encodingTypeStr ==
"sfm") {
547 }
else if (encodingTypeStr ==
"keyvalues2") {
549 }
else if (encodingTypeStr ==
"keyvalues2_flat") {
558 std::string_view encodingTypeStr = encodingTypeData.data();
559 if (encodingTypeStr.starts_with(
"unicode_")) {
561 encodingTypeStr = encodingTypeStr.substr(8);
564 if (encodingTypeStr ==
"binary") {
566 }
else if (encodingTypeStr ==
"binary_seqids") {
568 }
else if (encodingTypeStr ==
"keyvalues2") {
570 }
else if (encodingTypeStr ==
"keyvalues2_flat") {
572 }
else if (encodingTypeStr ==
"keyvalues2_noids") {
585 const auto readBinary = [
this, &stream] {
589 const bool stringListExists = !isLegacyEncoding && this->
encodingVersion > 1;
590 const bool elementNamesAndStringValuesAreStoredInStringList = !isLegacyEncoding && this->encodingVersion > 3;
591 const bool stringListLengthIsShort = this->encodingVersion < 4;
592 const bool stringListIndicesAreShort = this->encodingVersion < 5;
593 const bool preloadAttributeListExists = !isLegacyEncoding && this->encodingVersion > 5;
596 if (stream.read<
char>() != 0) {
601 std::vector<std::string> stringList;
602 const auto readStringFromIndex = [stringListExists, stringListIndicesAreShort, &stringList](BufferStream& stream_) -> std::string {
603 if (!stringListExists) {
604 return stream_.read_string();
607 if (stringListIndicesAreShort) {
608 index = stream_.read<uint16_t>();
610 index = stream_.read<uint32_t>();
612 if (index >= stringList.size()) {
616 return stringList.at(index);
622 const auto readArrayValue = [&stream, &readValue]<
typename T>(
DMXValue::ID type_) {
624 auto size = stream.read<uint32_t>();
626 for (
int i = 0; i < size; i++) {
635 return std::monostate{};
638 value.
index = stream.read<int32_t>();
639 if (value.
index == -2) {
646 return stream.read<int32_t>();
648 return stream.read<
float>();
650 return stream.read<
bool>();
652 return useStringList ? readStringFromIndex(stream) : stream.read_string();
654 return stream.read_bytes(stream.read<uint32_t>());
656 return stream.read_bytes<16>();
658 return DMXValue::Time{
static_cast<float>(
static_cast<double>(stream.read<int32_t>()) / 10000.0)};
661 stream >> value.
r >> value.
g >> value.
b >> value.
a;
666 stream >> value[0] >> value[1];
671 stream >> value[0] >> value[1] >> value[2];
676 stream >> value[0] >> value[1] >> value[2] >> value[3];
681 stream >> value[0] >> value[1] >> value[2];
686 stream >> value[0] >> value[1] >> value[2] >> value[3];
692 >> value[0][0] >> value[0][1] >> value[0][2] >> value[0][3]
693 >> value[1][0] >> value[1][1] >> value[1][2] >> value[1][3]
694 >> value[2][0] >> value[2][1] >> value[2][2] >> value[2][3]
695 >> value[3][0] >> value[3][1] >> value[3][2] >> value[3][3];
699 return stream.read<uint64_t>();
701 return stream.read<uint8_t>();
705 return readArrayValue.operator()<int32_t>(
type);
707 return readArrayValue.operator()<
float>(
type);
709 return readArrayValue.operator()<
bool>(
type);
711 return readArrayValue.operator()<std::string>(
type);
712 case ARRAY_BYTEARRAY:
713 return readArrayValue.operator()<std::vector<std::byte>>(
type);
726 case ARRAY_EULER_ANGLES:
728 case ARRAY_QUATERNION:
730 case ARRAY_MATRIX_4X4:
733 return readArrayValue.operator()<uint64_t>(
type);
735 return readArrayValue.operator()<uint8_t>(
type);
737 return std::monostate{};
741 const auto readAttributes = [&stream, attributeIDVersion, &readStringFromIndex, &readValue](
DMXElement& element,
bool useStringList) {
742 const auto attributeCount = stream.read<int32_t>();
743 element.attributes.reserve(attributeCount);
745 for (
int i = 0; i < attributeCount; i++) {
747 auto& attribute = element.attributes.back();
749 attribute.setKey(readStringFromIndex(stream));
752 switch (attributeIDVersion) {
758 attribute.setValue(readValue(attributeID, useStringList));
763 if (preloadAttributeListExists) {
764 if (
const auto preloadElementCount = stream.read<uint32_t>()) {
766 for (uint32_t i = 0; i < preloadElementCount; i++) {
768 readAttributes(element,
false);
774 if (stringListExists) {
775 uint32_t stringCount;
776 if (stringListLengthIsShort) {
777 stringCount = stream.read<uint16_t>();
779 stringCount = stream.read<uint32_t>();
781 stringList.reserve(stringCount);
782 for (
int i = 0; i < stringCount; i++) {
783 stringList.push_back(stream.read_string());
788 const auto elementCount = stream.read<int32_t>();
789 this->
elements.reserve(elementCount);
791 for (
int i = 0; i < elementCount; i++) {
793 auto& element = this->
elements.back();
795 element.setType(readStringFromIndex(stream));
796 if (elementNamesAndStringValuesAreStoredInStringList) {
797 element.setKey(readStringFromIndex(stream));
799 element.setKey(stream.read_string());
801 element.setUUID(stream.read_bytes<16>());
805 for (
auto& element : this->
elements) {
806 readAttributes(element, elementNamesAndStringValuesAreStoredInStringList);
812 bool parseSuccess =
false;
820 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