
TinyXML 2.6.2 with fixes for CVE-2021-42260 and CVE-2023-34194
/** @mainpage
TinyXML — это простой, небольшой парсер XML на C++, который можно легко интегрировать в другие программы.
Вкратце, TinyXML разбирает XML-документ и строит из него объектную модель документа (DOM), которую можно читать, изменять и сохранять.
XML расшифровывается как «eXtensible Markup Language» (расширяемый язык разметки). Он позволяет создавать собственные разметки документов. В то время как HTML отлично подходит для разметки документов для браузеров, XML позволяет определить любой вид разметки документов, например, документ, описывающий список «дел» для приложения-органайзера. XML — очень структурированный и удобный формат. Все те случайные форматы файлов, созданные для хранения данных приложений, могут быть заменены XML. Один парсер для всего.
Лучшее место для полной, корректной и, честно говоря, сложной для чтения спецификации находится по адресу http://www.w3.org/TR/2004/REC-xml-20040204/. Введение в XML (которое мне очень нравится) можно найти по адресу http://skew.org/xml/tutorial.
Существуют разные способы доступа и взаимодействия с XML-данными. TinyXML использует объектную модель документа (DOM), то есть XML-данные разбираются в объекты C++, которые можно просматривать и изменять, а затем записывать на диск или в другой выходной поток. Вы также можете создать XML-документ с нуля с помощью объектов C++ и записать его на диск или в другой выходной поток.
TinyXML спроектирован так, чтобы его было легко и быстро изучать. Он состоит из двух заголовочных файлов и четырёх файлов cpp. Просто добавьте их в свой проект — и готово. Есть пример файла — xmltest.cpp, чтобы вы могли начать.
TinyXML распространяется под лицензией ZLib, поэтому вы можете использовать его как в открытом, так и в коммерческом коде. Подробности лицензии находятся в начале каждого исходного файла.
TinyXML стремится быть гибким парсером, но с действительно корректным и соответствующим стандарту XML-выводом. TinyXML должен компилироваться на любой достаточно соответствующей стандарту C++ системе. Он не полагается на исключения или RTTI. Его можно скомпилировать с поддержкой STL или без неё. TinyXML полностью поддерживает кодировку UTF-8 и первые 64k символьных сущностей.
TinyXML не разбирает и не использует DTD (определения типов документов) или XSL (расширяемый язык таблиц стилей). Существуют другие парсеры (посмотрите на www.sourceforge.org, поищите XML), которые обладают гораздо более полными возможностями. Но они также гораздо больше, требуют больше времени на настройку в вашем проекте, имеют более крутую кривую обучения и часто имеют более ограничительную лицензию. Если вы работаете с браузерами или вам нужны более полные возможности XML, TinyXML — не ваш выбор.
Следующий синтаксис DTD не будет разобран в текущей версии TinyXML:
@verbatim ]> @endverbatim
потому что TinyXML видит это как узел !DOCTYPE с незаконно встроенным узлом !ELEMENT. Это может быть исправлено в будущем.
Для нетерпеливых — вот руководство, чтобы начать. Отличный способ начать, но стоит прочитать это (очень короткое) руководство полностью.
TinyXML — зрелый, проверенный код. Он очень стабилен. Если вы найдёте ошибки, пожалуйста, отправьте отчёт об ошибке на веб-сайте sourceforge (www.sourceforge.net/projects/tinyxml). Мы исправим их как можно скорее.
Есть некоторые области для улучшения; пожалуйста, проверьте sourceforge, если вы заинтересованы в работе над TinyXML.
Проекты TinyXML, которые могут вам пригодиться! (Описания предоставлены проектами.)
TinyXML может быть скомпилирован с использованием или без использования STL. При использовании STL TinyXML использует класс std::string и полностью поддерживает std::istream, std::ostream, operator<< и operator>>. Многие методы API имеют как формы 'const char*', так и 'const std::string&'.
Когда поддержка STL отключена, файлы STL вообще не включаются. Все строковые классы реализованы самим TinyXML. Методы API используют форму 'const char*' для ввода.
Используйте директиву времени компиляции #define:
TIXML_USE_STL
чтобы скомпилировать одну или другую версию. Это можно передать компилятору или установить в первой строке «tinyxml.h».
Примечание: При компиляции тестового кода в Linux установка переменной среды TINYXML_USE_STL=YES/NO будет управлять компиляцией STL. В файле проекта Windows предоставлены цели для STL и без STL. В вашем проекте, вероятно, проще всего добавить строку «#define TIXML_USE_STL» в качестве первой строки tinyxml.h.
TinyXML поддерживает UTF-8, что позволяет манипулировать XML-файлами на любом языке. TinyXML также поддерживает «устаревший режим» — кодировку, использовавшуюся до поддержки UTF-8 и вероятно лучше всего описываемую как «расширенный ASCII».
Обычно TinyXML пытается определить правильную кодировку и использовать её. Однако, установив значение TIXML_DEFAULT_ENCODING в заголовочном файле, TinyXML можно заставить всегда использовать одну кодировку.
TinyXML будет предполагать устаревший режим, пока не произойдет одно из следующего:
Что произойдёт, если кодировка установлена или определена неправильно? TinyXML попытается читать и пропускать текст, который выглядит неправильно закодированным. Вы можете получить странные результаты или искажённые символы. Возможно, вам потребуется принудительно установить для TinyXML правильный режим.
Вы можете принудительно переключить TinyXML в устаревший режим с помощью LoadFile( TIXML_ENCODING_LEGACY ) или LoadFile( filename, TIXML_ENCODING_LEGACY ). Вы можете принудительно заставить его использовать устаревший режим всё время, установив TIXML_DEFAULT_ENCODING = TIXML_ENCODING_LEGACY. Аналогично, вы можете принудительно установить TIXML_ENCODING_UTF8 с помощью той же техники.
Для англоязычных пользователей, использующих английский XML, UTF-8 — это то же самое, что низкий ASCII. Вам не нужно знать о UTF-8 или как-либо менять свой код. Вы можете думать о UTF-8 как о «надмножестве» ASCII.
UTF-8 — это не двухбайтовый формат — это стандартная кодировка Unicode! TinyXML в настоящее время не использует и не поддерживает напрямую wchar, TCHAR или Microsoft _UNICODE. Часто можно встретить неправильное использование термина «Unicode» для обозначения UTF-16, широкобайтной кодировки юникода. Это источник путаницы.
Для языков с «высоким ASCII» — практически всё, кроме английского — TinyXML может обрабатывать все языки одновременно, при условии, что XML закодирован в UTF-8. Это может быть немного сложно: старые программы и операционные системы часто используют «стандартную» или «традиционную» кодовую страницу. Многие приложения (и почти все современные) могут выводить UTF-8, но старые или упрямые (или просто сломанные) до сих пор выводят текст в стандартной кодовой странице.
Например, японские системы традиционно используют кодировку SHIFT-JIS. Текст, закодированный как SHIFT-JIS, не может быть прочитан TinyXML. Хороший текстовый редактор может импортировать SHIFT-JIS, а затем сохранить как UTF-8.
Ссылка на Skew.org отлично освещает проблему кодировки.
Тестовый файл «utf8test.xml» — это XML, содержащий английский, испанский, русский и упрощённый китайский языки. (Надеюсь, они переведены правильно). Файл «utf8test.gif» — это снимок экрана XML-файла, отображённого в IE. Обратите внимание, что если у вас нет правильных шрифтов (упрощённый китайский или русский) в вашей системе, вы не увидите вывод, соответствующий GIF-файлу, даже если сможете разобрать его правильно. Также обратите внимание, что (по крайней мере на моей Windows-машине) вывод консоли находится в западной кодовой странице, поэтому Print() или printf() не могут правильно отобразить файл. Это не ошибка TinyXML — просто проблема ОС. Никакие данные не теряются и не повреждаются TinyXML. Просто консоль не отображает UTF-8.
@verbatim & & < < > > " " ' ' @endverbatim
Они распознаются при чтении XML-документа и преобразуются в их эквиваленты UTF-8. Например, текст с XML:
@verbatim Far & Away @endverbatim
будет иметь Value() = «Far & Away» при запросе из объекта TiXmlText, и будет записан обратно в XML-поток/файл как амперсанд. Старые версии TinyXML «сохраняли» символьные сущности, но новые версии преобразуют их в символы.
Кроме того, любой символ может быть указан по его кодовой точке Unicode: синтаксис « » или « » оба относятся к символу неразрывного пробела.
Print( FILE* ). Вывод в поток std-C, который включает все C-файлы, а также stdout.
operator<<. Вывод в поток c++.
TiXmlPrinter. Вывод в std::string или буфер памяти.
Вывод в стиле C: - основан на FILE* - методы Print() и SaveFile()
Создаёт форматированный вывод, с большим количеством пробелов, предназначенный для максимальной
читаемости человеком. Они очень быстры и терпимы к плохо сформированным
XML-документам. Например, XML-документ, содержащий 2 корневых элемента
и 2 объявления, всё равно будет напечатан.
Ввод в стиле C: - основан на FILE* - методы Parse() и LoadFile()
Быстрое, терпимое чтение. Используйте, когда не нужны потоки C++.
Вывод в стиле C++: - основан на std::ostream - operator<<
Создаёт сжатый вывод, предназначенный для сетевой передачи, а не для
читаемости. В зависимости от реализации класса ostream в вашей системе,
они могут быть несколько медленнее. (Или не могут.) Не терпим к плохо сформированному XML:
документ должен содержать один правильный корневой элемент. Дополнительные корневые
элементы не будут выведены.
Ввод в стиле C++: - основан на std::istream - operator>>
Читает XML из потока, что делает его полезным для сетевой передачи. Сложная
часть — знать, когда XML-документ завершён, поскольку в потоке почти наверняка будут
другие данные. TinyXML будет считать XML-данные
полными после чтения корневого элемента. Другими словами, документы,
которые плохо построены и содержат более одного корневого элемента, не будут читаться правильно.
Также обратите внимание, что operator>> несколько медленнее, чем Parse, из-за как
реализации STL, так и ограничений TinyXML.
Это вопрос, который не был решён к моему удовлетворению. TinyXML поддерживает первые 2 подхода. Вызовите TiXmlBase::SetCondenseWhiteSpace( bool ), чтобы установить желаемое поведение. По умолчанию пробелы сжимаются.
Если вы измените значение по умолчанию, вам следует вызвать TiXmlBase::SetCondenseWhiteSpace( bool ) перед любыми вызовами для разбора XML-данных, и я не рекомендую изменять его после установки.
При надёжном просмотре XML-документа важно проверять нулевые возвраты из вызовов методов. Безопасная с точки зрения обработки ошибок реализация может генерировать много кода, например:
@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
Для упрощения были введены дескрипторы. Используя класс TiXmlHandle, предыдущий код сводится к:
@verbatim TiXmlHandle docHandle( &document ); TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); if ( child2 ) { // do something useful @endverbatim
Что гораздо проще в работе. Смотрите TiXmlHandle для получения дополнительной информации.
TinyXML может отслеживать строку и столбец происхождения всех узлов и атрибутов в текстовом файле. Методы TiXmlBase::Row() и TiXmlBase::Column() возвращают происхождение узла в исходном тексте. Правильные табуляции можно настроить в TiXmlDocument::SetTabSize().
Чтобы скомпилировать и запустить xmltest:
Предоставлены Makefile для Linux и файл .dsw для Windows Visual C++. Просто скомпилируйте и запустите. Он запишет файл demotest.xml на ваш диск и выведет результат на экран. Он также тестирует обход DOM, выводя количество найденных узлов с использованием различных методов.
Makefile для Linux очень универсален и работает во многих системах — он в настоящее время протестирован на mingw и MacOSX. Вам не нужно запускать 'make depend'. Зависимости прописаны жёстко.
PROFILE, DEBUG и TINYXML_USE_STL. Подробности (насколько они есть) находятся в makefile.
В каталоге tinyxml введите "make clean", затем "make". Исполняемый файл 'xmltest' будет создан.
Добавьте tinyxml.cpp, tinyxml.h, tinyxmlerror.cpp, tinyxmlparser.cpp, tinystr.cpp и tinystr.h в ваш проект или make-файл. Вот и всё! Он должен компилироваться на любой достаточно соответствующей стандарту C++ системе. Вам не нужно включать исключения или RTTI для TinyXML.
Лучший способ — это пример. Возьмём: @verbatim <?xml version="1.0" standalone=no> Пойти в Магазин игрушек! Оплатить счета @endverbatim
Это не самый большой список дел, но подойдёт. Чтобы прочитать этот файл (скажем, «demo.xml»), вы создадите документ и разберёте его: @verbatim TiXmlDocument doc( "demo.xml" ); doc.LoadFile(); @endverbatim
И он готов к использованию. Теперь давайте посмотрим на несколько строк и как они соотносятся с DOM.
@verbatim
@endverbatim Первая строка — это объявление, и она превращается в класс TiXmlDeclaration. Это будет первый дочерний элемент узла документа. Это единственная директива/специальный тег, разбираемый TinyXML. Обычно директивы хранятся в TiXmlUnknown, чтобы команды не были потеряны при сохранении обратно на диск. @verbatim @endverbatim Комментарий. Станет объектом TiXmlComment. @verbatim @endverbatim Тег «ToDo» определяет объект TiXmlElement. Этот не имеет атрибутов, но содержит 2 других элемента. @verbatim @endverbatim Создаёт ещё один TiXmlElement, который является дочерним элементом «ToDo». Этот элемент имеет 1 атрибут с именем «priority» и значением «1». @verbatim Пойти в @endverbatim TiXmlText. Это листовой узел и не может содержать другие узлы. Он является дочерним элементом TiXmlElement «Item». @verbatim @endverbatim Ещё один TiXmlElement, на этот раз дочерний элемент «Item». И так далее. Рассматривая всё дерево объектов, вы получаете: @verbatim TiXmlDocument "demo.xml" TiXmlDeclaration "version='1.0'" "standalone=no" TiXmlComment " Наш список дел" TiXmlElement "ToDo" TiXmlElement "Item" Атрибуты: priority = 1 TiXmlText "Пойти в " TiXmlElement "bold" TiXmlText "Магазин игрушек!" TiXmlElement "Item" Атрибуты: priority=2 TiXmlText "Оплатить счета" @endverbatim