
TinyXML 2.6.2 mit Korrekturen für CVE-2021-42260 und CVE-2023-34194
/** @mainpage
TinyXML ist ein einfacher, kleiner C++-XML-Parser, der leicht in andere Programme integriert werden kann.
Kurz gesagt: TinyXML parst ein XML-Dokument und erstellt daraus ein Document Object Model (DOM), das gelesen, geändert und gespeichert werden kann.
XML steht für „eXtensible Markup Language". Es ermöglicht Ihnen, eigene Dokument-Auszeichnungen zu erstellen. Während HTML Dokumente für Browser sehr gut auszeichnet, erlaubt es XML, jede Art von Dokument-Auszeichnung zu definieren, zum Beispiel ein Dokument, das eine „To-do"-Liste für eine Organizer-Anwendung beschreibt. XML ist ein sehr strukturiertes und praktisches Format. Alle beliebigen Dateiformate, die zum Speichern von Anwendungsdaten erstellt wurden, können durch XML ersetzt werden. Ein Parser für alles.
Der beste Ort für die vollständige, korrekte und offen gesagt schwer zu lesende Spezifikation ist http://www.w3.org/TR/2004/REC-xml-20040204/. Eine Einführung in XML (die ich wirklich mag) finden Sie unter http://skew.org/xml/tutorial.
Es gibt verschiedene Möglichkeiten, auf XML-Daten zuzugreifen und mit ihnen zu interagieren. TinyXML verwendet ein Document Object Model (DOM), d. h. die XML-Daten werden in C++-Objekte geparst, die durchsucht und manipuliert und dann auf die Festplatte oder in einen anderen Ausgabestrom geschrieben werden können. Sie können ein XML-Dokument auch von Grund auf mit C++-Objekten erstellen und dieses auf die Festplatte oder in einen anderen Ausgabestrom schreiben.
TinyXML ist darauf ausgelegt, einfach und schnell erlernbar zu sein. Es besteht aus zwei Headern und vier CPP-Dateien. Fügen Sie diese einfach zu Ihrem Projekt hinzu und los geht's. Es gibt eine Beispieldatei – xmltest.cpp –, die Ihnen den Einstieg erleichtert.
TinyXML wird unter der ZLib-Lizenz veröffentlicht, sodass Sie es in Open-Source- oder kommerziellem Code verwenden können. Die Details der Lizenz stehen am Anfang jeder Quelldatei.
TinyXML versucht, ein flexibler Parser zu sein, aber mit wirklich korrekter und konformer XML-Ausgabe. TinyXML sollte auf jedem halbwegs C++-konformen System kompilieren. Es verlässt sich nicht auf Exceptions oder RTTI. Es kann mit oder ohne STL-Unterstützung kompiliert werden. TinyXML unterstützt die UTF-8-Kodierung und die ersten 64k Zeichenentitäten vollständig.
TinyXML parst oder verwendet keine DTDs (Document Type Definitions) oder XSLs (eXtensible Stylesheet Language). Es gibt andere Parser da draußen (schauen Sie auf www.sourceforge.org vorbei, suchen Sie nach XML), die wesentlich umfangreicher ausgestattet sind. Aber sie sind auch viel größer, brauchen länger für die Einrichtung in Ihrem Projekt, haben eine steilere Lernkurve und oft eine restriktivere Lizenz. Wenn Sie mit Browsern arbeiten oder umfassendere XML-Anforderungen haben, ist TinyXML nicht der richtige Parser für Sie.
Die folgende DTD-Syntax wird derzeit in TinyXML nicht geparst:
@verbatim ]> @endverbatim
da TinyXML dies als einen !DOCTYPE-Knoten mit einem unzulässig eingebetteten !ELEMENT-Knoten betrachtet. Dies könnte in Zukunft behoben werden.
Für die Ungeduldigen gibt es hier ein Tutorial, um loszulegen. Ein großartiger Weg, um den Einstieg zu finden, aber es lohnt sich, dieses (sehr kurze) Handbuch vollständig zu lesen.
TinyXML ist ausgereifter, getesteter Code. Es ist sehr stabil. Wenn Sie Fehler finden, melden Sie bitte einen Fehlerbericht auf der SourceForge-Website (www.sourceforge.net/projects/tinyxml). Wir werden sie so schnell wie möglich beheben.
Es gibt einige Bereiche mit Verbesserungspotenzial; schauen Sie bitte auf SourceForge vorbei, wenn Sie Interesse daran haben, an TinyXML mitzuarbeiten.
TinyXML-Projekte, die Sie nützlich finden könnten! (Beschreibungen von den Projekten bereitgestellt.)
TinyXML kann so kompiliert werden, dass es STL verwendet oder nicht. Bei Verwendung von STL nutzt TinyXML die Klasse std::string und unterstützt vollständig std::istream, std::ostream, operator<< und operator>>. Viele API-Methoden gibt es sowohl in der 'const char*'- als auch in der 'const std::string&'-Form.
Wenn die STL-Unterstützung herauskompiliert wird, werden überhaupt keine STL-Dateien eingebunden. Alle String-Klassen werden von TinyXML selbst implementiert. API-Methoden verwenden für die Eingabe alle die 'const char*'-Form.
Verwenden Sie das #define zur Compile-Zeit:
TIXML_USE_STL
um die eine oder andere Version zu kompilieren. Dies kann dem Compiler übergeben oder als erste Zeile von „tinyxml.h" gesetzt werden.
Hinweis: Wenn Sie den Testcode unter Linux kompilieren, steuert das Setzen der Umgebungsvariable TINYXML_USE_STL=YES/NO die STL-Kompilierung. In der Windows-Projektdatei werden STL- und Nicht-STL-Ziele bereitgestellt. In Ihrem Projekt ist es wahrscheinlich am einfachsten, die Zeile „#define TIXML_USE_STL" als erste Zeile von tinyxml.h hinzuzufügen.
TinyXML unterstützt UTF-8 und ermöglicht so die Bearbeitung von XML-Dateien in jeder Sprache. TinyXML unterstützt auch den „Legacy-Modus" – die Kodierung, die vor der UTF-8-Unterstützung verwendet wurde und wohl am besten als „erweitertes ASCII" beschrieben werden kann.
Normalerweise versucht TinyXML, die korrekte Kodierung zu erkennen und zu verwenden. Durch das Setzen des Werts von TIXML_DEFAULT_ENCODING in der Header-Datei kann TinyXML jedoch gezwungen werden, immer eine bestimmte Kodierung zu verwenden.
TinyXML geht vom Legacy-Modus aus, bis einer der folgenden Fälle eintritt:
Was passiert, wenn die Kodierung falsch gesetzt oder erkannt wird? TinyXML versucht, Text, der als falsch kodiert angesehen wird, zu lesen und durchzureichen. Möglicherweise erhalten Sie seltsame Ergebnisse oder verstümmelte Zeichen. Möglicherweise möchten Sie TinyXML in den korrekten Modus zwingen.
Sie können TinyXML mit LoadFile( TIXML_ENCODING_LEGACY ) oder LoadFile( filename, TIXML_ENCODING_LEGACY ) in den Legacy-Modus zwingen. Sie können es zwingen, den Legacy-Modus immer zu verwenden, indem Sie TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY setzen. Ebenso können Sie es mit derselben Technik auf TIXML_ENCODING_UTF8 zwingen.
Für englischsprachige Benutzer, die englisches XML verwenden, ist UTF-8 dasselbe wie Low-ASCII. Sie müssen sich UTF-8 nicht bewusst sein oder Ihren Code in irgendeiner Weise ändern. Sie können sich UTF-8 als „Obermenge" von ASCII vorstellen.
UTF-8 ist kein Doppelbyte-Format – aber es ist eine Standardkodierung von Unicode! TinyXML verwendet oder unterstützt derzeit weder wchar, TCHAR noch Microsofts _UNICODE. Es ist üblich, dass der Begriff „Unicode" fälschlich für UTF-16 verwendet wird, eine Breitbyte-Kodierung von Unicode. Dies ist eine Quelle der Verwirrung.
Für „Hoch-ASCII"-Sprachen – so ziemlich alles außer Englisch – kann TinyXML alle Sprachen gleichzeitig verarbeiten, solange das XML in UTF-8 kodiert ist. Das kann etwas knifflig sein: Ältere Programme und Betriebssysteme neigen dazu, die „Standard"- oder „traditionelle" Codepage zu verwenden. Viele Apps (und fast alle modernen) können UTF-8 ausgeben, aber ältere oder hartnäckige (oder einfach defekte) geben Text weiterhin in der Standard-Codepage aus.
Japanische Systeme verwenden beispielsweise traditionell die SHIFT-JIS-Kodierung. Mit SHIFT-JIS kodierter Text kann von TinyXML nicht gelesen werden. Ein guter Texteditor kann SHIFT-JIS importieren und dann als UTF-8 speichern.
Der Skew.org-Link leistet hervorragende Arbeit bei der Behandlung des Kodierungsthemas.
Die Testdatei „utf8test.xml" ist ein XML, das Englisch, Spanisch, Russisch und vereinfachtes Chinesisch enthält. (Hoffentlich sind sie korrekt übersetzt.) Die Datei „utf8test.gif" ist ein Screenshot der XML-Datei, gerendert im IE. Beachten Sie, dass Sie ohne die richtigen Schriftarten (Vereinfachtes Chinesisch oder Russisch) auf Ihrem System keine Ausgabe sehen, die zur GIF-Datei passt, selbst wenn Sie sie korrekt parsen können. Beachten Sie außerdem, dass (zumindest auf meinem Windows-Rechner) die Konsolenausgabe in einer westlichen Codepage erfolgt, sodass Print() oder printf() die Datei nicht korrekt anzeigen können. Das ist kein Fehler in TinyXML – nur ein OS-Problem. Von TinyXML gehen keine Daten verloren oder werden zerstört. Die Konsole rendert UTF-8 einfach nicht.
@verbatim & & < < > > " " ' ' @endverbatim
Diese werden beim Lesen des XML-Dokuments erkannt und in ihre UTF-8-Äquivalente übersetzt. Zum Beispiel hat Text mit dem folgenden XML:
@verbatim Far & Away @endverbatim
beim Abfragen des TiXmlText-Objekts den Wert Value() von „Far & Away" und wird als kaufmännisches Und zurück in den XML-Stream bzw. die XML-Datei geschrieben. Ältere Versionen von TinyXML haben Zeichenentitäten „erhalten", die neueren Versionen übersetzen sie jedoch in Zeichen.
Darüber hinaus kann jedes Zeichen über seinen Unicode-Codepunkt angegeben werden: Die Syntax „ " oder „ " verweist beides auf das geschützte Leerzeichen.
Print( FILE* ). Ausgabe in einen C-Standard-Stream, der alle C-Dateien sowie stdout umfasst.
operator<<. Ausgabe in einen C++-Stream.
TiXmlPrinter. Ausgabe in einen std::string oder Speicherpuffer.
C-Stil-Ausgabe: - basiert auf FILE* - die Methoden Print() und SaveFile()
Erzeugt formatierte Ausgabe mit viel Leerraum, die so gut wie möglich
für Menschen lesbar sein soll. Sie sind sehr schnell und tolerant gegenüber fehlerhaft
aufgebauten XML-Dokumenten. Beispielsweise wird ein XML-Dokument, das 2 Wurzelelemente
und 2 Deklarationen enthält, trotzdem ausgegeben.
C-Stil-Eingabe: - basiert auf FILE* - die Methoden Parse() und LoadFile()
Ein schnelles, tolerantes Lesen. Verwenden Sie es, wann immer Sie die C++-Streams
nicht benötigen.
C++-Stil-Ausgabe: - basiert auf std::ostream - operator<<
Erzeugt kompakte Ausgabe, die eher für die Netzwerkübertragung als für die
Lesbarkeit gedacht ist. Je nach Implementierung der ostream-Klasse auf Ihrem System
können diese etwas langsamer sein. (Oder auch nicht.) Nicht tolerant gegenüber fehlerhaft
aufgebautem XML: Ein Dokument sollte das eine korrekte Wurzelelement enthalten.
Zusätzliche Elemente auf Wurzelebene werden nicht gestreamt.
C++-Stil-Eingabe: - basiert auf std::istream - operator>>
Liest XML aus einem Stream, was es für die Netzwerkübertragung nützlich macht. Der knifflige
Teil ist zu wissen, wann das XML-Dokument vollständig ist, da mit ziemlicher
Sicherheit weitere Daten im Stream vorhanden sein werden. TinyXML nimmt an, dass die XML-Daten
vollständig sind, sobald es das Wurzelelement gelesen hat. Anders ausgedrückt: Dokumente,
die fehlerhaft mit mehr als einem Wurzelelement aufgebaut sind, werden nicht korrekt gelesen.
Beachten Sie auch, dass operator>> etwas langsamer ist als Parse, sowohl aufgrund der
STL-Implementierung als auch aufgrund von Einschränkungen von TinyXML.
Dies ist ein Problem, das zu meiner Zufriedenheit noch nicht gelöst ist. TinyXML unterstützt die ersten 2 Ansätze. Rufen Sie TiXmlBase::SetCondenseWhiteSpace( bool ) auf, um das gewünschte Verhalten festzulegen. Standardmäßig wird Leerraum komprimiert.
Wenn Sie die Standardeinstellung ändern, sollten Sie TiXmlBase::SetCondenseWhiteSpace( bool ) aufrufen, bevor Sie Aufrufe zum Parsen von XML-Daten tätigen, und ich empfehle nicht, dies zu ändern, nachdem es gesetzt wurde.
Beim robusten Durchsuchen eines XML-Dokuments ist es wichtig, auf Null-Rückgaben von Methodenaufrufen zu prüfen. Eine fehlersichere Implementierung kann viel Code erzeugen, etwa so:
@verbatim TiXmlElement* root = document.FirstChildElement( "Document" ); if ( root ) { TiXmlElement* element = root->FirstChildElement( "Element" ); if ( element ) { TiXmlElement* child = element->FirstChildElement( "Child" ); if ( child ) { TiXmlElement* child2 = child->NextSiblingElement( "Child" ); if ( child2 ) { // Finally do something useful. @endverbatim
Zur Bereinigung wurden Handles eingeführt. Mit der Klasse TiXmlHandle reduziert sich der vorherige Code zu:
@verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // do something useful @endverbatim
Das ist viel einfacher zu handhaben. Weitere Informationen finden Sie unter TiXmlHandle.
TinyXML kann den Zeilen- und Spaltenursprung aller Knoten und Attribute in einer Textdatei verfolgen. Die Methoden TiXmlBase::Row() und TiXmlBase::Column() geben den Ursprung des Knotens im Quelltext zurück. Die korrekten Tabs können in TiXmlDocument::SetTabSize() konfiguriert werden.
So kompilieren und führen Sie xmltest aus:
Es werden ein Linux-Makefile und eine Windows-Visual-C++-.dsw-Datei bereitgestellt. Einfach kompilieren und ausführen. Es schreibt die Datei demotest.xml auf Ihre Festplatte und erzeugt eine Ausgabe auf dem Bildschirm. Es testet auch das Durchlaufen des DOM, indem es die Anzahl der mit verschiedenen Techniken gefundenen Knoten ausgibt.
Das Linux-Makefile ist sehr generisch und läuft auf vielen Systemen – es wird derzeit auf MinGW und MacOSX getestet. Sie müssen kein 'make depend' ausführen. Die Abhängigkeiten wurden fest kodiert.
PROFILE, DEBUG und TINYXML_USE_STL. Details (so gut sie auch sind) finden Sie im Makefile.
Geben Sie im Verzeichnis tinyxml „make clean" und dann „make" ein. Die ausführbare Datei 'xmltest' wird erstellt.
Fügen Sie tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp und tinystr.h zu Ihrem Projekt oder Ihrer Make-Datei hinzu. Das war's! Es sollte auf jedem halbwegs konformen C++-System kompilieren. Sie müssen für TinyXML weder Exceptions noch RTTI aktivieren.
Ein Beispiel ist wahrscheinlich der beste Weg. Nehmen Sie: @verbatim <?xml version="1.0" standalone=no> Go to the Toy store! Do bills @endverbatim
Es ist nicht gerade eine großartige To-do-Liste, aber es genügt. Um diese Datei zu lesen (sagen wir „demo.xml"), würden Sie ein Dokument erstellen und es einlesen: @verbatim TiXmlDocument doc( "demo.xml" ); doc.LoadFile(); @endverbatim
Und es ist bereit. Schauen wir uns nun einige Zeilen an und wie sie sich zum DOM verhalten.
@verbatim
@endverbatim Die erste Zeile ist eine Deklaration und wird in die Klasse TiXmlDeclaration umgewandelt. Sie wird das erste Kind des Dokumentknotens sein. Dies ist das einzige Direktiven-/Sonder-Tag, das von TinyXML geparst wird. Im Allgemeinen werden Direktiven-Tags in TiXmlUnknown gespeichert, damit die Befehle beim Speichern auf der Festplatte nicht verloren gehen. @verbatim @endverbatim Ein Kommentar. Wird zu einem TiXmlComment-Objekt. @verbatim @endverbatim Das „ToDo"-Tag definiert ein TiXmlElement-Objekt. Dieses hat keine Attribute, enthält aber 2 weitere Elemente. @verbatim @endverbatim Erzeugt ein weiteres TiXmlElement, das ein Kind des „ToDo"-Elements ist. Dieses Element hat 1 Attribut mit dem Namen „priority" und dem Wert „1". @verbatim Go to the @endverbatim Ein TiXmlText. Dies ist ein Blattknoten und kann keine anderen Knoten enthalten. Es ist ein Kind des „Item"-TiXmlElements. @verbatim @endverbatim Ein weiteres TiXmlElement, diesmal ein Kind des „Item"-Elements. Usw. Betrachtet man den gesamten Objektbaum, erhält man: @verbatim TiXmlDocument "demo.xml" TiXmlDeclaration "version='1.0'" "standalone=no" TiXmlComment " Our to do list data" TiXmlElement "ToDo" TiXmlElement "Item" Attribtutes: priority = 1 TiXmlText "Go to the " TiXmlElement "bold" TiXmlText "Toy store!" TiXmlElement "Item" Attributes: priority=2 TiXmlText "Do bills" @endverbatim