From fe7bceeb794bc227050fae46e37e6ceff606b131 Mon Sep 17 00:00:00 2001 From: tetektoza Date: Sat, 27 Dec 2025 18:51:01 +0100 Subject: [PATCH] Gui: Escape XML special characters in attributes for XHTML Add escapeXmlAttribute() helper function to properly escape special characters in XML attribute values: - Double quotes (") --> " - Ampersands (&) --> & - Less-than (<) --> < - Greater-than (>) --> > - Single quotes (') --> ' --- src/Gui/SoFCDB.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/Gui/SoFCDB.cpp b/src/Gui/SoFCDB.cpp index ce403a6483..4144658330 100644 --- a/src/Gui/SoFCDB.cpp +++ b/src/Gui/SoFCDB.cpp @@ -497,6 +497,43 @@ bool Gui::SoFCDB::writeToX3D(SoNode* node, bool exportViewpoints, std::string& b return true; } +namespace +{ +std::string escapeXmlAttribute(const char* str) +{ + if (!str) { + return std::string(); + } + + std::string result; + result.reserve(strlen(str)); + + for (const char* p = str; *p; ++p) { + switch (*p) { + case '"': + result.append("""); + break; + case '&': + result.append("&"); + break; + case '<': + result.append("<"); + break; + case '>': + result.append(">"); + break; + case '\'': + result.append("'"); + break; + default: + result.push_back(*p); + break; + } + } + return result; +} +} // namespace + void Gui::SoFCDB::writeX3DFields( SoNode* node, std::map& nodeMap, @@ -522,7 +559,8 @@ void Gui::SoFCDB::writeX3DFields( } nodeMap[node] = str.str(); - out << " DEF=\"" << str.str() << "\""; + std::string escapedName = escapeXmlAttribute(str.str().c_str()); + out << " DEF=\"" << escapedName << "\""; } const SoFieldData* fielddata = node->getFieldData(); @@ -545,9 +583,12 @@ void Gui::SoFCDB::writeX3DFields( ba = ba.simplified(); } + // escape XML special characters in attribute value + std::string escapedValue = escapeXmlAttribute(ba.data()); + out << '\n' << Base::blanks(spaces + 2) << fielddata->getFieldName(i).getString() - << "=\"" << ba.data() << "\" "; + << "=\"" << escapedValue << "\" "; } else { numFieldNodes++; @@ -606,7 +647,8 @@ void Gui::SoFCDB::writeX3DChild( // remove the VRML prefix from the type name std::string sftype(node->getTypeId().getName().getString()); sftype = sftype.substr(4); - out << Base::blanks(spaces) << "<" << sftype << " USE=\"" << mapIt->second << "\" />\n"; + std::string escapedRef = escapeXmlAttribute(mapIt->second.c_str()); + out << Base::blanks(spaces) << "<" << sftype << " USE=\"" << escapedRef << "\" />\n"; } }