From 487f42aa693724ece9e696c809f5c869d1295723 Mon Sep 17 00:00:00 2001 From: Malcolm Tyrrell Date: Sat, 29 Mar 2025 18:13:43 +0000 Subject: [PATCH 1/2] Optional apos escaping --- tinyxml2.cpp | 10 ++++++---- tinyxml2.h | 7 ++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index 66ef0c9..af48c14 100644 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -2577,7 +2577,7 @@ void XMLDocument::PopDepth() --_parsingDepth; } -XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : +XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth, EscapeAposCharsInAttributes aposInAttributes ) : _elementJustOpened( false ), _stack(), _firstElement( true ), @@ -2594,9 +2594,11 @@ XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) : } for( int i=0; i(entityValue); - TIXMLASSERT( flagIndex < ENTITY_RANGE ); - _entityFlag[flagIndex] = true; + if ((aposInAttributes == ESCAPE_APOS_CHARS_IN_ATTRIBUTES) || (entityValue != SINGLE_QUOTE)) { + const unsigned char flagIndex = static_cast(entityValue); + TIXMLASSERT( flagIndex < ENTITY_RANGE ); + _entityFlag[flagIndex] = true; + } } _restrictedEntityFlag[static_cast('&')] = true; _restrictedEntityFlag[static_cast('<')] = true; diff --git a/tinyxml2.h b/tinyxml2.h index 8179f57..aefe876 100644 --- a/tinyxml2.h +++ b/tinyxml2.h @@ -2240,13 +2240,18 @@ private: class TINYXML2_LIB XMLPrinter : public XMLVisitor { public: + enum EscapeAposCharsInAttributes { + ESCAPE_APOS_CHARS_IN_ATTRIBUTES, + DONT_ESCAPE_APOS_CHARS_IN_ATTRIBUTES + }; + /** Construct the printer. If the FILE* is specified, this will print to the FILE. Else it will print to memory, and the result is available in CStr(). If 'compact' is set to true, then output is created with only required whitespace and newlines. */ - XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 ); + XMLPrinter( FILE* file=0, bool compact = false, int depth = 0, EscapeAposCharsInAttributes aposInAttributes = ESCAPE_APOS_CHARS_IN_ATTRIBUTES ); virtual ~XMLPrinter() {} /** If streaming, write the BOM and declaration. */ From f87d0e30777753deb40986ee4fa6970607bad0ab Mon Sep 17 00:00:00 2001 From: Malcolm Tyrrell Date: Sun, 30 Mar 2025 10:20:26 +0100 Subject: [PATCH 2/2] Add test for new and default behaviour --- xmltest.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/xmltest.cpp b/xmltest.cpp index f7408d1..75d4bab 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -2695,6 +2695,41 @@ int main( int argc, const char ** argv ) XMLTest("Test attribute encode with a Hex value", value5, "!"); // hex value in unicode value } + // ---------- XMLPrinter Apos Escaping ------ + { + const char* testText = "text containing a ' character"; + XMLDocument doc; + XMLElement* element = doc.NewElement( "element" ); + doc.InsertEndChild( element ); + element->SetAttribute( "attrib", testText ); + { + XMLPrinter defaultPrinter; + doc.Print( &defaultPrinter ); + const char* defaultOutput = defaultPrinter.CStr(); + const bool foundTextWithUnescapedApos = (strstr(defaultOutput, testText) != nullptr); + XMLTest("Default XMLPrinter should escape ' characters", false, foundTextWithUnescapedApos); + { + XMLDocument parsingDoc; + parsingDoc.Parse(defaultOutput); + const XMLAttribute* attrib = parsingDoc.FirstChildElement("element")->FindAttribute("attrib"); + XMLTest("Default XMLPrinter should output parsable xml", testText, attrib->Value(), true); + } + } + { + XMLPrinter customPrinter(0, false, 0, XMLPrinter::DONT_ESCAPE_APOS_CHARS_IN_ATTRIBUTES); + doc.Print( &customPrinter ); + const char* customOutput = customPrinter.CStr(); + const bool foundTextWithUnescapedApos = (strstr(customOutput, testText) != nullptr); + XMLTest("Custom XMLPrinter should not escape ' characters", true, foundTextWithUnescapedApos); + { + XMLDocument parsingDoc; + parsingDoc.Parse(customOutput); + const XMLAttribute* attrib = parsingDoc.FirstChildElement("element")->FindAttribute("attrib"); + XMLTest("Custom XMLPrinter should output parsable xml", testText, attrib->Value(), true); + } + } + } + // ----------- Performance tracking -------------- { #if defined( _MSC_VER )