blob: ae6a7475b81ff676cf9e89bb0392e7166d87e939 [file] [log] [blame]
U-Lama\Lee560bd472011-12-28 19:42:49 -08001#include "tinyxml2.h"
2
3#include <string.h>
4#include <stdlib.h>
5#include <stdio.h>
U-Lama\Lee4cee6112011-12-31 14:58:18 -08006#include <ctype.h>
U-Lama\Lee560bd472011-12-28 19:42:49 -08007
8using namespace tinyxml2;
9
Lee Thomasonfde6a752012-01-14 18:08:12 -080010static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
11static const char LF = LINE_FEED;
12static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
13static const char CR = CARRIAGE_RETURN;
14
15
Lee Thomason3f57d272012-01-11 15:30:03 -080016// --------- CharBuffer ----------- //
U-Lama\Lee560bd472011-12-28 19:42:49 -080017/*static*/ CharBuffer* CharBuffer::Construct( const char* in )
18{
19 size_t len = strlen( in );
20 size_t size = len + sizeof( CharBuffer );
21 CharBuffer* cb = (CharBuffer*) malloc( size );
22 cb->length = len;
23 strcpy( cb->mem, in );
24 return cb;
25}
26
27
28/*static*/ void CharBuffer::Free( CharBuffer* cb )
29{
30 free( cb );
31}
32
33
Lee Thomason3f57d272012-01-11 15:30:03 -080034// --------- XMLNode ----------- //
35
36XMLNode::XMLNode( XMLDocument* doc ) :
37 document( doc ),
38 parent( 0 ),
39 firstChild( 0 ), lastChild( 0 ),
40 prev( 0 ), next( 0 )
U-Lama\Lee4cee6112011-12-31 14:58:18 -080041{
Lee Thomason3f57d272012-01-11 15:30:03 -080042
43}
44
45
46XMLNode::~XMLNode()
47{
48 XMLNode* node=firstChild;
49 while( node ) {
50 XMLNode* temp = node->next;
51 delete node;
52 node = temp;
U-Lama\Lee4cee6112011-12-31 14:58:18 -080053 }
Lee Thomason3f57d272012-01-11 15:30:03 -080054}
55
56
57XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
58{
59 if ( lastChild ) {
60 TIXMLASSERT( firstChild );
61 TIXMLASSERT( lastChild->next == 0 );
62 lastChild->next = addThis;
63 addThis->prev = lastChild;
64 lastChild = addThis;
65
66 addThis->parent = this;
Lee Thomasonce0763e2012-01-11 15:43:54 -080067 addThis->next = 0;
Lee Thomason3f57d272012-01-11 15:30:03 -080068 }
69 else {
70 TIXMLASSERT( firstChild == 0 );
71 firstChild = lastChild = addThis;
72
73 addThis->parent = this;
74 addThis->prev = 0;
Lee Thomasonce0763e2012-01-11 15:43:54 -080075 addThis->next = 0;
76 }
77 return addThis;
78}
79
80
81void XMLNode::Print( FILE* fp, int depth )
82{
Lee Thomason85403d82012-01-11 15:55:05 -080083 for( XMLNode* node = firstChild; node; node=node->next ) {
84 node->Print( fp, depth );
85 }
86}
87
88void XMLNode::PrintSpace( FILE* fp, int depth )
89{
Lee Thomasonce0763e2012-01-11 15:43:54 -080090 for( int i=0; i<depth; ++i ) {
91 fprintf( fp, " " );
Lee Thomason3f57d272012-01-11 15:30:03 -080092 }
93}
94
95
96const char* XMLNode::ParseText( char* p, const char* endTag, char** next )
97{
98 TIXMLASSERT( endTag && *endTag );
99
Lee Thomasonfde6a752012-01-14 18:08:12 -0800100 char* start = p;
101 char* q = p; // q (target) <= p (src) in same buffer.
102 char endChar = *endTag;
103 int length = strlen( endTag );
104 char* nextTag = 0;
Lee Thomason3f57d272012-01-11 15:30:03 -0800105
Lee Thomasonfde6a752012-01-14 18:08:12 -0800106 // Inner loop of text parsing.
Lee Thomason3f57d272012-01-11 15:30:03 -0800107 while ( *p ) {
Lee Thomasonfde6a752012-01-14 18:08:12 -0800108 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
109 *q = 0;
110 nextTag = p + length;
111 break;
Lee Thomason3f57d272012-01-11 15:30:03 -0800112 }
Lee Thomasonfde6a752012-01-14 18:08:12 -0800113 else if ( *p == CR ) {
114 // CR-LF pair becomes LF
115 // CR alone becomes LF
116 // LF-CR becomes LF
117 if ( *(p+1) == LF ) {
118 p += 2;
119 }
120 else {
121 ++p;
122 }
123 *q = LF;
124 }
125 else if ( *p == LF ) {
126 if ( *(p+1) == CR ) {
127 p += 2;
128 }
129 else {
130 ++p;
131 }
132 *q = LF;
133 }
134 else {
135 *q = *p;
136 ++p;
137 }
138 ++q;
Lee Thomason3f57d272012-01-11 15:30:03 -0800139 }
Lee Thomasonfde6a752012-01-14 18:08:12 -0800140
141 // Error? If we don't have a text tag, something went wrong. (Although
142 // what the nextTag points at may be null.)
143 if ( nextTag == 0 ) {
144 return 0;
145 }
146 *next = nextTag;
147 return start;
Lee Thomason3f57d272012-01-11 15:30:03 -0800148}
149
150
151// --------- XMLComment ---------- //
152
153XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
154{
155}
156
157
Lee Thomasonce0763e2012-01-11 15:43:54 -0800158XMLComment::~XMLComment()
Lee Thomason3f57d272012-01-11 15:30:03 -0800159{
160
161}
162
163
Lee Thomasonce0763e2012-01-11 15:43:54 -0800164void XMLComment::Print( FILE* fp, int depth )
165{
166 XMLNode::Print( fp, depth );
Lee Thomasonfde6a752012-01-14 18:08:12 -0800167 fprintf( fp, "<!--%s-->\n", value );
Lee Thomasonce0763e2012-01-11 15:43:54 -0800168}
169
170
171char* XMLComment::ParseDeep( char* p )
Lee Thomason3f57d272012-01-11 15:30:03 -0800172{
173 // Comment parses as text.
174 value = ParseText( p, "-->", &p );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800175 return p;
176}
177
178
Lee Thomason3f57d272012-01-11 15:30:03 -0800179// --------- XMLDocument ----------- //
U-Lama\Lee560bd472011-12-28 19:42:49 -0800180XMLDocument::XMLDocument() :
181 charBuffer( 0 )
182{
Lee Thomason85403d82012-01-11 15:55:05 -0800183 root = new XMLNode( this );
U-Lama\Lee560bd472011-12-28 19:42:49 -0800184}
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800185
186
Lee Thomason3f57d272012-01-11 15:30:03 -0800187XMLDocument::~XMLDocument()
188{
189 delete root;
190 delete charBuffer;
191}
192
193
194
195bool XMLDocument::Parse( const char* p )
196{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800197 charBuffer = CharBuffer::Construct( p );
Lee Thomason3f57d272012-01-11 15:30:03 -0800198 XMLNode* node = 0;
Lee Thomason85403d82012-01-11 15:55:05 -0800199
Lee Thomasonce0763e2012-01-11 15:43:54 -0800200 char* q = Identify( charBuffer->mem, &node );
Lee Thomason85403d82012-01-11 15:55:05 -0800201 root->InsertEndChild( node );
Lee Thomasonce0763e2012-01-11 15:43:54 -0800202 node->ParseDeep( q );
Lee Thomason85403d82012-01-11 15:55:05 -0800203
Lee Thomasonce0763e2012-01-11 15:43:54 -0800204 return true;
Lee Thomason3f57d272012-01-11 15:30:03 -0800205}
206
207
Lee Thomasonce0763e2012-01-11 15:43:54 -0800208void XMLDocument::Print( FILE* fp, int depth )
Lee Thomason3f57d272012-01-11 15:30:03 -0800209{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800210 for( XMLNode* node = root->firstChild; node; node=node->next ) {
211 node->Print( fp, depth );
212 }
Lee Thomason3f57d272012-01-11 15:30:03 -0800213}
214
215
Lee Thomason3f57d272012-01-11 15:30:03 -0800216char* XMLDocument::Identify( char* p, XMLNode** node )
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800217{
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800218 XMLNode* returnNode = 0;
219
220 p = XMLNode::SkipWhiteSpace( p );
221 if( !p || !*p || *p != '<' )
222 {
223 return 0;
224 }
225
226 // What is this thing?
227 // - Elements start with a letter or underscore, but xml is reserved.
228 // - Comments: <!--
229 // - Decleration: <?xml
230 // - Everthing else is unknown to tinyxml.
231 //
232
Lee Thomason85403d82012-01-11 15:55:05 -0800233 static const char* xmlHeader = { "<?xml" };
234 static const char* commentHeader = { "<!--" };
235 static const char* dtdHeader = { "<!" };
236 static const char* cdataHeader = { "<![CDATA[" };
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800237
Lee Thomason85403d82012-01-11 15:55:05 -0800238 static const int xmlHeaderLen = 5;
239 static const int commentHeaderLen = 4;
240 static const int dtdHeaderLen = 2;
241 static const int cdataHeaderLen = 9;
242
243 if ( XMLNode::StringEqual( p, commentHeader, commentHeaderLen ) ) {
Lee Thomasonce0763e2012-01-11 15:43:54 -0800244 returnNode = new XMLComment( this );
Lee Thomason85403d82012-01-11 15:55:05 -0800245 p += commentHeaderLen;
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800246 }
247 else {
248 TIXMLASSERT( 0 );
249 }
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800250
Lee Thomason3f57d272012-01-11 15:30:03 -0800251 *node = returnNode;
252 return p;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800253}