mirror of
https://github.com/leethomason/tinyxml2.git
synced 2026-07-25 21:23:00 +04:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8224e427b6 | |||
| 935ddecc91 | |||
| 88d678c39e | |||
| 999a21fa86 | |||
| a737ecb2cb | |||
| 9901919829 | |||
| 63428c8852 | |||
| beb16fbca0 | |||
| 26ab0bd591 | |||
| 8d8472fe1a | |||
| 3dcad8e3c3 | |||
| 418229dc5c |
@@ -1,12 +1,11 @@
|
|||||||
TinyXML-2
|
# TinyXML-2
|
||||||
=========
|
|
||||||
|
|
||||||
[](https://github.com/leethomason/tinyxml2/actions/workflows/test.yml)
|
[](https://github.com/leethomason/tinyxml2/actions/workflows/test.yml)
|
||||||
|
|
||||||
TinyXML-2 is a simple, small, efficient, C++ XML parser that can be
|
TinyXML-2 is a simple, small, efficient, C++ XML parser that can be
|
||||||
easily integrated into other programs.
|
easily integrated into other programs.
|
||||||
|
|
||||||
The master is hosted on github:
|
The master is hosted on GitHub:
|
||||||
https://github.com/leethomason/tinyxml2
|
https://github.com/leethomason/tinyxml2
|
||||||
|
|
||||||
The online HTML version of these docs:
|
The online HTML version of these docs:
|
||||||
@@ -14,8 +13,7 @@ http://leethomason.github.io/tinyxml2/
|
|||||||
|
|
||||||
Examples are in the "related pages" tab of the HTML docs.
|
Examples are in the "related pages" tab of the HTML docs.
|
||||||
|
|
||||||
What it does.
|
## What it does.
|
||||||
-------------
|
|
||||||
|
|
||||||
In brief, TinyXML-2 parses an XML document, and builds from that a
|
In brief, TinyXML-2 parses an XML document, and builds from that a
|
||||||
Document Object Model (DOM) that can be read, modified, and saved.
|
Document Object Model (DOM) that can be read, modified, and saved.
|
||||||
@@ -37,7 +35,7 @@ code without creating a document first.
|
|||||||
|
|
||||||
TinyXML-2 is designed to be easy and fast to learn. It is one header and
|
TinyXML-2 is designed to be easy and fast to learn. It is one header and
|
||||||
one cpp file. Simply add these to your project and off you go.
|
one cpp file. Simply add these to your project and off you go.
|
||||||
There is an example file - xmltest.cpp - to get you started.
|
There is an example file - `xmltest.cpp` - to get you started.
|
||||||
|
|
||||||
TinyXML-2 is released under the ZLib license,
|
TinyXML-2 is released under the ZLib license,
|
||||||
so you can use it in open source or commercial code. The details
|
so you can use it in open source or commercial code. The details
|
||||||
@@ -45,10 +43,10 @@ of the license are at the top of every source file.
|
|||||||
|
|
||||||
TinyXML-2 attempts to be a flexible parser, but with truly correct and
|
TinyXML-2 attempts to be a flexible parser, but with truly correct and
|
||||||
compliant XML output. TinyXML-2 should compile on any reasonably C++
|
compliant XML output. TinyXML-2 should compile on any reasonably C++
|
||||||
compliant system. It does not rely on exceptions, RTTI, or the STL.
|
compliant system. It does not rely on exceptions, run-time type information,
|
||||||
|
or the C++ Standard Library.
|
||||||
|
|
||||||
What it doesn't do.
|
## What it doesn't do.
|
||||||
-------------------
|
|
||||||
|
|
||||||
TinyXML-2 doesn't parse or use DTDs (Document Type Definitions) or XSLs
|
TinyXML-2 doesn't parse or use DTDs (Document Type Definitions) or XSLs
|
||||||
(eXtensible Stylesheet Language.) There are other parsers out there
|
(eXtensible Stylesheet Language.) There are other parsers out there
|
||||||
@@ -56,8 +54,7 @@ that are much more fully featured. But they are generally bigger and
|
|||||||
more difficult to use. If you are working with
|
more difficult to use. If you are working with
|
||||||
browsers or have more complete XML needs, TinyXML-2 is not the parser for you.
|
browsers or have more complete XML needs, TinyXML-2 is not the parser for you.
|
||||||
|
|
||||||
TinyXML-1 vs. TinyXML-2
|
## TinyXML-1 vs. TinyXML-2
|
||||||
-----------------------
|
|
||||||
|
|
||||||
TinyXML-2 has long been the focus of all development. It is well tested
|
TinyXML-2 has long been the focus of all development. It is well tested
|
||||||
and should be used instead of TinyXML-1.
|
and should be used instead of TinyXML-1.
|
||||||
@@ -67,10 +64,10 @@ rich test cases. But the implementation of the parser is completely re-written
|
|||||||
to make it more appropriate for use in a game. It uses less memory, is faster,
|
to make it more appropriate for use in a game. It uses less memory, is faster,
|
||||||
and uses far fewer memory allocations.
|
and uses far fewer memory allocations.
|
||||||
|
|
||||||
TinyXML-2 has no requirement or support for STL.
|
TinyXML-2 has no dependency on the C++ Standard Library, and does not adapt or use any
|
||||||
|
of its collection types either.
|
||||||
|
|
||||||
Features
|
## Features
|
||||||
--------
|
|
||||||
|
|
||||||
### Code Page
|
### Code Page
|
||||||
|
|
||||||
@@ -81,17 +78,17 @@ Filenames for loading / saving are passed unchanged to the underlying OS.
|
|||||||
|
|
||||||
### Memory Model
|
### Memory Model
|
||||||
|
|
||||||
An XMLDocument is a C++ object like any other, that can be on the stack, or
|
An `XMLDocument` is a C++ object like any other, that can be on the stack, or
|
||||||
new'd and deleted on the heap.
|
`new`'d and `delete`d on the heap.
|
||||||
|
|
||||||
However, any sub-node of the Document, XMLElement, XMLText, etc, can only
|
However, any sub-node of the `XMLDocument`, `XMLElement`, `XMLText`, etc, can only
|
||||||
be created by calling the appropriate XMLDocument::NewElement, NewText, etc.
|
be created by calling the appropriate `XMLDocument::NewElement`, `XMLDocument::NewText`, etc.
|
||||||
method. Although you have pointers to these objects, they are still owned
|
method. Although you have pointers to these objects, they are still owned
|
||||||
by the Document. When the Document is deleted, so are all the nodes it contains.
|
by the `XMLDocument`. When the `XMLDocument` is `delete`d, so are all the nodes it contains.
|
||||||
|
|
||||||
### White Space
|
### White Space
|
||||||
|
|
||||||
#### Whitespace Preservation (default, PRESERVE_WHITESPACE)
|
#### Whitespace Preservation (default, `PRESERVE_WHITESPACE`)
|
||||||
|
|
||||||
Microsoft has an excellent article on white space: http://msdn.microsoft.com/en-us/library/ms256097.aspx
|
Microsoft has an excellent article on white space: http://msdn.microsoft.com/en-us/library/ms256097.aspx
|
||||||
|
|
||||||
@@ -103,51 +100,57 @@ line-feed character, as required by the XML spec.
|
|||||||
|
|
||||||
White space in text is preserved. For example:
|
White space in text is preserved. For example:
|
||||||
|
|
||||||
<element> Hello, World</element>
|
```xml
|
||||||
|
<element> Hello, World</element>
|
||||||
|
```
|
||||||
|
|
||||||
The leading space before the "Hello" and the double space after the comma are
|
The leading space before the `"Hello"` and the double space after the comma are
|
||||||
preserved. Line-feeds are preserved, as in this example:
|
preserved. Line-feeds are preserved, as in this example:
|
||||||
|
|
||||||
<element> Hello again,
|
```xml
|
||||||
World</element>
|
<element> Hello again,
|
||||||
|
World</element>
|
||||||
|
```
|
||||||
|
|
||||||
However, white space between elements is **not** preserved. Although not strictly
|
However, white space between elements is **not** preserved. Although not strictly
|
||||||
compliant, tracking and reporting inter-element space is awkward, and not normally
|
compliant, tracking and reporting inter-element space is awkward, and not normally
|
||||||
valuable. TinyXML-2 sees these as the same XML:
|
valuable. TinyXML-2 sees these as the same XML:
|
||||||
|
|
||||||
<document>
|
```xml
|
||||||
<data>1</data>
|
<document>
|
||||||
<data>2</data>
|
<data>1</data>
|
||||||
<data>3</data>
|
<data>2</data>
|
||||||
</document>
|
<data>3</data>
|
||||||
|
</document>
|
||||||
|
|
||||||
<document><data>1</data><data>2</data><data>3</data></document>
|
<document><data>1</data><data>2</data><data>3</data></document>
|
||||||
|
```
|
||||||
|
|
||||||
#### Whitespace Collapse (COLLAPSE_WHITESPACE)
|
#### Whitespace Collapse (`COLLAPSE_WHITESPACE`)
|
||||||
|
|
||||||
For some applications, it is preferable to collapse whitespace. Collapsing
|
For some applications, it is preferable to collapse whitespace. Collapsing
|
||||||
whitespace gives you "HTML-like" behavior, which is sometimes more suitable
|
whitespace gives you "HTML-like" behavior, which is sometimes more suitable
|
||||||
for hand typed documents.
|
for hand typed documents.
|
||||||
|
|
||||||
TinyXML-2 supports this with the 'whitespace' parameter to the XMLDocument constructor.
|
TinyXML-2 supports this with the `whitespace` parameter to the `XMLDocument` constructor.
|
||||||
(The default is to preserve whitespace, as described above.)
|
(The default is to preserve whitespace, as described above.)
|
||||||
|
|
||||||
However, you may also use COLLAPSE_WHITESPACE, which will:
|
However, you may also use `COLLAPSE_WHITESPACE`, which will:
|
||||||
|
|
||||||
* Remove leading and trailing whitespace
|
* Remove leading and trailing whitespace
|
||||||
* Convert newlines and line-feeds into a space character
|
* Convert newlines and line-feeds into a space character
|
||||||
* Collapse a run of any number of space characters into a single space character
|
* Collapse a run of any number of space characters into a single space character
|
||||||
|
|
||||||
Note that (currently) there is a performance impact for using COLLAPSE_WHITESPACE.
|
Note that (currently) there is a performance impact for using `COLLAPSE_WHITESPACE`.
|
||||||
It essentially causes the XML to be parsed twice.
|
It essentially causes the XML to be parsed twice.
|
||||||
|
|
||||||
#### Pedantic Whitespace (PEDANTIC_WHITESPACE)
|
#### Pedantic Whitespace (`PEDANTIC_WHITESPACE`)
|
||||||
|
|
||||||
For applications that need to know about text nodes that are composed entirely of
|
For applications that need to know about text nodes that are composed entirely of
|
||||||
whitespace, PEDANTIC_WHITESPACE is available. PEDANTIC_WHITESPACE maintains all the
|
whitespace, `PEDANTIC_WHITESPACE` is available. `PEDANTIC_WHITESPACE` maintains all the
|
||||||
whitespace between elements.
|
whitespace between elements.
|
||||||
|
|
||||||
PEDANTIC_WHITESPACE is a new mode and not as tested as the other whitespace modes.
|
`PEDANTIC_WHITESPACE` is a new mode and not as tested as the other whitespace modes.
|
||||||
|
|
||||||
### Error Reporting
|
### Error Reporting
|
||||||
|
|
||||||
@@ -163,18 +166,22 @@ line number information for error messages.
|
|||||||
TinyXML-2 recognizes the pre-defined "character entities", meaning special
|
TinyXML-2 recognizes the pre-defined "character entities", meaning special
|
||||||
characters. Namely:
|
characters. Namely:
|
||||||
|
|
||||||
& &
|
```html
|
||||||
< <
|
& &
|
||||||
> >
|
< <
|
||||||
" "
|
> >
|
||||||
' '
|
" "
|
||||||
|
' '
|
||||||
|
```
|
||||||
|
|
||||||
These are recognized when the XML document is read, and translated to their
|
These are recognized when the XML document is read, and translated to their
|
||||||
UTF-8 equivalents. For instance, text with the XML of:
|
UTF-8 equivalents. For instance, text with the XML of:
|
||||||
|
|
||||||
Far & Away
|
```xml
|
||||||
|
Far & Away
|
||||||
|
```
|
||||||
|
|
||||||
will have the Value() of "Far & Away" when queried from the XMLText object,
|
will have the `Value()` of `"Far & Away"` when queried from the `XMLText` object,
|
||||||
and will be written back to the XML stream/file as an ampersand.
|
and will be written back to the XML stream/file as an ampersand.
|
||||||
|
|
||||||
Additionally, any character can be specified by its Unicode code point:
|
Additionally, any character can be specified by its Unicode code point:
|
||||||
@@ -188,21 +195,27 @@ regular code point. The output is correct, but the entity syntax isn't preserved
|
|||||||
#### Print to file
|
#### Print to file
|
||||||
You can directly use the convenience function:
|
You can directly use the convenience function:
|
||||||
|
|
||||||
XMLDocument doc;
|
```cpp
|
||||||
...
|
XMLDocument doc;
|
||||||
doc.SaveFile( "foo.xml" );
|
// ...
|
||||||
|
doc.SaveFile("foo.xml");
|
||||||
|
```
|
||||||
|
|
||||||
Or the XMLPrinter class:
|
Or the `XMLPrinter` class:
|
||||||
|
|
||||||
XMLPrinter printer( fp );
|
```cpp
|
||||||
doc.Print( &printer );
|
XMLPrinter printer(fp);
|
||||||
|
doc.Print(&printer);
|
||||||
|
```
|
||||||
|
|
||||||
#### Print to memory
|
#### Print to memory
|
||||||
Printing to memory is supported by the XMLPrinter.
|
Printing to memory is supported by the `XMLPrinter`.
|
||||||
|
|
||||||
XMLPrinter printer;
|
```cpp
|
||||||
doc.Print( &printer );
|
XMLPrinter printer;
|
||||||
// printer.CStr() has a const char* to the XML
|
doc.Print(&printer);
|
||||||
|
// printer.CStr() has a const char* to the XML
|
||||||
|
```
|
||||||
|
|
||||||
#### Print without an XMLDocument
|
#### Print without an XMLDocument
|
||||||
|
|
||||||
@@ -210,92 +223,95 @@ When loading, an XML parser is very useful. However, sometimes
|
|||||||
when saving, it just gets in the way. The code is often set up
|
when saving, it just gets in the way. The code is often set up
|
||||||
for streaming, and constructing the DOM is just overhead.
|
for streaming, and constructing the DOM is just overhead.
|
||||||
|
|
||||||
The Printer supports the streaming case. The following code
|
The `XMLPrinter` supports the streaming case. The following code
|
||||||
prints out a trivially simple XML file without ever creating
|
prints out a trivially simple XML file without ever creating
|
||||||
an XML document.
|
an XML document.
|
||||||
|
|
||||||
XMLPrinter printer( fp );
|
```cpp
|
||||||
printer.OpenElement( "foo" );
|
XMLPrinter printer(fp);
|
||||||
printer.PushAttribute( "foo", "bar" );
|
printer.OpenElement("foo");
|
||||||
printer.CloseElement();
|
printer.PushAttribute("foo", "bar");
|
||||||
|
printer.CloseElement();
|
||||||
|
```
|
||||||
|
|
||||||
Examples
|
### Examples
|
||||||
--------
|
|
||||||
|
|
||||||
#### Load and parse an XML file.
|
#### Load and parse an XML file.
|
||||||
|
|
||||||
/* ------ Example 1: Load and parse an XML file. ---- */
|
```cpp
|
||||||
{
|
/* ------ Example 1: Load and parse an XML file. ---- */
|
||||||
XMLDocument doc;
|
{
|
||||||
doc.LoadFile( "dream.xml" );
|
XMLDocument doc;
|
||||||
}
|
doc.LoadFile("dream.xml");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
#### Lookup information.
|
#### Lookup information.
|
||||||
|
|
||||||
/* ------ Example 2: Lookup information. ---- */
|
```cpp
|
||||||
{
|
/* ------ Example 2: Lookup information. ---- */
|
||||||
XMLDocument doc;
|
{
|
||||||
doc.LoadFile( "dream.xml" );
|
XMLDocument doc;
|
||||||
|
doc.LoadFile("dream.xml");
|
||||||
|
|
||||||
// Structure of the XML file:
|
// Structure of the XML file:
|
||||||
// - Element "PLAY" the root Element, which is the
|
// - Element "PLAY" the root Element, which is the
|
||||||
// FirstChildElement of the Document
|
// FirstChildElement of the Document
|
||||||
// - - Element "TITLE" child of the root PLAY Element
|
// - - Element "TITLE" child of the root PLAY Element
|
||||||
// - - - Text child of the TITLE Element
|
// - - - Text child of the TITLE Element
|
||||||
|
|
||||||
// Navigate to the title, using the convenience function,
|
// Navigate to the title, using the convenience function,
|
||||||
// with a dangerous lack of error checking.
|
// with a dangerous lack of error checking.
|
||||||
const char* title = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->GetText();
|
const char* title = doc.FirstChildElement("PLAY")->FirstChildElement("TITLE")->GetText();
|
||||||
printf( "Name of play (1): %s\n", title );
|
printf("Name of play (1): %s\n", title);
|
||||||
|
|
||||||
// Text is just another Node to TinyXML-2. The more
|
// Text is just another Node to TinyXML-2. The more
|
||||||
// general way to get to the XMLText:
|
// general way to get to the XMLText:
|
||||||
XMLText* textNode = doc.FirstChildElement( "PLAY" )->FirstChildElement( "TITLE" )->FirstChild()->ToText();
|
XMLText* textNode = doc.FirstChildElement("PLAY")->FirstChildElement("TITLE")->FirstChild()->ToText();
|
||||||
title = textNode->Value();
|
title = textNode->Value();
|
||||||
printf( "Name of play (2): %s\n", title );
|
printf("Name of play (2): %s\n", title);
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Using and Installing
|
## Using and Installing
|
||||||
--------------------
|
|
||||||
|
|
||||||
There are 2 files in TinyXML-2:
|
There are 2 files in TinyXML-2:
|
||||||
* tinyxml2.cpp
|
* `tinyxml2.cpp`
|
||||||
* tinyxml2.h
|
* `tinyxml2.h`
|
||||||
|
|
||||||
And additionally a test file:
|
And additionally a test file:
|
||||||
* xmltest.cpp
|
* `xmltest.cpp`
|
||||||
|
|
||||||
Generally speaking, the intent is that you simply include the tinyxml2.cpp and
|
Generally speaking, the intent is that you simply include the `tinyxml2.cpp` and
|
||||||
tinyxml2.h files in your project and build with your other source code.
|
`tinyxml2.h` files in your project and build with your other source code.
|
||||||
|
|
||||||
There is also a CMake build included. CMake is the general build for TinyXML-2.
|
There is also a CMake build included. CMake is the general build for TinyXML-2.
|
||||||
|
|
||||||
(Additional build systems are costly to maintain, and tend to become outdated. They are
|
(Additional build systems are costly to maintain, and tend to become outdated. They are
|
||||||
being removed over time.)
|
being removed over time.)
|
||||||
|
|
||||||
Building TinyXML-2 - Using vcpkg
|
### Building TinyXML-2 - Using vcpkg
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
You can download and install TinyXML-2 using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
You can download and install TinyXML-2 using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||||
|
|
||||||
git clone https://github.com/Microsoft/vcpkg.git
|
```sh
|
||||||
cd vcpkg
|
git clone https://github.com/Microsoft/vcpkg.git
|
||||||
./bootstrap-vcpkg.sh
|
cd vcpkg
|
||||||
./vcpkg integrate install
|
./bootstrap-vcpkg.sh
|
||||||
./vcpkg install tinyxml2
|
./vcpkg integrate install
|
||||||
|
./vcpkg install tinyxml2
|
||||||
|
```
|
||||||
|
|
||||||
The TinyXML-2 port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
The TinyXML-2 port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
|
||||||
|
|
||||||
Versioning
|
## Versioning
|
||||||
----------
|
|
||||||
|
|
||||||
TinyXML-2 uses semantic versioning. http://semver.org/ Releases are now tagged in github.
|
TinyXML-2 uses semantic versioning. http://semver.org/ Releases are now tagged in GitHub.
|
||||||
|
|
||||||
Note that the major version will (probably) change fairly rapidly. API changes are fairly
|
Note that the major version will (probably) change fairly rapidly. API changes are fairly
|
||||||
common.
|
common.
|
||||||
|
|
||||||
License
|
## License
|
||||||
-------
|
|
||||||
|
|
||||||
TinyXML-2 is released under the zlib license:
|
TinyXML-2 is released under the zlib license:
|
||||||
|
|
||||||
@@ -316,8 +332,7 @@ must not be misrepresented as being the original software.
|
|||||||
3. This notice may not be removed or altered from any source
|
3. This notice may not be removed or altered from any source
|
||||||
distribution.
|
distribution.
|
||||||
|
|
||||||
Contributors
|
## Contributors
|
||||||
------------
|
|
||||||
|
|
||||||
Thanks very much to everyone who sends suggestions, bugs, ideas, and
|
Thanks very much to everyone who sends suggestions, bugs, ideas, and
|
||||||
encouragement. It all helps, and makes this project fun.
|
encouragement. It all helps, and makes this project fun.
|
||||||
|
|||||||
+33
-52
@@ -24,7 +24,7 @@ distribution.
|
|||||||
#include "tinyxml2.h"
|
#include "tinyxml2.h"
|
||||||
|
|
||||||
#include <new> // yes, this one new style header, is in the Android SDK.
|
#include <new> // yes, this one new style header, is in the Android SDK.
|
||||||
#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__) || defined(__CC_ARM)
|
#if defined(ANDROID_NDK)
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdarg.h>
|
# include <stdarg.h>
|
||||||
#else
|
#else
|
||||||
@@ -40,9 +40,7 @@ distribution.
|
|||||||
# define __has_cpp_attribute(x) 0
|
# define __has_cpp_attribute(x) 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if (__cplusplus >= 201703L && __has_cpp_attribute(fallthrough))
|
||||||
# define TIXML_FALLTHROUGH (void(0))
|
|
||||||
#elif (__cplusplus >= 201703L && __has_cpp_attribute(fallthrough))
|
|
||||||
# define TIXML_FALLTHROUGH [[fallthrough]]
|
# define TIXML_FALLTHROUGH [[fallthrough]]
|
||||||
#elif __has_cpp_attribute(clang::fallthrough)
|
#elif __has_cpp_attribute(clang::fallthrough)
|
||||||
# define TIXML_FALLTHROUGH [[clang::fallthrough]]
|
# define TIXML_FALLTHROUGH [[clang::fallthrough]]
|
||||||
@@ -53,15 +51,8 @@ distribution.
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
|
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||||
// Microsoft Visual Studio, version 2005 and higher. Not WinCE.
|
// Microsoft Visual Studio, version 2005 and higher.
|
||||||
/*int _snprintf_s(
|
|
||||||
char *buffer,
|
|
||||||
size_t sizeOfBuffer,
|
|
||||||
size_t count,
|
|
||||||
const char *format [,
|
|
||||||
argument] ...
|
|
||||||
);*/
|
|
||||||
static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
|
static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
@@ -80,33 +71,11 @@ distribution.
|
|||||||
#define TIXML_VSCPRINTF _vscprintf
|
#define TIXML_VSCPRINTF _vscprintf
|
||||||
#define TIXML_SSCANF sscanf_s
|
#define TIXML_SSCANF sscanf_s
|
||||||
#elif defined _MSC_VER
|
#elif defined _MSC_VER
|
||||||
// Microsoft Visual Studio 2003 and earlier or WinCE
|
// Microsoft Visual Studio 2003 and earlier.
|
||||||
#define TIXML_SNPRINTF _snprintf
|
#define TIXML_SNPRINTF _snprintf
|
||||||
#define TIXML_VSNPRINTF _vsnprintf
|
#define TIXML_VSNPRINTF _vsnprintf
|
||||||
#define TIXML_SSCANF sscanf
|
#define TIXML_SSCANF sscanf
|
||||||
#if (_MSC_VER < 1400 ) && (!defined WINCE)
|
#define TIXML_VSCPRINTF _vscprintf
|
||||||
// Microsoft Visual Studio 2003 and not WinCE.
|
|
||||||
#define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
|
|
||||||
#else
|
|
||||||
// Microsoft Visual Studio 2003 and earlier or WinCE.
|
|
||||||
static inline int TIXML_VSCPRINTF( const char* format, va_list va )
|
|
||||||
{
|
|
||||||
int len = 512;
|
|
||||||
for (;;) {
|
|
||||||
len = len*2;
|
|
||||||
char* str = new char[len]();
|
|
||||||
const int required = _vsnprintf(str, len, format, va);
|
|
||||||
delete[] str;
|
|
||||||
if ( required != -1 ) {
|
|
||||||
TIXMLASSERT( required >= 0 );
|
|
||||||
len = required;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TIXMLASSERT( len >= 0 );
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
// GCC version 3 and higher
|
// GCC version 3 and higher
|
||||||
//#warning( "Using sn* functions." )
|
//#warning( "Using sn* functions." )
|
||||||
@@ -124,7 +93,7 @@ distribution.
|
|||||||
#define TIXML_SSCANF sscanf
|
#define TIXML_SSCANF sscanf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN64)
|
#if defined(_MSC_VER)
|
||||||
#define TIXML_FSEEK _fseeki64
|
#define TIXML_FSEEK _fseeki64
|
||||||
#define TIXML_FTELL _ftelli64
|
#define TIXML_FTELL _ftelli64
|
||||||
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
|
#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
|
||||||
@@ -552,12 +521,15 @@ const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)
|
|||||||
TIXMLASSERT(digit < radix);
|
TIXMLASSERT(digit < radix);
|
||||||
|
|
||||||
const unsigned int digitScaled = mult * digit;
|
const unsigned int digitScaled = mult * digit;
|
||||||
|
// Reject before adding: if digitScaled alone exceeds MAX_CODE_POINT,
|
||||||
|
// or if adding it to ucs would exceed it (checked without overflow by
|
||||||
|
// testing ucs > MAX_CODE_POINT - digitScaled, safe since digitScaled
|
||||||
|
// <= MAX_CODE_POINT at this point).
|
||||||
|
if (digitScaled > MAX_CODE_POINT || ucs > MAX_CODE_POINT - digitScaled) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
ucs += digitScaled;
|
ucs += digitScaled;
|
||||||
mult *= radix;
|
mult *= radix;
|
||||||
|
|
||||||
// Security check: could a value exist that is out of range?
|
|
||||||
// Easily; limit to the MAX_CODE_POINT, which also allows for a
|
|
||||||
// bunch of leading zeroes.
|
|
||||||
if (mult > MAX_CODE_POINT) {
|
if (mult > MAX_CODE_POINT) {
|
||||||
mult = MAX_CODE_POINT;
|
mult = MAX_CODE_POINT;
|
||||||
}
|
}
|
||||||
@@ -569,11 +541,11 @@ const char* XMLUtil::GetCharacterRef(const char* p, char* value, int* length)
|
|||||||
}
|
}
|
||||||
// convert the UCS to UTF-8
|
// convert the UCS to UTF-8
|
||||||
ConvertUTF32ToUTF8(ucs, value, length);
|
ConvertUTF32ToUTF8(ucs, value, length);
|
||||||
if (length == 0) {
|
if (*length == 0) {
|
||||||
// If length is 0, there was an error. (Security? Bad input?)
|
// If *length is 0, ConvertUTF32ToUTF8 rejected the code point.
|
||||||
// Fail safely.
|
// Fail safely.
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return p + delta + 1;
|
return p + delta + 1;
|
||||||
}
|
}
|
||||||
return p + 1;
|
return p + 1;
|
||||||
@@ -834,7 +806,17 @@ XMLNode::XMLNode( XMLDocument* doc ) :
|
|||||||
|
|
||||||
XMLNode::~XMLNode()
|
XMLNode::~XMLNode()
|
||||||
{
|
{
|
||||||
DeleteChildren();
|
// Fast path: this node is dying, so maintaining _firstChild/_lastChild and
|
||||||
|
// sibling _prev/_next links is unnecessary. Only _parent must be zeroed to
|
||||||
|
// satisfy the MarkInUse assertion inside DeleteNode.
|
||||||
|
XMLNode *currentChild = _firstChild;
|
||||||
|
while (currentChild != NULL) {
|
||||||
|
XMLNode *next = currentChild->_next;
|
||||||
|
currentChild->_parent = 0;
|
||||||
|
DeleteNode(currentChild);
|
||||||
|
currentChild = next;
|
||||||
|
}
|
||||||
|
|
||||||
if ( _parent ) {
|
if ( _parent ) {
|
||||||
_parent->Unlink( this );
|
_parent->Unlink( this );
|
||||||
}
|
}
|
||||||
@@ -2260,7 +2242,7 @@ void XMLDocument::Clear()
|
|||||||
delete [] _charBuffer;
|
delete [] _charBuffer;
|
||||||
_charBuffer = 0;
|
_charBuffer = 0;
|
||||||
_parsingDepth = 0;
|
_parsingDepth = 0;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
_textPool.Trace( "text" );
|
_textPool.Trace( "text" );
|
||||||
_elementPool.Trace( "element" );
|
_elementPool.Trace( "element" );
|
||||||
@@ -2335,7 +2317,7 @@ static FILE* callfopen( const char* filepath, const char* mode )
|
|||||||
{
|
{
|
||||||
TIXMLASSERT( filepath );
|
TIXMLASSERT( filepath );
|
||||||
TIXMLASSERT( mode );
|
TIXMLASSERT( mode );
|
||||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
|
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||||
FILE* fp = 0;
|
FILE* fp = 0;
|
||||||
const errno_t err = fopen_s( &fp, filepath, mode );
|
const errno_t err = fopen_s( &fp, filepath, mode );
|
||||||
if ( err ) {
|
if ( err ) {
|
||||||
@@ -2348,11 +2330,10 @@ static FILE* callfopen( const char* filepath, const char* mode )
|
|||||||
}
|
}
|
||||||
|
|
||||||
void XMLDocument::DeleteNode( XMLNode* node ) {
|
void XMLDocument::DeleteNode( XMLNode* node ) {
|
||||||
TIXMLASSERT( node );
|
|
||||||
TIXMLASSERT(node->_document == this );
|
|
||||||
if(node == 0) {
|
if(node == 0) {
|
||||||
return; // check for null pointer
|
return; // check for null pointer
|
||||||
}
|
}
|
||||||
|
TIXMLASSERT(node->_document == this);
|
||||||
if (node->_parent) {
|
if (node->_parent) {
|
||||||
node->_parent->DeleteChild( node );
|
node->_parent->DeleteChild( node );
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-8
@@ -24,15 +24,12 @@ distribution.
|
|||||||
#ifndef TINYXML2_INCLUDED
|
#ifndef TINYXML2_INCLUDED
|
||||||
#define TINYXML2_INCLUDED
|
#define TINYXML2_INCLUDED
|
||||||
|
|
||||||
#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
|
#if defined(ANDROID_NDK)
|
||||||
# include <ctype.h>
|
# include <ctype.h>
|
||||||
# include <limits.h>
|
# include <limits.h>
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
# if defined(__PS3__)
|
|
||||||
# include <stddef.h>
|
|
||||||
# endif
|
|
||||||
#else
|
#else
|
||||||
# include <cctype>
|
# include <cctype>
|
||||||
# include <climits>
|
# include <climits>
|
||||||
@@ -85,12 +82,20 @@ distribution.
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus) && __cplusplus >= 201703L
|
||||||
|
#define TINYXML2_CONSTANT inline constexpr
|
||||||
|
#elif defined(__cplusplus) && __cplusplus >= 201103L
|
||||||
|
#define TINYXML2_CONSTANT static constexpr
|
||||||
|
#else
|
||||||
|
#define TINYXML2_CONSTANT static const
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Versioning, past 1.0.14:
|
/* Versioning, past 1.0.14:
|
||||||
http://semver.org/
|
http://semver.org/
|
||||||
*/
|
*/
|
||||||
static const int TIXML2_MAJOR_VERSION = 11;
|
TINYXML2_CONSTANT int TIXML2_MAJOR_VERSION = 11;
|
||||||
static const int TIXML2_MINOR_VERSION = 0;
|
TINYXML2_CONSTANT int TIXML2_MINOR_VERSION = 0;
|
||||||
static const int TIXML2_PATCH_VERSION = 0;
|
TINYXML2_CONSTANT int TIXML2_PATCH_VERSION = 0;
|
||||||
|
|
||||||
#define TINYXML2_MAJOR_VERSION 11
|
#define TINYXML2_MAJOR_VERSION 11
|
||||||
#define TINYXML2_MINOR_VERSION 0
|
#define TINYXML2_MINOR_VERSION 0
|
||||||
@@ -101,7 +106,7 @@ static const int TIXML2_PATCH_VERSION = 0;
|
|||||||
// system, and the capacity of the stack. On the other hand, it's a trivial
|
// system, and the capacity of the stack. On the other hand, it's a trivial
|
||||||
// attack that can result from ill, malicious, or even correctly formed XML,
|
// attack that can result from ill, malicious, or even correctly formed XML,
|
||||||
// so there needs to be a limit in place.
|
// so there needs to be a limit in place.
|
||||||
static const int TINYXML2_MAX_ELEMENT_DEPTH = 500;
|
TINYXML2_CONSTANT int TINYXML2_MAX_ELEMENT_DEPTH = 500;
|
||||||
|
|
||||||
namespace tinyxml2
|
namespace tinyxml2
|
||||||
{
|
{
|
||||||
|
|||||||
+55
-3
@@ -45,13 +45,15 @@ bool XMLTest (const char* testString, const char* expected, const char* found, b
|
|||||||
printf (" %s\n", testString);
|
printf (" %s\n", testString);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
const char* expectedStr = expected ? expected : "(null)";
|
||||||
|
const char* foundStr = found ? found : "(null)";
|
||||||
if ( extraNL ) {
|
if ( extraNL ) {
|
||||||
printf( " %s\n", testString );
|
printf( " %s\n", testString );
|
||||||
printf( "%s\n", expected );
|
printf( "%s\n", expectedStr );
|
||||||
printf( "%s\n", found );
|
printf( "%s\n", foundStr );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf (" %s [%s][%s]\n", testString, expected, found);
|
printf (" %s [%s][%s]\n", testString, expectedStr, foundStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2701,6 +2703,56 @@ int main( int argc, const char ** argv )
|
|||||||
XMLTest("Test attribute encode with a Hex value", value5, "!"); // hex value in unicode value
|
XMLTest("Test attribute encode with a Hex value", value5, "!"); // hex value in unicode value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- Security: numeric character reference bounds ----------
|
||||||
|
{
|
||||||
|
// Regression: U+10FFFF is the last valid Unicode code point and must
|
||||||
|
// parse correctly. The in-loop overflow guard must not reject it.
|
||||||
|
XMLDocument doc;
|
||||||
|
doc.Parse( "<t v=''/>" );
|
||||||
|
XMLTest( "Numeric ref U+10FFFF: no error", false, doc.Error() );
|
||||||
|
const char* v = doc.FirstChildElement()->Attribute( "v" );
|
||||||
|
// U+10FFFF encodes to the 4-byte UTF-8 sequence F4 8F BF BF.
|
||||||
|
const char expected[] = {
|
||||||
|
static_cast<char>(0xF4), static_cast<char>(0x8F),
|
||||||
|
static_cast<char>(0xBF), static_cast<char>(0xBF), 0
|
||||||
|
};
|
||||||
|
XMLTest( "Numeric ref U+10FFFF: correct UTF-8 output", expected, v );
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Boundary check: U+110000 is one above the maximum code point.
|
||||||
|
// The in-loop overflow guard must catch this before ucs is written,
|
||||||
|
// leaving the entity as a literal (starting with '&').
|
||||||
|
XMLDocument doc;
|
||||||
|
doc.Parse( "<t v='�'/>" );
|
||||||
|
XMLTest( "Numeric ref U+110000: no parse error", false, doc.Error() );
|
||||||
|
const char* v = doc.FirstChildElement()->Attribute( "v" );
|
||||||
|
XMLTest( "Numeric ref U+110000: not resolved (left as literal)", true,
|
||||||
|
v != nullptr && v[0] == '&' );
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// A hex entity with enough digits to overflow uint32_t must
|
||||||
|
// be rejected by the in-loop guard before the accumulator wraps.
|
||||||
|
// Before the fix, ucs could wrap around and pass the post-loop range
|
||||||
|
// check, producing an attacker-chosen character in the parsed output.
|
||||||
|
// Build "&#x" + 300 'F' digits + ";" -- far beyond what fits in uint32_t.
|
||||||
|
const char prefix[] = "<t v='&#x";
|
||||||
|
const char suffix[] = ";'/>";
|
||||||
|
static const int NDIGITS = 300;
|
||||||
|
char xml[sizeof(prefix) + NDIGITS + sizeof(suffix)];
|
||||||
|
strcpy( xml, prefix );
|
||||||
|
memset( xml + strlen(prefix), 'F', NDIGITS );
|
||||||
|
strcpy( xml + strlen(prefix) + NDIGITS, suffix );
|
||||||
|
|
||||||
|
XMLDocument doc;
|
||||||
|
doc.Parse( xml );
|
||||||
|
XMLTest( "Overflow hex entity: no parse error", false, doc.Error() );
|
||||||
|
const char* v = doc.FirstChildElement()->Attribute( "v" );
|
||||||
|
// GetCharacterRef returns 0 for rejected refs; the caller then copies
|
||||||
|
// the literal '&', so the attribute must start with '&', not a char.
|
||||||
|
XMLTest( "Overflow hex entity: not resolved to a character", true,
|
||||||
|
v != nullptr && v[0] == '&' );
|
||||||
|
}
|
||||||
|
|
||||||
// ---------- XMLPrinter Apos Escaping ------
|
// ---------- XMLPrinter Apos Escaping ------
|
||||||
{
|
{
|
||||||
const char* testText = "text containing a ' character";
|
const char* testText = "text containing a ' character";
|
||||||
|
|||||||
Reference in New Issue
Block a user