Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Extras / Serialize / BulletXmlWorldImporter / tinyxmlparser.cpp
1 /*\r
2 www.sourceforge.net/projects/tinyxml\r
3 Original code by Lee Thomason (www.grinninglizard.com)\r
4 \r
5 This software is provided 'as-is', without any express or implied \r
6 warranty. In no event will the authors be held liable for any \r
7 damages arising from the use of this software.\r
8 \r
9 Permission is granted to anyone to use this software for any \r
10 purpose, including commercial applications, and to alter it and \r
11 redistribute it freely, subject to the following restrictions:\r
12 \r
13 1. The origin of this software must not be misrepresented; you must \r
14 not claim that you wrote the original software. If you use this\r
15 software in a product, an acknowledgment in the product documentation\r
16 would be appreciated but is not required.\r
17 \r
18 2. Altered source versions must be plainly marked as such, and \r
19 must not be misrepresented as being the original software.\r
20 \r
21 3. This notice may not be removed or altered from any source \r
22 distribution.\r
23 */\r
24 \r
25 #include <ctype.h>\r
26 #include <stddef.h>\r
27 \r
28 #include "tinyxml.h"\r
29 \r
30 //#define DEBUG_PARSER\r
31 #if defined( DEBUG_PARSER )\r
32 #       if defined( DEBUG ) && defined( _MSC_VER )\r
33 #               include <windows.h>\r
34 #               define TIXML_LOG OutputDebugString\r
35 #       else\r
36 #               define TIXML_LOG printf\r
37 #       endif\r
38 #endif\r
39 \r
40 // Note tha "PutString" hardcodes the same list. This\r
41 // is less flexible than it appears. Changing the entries\r
42 // or order will break putstring.       \r
43 TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = \r
44 {\r
45         { "&amp;",  5, '&' },\r
46         { "&lt;",   4, '<' },\r
47         { "&gt;",   4, '>' },\r
48         { "&quot;", 6, '\"' },\r
49         { "&apos;", 6, '\'' }\r
50 };\r
51 \r
52 // Bunch of unicode info at:\r
53 //              http://www.unicode.org/faq/utf_bom.html\r
54 // Including the basic of this table, which determines the #bytes in the\r
55 // sequence from the lead byte. 1 placed for invalid sequences --\r
56 // although the result will be junk, pass it through as much as possible.\r
57 // Beware of the non-characters in UTF-8:       \r
58 //                              ef bb bf (Microsoft "lead bytes")\r
59 //                              ef bf be\r
60 //                              ef bf bf \r
61 \r
62 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;\r
63 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;\r
64 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;\r
65 \r
66 const int TiXmlBase::utf8ByteTable[256] = \r
67 {\r
68         //      0       1       2       3       4       5       6       7       8       9       a       b       c       d       e       f\r
69                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x00\r
70                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x10\r
71                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x20\r
72                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x30\r
73                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x40\r
74                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x50\r
75                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x60\r
76                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x70 End of ASCII range\r
77                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x80 0x80 to 0xc1 invalid\r
78                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0x90 \r
79                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0xa0 \r
80                 1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      // 0xb0 \r
81                 1,      1,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      // 0xc0 0xc2 to 0xdf 2 byte\r
82                 2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      2,      // 0xd0\r
83                 3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      3,      // 0xe0 0xe0 to 0xef 3 byte\r
84                 4,      4,      4,      4,      4,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1,      1       // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid\r
85 };\r
86 \r
87 \r
88 void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )\r
89 {\r
90         const unsigned long BYTE_MASK = 0xBF;\r
91         const unsigned long BYTE_MARK = 0x80;\r
92         const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };\r
93 \r
94         if (input < 0x80) \r
95                 *length = 1;\r
96         else if ( input < 0x800 )\r
97                 *length = 2;\r
98         else if ( input < 0x10000 )\r
99                 *length = 3;\r
100         else if ( input < 0x200000 )\r
101                 *length = 4;\r
102         else\r
103                 { *length = 0; return; }        // This code won't covert this correctly anyway.\r
104 \r
105         output += *length;\r
106 \r
107         // Scary scary fall throughs.\r
108         switch (*length) \r
109         {\r
110                 case 4:\r
111                         --output; \r
112                         *output = (char)((input | BYTE_MARK) & BYTE_MASK); \r
113                         input >>= 6;\r
114                 case 3:\r
115                         --output; \r
116                         *output = (char)((input | BYTE_MARK) & BYTE_MASK); \r
117                         input >>= 6;\r
118                 case 2:\r
119                         --output; \r
120                         *output = (char)((input | BYTE_MARK) & BYTE_MASK); \r
121                         input >>= 6;\r
122                 case 1:\r
123                         --output; \r
124                         *output = (char)(input | FIRST_BYTE_MARK[*length]);\r
125         }\r
126 }\r
127 \r
128 \r
129 /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )\r
130 {\r
131         // This will only work for low-ascii, everything else is assumed to be a valid\r
132         // letter. I'm not sure this is the best approach, but it is quite tricky trying\r
133         // to figure out alhabetical vs. not across encoding. So take a very \r
134         // conservative approach.\r
135 \r
136 //      if ( encoding == TIXML_ENCODING_UTF8 )\r
137 //      {\r
138                 if ( anyByte < 127 )\r
139                         return isalpha( anyByte );\r
140                 else\r
141                         return 1;       // What else to do? The unicode set is huge...get the english ones right.\r
142 //      }\r
143 //      else\r
144 //      {\r
145 //              return isalpha( anyByte );\r
146 //      }\r
147 }\r
148 \r
149 \r
150 /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )\r
151 {\r
152         // This will only work for low-ascii, everything else is assumed to be a valid\r
153         // letter. I'm not sure this is the best approach, but it is quite tricky trying\r
154         // to figure out alhabetical vs. not across encoding. So take a very \r
155         // conservative approach.\r
156 \r
157 //      if ( encoding == TIXML_ENCODING_UTF8 )\r
158 //      {\r
159                 if ( anyByte < 127 )\r
160                         return isalnum( anyByte );\r
161                 else\r
162                         return 1;       // What else to do? The unicode set is huge...get the english ones right.\r
163 //      }\r
164 //      else\r
165 //      {\r
166 //              return isalnum( anyByte );\r
167 //      }\r
168 }\r
169 \r
170 \r
171 class TiXmlParsingData\r
172 {\r
173         friend class TiXmlDocument;\r
174   public:\r
175         void Stamp( const char* now, TiXmlEncoding encoding );\r
176 \r
177         const TiXmlCursor& Cursor() const       { return cursor; }\r
178 \r
179   private:\r
180         // Only used by the document!\r
181         TiXmlParsingData( const char* start, int _tabsize, int row, int col )\r
182         {\r
183                 assert( start );\r
184                 stamp = start;\r
185                 tabsize = _tabsize;\r
186                 cursor.row = row;\r
187                 cursor.col = col;\r
188         }\r
189 \r
190         TiXmlCursor             cursor;\r
191         const char*             stamp;\r
192         int                             tabsize;\r
193 };\r
194 \r
195 \r
196 void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )\r
197 {\r
198         assert( now );\r
199 \r
200         // Do nothing if the tabsize is 0.\r
201         if ( tabsize < 1 )\r
202         {\r
203                 return;\r
204         }\r
205 \r
206         // Get the current row, column.\r
207         int row = cursor.row;\r
208         int col = cursor.col;\r
209         const char* p = stamp;\r
210         assert( p );\r
211 \r
212         while ( p < now )\r
213         {\r
214                 // Treat p as unsigned, so we have a happy compiler.\r
215                 const unsigned char* pU = (const unsigned char*)p;\r
216 \r
217                 // Code contributed by Fletcher Dunn: (modified by lee)\r
218                 switch (*pU) {\r
219                         case 0:\r
220                                 // We *should* never get here, but in case we do, don't\r
221                                 // advance past the terminating null character, ever\r
222                                 return;\r
223 \r
224                         case '\r':\r
225                                 // bump down to the next line\r
226                                 ++row;\r
227                                 col = 0;                                \r
228                                 // Eat the character\r
229                                 ++p;\r
230 \r
231                                 // Check for \r\n sequence, and treat this as a single character\r
232                                 if (*p == '\n') {\r
233                                         ++p;\r
234                                 }\r
235                                 break;\r
236 \r
237                         case '\n':\r
238                                 // bump down to the next line\r
239                                 ++row;\r
240                                 col = 0;\r
241 \r
242                                 // Eat the character\r
243                                 ++p;\r
244 \r
245                                 // Check for \n\r sequence, and treat this as a single\r
246                                 // character.  (Yes, this bizarre thing does occur still\r
247                                 // on some arcane platforms...)\r
248                                 if (*p == '\r') {\r
249                                         ++p;\r
250                                 }\r
251                                 break;\r
252 \r
253                         case '\t':\r
254                                 // Eat the character\r
255                                 ++p;\r
256 \r
257                                 // Skip to next tab stop\r
258                                 col = (col / tabsize + 1) * tabsize;\r
259                                 break;\r
260 \r
261                         case TIXML_UTF_LEAD_0:\r
262                                 if ( encoding == TIXML_ENCODING_UTF8 )\r
263                                 {\r
264                                         if ( *(p+1) && *(p+2) )\r
265                                         {\r
266                                                 // In these cases, don't advance the column. These are\r
267                                                 // 0-width spaces.\r
268                                                 if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )\r
269                                                         p += 3; \r
270                                                 else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )\r
271                                                         p += 3; \r
272                                                 else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )\r
273                                                         p += 3; \r
274                                                 else\r
275                                                         { p +=3; ++col; }       // A normal character.\r
276                                         }\r
277                                 }\r
278                                 else\r
279                                 {\r
280                                         ++p;\r
281                                         ++col;\r
282                                 }\r
283                                 break;\r
284 \r
285                         default:\r
286                                 if ( encoding == TIXML_ENCODING_UTF8 )\r
287                                 {\r
288                                         // Eat the 1 to 4 byte utf8 character.\r
289                                         int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];\r
290                                         if ( step == 0 )\r
291                                                 step = 1;               // Error case from bad encoding, but handle gracefully.\r
292                                         p += step;\r
293 \r
294                                         // Just advance one column, of course.\r
295                                         ++col;\r
296                                 }\r
297                                 else\r
298                                 {\r
299                                         ++p;\r
300                                         ++col;\r
301                                 }\r
302                                 break;\r
303                 }\r
304         }\r
305         cursor.row = row;\r
306         cursor.col = col;\r
307         assert( cursor.row >= -1 );\r
308         assert( cursor.col >= -1 );\r
309         stamp = p;\r
310         assert( stamp );\r
311 }\r
312 \r
313 \r
314 const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )\r
315 {\r
316         if ( !p || !*p )\r
317         {\r
318                 return 0;\r
319         }\r
320         if ( encoding == TIXML_ENCODING_UTF8 )\r
321         {\r
322                 while ( *p )\r
323                 {\r
324                         const unsigned char* pU = (const unsigned char*)p;\r
325                         \r
326                         // Skip the stupid Microsoft UTF-8 Byte order marks\r
327                         if (    *(pU+0)==TIXML_UTF_LEAD_0\r
328                                  && *(pU+1)==TIXML_UTF_LEAD_1 \r
329                                  && *(pU+2)==TIXML_UTF_LEAD_2 )\r
330                         {\r
331                                 p += 3;\r
332                                 continue;\r
333                         }\r
334                         else if(*(pU+0)==TIXML_UTF_LEAD_0\r
335                                  && *(pU+1)==0xbfU\r
336                                  && *(pU+2)==0xbeU )\r
337                         {\r
338                                 p += 3;\r
339                                 continue;\r
340                         }\r
341                         else if(*(pU+0)==TIXML_UTF_LEAD_0\r
342                                  && *(pU+1)==0xbfU\r
343                                  && *(pU+2)==0xbfU )\r
344                         {\r
345                                 p += 3;\r
346                                 continue;\r
347                         }\r
348 \r
349                         if ( IsWhiteSpace( *p ) )               // Still using old rules for white space.\r
350                                 ++p;\r
351                         else\r
352                                 break;\r
353                 }\r
354         }\r
355         else\r
356         {\r
357                 while ( *p && IsWhiteSpace( *p ) )\r
358                         ++p;\r
359         }\r
360 \r
361         return p;\r
362 }\r
363 \r
364 #ifdef TIXML_USE_STL\r
365 /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )\r
366 {\r
367         for( ;; )\r
368         {\r
369                 if ( !in->good() ) return false;\r
370 \r
371                 int c = in->peek();\r
372                 // At this scope, we can't get to a document. So fail silently.\r
373                 if ( !IsWhiteSpace( c ) || c <= 0 )\r
374                         return true;\r
375 \r
376                 *tag += (char) in->get();\r
377         }\r
378 }\r
379 \r
380 /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )\r
381 {\r
382         //assert( character > 0 && character < 128 );   // else it won't work in utf-8\r
383         while ( in->good() )\r
384         {\r
385                 int c = in->peek();\r
386                 if ( c == character )\r
387                         return true;\r
388                 if ( c <= 0 )           // Silent failure: can't get document at this scope\r
389                         return false;\r
390 \r
391                 in->get();\r
392                 *tag += (char) c;\r
393         }\r
394         return false;\r
395 }\r
396 #endif\r
397 \r
398 // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The\r
399 // "assign" optimization removes over 10% of the execution time.\r
400 //\r
401 const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )\r
402 {\r
403         // Oddly, not supported on some comilers,\r
404         //name->clear();\r
405         // So use this:\r
406         *name = "";\r
407         assert( p );\r
408 \r
409         // Names start with letters or underscores.\r
410         // Of course, in unicode, tinyxml has no idea what a letter *is*. The\r
411         // algorithm is generous.\r
412         //\r
413         // After that, they can be letters, underscores, numbers,\r
414         // hyphens, or colons. (Colons are valid ony for namespaces,\r
415         // but tinyxml can't tell namespaces from names.)\r
416         if (    p && *p \r
417                  && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )\r
418         {\r
419                 const char* start = p;\r
420                 while(          p && *p\r
421                                 &&      (               IsAlphaNum( (unsigned char ) *p, encoding ) \r
422                                                  || *p == '_'\r
423                                                  || *p == '-'\r
424                                                  || *p == '.'\r
425                                                  || *p == ':' ) )\r
426                 {\r
427                         //(*name) += *p; // expensive\r
428                         ++p;\r
429                 }\r
430                 if ( p-start > 0 ) {\r
431                         name->assign( start, p-start );\r
432                 }\r
433                 return p;\r
434         }\r
435         return 0;\r
436 }\r
437 \r
438 const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )\r
439 {\r
440         // Presume an entity, and pull it out.\r
441     TIXML_STRING ent;\r
442         int i;\r
443         *length = 0;\r
444 \r
445         if ( *(p+1) && *(p+1) == '#' && *(p+2) )\r
446         {\r
447                 unsigned long ucs = 0;\r
448                 ptrdiff_t delta = 0;\r
449                 unsigned mult = 1;\r
450 \r
451                 if ( *(p+2) == 'x' )\r
452                 {\r
453                         // Hexadecimal.\r
454                         if ( !*(p+3) ) return 0;\r
455 \r
456                         const char* q = p+3;\r
457                         q = strchr( q, ';' );\r
458 \r
459                         if ( !q || !*q ) return 0;\r
460 \r
461                         delta = q-p;\r
462                         --q;\r
463 \r
464                         while ( *q != 'x' )\r
465                         {\r
466                                 if ( *q >= '0' && *q <= '9' )\r
467                                         ucs += mult * (*q - '0');\r
468                                 else if ( *q >= 'a' && *q <= 'f' )\r
469                                         ucs += mult * (*q - 'a' + 10);\r
470                                 else if ( *q >= 'A' && *q <= 'F' )\r
471                                         ucs += mult * (*q - 'A' + 10 );\r
472                                 else \r
473                                         return 0;\r
474                                 mult *= 16;\r
475                                 --q;\r
476                         }\r
477                 }\r
478                 else\r
479                 {\r
480                         // Decimal.\r
481                         if ( !*(p+2) ) return 0;\r
482 \r
483                         const char* q = p+2;\r
484                         q = strchr( q, ';' );\r
485 \r
486                         if ( !q || !*q ) return 0;\r
487 \r
488                         delta = q-p;\r
489                         --q;\r
490 \r
491                         while ( *q != '#' )\r
492                         {\r
493                                 if ( *q >= '0' && *q <= '9' )\r
494                                         ucs += mult * (*q - '0');\r
495                                 else \r
496                                         return 0;\r
497                                 mult *= 10;\r
498                                 --q;\r
499                         }\r
500                 }\r
501                 if ( encoding == TIXML_ENCODING_UTF8 )\r
502                 {\r
503                         // convert the UCS to UTF-8\r
504                         ConvertUTF32ToUTF8( ucs, value, length );\r
505                 }\r
506                 else\r
507                 {\r
508                         *value = (char)ucs;\r
509                         *length = 1;\r
510                 }\r
511                 return p + delta + 1;\r
512         }\r
513 \r
514         // Now try to match it.\r
515         for( i=0; i<NUM_ENTITY; ++i )\r
516         {\r
517                 if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )\r
518                 {\r
519                         assert( strlen( entity[i].str ) == entity[i].strLength );\r
520                         *value = entity[i].chr;\r
521                         *length = 1;\r
522                         return ( p + entity[i].strLength );\r
523                 }\r
524         }\r
525 \r
526         // So it wasn't an entity, its unrecognized, or something like that.\r
527         *value = *p;    // Don't put back the last one, since we return it!\r
528         //*length = 1;  // Leave unrecognized entities - this doesn't really work.\r
529                                         // Just writes strange XML.\r
530         return p+1;\r
531 }\r
532 \r
533 \r
534 bool TiXmlBase::StringEqual( const char* p,\r
535                                                          const char* tag,\r
536                                                          bool ignoreCase,\r
537                                                          TiXmlEncoding encoding )\r
538 {\r
539         assert( p );\r
540         assert( tag );\r
541         if ( !p || !*p )\r
542         {\r
543                 assert( 0 );\r
544                 return false;\r
545         }\r
546 \r
547         const char* q = p;\r
548 \r
549         if ( ignoreCase )\r
550         {\r
551                 while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )\r
552                 {\r
553                         ++q;\r
554                         ++tag;\r
555                 }\r
556 \r
557                 if ( *tag == 0 )\r
558                         return true;\r
559         }\r
560         else\r
561         {\r
562                 while ( *q && *tag && *q == *tag )\r
563                 {\r
564                         ++q;\r
565                         ++tag;\r
566                 }\r
567 \r
568                 if ( *tag == 0 )                // Have we found the end of the tag, and everything equal?\r
569                         return true;\r
570         }\r
571         return false;\r
572 }\r
573 \r
574 const char* TiXmlBase::ReadText(        const char* p, \r
575                                                                         TIXML_STRING * text, \r
576                                                                         bool trimWhiteSpace, \r
577                                                                         const char* endTag, \r
578                                                                         bool caseInsensitive,\r
579                                                                         TiXmlEncoding encoding )\r
580 {\r
581     *text = "";\r
582         if (    !trimWhiteSpace                 // certain tags always keep whitespace\r
583                  || !condenseWhiteSpace )       // if true, whitespace is always kept\r
584         {\r
585                 // Keep all the white space.\r
586                 while (    p && *p\r
587                                 && !StringEqual( p, endTag, caseInsensitive, encoding )\r
588                           )\r
589                 {\r
590                         int len;\r
591                         char cArr[4] = { 0, 0, 0, 0 };\r
592                         p = GetChar( p, cArr, &len, encoding );\r
593                         text->append( cArr, len );\r
594                 }\r
595         }\r
596         else\r
597         {\r
598                 bool whitespace = false;\r
599 \r
600                 // Remove leading white space:\r
601                 p = SkipWhiteSpace( p, encoding );\r
602                 while (    p && *p\r
603                                 && !StringEqual( p, endTag, caseInsensitive, encoding ) )\r
604                 {\r
605                         if ( *p == '\r' || *p == '\n' )\r
606                         {\r
607                                 whitespace = true;\r
608                                 ++p;\r
609                         }\r
610                         else if ( IsWhiteSpace( *p ) )\r
611                         {\r
612                                 whitespace = true;\r
613                                 ++p;\r
614                         }\r
615                         else\r
616                         {\r
617                                 // If we've found whitespace, add it before the\r
618                                 // new character. Any whitespace just becomes a space.\r
619                                 if ( whitespace )\r
620                                 {\r
621                                         (*text) += ' ';\r
622                                         whitespace = false;\r
623                                 }\r
624                                 int len;\r
625                                 char cArr[4] = { 0, 0, 0, 0 };\r
626                                 p = GetChar( p, cArr, &len, encoding );\r
627                                 if ( len == 1 )\r
628                                         (*text) += cArr[0];     // more efficient\r
629                                 else\r
630                                         text->append( cArr, len );\r
631                         }\r
632                 }\r
633         }\r
634         if ( p && *p )\r
635                 p += strlen( endTag );\r
636         return ( p && *p ) ? p : 0;\r
637 }\r
638 \r
639 #ifdef TIXML_USE_STL\r
640 \r
641 void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )\r
642 {\r
643         // The basic issue with a document is that we don't know what we're\r
644         // streaming. Read something presumed to be a tag (and hope), then\r
645         // identify it, and call the appropriate stream method on the tag.\r
646         //\r
647         // This "pre-streaming" will never read the closing ">" so the\r
648         // sub-tag can orient itself.\r
649 \r
650         if ( !StreamTo( in, '<', tag ) ) \r
651         {\r
652                 SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );\r
653                 return;\r
654         }\r
655 \r
656         while ( in->good() )\r
657         {\r
658                 int tagIndex = (int) tag->length();\r
659                 while ( in->good() && in->peek() != '>' )\r
660                 {\r
661                         int c = in->get();\r
662                         if ( c <= 0 )\r
663                         {\r
664                                 SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
665                                 break;\r
666                         }\r
667                         (*tag) += (char) c;\r
668                 }\r
669 \r
670                 if ( in->good() )\r
671                 {\r
672                         // We now have something we presume to be a node of \r
673                         // some sort. Identify it, and call the node to\r
674                         // continue streaming.\r
675                         TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );\r
676 \r
677                         if ( node )\r
678                         {\r
679                                 node->StreamIn( in, tag );\r
680                                 bool isElement = node->ToElement() != 0;\r
681                                 delete node;\r
682                                 node = 0;\r
683 \r
684                                 // If this is the root element, we're done. Parsing will be\r
685                                 // done by the >> operator.\r
686                                 if ( isElement )\r
687                                 {\r
688                                         return;\r
689                                 }\r
690                         }\r
691                         else\r
692                         {\r
693                                 SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );\r
694                                 return;\r
695                         }\r
696                 }\r
697         }\r
698         // We should have returned sooner.\r
699         SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );\r
700 }\r
701 \r
702 #endif\r
703 \r
704 const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )\r
705 {\r
706         ClearError();\r
707 \r
708         // Parse away, at the document level. Since a document\r
709         // contains nothing but other tags, most of what happens\r
710         // here is skipping white space.\r
711         if ( !p || !*p )\r
712         {\r
713                 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );\r
714                 return 0;\r
715         }\r
716 \r
717         // Note that, for a document, this needs to come\r
718         // before the while space skip, so that parsing\r
719         // starts from the pointer we are given.\r
720         location.Clear();\r
721         if ( prevData )\r
722         {\r
723                 location.row = prevData->cursor.row;\r
724                 location.col = prevData->cursor.col;\r
725         }\r
726         else\r
727         {\r
728                 location.row = 0;\r
729                 location.col = 0;\r
730         }\r
731         TiXmlParsingData data( p, TabSize(), location.row, location.col );\r
732         location = data.Cursor();\r
733 \r
734         if ( encoding == TIXML_ENCODING_UNKNOWN )\r
735         {\r
736                 // Check for the Microsoft UTF-8 lead bytes.\r
737                 const unsigned char* pU = (const unsigned char*)p;\r
738                 if (    *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0\r
739                          && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1\r
740                          && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )\r
741                 {\r
742                         encoding = TIXML_ENCODING_UTF8;\r
743                         useMicrosoftBOM = true;\r
744                 }\r
745         }\r
746 \r
747     p = SkipWhiteSpace( p, encoding );\r
748         if ( !p )\r
749         {\r
750                 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );\r
751                 return 0;\r
752         }\r
753 \r
754         while ( p && *p )\r
755         {\r
756                 TiXmlNode* node = Identify( p, encoding );\r
757                 if ( node )\r
758                 {\r
759                         p = node->Parse( p, &data, encoding );\r
760                         LinkEndChild( node );\r
761                 }\r
762                 else\r
763                 {\r
764                         break;\r
765                 }\r
766 \r
767                 // Did we get encoding info?\r
768                 if (    encoding == TIXML_ENCODING_UNKNOWN\r
769                          && node->ToDeclaration() )\r
770                 {\r
771                         TiXmlDeclaration* dec = node->ToDeclaration();\r
772                         const char* enc = dec->Encoding();\r
773                         assert( enc );\r
774 \r
775                         if ( *enc == 0 )\r
776                                 encoding = TIXML_ENCODING_UTF8;\r
777                         else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )\r
778                                 encoding = TIXML_ENCODING_UTF8;\r
779                         else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )\r
780                                 encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice\r
781                         else \r
782                                 encoding = TIXML_ENCODING_LEGACY;\r
783                 }\r
784 \r
785                 p = SkipWhiteSpace( p, encoding );\r
786         }\r
787 \r
788         // Was this empty?\r
789         if ( !firstChild ) {\r
790                 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );\r
791                 return 0;\r
792         }\r
793 \r
794         // All is well.\r
795         return p;\r
796 }\r
797 \r
798 void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )\r
799 {       \r
800         // The first error in a chain is more accurate - don't set again!\r
801         if ( error )\r
802                 return;\r
803 \r
804         assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );\r
805         error   = true;\r
806         errorId = err;\r
807         errorDesc = errorString[ errorId ];\r
808 \r
809         errorLocation.Clear();\r
810         if ( pError && data )\r
811         {\r
812                 data->Stamp( pError, encoding );\r
813                 errorLocation = data->Cursor();\r
814         }\r
815 }\r
816 \r
817 \r
818 TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )\r
819 {\r
820         TiXmlNode* returnNode = 0;\r
821 \r
822         p = SkipWhiteSpace( p, encoding );\r
823         if( !p || !*p || *p != '<' )\r
824         {\r
825                 return 0;\r
826         }\r
827 \r
828         p = SkipWhiteSpace( p, encoding );\r
829 \r
830         if ( !p || !*p )\r
831         {\r
832                 return 0;\r
833         }\r
834 \r
835         // What is this thing? \r
836         // - Elements start with a letter or underscore, but xml is reserved.\r
837         // - Comments: <!--\r
838         // - Decleration: <?xml\r
839         // - Everthing else is unknown to tinyxml.\r
840         //\r
841 \r
842         const char* xmlHeader = { "<?xml" };\r
843         const char* commentHeader = { "<!--" };\r
844         const char* dtdHeader = { "<!" };\r
845         const char* cdataHeader = { "<![CDATA[" };\r
846 \r
847         if ( StringEqual( p, xmlHeader, true, encoding ) )\r
848         {\r
849                 #ifdef DEBUG_PARSER\r
850                         TIXML_LOG( "XML parsing Declaration\n" );\r
851                 #endif\r
852                 returnNode = new TiXmlDeclaration();\r
853         }\r
854         else if ( StringEqual( p, commentHeader, false, encoding ) )\r
855         {\r
856                 #ifdef DEBUG_PARSER\r
857                         TIXML_LOG( "XML parsing Comment\n" );\r
858                 #endif\r
859                 returnNode = new TiXmlComment();\r
860         }\r
861         else if ( StringEqual( p, cdataHeader, false, encoding ) )\r
862         {\r
863                 #ifdef DEBUG_PARSER\r
864                         TIXML_LOG( "XML parsing CDATA\n" );\r
865                 #endif\r
866                 TiXmlText* text = new TiXmlText( "" );\r
867                 text->SetCDATA( true );\r
868                 returnNode = text;\r
869         }\r
870         else if ( StringEqual( p, dtdHeader, false, encoding ) )\r
871         {\r
872                 #ifdef DEBUG_PARSER\r
873                         TIXML_LOG( "XML parsing Unknown(1)\n" );\r
874                 #endif\r
875                 returnNode = new TiXmlUnknown();\r
876         }\r
877         else if (    IsAlpha( *(p+1), encoding )\r
878                           || *(p+1) == '_' )\r
879         {\r
880                 #ifdef DEBUG_PARSER\r
881                         TIXML_LOG( "XML parsing Element\n" );\r
882                 #endif\r
883                 returnNode = new TiXmlElement( "" );\r
884         }\r
885         else\r
886         {\r
887                 #ifdef DEBUG_PARSER\r
888                         TIXML_LOG( "XML parsing Unknown(2)\n" );\r
889                 #endif\r
890                 returnNode = new TiXmlUnknown();\r
891         }\r
892 \r
893         if ( returnNode )\r
894         {\r
895                 // Set the parent, so it can report errors\r
896                 returnNode->parent = this;\r
897         }\r
898         return returnNode;\r
899 }\r
900 \r
901 #ifdef TIXML_USE_STL\r
902 \r
903 void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)\r
904 {\r
905         // We're called with some amount of pre-parsing. That is, some of "this"\r
906         // element is in "tag". Go ahead and stream to the closing ">"\r
907         while( in->good() )\r
908         {\r
909                 int c = in->get();\r
910                 if ( c <= 0 )\r
911                 {\r
912                         TiXmlDocument* document = GetDocument();\r
913                         if ( document )\r
914                                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
915                         return;\r
916                 }\r
917                 (*tag) += (char) c ;\r
918                 \r
919                 if ( c == '>' )\r
920                         break;\r
921         }\r
922 \r
923         if ( tag->length() < 3 ) return;\r
924 \r
925         // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.\r
926         // If not, identify and stream.\r
927 \r
928         if (    tag->at( tag->length() - 1 ) == '>' \r
929                  && tag->at( tag->length() - 2 ) == '/' )\r
930         {\r
931                 // All good!\r
932                 return;\r
933         }\r
934         else if ( tag->at( tag->length() - 1 ) == '>' )\r
935         {\r
936                 // There is more. Could be:\r
937                 //              text\r
938                 //              cdata text (which looks like another node)\r
939                 //              closing tag\r
940                 //              another node.\r
941                 for ( ;; )\r
942                 {\r
943                         StreamWhiteSpace( in, tag );\r
944 \r
945                         // Do we have text?\r
946                         if ( in->good() && in->peek() != '<' ) \r
947                         {\r
948                                 // Yep, text.\r
949                                 TiXmlText text( "" );\r
950                                 text.StreamIn( in, tag );\r
951 \r
952                                 // What follows text is a closing tag or another node.\r
953                                 // Go around again and figure it out.\r
954                                 continue;\r
955                         }\r
956 \r
957                         // We now have either a closing tag...or another node.\r
958                         // We should be at a "<", regardless.\r
959                         if ( !in->good() ) return;\r
960                         assert( in->peek() == '<' );\r
961                         int tagIndex = (int) tag->length();\r
962 \r
963                         bool closingTag = false;\r
964                         bool firstCharFound = false;\r
965 \r
966                         for( ;; )\r
967                         {\r
968                                 if ( !in->good() )\r
969                                         return;\r
970 \r
971                                 int c = in->peek();\r
972                                 if ( c <= 0 )\r
973                                 {\r
974                                         TiXmlDocument* document = GetDocument();\r
975                                         if ( document )\r
976                                                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
977                                         return;\r
978                                 }\r
979                                 \r
980                                 if ( c == '>' )\r
981                                         break;\r
982 \r
983                                 *tag += (char) c;\r
984                                 in->get();\r
985 \r
986                                 // Early out if we find the CDATA id.\r
987                                 if ( c == '[' && tag->size() >= 9 )\r
988                                 {\r
989                                         size_t len = tag->size();\r
990                                         const char* start = tag->c_str() + len - 9;\r
991                                         if ( strcmp( start, "<![CDATA[" ) == 0 ) {\r
992                                                 assert( !closingTag );\r
993                                                 break;\r
994                                         }\r
995                                 }\r
996 \r
997                                 if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )\r
998                                 {\r
999                                         firstCharFound = true;\r
1000                                         if ( c == '/' )\r
1001                                                 closingTag = true;\r
1002                                 }\r
1003                         }\r
1004                         // If it was a closing tag, then read in the closing '>' to clean up the input stream.\r
1005                         // If it was not, the streaming will be done by the tag.\r
1006                         if ( closingTag )\r
1007                         {\r
1008                                 if ( !in->good() )\r
1009                                         return;\r
1010 \r
1011                                 int c = in->get();\r
1012                                 if ( c <= 0 )\r
1013                                 {\r
1014                                         TiXmlDocument* document = GetDocument();\r
1015                                         if ( document )\r
1016                                                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
1017                                         return;\r
1018                                 }\r
1019                                 assert( c == '>' );\r
1020                                 *tag += (char) c;\r
1021 \r
1022                                 // We are done, once we've found our closing tag.\r
1023                                 return;\r
1024                         }\r
1025                         else\r
1026                         {\r
1027                                 // If not a closing tag, id it, and stream.\r
1028                                 const char* tagloc = tag->c_str() + tagIndex;\r
1029                                 TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );\r
1030                                 if ( !node )\r
1031                                         return;\r
1032                                 node->StreamIn( in, tag );\r
1033                                 delete node;\r
1034                                 node = 0;\r
1035 \r
1036                                 // No return: go around from the beginning: text, closing tag, or node.\r
1037                         }\r
1038                 }\r
1039         }\r
1040 }\r
1041 #endif\r
1042 \r
1043 const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\r
1044 {\r
1045         p = SkipWhiteSpace( p, encoding );\r
1046         TiXmlDocument* document = GetDocument();\r
1047 \r
1048         if ( !p || !*p )\r
1049         {\r
1050                 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );\r
1051                 return 0;\r
1052         }\r
1053 \r
1054         if ( data )\r
1055         {\r
1056                 data->Stamp( p, encoding );\r
1057                 location = data->Cursor();\r
1058         }\r
1059 \r
1060         if ( *p != '<' )\r
1061         {\r
1062                 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );\r
1063                 return 0;\r
1064         }\r
1065 \r
1066         p = SkipWhiteSpace( p+1, encoding );\r
1067 \r
1068         // Read the name.\r
1069         const char* pErr = p;\r
1070 \r
1071     p = ReadName( p, &value, encoding );\r
1072         if ( !p || !*p )\r
1073         {\r
1074                 if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );\r
1075                 return 0;\r
1076         }\r
1077 \r
1078     TIXML_STRING endTag ("</");\r
1079         endTag += value;\r
1080 \r
1081         // Check for and read attributes. Also look for an empty\r
1082         // tag or an end tag.\r
1083         while ( p && *p )\r
1084         {\r
1085                 pErr = p;\r
1086                 p = SkipWhiteSpace( p, encoding );\r
1087                 if ( !p || !*p )\r
1088                 {\r
1089                         if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );\r
1090                         return 0;\r
1091                 }\r
1092                 if ( *p == '/' )\r
1093                 {\r
1094                         ++p;\r
1095                         // Empty tag.\r
1096                         if ( *p  != '>' )\r
1097                         {\r
1098                                 if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );             \r
1099                                 return 0;\r
1100                         }\r
1101                         return (p+1);\r
1102                 }\r
1103                 else if ( *p == '>' )\r
1104                 {\r
1105                         // Done with attributes (if there were any.)\r
1106                         // Read the value -- which can include other\r
1107                         // elements -- read the end tag, and return.\r
1108                         ++p;\r
1109                         p = ReadValue( p, data, encoding );             // Note this is an Element method, and will set the error if one happens.\r
1110                         if ( !p || !*p ) {\r
1111                                 // We were looking for the end tag, but found nothing.\r
1112                                 // Fix for [ 1663758 ] Failure to report error on bad XML\r
1113                                 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );\r
1114                                 return 0;\r
1115                         }\r
1116 \r
1117                         // We should find the end tag now\r
1118                         // note that:\r
1119                         // </foo > and\r
1120                         // </foo> \r
1121                         // are both valid end tags.\r
1122                         if ( StringEqual( p, endTag.c_str(), false, encoding ) )\r
1123                         {\r
1124                                 p += endTag.length();\r
1125                                 p = SkipWhiteSpace( p, encoding );\r
1126                                 if ( p && *p && *p == '>' ) {\r
1127                                         ++p;\r
1128                                         return p;\r
1129                                 }\r
1130                                 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );\r
1131                                 return 0;\r
1132                         }\r
1133                         else\r
1134                         {\r
1135                                 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );\r
1136                                 return 0;\r
1137                         }\r
1138                 }\r
1139                 else\r
1140                 {\r
1141                         // Try to read an attribute:\r
1142                         TiXmlAttribute* attrib = new TiXmlAttribute();\r
1143                         if ( !attrib )\r
1144                         {\r
1145                                 return 0;\r
1146                         }\r
1147 \r
1148                         attrib->SetDocument( document );\r
1149                         pErr = p;\r
1150                         p = attrib->Parse( p, data, encoding );\r
1151 \r
1152                         if ( !p || !*p )\r
1153                         {\r
1154                                 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );\r
1155                                 delete attrib;\r
1156                                 return 0;\r
1157                         }\r
1158 \r
1159                         // Handle the strange case of double attributes:\r
1160                         #ifdef TIXML_USE_STL\r
1161                         TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );\r
1162                         #else\r
1163                         TiXmlAttribute* node = attributeSet.Find( attrib->Name() );\r
1164                         #endif\r
1165                         if ( node )\r
1166                         {\r
1167                                 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );\r
1168                                 delete attrib;\r
1169                                 return 0;\r
1170                         }\r
1171 \r
1172                         attributeSet.Add( attrib );\r
1173                 }\r
1174         }\r
1175         return p;\r
1176 }\r
1177 \r
1178 \r
1179 const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\r
1180 {\r
1181         TiXmlDocument* document = GetDocument();\r
1182 \r
1183         // Read in text and elements in any order.\r
1184         const char* pWithWhiteSpace = p;\r
1185         p = SkipWhiteSpace( p, encoding );\r
1186 \r
1187         while ( p && *p )\r
1188         {\r
1189                 if ( *p != '<' )\r
1190                 {\r
1191                         // Take what we have, make a text element.\r
1192                         TiXmlText* textNode = new TiXmlText( "" );\r
1193 \r
1194                         if ( !textNode )\r
1195                         {\r
1196                             return 0;\r
1197                         }\r
1198 \r
1199                         if ( TiXmlBase::IsWhiteSpaceCondensed() )\r
1200                         {\r
1201                                 p = textNode->Parse( p, data, encoding );\r
1202                         }\r
1203                         else\r
1204                         {\r
1205                                 // Special case: we want to keep the white space\r
1206                                 // so that leading spaces aren't removed.\r
1207                                 p = textNode->Parse( pWithWhiteSpace, data, encoding );\r
1208                         }\r
1209 \r
1210                         if ( !textNode->Blank() )\r
1211                                 LinkEndChild( textNode );\r
1212                         else\r
1213                                 delete textNode;\r
1214                 } \r
1215                 else \r
1216                 {\r
1217                         // We hit a '<'\r
1218                         // Have we hit a new element or an end tag? This could also be\r
1219                         // a TiXmlText in the "CDATA" style.\r
1220                         if ( StringEqual( p, "</", false, encoding ) )\r
1221                         {\r
1222                                 return p;\r
1223                         }\r
1224                         else\r
1225                         {\r
1226                                 TiXmlNode* node = Identify( p, encoding );\r
1227                                 if ( node )\r
1228                                 {\r
1229                                         p = node->Parse( p, data, encoding );\r
1230                                         LinkEndChild( node );\r
1231                                 }                               \r
1232                                 else\r
1233                                 {\r
1234                                         return 0;\r
1235                                 }\r
1236                         }\r
1237                 }\r
1238                 pWithWhiteSpace = p;\r
1239                 p = SkipWhiteSpace( p, encoding );\r
1240         }\r
1241 \r
1242         if ( !p )\r
1243         {\r
1244                 if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );\r
1245         }       \r
1246         return p;\r
1247 }\r
1248 \r
1249 \r
1250 #ifdef TIXML_USE_STL\r
1251 void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )\r
1252 {\r
1253         while ( in->good() )\r
1254         {\r
1255                 int c = in->get();      \r
1256                 if ( c <= 0 )\r
1257                 {\r
1258                         TiXmlDocument* document = GetDocument();\r
1259                         if ( document )\r
1260                                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
1261                         return;\r
1262                 }\r
1263                 (*tag) += (char) c;\r
1264 \r
1265                 if ( c == '>' )\r
1266                 {\r
1267                         // All is well.\r
1268                         return;         \r
1269                 }\r
1270         }\r
1271 }\r
1272 #endif\r
1273 \r
1274 \r
1275 const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\r
1276 {\r
1277         TiXmlDocument* document = GetDocument();\r
1278         p = SkipWhiteSpace( p, encoding );\r
1279 \r
1280         if ( data )\r
1281         {\r
1282                 data->Stamp( p, encoding );\r
1283                 location = data->Cursor();\r
1284         }\r
1285         if ( !p || !*p || *p != '<' )\r
1286         {\r
1287                 if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );\r
1288                 return 0;\r
1289         }\r
1290         ++p;\r
1291     value = "";\r
1292 \r
1293         while ( p && *p && *p != '>' )\r
1294         {\r
1295                 value += *p;\r
1296                 ++p;\r
1297         }\r
1298 \r
1299         if ( !p )\r
1300         {\r
1301                 if ( document ) \r
1302                         document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );\r
1303         }\r
1304         if ( p && *p == '>' )\r
1305                 return p+1;\r
1306         return p;\r
1307 }\r
1308 \r
1309 #ifdef TIXML_USE_STL\r
1310 void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )\r
1311 {\r
1312         while ( in->good() )\r
1313         {\r
1314                 int c = in->get();      \r
1315                 if ( c <= 0 )\r
1316                 {\r
1317                         TiXmlDocument* document = GetDocument();\r
1318                         if ( document )\r
1319                                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
1320                         return;\r
1321                 }\r
1322 \r
1323                 (*tag) += (char) c;\r
1324 \r
1325                 if ( c == '>' \r
1326                          && tag->at( tag->length() - 2 ) == '-'\r
1327                          && tag->at( tag->length() - 3 ) == '-' )\r
1328                 {\r
1329                         // All is well.\r
1330                         return;         \r
1331                 }\r
1332         }\r
1333 }\r
1334 #endif\r
1335 \r
1336 \r
1337 const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\r
1338 {\r
1339         TiXmlDocument* document = GetDocument();\r
1340         value = "";\r
1341 \r
1342         p = SkipWhiteSpace( p, encoding );\r
1343 \r
1344         if ( data )\r
1345         {\r
1346                 data->Stamp( p, encoding );\r
1347                 location = data->Cursor();\r
1348         }\r
1349         const char* startTag = "<!--";\r
1350         const char* endTag   = "-->";\r
1351 \r
1352         if ( !StringEqual( p, startTag, false, encoding ) )\r
1353         {\r
1354                 if ( document )\r
1355                         document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );\r
1356                 return 0;\r
1357         }\r
1358         p += strlen( startTag );\r
1359 \r
1360         // [ 1475201 ] TinyXML parses entities in comments\r
1361         // Oops - ReadText doesn't work, because we don't want to parse the entities.\r
1362         // p = ReadText( p, &value, false, endTag, false, encoding );\r
1363         //\r
1364         // from the XML spec:\r
1365         /*\r
1366          [Definition: Comments may appear anywhere in a document outside other markup; in addition, \r
1367                       they may appear within the document type declaration at places allowed by the grammar. \r
1368                                   They are not part of the document's character data; an XML processor MAY, but need not, \r
1369                                   make it possible for an application to retrieve the text of comments. For compatibility, \r
1370                                   the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity \r
1371                                   references MUST NOT be recognized within comments.\r
1372 \r
1373                                   An example of a comment:\r
1374 \r
1375                                   <!-- declarations for <head> & <body> -->\r
1376         */\r
1377 \r
1378     value = "";\r
1379         // Keep all the white space.\r
1380         while ( p && *p && !StringEqual( p, endTag, false, encoding ) )\r
1381         {\r
1382                 value.append( p, 1 );\r
1383                 ++p;\r
1384         }\r
1385         if ( p && *p ) \r
1386                 p += strlen( endTag );\r
1387 \r
1388         return p;\r
1389 }\r
1390 \r
1391 \r
1392 const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\r
1393 {\r
1394         p = SkipWhiteSpace( p, encoding );\r
1395         if ( !p || !*p ) return 0;\r
1396 \r
1397         if ( data )\r
1398         {\r
1399                 data->Stamp( p, encoding );\r
1400                 location = data->Cursor();\r
1401         }\r
1402         // Read the name, the '=' and the value.\r
1403         const char* pErr = p;\r
1404         p = ReadName( p, &name, encoding );\r
1405         if ( !p || !*p )\r
1406         {\r
1407                 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );\r
1408                 return 0;\r
1409         }\r
1410         p = SkipWhiteSpace( p, encoding );\r
1411         if ( !p || !*p || *p != '=' )\r
1412         {\r
1413                 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );\r
1414                 return 0;\r
1415         }\r
1416 \r
1417         ++p;    // skip '='\r
1418         p = SkipWhiteSpace( p, encoding );\r
1419         if ( !p || !*p )\r
1420         {\r
1421                 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );\r
1422                 return 0;\r
1423         }\r
1424         \r
1425         const char* end;\r
1426         const char SINGLE_QUOTE = '\'';\r
1427         const char DOUBLE_QUOTE = '\"';\r
1428 \r
1429         if ( *p == SINGLE_QUOTE )\r
1430         {\r
1431                 ++p;\r
1432                 end = "\'";             // single quote in string\r
1433                 p = ReadText( p, &value, false, end, false, encoding );\r
1434         }\r
1435         else if ( *p == DOUBLE_QUOTE )\r
1436         {\r
1437                 ++p;\r
1438                 end = "\"";             // double quote in string\r
1439                 p = ReadText( p, &value, false, end, false, encoding );\r
1440         }\r
1441         else\r
1442         {\r
1443                 // All attribute values should be in single or double quotes.\r
1444                 // But this is such a common error that the parser will try\r
1445                 // its best, even without them.\r
1446                 value = "";\r
1447                 while (    p && *p                                                                                      // existence\r
1448                                 && !IsWhiteSpace( *p )                                                          // whitespace\r
1449                                 && *p != '/' && *p != '>' )                                                     // tag end\r
1450                 {\r
1451                         if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {\r
1452                                 // [ 1451649 ] Attribute values with trailing quotes not handled correctly\r
1453                                 // We did not have an opening quote but seem to have a \r
1454                                 // closing one. Give up and throw an error.\r
1455                                 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );\r
1456                                 return 0;\r
1457                         }\r
1458                         value += *p;\r
1459                         ++p;\r
1460                 }\r
1461         }\r
1462         return p;\r
1463 }\r
1464 \r
1465 #ifdef TIXML_USE_STL\r
1466 void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )\r
1467 {\r
1468         while ( in->good() )\r
1469         {\r
1470                 int c = in->peek();     \r
1471                 if ( !cdata && (c == '<' ) ) \r
1472                 {\r
1473                         return;\r
1474                 }\r
1475                 if ( c <= 0 )\r
1476                 {\r
1477                         TiXmlDocument* document = GetDocument();\r
1478                         if ( document )\r
1479                                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
1480                         return;\r
1481                 }\r
1482 \r
1483                 (*tag) += (char) c;\r
1484                 in->get();      // "commits" the peek made above\r
1485 \r
1486                 if ( cdata && c == '>' && tag->size() >= 3 ) {\r
1487                         size_t len = tag->size();\r
1488                         if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {\r
1489                                 // terminator of cdata.\r
1490                                 return;\r
1491                         }\r
1492                 }    \r
1493         }\r
1494 }\r
1495 #endif\r
1496 \r
1497 const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )\r
1498 {\r
1499         value = "";\r
1500         TiXmlDocument* document = GetDocument();\r
1501 \r
1502         if ( data )\r
1503         {\r
1504                 data->Stamp( p, encoding );\r
1505                 location = data->Cursor();\r
1506         }\r
1507 \r
1508         const char* const startTag = "<![CDATA[";\r
1509         const char* const endTag   = "]]>";\r
1510 \r
1511         if ( cdata || StringEqual( p, startTag, false, encoding ) )\r
1512         {\r
1513                 cdata = true;\r
1514 \r
1515                 if ( !StringEqual( p, startTag, false, encoding ) )\r
1516                 {\r
1517                         if ( document )\r
1518                                 document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );\r
1519                         return 0;\r
1520                 }\r
1521                 p += strlen( startTag );\r
1522 \r
1523                 // Keep all the white space, ignore the encoding, etc.\r
1524                 while (    p && *p\r
1525                                 && !StringEqual( p, endTag, false, encoding )\r
1526                           )\r
1527                 {\r
1528                         value += *p;\r
1529                         ++p;\r
1530                 }\r
1531 \r
1532                 TIXML_STRING dummy; \r
1533                 p = ReadText( p, &dummy, false, endTag, false, encoding );\r
1534                 return p;\r
1535         }\r
1536         else\r
1537         {\r
1538                 bool ignoreWhite = true;\r
1539 \r
1540                 const char* end = "<";\r
1541                 p = ReadText( p, &value, ignoreWhite, end, false, encoding );\r
1542                 if ( p && *p )\r
1543                         return p-1;     // don't truncate the '<'\r
1544                 return 0;\r
1545         }\r
1546 }\r
1547 \r
1548 #ifdef TIXML_USE_STL\r
1549 void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )\r
1550 {\r
1551         while ( in->good() )\r
1552         {\r
1553                 int c = in->get();\r
1554                 if ( c <= 0 )\r
1555                 {\r
1556                         TiXmlDocument* document = GetDocument();\r
1557                         if ( document )\r
1558                                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );\r
1559                         return;\r
1560                 }\r
1561                 (*tag) += (char) c;\r
1562 \r
1563                 if ( c == '>' )\r
1564                 {\r
1565                         // All is well.\r
1566                         return;\r
1567                 }\r
1568         }\r
1569 }\r
1570 #endif\r
1571 \r
1572 const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )\r
1573 {\r
1574         p = SkipWhiteSpace( p, _encoding );\r
1575         // Find the beginning, find the end, and look for\r
1576         // the stuff in-between.\r
1577         TiXmlDocument* document = GetDocument();\r
1578         if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )\r
1579         {\r
1580                 if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );\r
1581                 return 0;\r
1582         }\r
1583         if ( data )\r
1584         {\r
1585                 data->Stamp( p, _encoding );\r
1586                 location = data->Cursor();\r
1587         }\r
1588         p += 5;\r
1589 \r
1590         version = "";\r
1591         encoding = "";\r
1592         standalone = "";\r
1593 \r
1594         while ( p && *p )\r
1595         {\r
1596                 if ( *p == '>' )\r
1597                 {\r
1598                         ++p;\r
1599                         return p;\r
1600                 }\r
1601 \r
1602                 p = SkipWhiteSpace( p, _encoding );\r
1603                 if ( StringEqual( p, "version", true, _encoding ) )\r
1604                 {\r
1605                         TiXmlAttribute attrib;\r
1606                         p = attrib.Parse( p, data, _encoding );         \r
1607                         version = attrib.Value();\r
1608                 }\r
1609                 else if ( StringEqual( p, "encoding", true, _encoding ) )\r
1610                 {\r
1611                         TiXmlAttribute attrib;\r
1612                         p = attrib.Parse( p, data, _encoding );         \r
1613                         encoding = attrib.Value();\r
1614                 }\r
1615                 else if ( StringEqual( p, "standalone", true, _encoding ) )\r
1616                 {\r
1617                         TiXmlAttribute attrib;\r
1618                         p = attrib.Parse( p, data, _encoding );         \r
1619                         standalone = attrib.Value();\r
1620                 }\r
1621                 else\r
1622                 {\r
1623                         // Read over whatever it is.\r
1624                         while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )\r
1625                                 ++p;\r
1626                 }\r
1627         }\r
1628         return 0;\r
1629 }\r
1630 \r
1631 bool TiXmlText::Blank() const\r
1632 {\r
1633         for ( unsigned i=0; i<value.length(); i++ )\r
1634                 if ( !IsWhiteSpace( value[i] ) )\r
1635                         return false;\r
1636         return true;\r
1637 }\r
1638 \r