Merge remote-tracking branch 'origin/master'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b58f9eb..12cac92 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,8 +10,8 @@
################################
# set lib version here
-set(GENERIC_LIB_VERSION "1.0.12")
-set(GENERIC_LIB_SOVERSION "1")
+set(GENERIC_LIB_VERSION "1.0.14")
+set(GENERIC_LIB_SOVERSION "1")
################################
@@ -53,6 +53,7 @@
endif(BUILD_STATIC_LIBS)
add_library(tinyxml2 SHARED tinyxml2.cpp tinyxml2.h)
set_target_properties(tinyxml2 PROPERTIES
+ COMPILE_DEFINITIONS "TINYXML2_EXPORT"
VERSION "${GENERIC_LIB_VERSION}"
SOVERSION "${GENERIC_LIB_SOVERSION}")
diff --git a/dox b/dox
index 7ab99ff..10878f4 100755
--- a/dox
+++ b/dox
@@ -32,7 +32,7 @@
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 1.0.12
+PROJECT_NUMBER = 1.0.14
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
diff --git a/readme.md b/readme.md
index 7644f41..8ecd536 100644
--- a/readme.md
+++ b/readme.md
@@ -51,11 +51,10 @@
TinyXML-2 doesn't parse or use DTDs (Document Type Definitions) or XSLs
(eXtensible Stylesheet Language.) There are other parsers out there
-that are much more fully
-featured. But they are also much bigger, take longer to set up in
-your project, have a higher learning curve, and often have a more
-restrictive license. If you are working with browsers or have more
-complete XML needs, TinyXML-2 is not the parser for you.
+that are much more fully featured. But they are also much bigger,
+take longer to set up in your project, have a higher learning curve,
+and often have a more restrictive license. If you are working with
+browsers or have more complete XML needs, TinyXML-2 is not the parser for you.
TinyXML-1 vs. TinyXML-2
-----------------------
@@ -309,8 +308,9 @@
Berquin and Andrew Ellerton who were key contributors.
TinyXML-2 grew from that effort. Lee Thomason is the original author
-of TinyXML-2 (and TinyXML-1) but hopefully TinyXML-2 will be improved
+of TinyXML-2 (and TinyXML-1) but TinyXML-2 has been and is being improved
by many contributors.
-Thanks to John Mackay for the TinyXML-2 logo.
+Thanks to John Mackay at http://john.mackay.rosalilastudio.com for the TinyXML-2 logo!
+
diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index 3b665c4..4e79ef5 100755
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -422,16 +422,19 @@
TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
}
-
+/*
+ ToStr() of a number is a very tricky topic.
+ https://github.com/leethomason/tinyxml2/issues/106
+*/
void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
{
- TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
+ TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
}
void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
{
- TIXML_SNPRINTF( buffer, bufferSize, "%f", v );
+ TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
}
@@ -497,12 +500,7 @@
}
// What is this thing?
- // - Elements start with a letter or underscore, but xml is reserved.
- // - Comments: <!--
- // - Declaration: <?
- // - Everything else is unknown to tinyxml.
- //
-
+ // These strings define the matching patters:
static const char* xmlHeader = { "<?" };
static const char* commentHeader = { "<!--" };
static const char* dtdHeader = { "<!" };
@@ -1262,6 +1260,57 @@
}
+void XMLElement::SetText( const char* inText )
+{
+ if ( FirstChild() && FirstChild()->ToText() )
+ FirstChild()->SetValue( inText );
+ else {
+ XMLText* theText = GetDocument()->NewText( inText );
+ InsertFirstChild( theText );
+ }
+}
+
+
+void XMLElement::SetText( int v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( unsigned v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( bool v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( float v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
+void XMLElement::SetText( double v )
+{
+ char buf[BUF_SIZE];
+ XMLUtil::ToStr( v, buf, BUF_SIZE );
+ SetText( buf );
+}
+
+
XMLError XMLElement::QueryIntText( int* ival ) const
{
if ( FirstChild() && FirstChild()->ToText() ) {
@@ -1639,6 +1688,13 @@
{
Clear();
+ fseek( fp, 0, SEEK_SET );
+ fgetc( fp );
+ if ( ferror( fp ) != 0 ) {
+ SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
+ return _errorID;
+ }
+
fseek( fp, 0, SEEK_END );
size_t size = ftell( fp );
fseek( fp, 0, SEEK_SET );
diff --git a/tinyxml2.h b/tinyxml2.h
index ca3d90e..fc54320 100755
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -116,9 +116,15 @@
#define TIXML_SSCANF sscanf
#endif
+/* Versioning, past 1.0.14:
+
+ A backwards-incompatible change or API change bumps the major version.
+ An API addition or a backwards-compatible change, bumps the minor version.
+ Simple bug fixes bump the build number.
+*/
static const int TIXML2_MAJOR_VERSION = 1;
-static const int TIXML2_MINOR_VERSION = 0;
-static const int TIXML2_PATCH_VERSION = 12;
+static const int TIXML2_MINOR_VERSION = 1;
+static const int TIXML2_PATCH_VERSION = 0;
namespace tinyxml2
{
@@ -216,6 +222,10 @@
}
}
+ void Clear() {
+ _size = 0;
+ }
+
void Push( T t ) {
EnsureCapacity( _size+1 );
_mem[_size++] = t;
@@ -1317,6 +1327,11 @@
XMLAttribute* a = FindOrCreateAttribute( name );
a->SetAttribute( value );
}
+ /// Sets the named attribute to value.
+ void SetAttribute( const char* name, float value ) {
+ XMLAttribute* a = FindOrCreateAttribute( name );
+ a->SetAttribute( value );
+ }
/**
Delete an attribute.
@@ -1360,6 +1375,52 @@
*/
const char* GetText() const;
+ /** Convenience function for easy access to the text inside an element. Although easy
+ and concise, SetText() is limited compared to creating an XMLText child
+ and mutating it directly.
+
+ If the first child of 'this' is a XMLText, SetText() sets its value to
+ the given string, otherwise it will create a first child that is an XMLText.
+
+ This is a convenient method for setting the text of simple contained text:
+ @verbatim
+ <foo>This is text</foo>
+ fooElement->SetText( "Hullaballoo!" );
+ <foo>Hullaballoo!</foo>
+ @endverbatim
+
+ Note that this function can be misleading. If the element foo was created from
+ this XML:
+ @verbatim
+ <foo><b>This is text</b></foo>
+ @endverbatim
+
+ then it will not change "This is text", but rather prefix it with a text element:
+ @verbatim
+ <foo>Hullaballoo!<b>This is text</b></foo>
+ @endverbatim
+
+ For this XML:
+ @verbatim
+ <foo />
+ @endverbatim
+ SetText() will generate
+ @verbatim
+ <foo>Hullaballoo!</foo>
+ @endverbatim
+ */
+ void SetText( const char* inText );
+ /// Convenience method for setting text inside and element. See SetText() for important limitations.
+ void SetText( int value );
+ /// Convenience method for setting text inside and element. See SetText() for important limitations.
+ void SetText( unsigned value );
+ /// Convenience method for setting text inside and element. See SetText() for important limitations.
+ void SetText( bool value );
+ /// Convenience method for setting text inside and element. See SetText() for important limitations.
+ void SetText( double value );
+ /// Convenience method for setting text inside and element. See SetText() for important limitations.
+ void SetText( float value );
+
/**
Convenience method to query the value of a child text node. This is probably best
shown by example. Given you have a document is this form:
@@ -1420,6 +1481,7 @@
//void LinkAttribute( XMLAttribute* attrib );
char* ParseAttributes( char* p );
+ enum { BUF_SIZE = 200 };
int _closingType;
// The attribute list is ordered; there is no 'lastAttribute'
// because the list needs to be scanned for dupes before adding
@@ -1962,23 +2024,35 @@
int CStrSize() const {
return _buffer.Size();
}
+ /**
+ If in print to memory mode, reset the buffer to the
+ beginning.
+ */
+ void ClearBuffer() {
+ _buffer.Clear();
+ _buffer.Push(0);
+ }
protected:
- void SealElement();
+ /** Prints out the space before an element. You may override to change
+ the space and tabs used. A PrintSpace() override should call Print().
+ */
+ virtual void PrintSpace( int depth );
+ void Print( const char* format, ... );
+
+ void SealElement();
bool _elementJustOpened;
DynArray< const char*, 10 > _stack;
private:
- void PrintSpace( int depth );
void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
- void Print( const char* format, ... );
bool _firstElement;
FILE* _fp;
int _depth;
int _textDepth;
bool _processEntities;
- bool _compactMode;
+ bool _compactMode;
enum {
ENTITY_RANGE = 64,
diff --git a/xmltest.cpp b/xmltest.cpp
index 533bcba..6fdc162 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -617,6 +617,61 @@
}
+ // --------SetText()-----------
+ {
+ const char* str = "<foo></foo>";
+ XMLDocument doc;
+ doc.Parse( str );
+ XMLElement* element = doc.RootElement();
+
+ element->SetText("darkness.");
+ XMLTest( "SetText() normal use (open/close).", "darkness.", element->GetText() );
+
+ element->SetText("blue flame.");
+ XMLTest( "SetText() replace.", "blue flame.", element->GetText() );
+
+ str = "<foo/>";
+ doc.Parse( str );
+ element = doc.RootElement();
+
+ element->SetText("The driver");
+ XMLTest( "SetText() normal use. (self-closing)", "The driver", element->GetText() );
+
+ element->SetText("<b>horses</b>");
+ XMLTest( "SetText() replace with tag-like text.", "<b>horses</b>", element->GetText() );
+ //doc.Print();
+
+ str = "<foo><bar>Text in nested element</bar></foo>";
+ doc.Parse( str );
+ element = doc.RootElement();
+
+ element->SetText("wolves");
+ XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
+
+ str = "<foo/>";
+ doc.Parse( str );
+ element = doc.RootElement();
+
+ element->SetText( "str" );
+ XMLTest( "SetText types", "str", element->GetText() );
+
+ element->SetText( 1 );
+ XMLTest( "SetText types", "1", element->GetText() );
+
+ element->SetText( 1U );
+ XMLTest( "SetText types", "1", element->GetText() );
+
+ element->SetText( true );
+ XMLTest( "SetText types", "1", element->GetText() ); // TODO: should be 'true'?
+
+ element->SetText( 1.5f );
+ XMLTest( "SetText types", "1.5", element->GetText() );
+
+ element->SetText( 1.5 );
+ XMLTest( "SetText types", "1.5", element->GetText() );
+ }
+
+
// ---------- CDATA ---------------
{
const char* str = "<xmlElement>"
@@ -1139,18 +1194,6 @@
XMLTest( "Whitespace all space", true, 0 == doc.FirstChildElement()->FirstChild() );
}
-#if 0 // the question being explored is what kind of print to use:
- // https://github.com/leethomason/tinyxml2/issues/63
- {
- const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9'/>";
- XMLDocument doc;
- doc.Parse( xml );
- doc.FirstChildElement()->SetAttribute( "attrA", 123456789.123456789 );
- doc.FirstChildElement()->SetAttribute( "attrB", 1.001e9 );
- doc.Print();
- }
-#endif
-
{
// An assert should not fire.
const char* xml = "<element/>";
@@ -1240,39 +1283,85 @@
"</root>";
XMLDocument doc;
- doc.Parse( xml );
+ doc.Parse(xml);
XMLElement* subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
XMLElement* two = doc.RootElement()->FirstChildElement("two");
two->InsertFirstChild(subtree);
- XMLPrinter printer1( 0, true );
- doc.Accept( &printer1 );
- XMLTest( "Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
+ XMLPrinter printer1(0, true);
+ doc.Accept(&printer1);
+ XMLTest("Move node from within <one> to <two>", xmlInsideTwo, printer1.CStr());
- doc.Parse( xml );
+ doc.Parse(xml);
subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
two = doc.RootElement()->FirstChildElement("two");
doc.RootElement()->InsertAfterChild(two, subtree);
- XMLPrinter printer2( 0, true );
- doc.Accept( &printer2 );
- XMLTest( "Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false );
+ XMLPrinter printer2(0, true);
+ doc.Accept(&printer2);
+ XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer2.CStr(), false);
- doc.Parse( xml );
+ doc.Parse(xml);
XMLNode* one = doc.RootElement()->FirstChildElement("one");
subtree = one->FirstChildElement("subtree");
doc.RootElement()->InsertAfterChild(one, subtree);
- XMLPrinter printer3( 0, true );
- doc.Accept( &printer3 );
- XMLTest( "Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false );
+ XMLPrinter printer3(0, true);
+ doc.Accept(&printer3);
+ XMLTest("Move node from within <one> after <one>", xmlAfterOne, printer3.CStr(), false);
- doc.Parse( xml );
+ doc.Parse(xml);
subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
two = doc.RootElement()->FirstChildElement("two");
doc.RootElement()->InsertEndChild(subtree);
- XMLPrinter printer4( 0, true );
- doc.Accept( &printer4 );
- XMLTest( "Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false );
+ XMLPrinter printer4(0, true);
+ doc.Accept(&printer4);
+ XMLTest("Move node from within <one> after <two>", xmlAfterTwo, printer4.CStr(), false);
}
+ {
+ const char* xml = "<svg width = \"128\" height = \"128\">"
+ " <text> </text>"
+ "</svg>";
+ XMLDocument doc;
+ doc.Parse(xml);
+ doc.Print();
+ }
+
+#if 1
+ // the question being explored is what kind of print to use:
+ // https://github.com/leethomason/tinyxml2/issues/63
+ {
+ //const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
+ const char* xml = "<element/>";
+ XMLDocument doc;
+ doc.Parse( xml );
+ doc.FirstChildElement()->SetAttribute( "attrA-f64", 123456789.123456789 );
+ doc.FirstChildElement()->SetAttribute( "attrB-f64", 1.001e9 );
+ doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e9 );
+ doc.FirstChildElement()->SetAttribute( "attrC-f64", 1.0e20 );
+ doc.FirstChildElement()->SetAttribute( "attrD-f64", 1.0e-10 );
+ doc.FirstChildElement()->SetAttribute( "attrD-f64", 0.123456789 );
+
+ doc.FirstChildElement()->SetAttribute( "attrA-f32", 123456789.123456789f );
+ doc.FirstChildElement()->SetAttribute( "attrB-f32", 1.001e9f );
+ doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e9f );
+ doc.FirstChildElement()->SetAttribute( "attrC-f32", 1.0e20f );
+ doc.FirstChildElement()->SetAttribute( "attrD-f32", 1.0e-10f );
+ doc.FirstChildElement()->SetAttribute( "attrD-f32", 0.123456789f );
+
+ doc.Print();
+
+ /* The result of this test is platform, compiler, and library version dependent. :("
+ XMLPrinter printer;
+ doc.Print( &printer );
+ XMLTest( "Float and double formatting.",
+ "<element attrA-f64=\"123456789.12345679\" attrB-f64=\"1001000000\" attrC-f64=\"1e+20\" attrD-f64=\"0.123456789\" attrA-f32=\"1.2345679e+08\" attrB-f32=\"1.001e+09\" attrC-f32=\"1e+20\" attrD-f32=\"0.12345679\"/>\n",
+ printer.CStr(),
+ true );
+ */
+ }
+#endif
+
+
+
// ----------- Performance tracking --------------
{
#if defined( _MSC_VER )