00001
00007 #include <stdio.h>
00008 #include "ctl/ctldef.h"
00009 #include "ctl/debug.h"
00010 #include "ctl/xml.h"
00011
00012 #ifndef CTL_UNIT
00013
00014
00015 static void DefaultXMLException( const ctl_xmlread* xml, const char* reason, const char* szP0, const char* szP1 )
00016 {
00017 assertobjconst(xml);
00018 assertconst(reason,1);
00019 LOG( LOG_ERROR, szconst(char,"%s: %.32s %.32s\n"), reason, szP0?szP0:"NULL", szP1?szP1:"" );
00020 assert( !isdebugging() );
00021 }
00022
00023
00024
00025
00026
00027
00028
00029
00030 static void xml_puts( ctl_xmlwrite* self, const char* str )
00031 {
00032 assertobjptr(self);
00033 assertconst(str,1);
00034 if( NULL != self->buff )
00035 {
00036 ctl_gstring_strcat(char, self->buff, str );
00037 }
00038 else if( NULL != self->fp )
00039 {
00040 cfputs(char)( str, self->fp );
00041 }
00042 else
00043 {
00044 throwassert("No file or buffer");
00045 }
00046 }
00047 static void xml_printf( ctl_xmlwrite* self, const char* fmt, ... )
00048 {
00049 va_list args;
00050 assertobjptr(self);
00051 assertconst(fmt,1);
00052 va_start( args, fmt );
00053 if( NULL != self->buff )
00054 {
00055 ctl_gstring_vsprintf( char, self->buff, fmt, args );
00056 }
00057 else if( NULL != self->fp )
00058 {
00059 cvfprintf(char)( self->fp, fmt, args );
00060 }
00061 else
00062 {
00063 throwassert("No file or buffer");
00064 }
00065 }
00066
00073 bool ctl_xmlwrite_begin( ctl_xmlwrite* self, ctl_gstring(char)* stringbuff )
00074 {
00075 assertobjptr(self);
00076 assertobjptr( stringbuff );
00077 self->indent = 0;
00078 self->pretty = true;
00079 self->buff = stringbuff;
00080 self->fp = NULL;
00081 return true;
00082 }
00083
00090 bool ctl_xmlwrite_create( ctl_xmlwrite* self, const char* szPath )
00091 {
00092 assertobjptr(self);
00093 assertconst(szPath,1);
00094 self->indent = 0;
00095 self->pretty = true;
00096 self->buff = NULL;
00097 self->fp = fopen( szPath, "wb" );
00098 if( NULL != self->fp )
00099 {
00100 ctl_xmlwrite_addheader( self );
00101 return true;
00102 }
00103 return false;
00104 }
00105
00111 void ctl_xmlwrite_close( ctl_xmlwrite* self )
00112 {
00113 assertobjptr(self);
00114 if( NULL != self->fp )
00115 {
00116 fclose( self->fp );
00117 self->fp = NULL;
00118 }
00119 }
00120
00126 void ctl_xmlwrite_addheader( ctl_xmlwrite* self )
00127 {
00128 xml_puts( self, szconst(char,"<?xml version=\"1.0\" ?>") );
00129 }
00130
00136 void ctl_xmlwrite_newline( ctl_xmlwrite* self )
00137 {
00138 assertobjptr(self);
00139 if( self->pretty )
00140 {
00141 xml_printf( self, szconst(char,"\n%*s"), self->indent,szconst(char,"") );
00142 }
00143 }
00144
00150 void ctl_xmlwrite_indent( ctl_xmlwrite* self )
00151 {
00152 assertobjptr(self);
00153 self->indent += XML_TAB_DEPTH;
00154 }
00155
00161 void ctl_xmlwrite_outdent( ctl_xmlwrite* self )
00162 {
00163 assertobjptr(self);
00164 self->indent -= XML_TAB_DEPTH;
00165 ctl_xmlwrite_newline( self );
00166 }
00167
00175 void ctl_xmlwrite_generaltag( ctl_xmlwrite* self, const char* type, const char* label )
00176 {
00177 assertobjptr(self);
00178 assertconst(type,1);
00179 assertconst(label,1);
00180 ctl_xmlwrite_newline( self );
00181 xml_printf( self, szconst(char,"<%s ") CTL_LABEL_TYPE szconst(char,"=\"%s\">"), label, type );
00182 }
00183
00192 void ctl_xmlwrite_containertag( ctl_xmlwrite* self, const char* type, size_t count, const char* label )
00193 {
00194 assertobjptr(self);
00195 assertconst(type,1);
00196 assertconst(label,1);
00197 ctl_xmlwrite_newline( self );
00198 xml_printf( self, szconst(char,"<%s ") CTL_LABEL_TYPE szconst(char,"=\"container\" ") CTL_LABEL_MBRTYPE szconst(char,"=\"%s\" ") CTL_LABEL_COUNT szconst(char,"=\"%d\">"), label, type, count );
00199 }
00200
00208 void ctl_xmlwrite_endtag( ctl_xmlwrite* self, const char* type, const char* label )
00209 {
00210 assertobjptr(self);
00211 assertconst(type,1);
00212 assertconst(label,1);
00213 xml_printf( self, szconst(char,"</%s>"), label );
00214
00215 }
00216
00221 void ctl_xmlwrite_string_char( ctl_xmlwrite* self, const char* begin, const char* end )
00222 {
00223 assertobjptr(self);
00224 assertconst(begin,1);
00225 if( NULL == end )
00226 end = begin + cstrlen(char)(begin);
00227 assert( begin && end >= begin );
00228 {
00229 ctl_gstring(char) tmp;
00230 const char* psz = begin;
00231 bool bigger = false;
00232 ctl_gstring_init(char, &tmp );
00233 while ( psz < end )
00234 {
00235 switch ( *psz )
00236 {
00237 case chconst(char,'<'):
00238 ctl_gstring_strcat(char, &tmp, szconst(char,"<") );
00239 break;
00240 case chconst(char,'>'):
00241 ctl_gstring_strcat(char, &tmp, szconst(char,">") );
00242 break;
00243 case chconst(char,'\"'):
00244 ctl_gstring_strcat(char, &tmp, szconst(char,""") );
00245 break;
00246 case chconst(char,'\''):
00247 ctl_gstring_strcat(char, &tmp, szconst(char,"'") );
00248 break;
00249 case chconst(char,'&'):
00250 ctl_gstring_strcat(char, &tmp, szconst(char,"&") );
00251 break;
00252 default:
00253 ctl_gstring_add(char, &tmp, *psz );
00254 break;
00255 }
00256 psz++;
00257 }
00258
00259 {
00260 char* poisonCDATA = cstrstr(char)( begin, szconst(char,"]]>") );
00261 if ( !bigger && ctl_gstring_size(char, &tmp ) > (size_t)((end-begin)+12) && !poisonCDATA && poisonCDATA < end )
00262 {
00263
00264 xml_printf( self, szconst(char,"<![CDATA[%.*s]]>"), (end-begin), begin );
00265 }
00266 else
00267 {
00268
00269 xml_puts( self, tmp.begin );
00270 }
00271 }
00272 ctl_gstring_destroy(char, &tmp );
00273 }
00274 }
00275
00280 void ctl_xmlwrite_string_wchar_t( ctl_xmlwrite* self, const wchar_t* begin, const wchar_t* end )
00281 {
00282 assertobjptr(self);
00283 assertconst(begin,1);
00284 if( NULL == end )
00285 end = begin + cstrlen(wchar_t)(begin);
00286 assert( begin && end >= begin );
00287 {
00288 ctl_gstring(char) tmp;
00289 const wchar_t* psz = begin;
00290 bool bigger = false;
00291 ctl_gstring_init(char, &tmp );
00292 while ( psz < end )
00293 {
00294 switch ( *psz )
00295 {
00296 case chconst(wchar_t,'<'):
00297 ctl_gstring_strcat(char, &tmp, szconst(char,"<") );
00298 break;
00299 case chconst(wchar_t,'>'):
00300 ctl_gstring_strcat(char, &tmp, szconst(char,">") );
00301 break;
00302 case chconst(wchar_t,'\"'):
00303 ctl_gstring_strcat(char, &tmp, szconst(char,""") );
00304 break;
00305 case chconst(wchar_t,'\''):
00306 ctl_gstring_strcat(char, &tmp, szconst(char,"'") );
00307 break;
00308 case chconst(wchar_t,'&'):
00309 ctl_gstring_strcat(char, &tmp, szconst(char,"&") );
00310 break;
00311 default:
00312 if ( *((uint8*)psz) > 127 )
00313 {
00314
00315 ctl_gstring_strcat(char, &tmp, szconst(char,"&#x") );
00316 ctl_gstring_putxint32(char, &tmp, (unsigned)*psz );
00317 ctl_gstring_strcat(char, &tmp, szconst(char,";") );
00318 bigger = true;
00319 }
00320 else
00321 {
00322
00323 ctl_gstring_add(char, &tmp, (char)*psz );
00324 }
00325 break;
00326 }
00327 psz++;
00328 }
00329
00330 xml_puts( self, tmp.begin );
00331 ctl_gstring_destroy(char, &tmp );
00332 }
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342 static const char* SkipSpace( const char* text, const char* szEnd );
00343 static const char* FindSpace( const char* text, const char* szEnd );
00344 static const char* FindChar( const char* text, const char* szEnd, char ch );
00345 static const char* FindGT( const char* text, const char* szEnd );
00346 static const char* FindLT( const char* text, const char* szEnd );
00347
00348
00349
00350 static const char* MatchQuote( const ctl_xmlread* self, const char* sz, const char* szEnd )
00351 {
00352 assertobjconst(self);
00353 assertconst(sz,1);
00354 assert( szEnd >= sz );
00355 {
00356 char matchMe = *sz;
00357 if ( matchMe != chconst(char,'\'') && matchMe != chconst(char,'\"') )
00358 {
00359 self->except(self,szconst(char,"Bad XML: Expected a quote here"), sz, NULL );
00360 return NULL;
00361 }
00362 {
00363 const char* found = FindChar( sz+1, szEnd, matchMe );
00364 if ( NULL == found )
00365 {
00366 self->except(self,szconst(char,"Bad XML: Missing closing quote"), sz, NULL );
00367 return NULL;
00368 }
00369 return found;
00370 }
00371 }
00372 }
00373
00374
00375 static const char* SkipSpace( const char* sz, const char* szEnd )
00376 {
00377 assertconst(sz,1);
00378 assert( szEnd >= sz );
00379 {
00380 const char* p = sz;
00381 while ( cisspace(char)(*p) && p < szEnd )
00382 p++;
00383 return p;
00384 }
00385 }
00386
00387
00388 static const char* FindSpace( const char* sz, const char* szEnd )
00389 {
00390 assertconst(sz,1);
00391 assert( szEnd >= sz );
00392 {
00393 const char* p = sz;
00394 while ( !cisspace(char)(*p) && p < szEnd )
00395 p++;
00396 return p;
00397 }
00398 }
00399
00400 static const char* FindChar( const char* sz, const char* szEnd, char ch )
00401 {
00402 assertconst(sz,1);
00403 assert( szEnd >= sz );
00404 while ( sz < szEnd )
00405 {
00406 if ( *sz == ch )
00407 return sz;
00408 sz++;
00409 }
00410 return NULL;
00411 }
00412
00413
00414 static const char* FindGT( const char* sz, const char* szEnd )
00415 {
00416
00417 bool bQuote = false;
00418 assertconst(sz,1);
00419 assert( szEnd >= sz );
00420 while ( sz < szEnd )
00421 {
00422 if ( *sz == chconst(char,'\"') )
00423 bQuote = !bQuote;
00424 else if ( *sz == chconst(char,'>') && !bQuote )
00425 return sz;
00426 sz++;
00427 }
00428 return NULL;
00429 }
00430
00431
00432 static const char* FindLT( const char* sz, const char* szEnd )
00433 {
00434 assertconst(sz,1);
00435 assert( szEnd >= sz );
00436 while ( sz < szEnd )
00437 {
00438 if ( *sz == '<' )
00439 return sz;
00440 sz++;
00441 }
00442 return NULL;
00443 }
00444
00445
00454 static const char* MatchTag( ctl_xmlread* self, const char* text )
00455 {
00456
00457 assertobjptr(self);
00458 assert( text );
00459 {
00460 const char* next = FindLT( text+1, self->szEnd );
00461 while ( next )
00462 {
00463
00464 if ( next[1] == '!' )
00465 {
00466
00467 if ( !cstrncmp(char)( text, szconst(char,"<![CDATA["), 9 ) )
00468 {
00469 const char* szGT = cstrstr(char)(text, szconst(char,"]]>"));
00470 if ( szGT && szGT < self->szEnd )
00471 {
00472
00473 next = FindLT( szGT+3, self->szEnd );
00474 }
00475 else
00476 {
00477 self->except( self,szconst(char,"Bad XML: <![CDATA[ doesn't have a ']]>'"), self->szpCurr, NULL );
00478 return NULL;
00479 }
00480 }
00481 else if ( !cstrncmp(char)( next, szconst(char,"<!--"), 4 ) )
00482 {
00483 const char* pGT = cstrstr(char)(next+4, szconst(char,"-->"));
00484 if ( pGT && pGT < self->szEnd )
00485 {
00486 next = FindLT( pGT+3, self->szEnd );
00487 continue;
00488 }
00489 else
00490 {
00491 self->except( self,szconst(char,"Bad XML: '<!--' comment doesn't have a '-->'"), self->szpCurr, pGT );
00492 return NULL;
00493 }
00494 }
00495 else
00496 {
00497
00498 const char* pGT = FindGT( next+1, self->szEnd );
00499 if ( pGT )
00500 {
00501 next = FindLT( pGT+1, self->szEnd );
00502 continue;
00503 }
00504 else
00505 {
00506 self->except( self,szconst(char,"Bad XML: '<!' data doesn't have a '>'"), text, pGT );
00507 return NULL;
00508 }
00509 }
00510 }
00511 else if ( next[1] == chconst(char,'/') )
00512 {
00513
00514 const char* p1 = text + 1;
00515 const char* p2 = next + 2;
00516 while ( *p2 != chconst(char,'>') )
00517 if ( *p1++ != *p2++ )
00518 {
00519 self->except( self,szconst(char,"Bad XML: Mismatched tags"), text, next );
00520 return NULL;
00521 }
00522
00523 return next;
00524 }
00525 else
00526 {
00527 const char* pGT = FindGT( next+1, self->szEnd );
00528 if ( pGT && *(pGT-1) == chconst(char,'/') )
00529 {
00530
00531 next = FindLT( pGT+1, self->szEnd );
00532 self->bRecursible = true;
00533 }
00534 else
00535 {
00536
00537 const char* pNext;
00538 self->bRecursible = true;
00539 pNext = MatchTag( self, next );
00540 if ( NULL == pNext )
00541 {
00542 self->except( self,szconst(char,"Bad XML: Mismatched tags"), text, pNext );
00543 return NULL;
00544 }
00545 next = FindLT( pNext+1, self->szEnd );
00546 }
00547 }
00548 }
00549 }
00550 return NULL;
00551 }
00552
00561 const char* ctl_xmlread_translate_char( const ctl_xmlread* self, char* begin, const char* end, bool bEatWhite )
00562 {
00563 assertobjconst(self);
00564 assertptr( begin,end-begin );
00565 assert( end >= begin );
00566 {
00567 const char* text = begin;
00568 char* outtext = begin;
00569
00570 if ( bEatWhite )
00571 {
00572 while( cisspace(char)(*text) )
00573 text++;
00574 }
00575 while ( text < end )
00576 {
00577 if ( text[0] == chconst(char,'&') )
00578 {
00579 if ( text[1] == chconst(char,'#') )
00580 {
00581 char *p;
00582 char ret;
00583 if ( text[2] == chconst(char,'x') )
00584 ret = (char)cstrtol(char)(text+3,&p,16);
00585 else
00586 ret = (char)cstrtol(char)(text+2,&p,10);
00587 if ( *p++ != chconst(char,';') )
00588 {
00589 self->except( self,szconst(char,"Bad XML: Bad character Reference"), begin, text );
00590 return NULL;
00591 }
00592 text = p;
00593 *outtext++ = ret;
00594 }
00595 else
00596 {
00597
00598 text++;
00599
00600 if( !cstrncmp(char)(text,szconst(char,"amp;"),4) )
00601 {
00602 *outtext++ = chconst(char,'&');
00603 text += 4;
00604 }
00605 else if( !cstrncmp(char)(text,szconst(char,"apos;"),5) )
00606 {
00607 *outtext++ = chconst(char,'\'');
00608 text += 5;
00609 }
00610 else if( !cstrncmp(char)(text,szconst(char,"lt;"),3) )
00611 {
00612 *outtext++ = chconst(char,'<');
00613 text += 3;
00614 }
00615 else if( !cstrncmp(char)(text,szconst(char,"gt;"),3) )
00616 {
00617 *outtext++ = chconst(char,'>');
00618 text += 3;
00619 }
00620 else if( !cstrncmp(char)(text,szconst(char,"quot;"),5) )
00621 {
00622 *outtext++ = chconst(char,'\"');
00623 text += 5;
00624 }
00625 else
00626 {
00627 self->except( self,szconst(char,"Bad XML: Unknown entity reference"), begin, text );
00628 return NULL;
00629 }
00630 }
00631 }
00632 else if ( text[0] == chconst(char,'<') )
00633 {
00634
00635 if ( !cstrncmp(char)( text, szconst(char,"<![CDATA["), 9 ) )
00636 {
00637 const char* szGT = cstrstr(char)(text+9, szconst(char,"]]>"));
00638 if ( szGT && szGT < end )
00639 {
00640
00641 text += 9;
00642 if ( bEatWhite )
00643 {
00644 text=SkipSpace(text,szGT);
00645 }
00646 while ( text < szGT )
00647 {
00648 *outtext++ = *text++;
00649 }
00650
00651 text += 3;
00652 }
00653 else
00654 {
00655 self->except( self,szconst(char,"Bad XML: <![CDATA[ doesn't have a ']]>'"), text, NULL );
00656 return NULL;
00657 }
00658 }
00659 else
00660 {
00661
00662 int count = 0;
00663 text++;
00664 while ( text < end )
00665 {
00666 if ( *text == chconst(char,'<') )
00667 count++;
00668 else if ( *text == chconst(char,'>') && !count-- )
00669 {
00670 text++;
00671 break;
00672 }
00673 text++;
00674 }
00675 }
00676 }
00677 else
00678 {
00679 *outtext++ = *text++;
00680 }
00681 }
00682
00683 if ( bEatWhite )
00684 {
00685 while( outtext > begin && cisspace(char)(*(outtext-1)) )
00686 outtext--;
00687 }
00688
00689 if( outtext < end )
00690 *outtext = 0;
00691 return outtext;
00692 }
00693 }
00694
00703 const wchar_t* ctl_xmlread_translate_wchar_t( const ctl_xmlread* self, wchar_t* begin, const wchar_t* end, bool bEatWhite )
00704 {
00705 assertobjconst(self);
00706 assertptr( begin, sizeof(wchar_t)*(end-begin) );
00707 assert( end >= begin );
00708 {
00709 const wchar_t* text = begin;
00710 wchar_t* outtext = begin;
00711
00712 if ( bEatWhite )
00713 {
00714 while( cisspace(wchar_t)(*text) )
00715 text++;
00716 }
00717 while ( text < end )
00718 {
00719 if ( text[0] == chconst(wchar_t,'&') )
00720 {
00721 if ( text[1] == chconst(wchar_t,'#') )
00722 {
00723 wchar_t *p;
00724 wchar_t ret;
00725 if ( text[2] == chconst(wchar_t,'x') )
00726 ret = (wchar_t)cstrtol(wchar_t)(text+3,&p,16);
00727 else
00728 ret = (wchar_t)cstrtol(wchar_t)(text+2,&p,10);
00729 if ( *p++ != chconst(wchar_t,';') )
00730 {
00731 self->except( self,szconst(char,"Bad XML: Bad character Reference"), NULL, NULL );
00732 return NULL;
00733 }
00734 text = p;
00735 *outtext++ = ret;
00736 }
00737 else
00738 {
00739
00740 text++;
00741
00742 if( !cstrncmp(wchar_t)(text,szconst(wchar_t,"amp;"),4) )
00743 {
00744 *outtext++ = chconst(wchar_t,'&');
00745 text += 4;
00746 }
00747 else if( !cstrncmp(wchar_t)(text,szconst(wchar_t,"apos;"),5) )
00748 {
00749 *outtext++ = chconst(wchar_t,'\'');
00750 text += 5;
00751 }
00752 else if( !cstrncmp(wchar_t)(text,szconst(wchar_t,"lt;"),3) )
00753 {
00754 *outtext++ = chconst(wchar_t,'<');
00755 text += 3;
00756 }
00757 else if( !cstrncmp(wchar_t)(text,szconst(wchar_t,"gt;"),3) )
00758 {
00759 *outtext++ = chconst(wchar_t,'>');
00760 text += 3;
00761 }
00762 else if( !cstrncmp(wchar_t)(text,szconst(wchar_t,"quot;"),5) )
00763 {
00764 *outtext++ = chconst(wchar_t,'\"');
00765 text += 5;
00766 }
00767 else
00768 {
00769 self->except( self,szconst(char,"Bad XML: Unknown entity reference"), NULL, NULL );
00770 return NULL;
00771 }
00772 }
00773 }
00774 else if ( text[0] == chconst(wchar_t,'<') )
00775 {
00776
00777 if ( !cstrncmp(wchar_t)( text, szconst(wchar_t,"<![CDATA["), 9 ) )
00778 {
00779 const wchar_t* szGT = cstrstr(wchar_t)(text+9, szconst(wchar_t,"]]>"));
00780 if ( szGT && szGT < end )
00781 {
00782
00783 text += 9;
00784 if ( bEatWhite )
00785 {
00786 while( cisspace(wchar_t)(*text) )
00787 text++;
00788 }
00789 while ( text < szGT )
00790 {
00791 *outtext++ = *text++;
00792 }
00793
00794 text += 3;
00795 }
00796 else
00797 {
00798 self->except( self,szconst(char,"Bad XML: <![CDATA[ doesn't have a ']]>'"), NULL, NULL );
00799 return NULL;
00800 }
00801 }
00802 else
00803 {
00804
00805 int count = 0;
00806 text++;
00807 while ( text < end )
00808 {
00809 if ( *text == chconst(wchar_t,'<') )
00810 count++;
00811 else if ( *text == chconst(wchar_t,'>') && !count-- )
00812 {
00813 text++;
00814 break;
00815 }
00816 text++;
00817 }
00818 }
00819 }
00820 else
00821 {
00822 *outtext++ = *text++;
00823 }
00824 }
00825
00826 if ( bEatWhite )
00827 {
00828 while( outtext > begin && cisspace(wchar_t)(*(outtext-1)) )
00829 outtext--;
00830 }
00831
00832 if( outtext < end )
00833 *outtext = 0;
00834 return outtext;
00835 }
00836 }
00837
00846 size_t ctl_xmlread_string( const ctl_xmlread* self, ctl_gstring(char)* str, const char* begin, const char* end, bool bEatWhite )
00847 {
00848 assertobjconst(self);
00849 assertobjptr( str );
00850 assertconst( begin,1 );
00851 assertconst( end,1 );
00852 assert( end >= begin );
00853 ctl_gstring_strncpy( char, str, begin, end-begin );
00854 str->end = (char*)ctl_xmlread_translate_char( self, str->begin, str->end, bEatWhite );
00855 return ctl_gstring_size(char, str );
00856 }
00857
00868 bool ctl_xmlread_init( ctl_xmlread* self, const char* begin, const char* end, ctl_xmlread_exception except, void* exceptParam )
00869 {
00870 assertobjptr(self);
00871 assertconst( begin,1 );
00872 assertconst( end,1 );
00873 assert( end >= begin );
00874 self->szBegin = begin;
00875 self->szEnd = end;
00876 self->szpCurr = self->szBegin;
00877 self->szpEnd = self->szBegin;
00878 self->szcCurr = self->szBegin;
00879 self->szcEnd = self->szEnd;
00880 self->bRecursible = false;
00881 self->except = except ? except : DefaultXMLException;
00882 assertcodeptr(self->except);
00883 self->exceptParam = exceptParam;
00884
00885 {
00886 const char* found = FindLT( self->szBegin, self->szEnd );
00887 if ( found && !cstrncmp(char)( found+1, szconst(char,"?xml"), 4 ) )
00888 {
00889 self->szBegin = self->szpCurr = found;
00890 self->szpEnd = FindGT( self->szpCurr+5, self->szEnd );
00891 if ( self->szpEnd && *(self->szpEnd-1) != chconst(char,'?') )
00892 {
00893 self->except( self, szconst(char,"Bad XML: '<?xml' does not end with '?>'"), self->szpCurr, self->szpEnd );
00894 return false;
00895 }
00896 self->szcCurr = self->szpEnd = self->szpCurr = self->szBegin = SkipSpace(self->szpEnd+1,self->szEnd);
00897 }
00898 }
00899 return ctl_xmlread_next( self );
00900 }
00901
00902
00903
00910 void ctl_xmlread_rewind( ctl_xmlread* self )
00911 {
00912 assertobjptr(self);
00913 ctl_xmlread_init( self, self->szBegin, self->szEnd, self->except, self->exceptParam );
00914 }
00915
00922 bool ctl_xmlread_next( ctl_xmlread* self )
00923 {
00924 assertobjptr(self);
00925 self->szpCurr = FindLT( self->szpEnd, self->szEnd );
00926
00927 while ( self->szpCurr && self->szpCurr[1] == chconst(char,'!') )
00928 {
00929
00930 if ( !cstrncmp(char)( self->szpCurr, szconst(char,"<![CDATA["), 9 ) )
00931 {
00932 const char* szGT = cstrstr(char)(self->szpCurr+9, szconst(char,"]]>"));
00933 if ( szGT && szGT < self->szEnd )
00934 {
00935
00936 self->szpCurr = FindLT( szGT+3, self->szEnd );
00937 }
00938 else
00939 {
00940 self->except( self, szconst(char,"Bad XML: <![CDATA[ doesn't have a ']]>'"), self->szpCurr, NULL );
00941 return false;
00942 }
00943 }
00944 else if ( !cstrncmp(char)( self->szpCurr, szconst(char,"<!--"), 4 ) )
00945 {
00946 const char* pGT = cstrstr(char)(self->szpCurr+4, szconst(char,"-->"));
00947 if ( pGT && pGT < self->szEnd )
00948 {
00949 self->szpCurr = FindLT( pGT+3, self->szEnd );
00950 continue;
00951 }
00952 else
00953 {
00954 self->except( self, szconst(char,"Bad XML: '<!--' comment doesn't have a '-->'"), self->szpCurr, pGT );
00955 return false;
00956 }
00957 }
00958 else
00959 {
00960 const char* szGT = FindGT( self->szpCurr+1, self->szEnd );
00961 if ( szGT )
00962 {
00963
00964 self->szpCurr = FindLT( szGT+1, self->szEnd );
00965 }
00966 else
00967 {
00968 self->except( self, szconst(char,"Bad XML: <! data doesn't have a '>'"), self->szpCurr, szGT );
00969 return false;
00970 }
00971 }
00972 }
00973 if ( self->szpCurr )
00974 {
00975
00976 self->szcCurr = FindGT(self->szpCurr+1, self->szEnd);
00977 if ( self->szcCurr )
00978 {
00979
00980 if ( *(self->szcCurr - 1) == chconst(char,'/') )
00981 {
00982 self->szcCurr++;
00983 self->szcEnd = self->szpEnd = self->szcCurr;
00984 self->bRecursible = false;
00985 return true;
00986 }
00987 else
00988 {
00989 self->szcCurr++;
00990 self->bRecursible = false;
00991 self->szcEnd = MatchTag( self, self->szpCurr );
00992 if ( self->szcEnd )
00993 {
00994 self->szpEnd = FindGT(self->szcEnd+1, self->szEnd);
00995 if ( self->szpEnd )
00996 {
00997 self->szpEnd++;
00998 return true;
00999 }
01000 else
01001 {
01002 self->except( self, szconst(char,"Bad XML: </tag> doesn't have a '>'"), self->szcCurr, self->szcEnd );
01003 return false;
01004 }
01005 }
01006 else
01007 {
01008 self->except( self, szconst(char,"Bad XML: Tag doesn't end with '</tag>', or same </tag>"), self->szcCurr, NULL );
01009 return false;
01010 }
01011 }
01012 }
01013 else
01014 {
01015 self->except( self, szconst(char,"Bad XML: Tag doesn't end with '>'"), self->szpCurr, NULL );
01016 return false;
01017 }
01018 }
01019 return false;
01020 }
01021
01029 bool ctl_xmlread_find( ctl_xmlread* self, const char* type )
01030 {
01031 assertobjptr(self);
01032 assertconst(type,1);
01033 ctl_xmlread_rewind(self);
01034 if( ctl_xmlread_is( self, type ) )
01035 return true;
01036 return ctl_xmlread_findnext( self,type );
01037 }
01038
01046 bool ctl_xmlread_findnext( ctl_xmlread* self, const char* type )
01047 {
01048
01049 const char* bszpCurr = self->szpCurr;
01050 const char* bszpEnd = self->szpEnd;
01051 const char* bszcCurr = self->szcCurr;
01052 const char* bszcEnd = self->szcEnd;
01053 bool bbRecursible = self->bRecursible;
01054 assertobjptr(self);
01055 assertconst(type,1);
01056 while ( ctl_xmlread_next(self) )
01057 {
01058 if( ctl_xmlread_is( self, type ) )
01059 return true;
01060 }
01061
01062 self->szpCurr = bszpCurr;
01063 self->szpEnd = bszpEnd;
01064 self->szcCurr = bszcCurr;
01065 self->szcEnd = bszcEnd;
01066 self->bRecursible = bbRecursible;
01067 return false;
01068 }
01069
01076 bool ctl_xmlread_canrecurse( ctl_xmlread* self )
01077 {
01078 assertobjptr(self);
01079 return self->bRecursible;
01080 }
01081
01089 bool ctl_xmlread_recurse( ctl_xmlread* newself, const ctl_xmlread* self )
01090 {
01091 assertobjconst(self);
01092 assertobjptr( newself );
01093 if( self->bRecursible )
01094 return ctl_xmlread_init( newself, self->szcCurr, self->szcEnd, self->except, self->exceptParam );
01095 return false;
01096 }
01097
01098
01099
01107 bool ctl_xmlread_getname( const ctl_xmlread* self, ctl_gstring(char)* str )
01108 {
01109 assertobjconst(self);
01110 assertobjptr( str );
01111 {
01112 const char* p = self->szpCurr+1;
01113 ctl_gstring_reset(char, str );
01114 while ( *p != chconst(char,'>') && (*p != chconst(char,'/') || p[1] != chconst(char,'>')) && !cisspace(char)(*p) )
01115 ctl_gstring_add(char, str, *p++ );
01116 return true;
01117 }
01118 }
01119
01127 bool ctl_xmlread_is( const ctl_xmlread* self, const char* str )
01128 {
01129 assertobjconst(self);
01130 assertconst( str, 1 );
01131 {
01132 const char* pStr = str;
01133 const char* p = self->szpCurr+1;
01134 while ( *p != chconst(char,'>') && (*p != chconst(char,'/') || p[1] != chconst(char,'>')) && !cisspace(char)(*p) )
01135 if ( *p++ != *pStr++ )
01136 return false;
01137 return !*pStr;
01138 }
01139 }
01140
01141
01142
01151 bool ctl_xmlread_getattribute( ctl_xmlread* self, ctl_gstring(char)* str, const char* label )
01152 {
01153 assertobjptr(self);
01154 assertobjptr( str );
01155 assertconst( label,1 );
01156 {
01157 ctl_sconst( char ) raw;
01158 ctl_gstring_reset(char, str );
01159 if( ctl_xmlread_rawattribute( self, &raw, label ) )
01160 return 0 != ctl_xmlread_string( self, str, raw.begin, raw.end, true );;
01161 return false;
01162 }
01163 }
01164
01173 bool ctl_xmlread_getcontent( const ctl_xmlread* self, ctl_gstring(char)* str, bool eatWhite )
01174 {
01175 assertobjconst(self);
01176 assertobjptr( str );
01177 {
01178 const char* p = self->szcCurr;
01179 ctl_gstring_reset(char, str );
01180 return 0 != ctl_xmlread_string( self, str, p, self->szcEnd, eatWhite );
01181 }
01182 }
01183
01192 bool ctl_xmlread_gettextbefore( const ctl_xmlread* self, ctl_gstring(char)* str, bool eatWhite )
01193 {
01194 assertobjconst(self);
01195 assertobjptr( str );
01196 {
01197 const char* pBegin = self->szpCurr-1;
01198 const char* pEnd = pBegin;
01199 ctl_gstring_reset(char, str );
01200 while ( pBegin > self->szBegin && *pBegin != chconst(char,'>') )
01201 pBegin--;
01202 if ( pBegin++ > self->szBegin )
01203 return 0 != ctl_xmlread_string( self, str, pBegin, pEnd, eatWhite );
01204 }
01205 return false;
01206 }
01207
01216 bool ctl_xmlread_gettextafter( const ctl_xmlread* self, ctl_gstring(char)* str, bool eatWhite )
01217 {
01218 assertobjconst(self);
01219 assertobjptr( str );
01220 {
01221 const char* p = self->szpEnd;
01222 const char* p2 = FindLT(p, self->szEnd);
01223 ctl_gstring_reset(char, str );
01224 if ( p2 )
01225 return 0 != ctl_xmlread_string( self, str, p, p2, eatWhite );
01226 }
01227 return false;
01228 }
01229
01230
01231
01239 bool ctl_xmlread_rawname( const ctl_xmlread* self, ctl_sconst( char )* str )
01240 {
01241 assertobjconst(self);
01242 assertobjptr( str );
01243 {
01244 const char* p = str->begin = str->parse = self->szpCurr+1;
01245 while ( *p != chconst(char,'>') && (*p != chconst(char,'/') || p[1] != chconst(char,'>')) && !cisspace(char)(*p) )
01246 p++;
01247 str->end = p;
01248 return true;
01249 }
01250 }
01251
01260 bool ctl_xmlread_rawattribute( ctl_xmlread* self, ctl_sconst( char )* str, const char* label )
01261 {
01262 assertobjptr(self);
01263 assertobjptr( str );
01264 assertconst( label,1 );
01265 {
01266
01267 const char* p = self->szpCurr+1;
01268 const char* tagEnd = self->szcCurr-1;
01269 p = SkipSpace(p,tagEnd);
01270 if ( *p == chconst(char,'>') )
01271 return false;
01272 while ( p < tagEnd )
01273 {
01274
01275 p = FindSpace(p,tagEnd);
01276 p = SkipSpace(p,tagEnd);
01277 if ( *p == chconst(char,'>') )
01278 return false;
01279 if ( !cstrncmp(char)(p,label,cstrlen(char)(label)) )
01280 {
01281 const char* end;
01282
01283 p = FindChar( p, tagEnd, chconst(char,'=') );
01284 if ( NULL == p )
01285 {
01286 self->except( self, szconst(char,"Bad XML: Expected an '=' in an attribute."), self->szpCurr, p );
01287 return false;
01288 }
01289
01290
01291
01292 p++;
01293 p = SkipSpace(p,tagEnd);
01294 end = MatchQuote( self, p, tagEnd );
01295 if( NULL == end )
01296 {
01297 return false;
01298 }
01299 p++;
01300
01301 str->begin = str->parse = p;
01302 str->end = end;
01303 return true;
01304 }
01305 else
01306 {
01307
01308 p = FindChar( p, tagEnd, chconst(char,'=') );
01309 if ( NULL == p )
01310 {
01311 self->except( self, szconst(char,"Bad XML: Expected an '=' in an attribute."), self->szpCurr, p );
01312 return false;
01313 }
01314
01315 p++;
01316 p = SkipSpace(p,tagEnd);
01317 p = MatchQuote( self, p, tagEnd ) + 1;
01318 if( NULL == p )
01319 {
01320 return false;
01321 }
01322 }
01323 }
01324 }
01325 return false;
01326 }
01327
01336 bool ctl_xmlread_getattribute_int( ctl_xmlread* self, const char* label, int32* value )
01337 {
01338 ctl_sconst( char ) tmp;
01339 if( ctl_xmlread_rawattribute( self, &tmp, label ) )
01340 return ctl_sconst_getint32(char, &tmp, value );
01341 return false;
01342 }
01343
01344
01353 bool ctl_xmlread_rawcontent( const ctl_xmlread* self, ctl_sconst(char)* str, bool eatWhite )
01354 {
01355 assertobjconst(self);
01356 assertobjptr( str );
01357 str->begin = str->parse = self->szcCurr;
01358 str->end = self->szcEnd;
01359 return str->end > str->begin;
01360 }
01361
01370 bool ctl_xmlread_rawtextbefore( const ctl_xmlread* self, ctl_sconst(char)* str, bool eatWhite )
01371 {
01372 assertobjconst(self);
01373 assertobjptr( str );
01374 {
01375 const char* pBegin = self->szpCurr-1;
01376 const char* pEnd = pBegin;
01377 while ( pBegin > self->szBegin && *pBegin != chconst(char,'>') )
01378 pBegin--;
01379 if ( pBegin++ > self->szBegin )
01380 {
01381 str->begin = str->parse = pBegin;
01382 str->end = pEnd;
01383 return str->end > str->begin;
01384 }
01385 }
01386 return false;
01387 }
01388
01397 bool ctl_xmlread_rawtextafter( const ctl_xmlread* self, ctl_sconst(char)* str, bool eatWhite )
01398 {
01399 assertobjconst(self);
01400 assertobjptr( str );
01401 str->begin = str->parse = self->szpEnd;
01402 str->end = FindLT(str->begin, self->szEnd);
01403 return str->end > str->begin;
01404 }
01405
01406
01411 #define DECL_DEF(type,unused) \
01412 void ppConcat(type,_xml_write)( const type* val, ctl_xmlwrite* self, const char* label )\
01413 {\
01414 if( NULL == label )\
01415 label = #type;\
01416 assertconst(label,1); \
01417 assertobjconst(val);\
01418 assertobjptr(self);\
01419 ctl_xmlwrite_generaltag( self, szconst(char,#type), label );\
01420 xml_printf( self, szconst(char,"%") type_printf(char,type), typecast_printf(type)*val );\
01421 ctl_xmlwrite_endtag( self, szconst(char,#type), label );\
01422 }
01423 DEF_ENUMTYPES(DECL_DEF,unused)
01424 #undef DECL_DEF
01425
01427 #define DECL_DEF(type,unused) \
01428 void ppConcat(type,_xml_write_array)( const type* ptr, size_t count, ctl_xmlwrite* self, const char* label )\
01429 {\
01430 if( NULL == label )\
01431 label = #type;\
01432 assertconst(label,1); \
01433 assertconst(ptr,sizeof(*ptr));\
01434 assertobjptr(self);\
01435 ctl_xmlwrite_containertag( self, szconst(char,#type), count, label );\
01436 while( count-- ) \
01437 xml_printf( self, szconst(char," %") type_printf(char,type), typecast_printf(type)*ptr++ );\
01438 ctl_xmlwrite_endtag( self, szconst(char,#type), label );\
01439 }
01440 DEF_ENUMTYPES(DECL_DEF,unused)
01441 #undef DECL_DEF
01442
01447 #define DECL_DEF(type,unused) \
01448 bool ppConcat(type,_xml_read)( type* val, ctl_xmlread* self, const char* label )\
01449 {\
01450 assertptr(val,sizeof(*val));\
01451 assertobjptr(self);\
01452 if( label ? ctl_xmlread_find( self, label ) : ctl_xmlread_is( self, #type ) )\
01453 {\
01454 ctl_sconst(char) body;\
01455 ctl_xmlread_rawcontent( self, &body, true );\
01456 ppConcat(ctl_sconst_get,type)(char, &body, val );\
01457 return true;\
01458 }\
01459 return false;\
01460 }
01461 DEF_ENUMTYPES(DECL_DEF,unused)
01462 #undef DECL_DEF
01463
01468 #define DECL_DEF(type,unused) \
01469 bool ppConcat(type,_xml_read_array)( type* ptr, size_t count, ctl_xmlread* self, const char* label )\
01470 {\
01471 int remain = (int)count;\
01472 bool ret = false;\
01473 assertptr(ptr,sizeof(*ptr));\
01474 assertobjptr(self);\
01475 if( ctl_xmlread_find( self, label ) )\
01476 {\
01477 ctl_sconst(char) body;\
01478 ctl_xmlread_rawcontent( self, &body, true );\
01479 while( remain-- && ppConcat(ctl_sconst_get,type)(char, &body, ptr ) )\
01480 ptr++;\
01481 ret = true;\
01482 }\
01483 return ret;\
01484 }
01485 DEF_ENUMTYPES(DECL_DEF,unused)
01486 #undef DECL_DEF
01487
01488
01497 void char_xml_write_string( const char* buff, size_t size, ctl_xmlwrite* xml, const char* label )
01498 {
01499 assertconst(buff,size);
01500 assertobjptr( xml );
01501 assertconst( label,1 );
01502 ctl_xmlwrite_generaltag( xml, "string_char", label );
01503 ctl_xmlwrite_string_char( xml, buff, buff+size );
01504 ctl_xmlwrite_endtag( xml, "string_char", label );
01505 }
01506
01515 void wchar_t_xml_write_string( const wchar_t* buff, size_t size, ctl_xmlwrite* xml, const char* label )
01516 {
01517 assertconst(buff,size*sizeof(wchar_t));
01518 assertobjptr( xml );
01519 assertconst( label,1 );
01520 ctl_xmlwrite_generaltag( xml, "string_wchar_t", label );
01521 ctl_xmlwrite_string_wchar_t( xml, buff, buff+size );
01522 ctl_xmlwrite_endtag( xml, "string_wchar_t", label );
01523 }
01524
01534 bool char_xml_read_string( char* buff, size_t size, ctl_xmlread* self, const char* label )
01535 {
01536 assertptr(buff,size*sizeof(char));
01537 assertobjptr( self );
01538 assertconst( label,1 );
01539 if( ctl_xmlread_find( self, label ) )
01540 {
01541 ctl_sconst(char) body;
01542 size_t readsize;
01543 ctl_xmlread_rawcontent( self, &body, true );
01544 readsize = min( ctl_sconst_size(char,&body), size );
01545 cmemcpy( char, buff, body.begin, readsize );
01546 if( readsize < size )
01547 buff[readsize] = 0;
01548 ctl_xmlread_translate_char( self, buff, buff+readsize, true );
01549 return true;
01550 }
01551 return false;
01552 }
01553
01563 bool wchar_t_xml_read_string( wchar_t* buff, size_t size, ctl_xmlread* self, const char* label )
01564 {
01565 assertptr(buff,size*sizeof(wchar_t));
01566 assertobjptr( self );
01567 assertconst( label,1 );
01568 if( ctl_xmlread_find( self, label ) )
01569 {
01570 ctl_sconst(char) body;
01571 ctl_xmlread_rawcontent( self, &body, true );
01572
01573 {
01574 ctl_gstring(wchar_t) tmp;
01575 ctl_gstring_init(wchar_t, &tmp);
01576 {
01577 ctl_sconst_foreach(char,&body,curr)
01578 {
01579 ctl_gstring_add(wchar_t, &tmp, (wchar_t)*curr );
01580 }
01581 }
01582 ctl_xmlread_translate_wchar_t( self, tmp.begin, tmp.end, true );
01583 cstrncpy(wchar_t)(buff,tmp.begin,size);
01584 ctl_gstring_destroy(wchar_t, &tmp);
01585 }
01586 return true;
01587 }
01588 return false;
01589 }
01590
01599 bool char_xml_read_gstring( ctl_gstring(char)* str, ctl_xmlread* self, const char* label )
01600 {
01601 assertobjptr(str);
01602 assertobjptr(self);
01603 assertconst( label,1 );
01604 if( ctl_xmlread_find( self, label ) )
01605 {
01606 ctl_sconst(char) body;
01607 size_t readsize;
01608 ctl_xmlread_rawcontent( self, &body, true );
01609 readsize = ctl_sconst_size(char,&body);
01610 ctl_gstring_resize(char, str, readsize );
01611 memcpy( str->begin, body.begin, ctl_chsize(char,readsize) );
01612 ctl_xmlread_translate_char( self, str->begin, str->end, true );
01613 str->end = str->begin + cstrlen(char)(str->begin);
01614 return true;
01615 }
01616 return false;
01617 }
01618
01627 bool wchar_t_xml_read_gstring( ctl_gstring(wchar_t)* str, ctl_xmlread* self, const char* label )
01628 {
01629 assertobjptr(str);
01630 assertobjptr(self);
01631 assertconst( label,1 );
01632 if( ctl_xmlread_find( self, label ) )
01633 {
01634 ctl_sconst(char) body;
01635 ctl_xmlread_rawcontent( self, &body, true );
01636 {
01637 ctl_gstring_reset(wchar_t, str );
01638 {
01639 ctl_sconst_foreach(char,&body,curr)
01640 {
01641 ctl_gstring_add(wchar_t, str, (wchar_t)*curr );
01642 }
01643 }
01644 ctl_xmlread_translate_wchar_t( self, str->begin, str->end, true );
01645 str->end = str->begin + cstrlen(wchar_t)(str->begin);
01646 }
01647 return true;
01648 }
01649 return false;
01650 }
01651
01658 void raw_xml_writebytes( const ctl_serial* serial, ctl_xmlwrite* self, const char* label )
01659 {
01660 size_t count;
01661 assertobjconst(serial);
01662 assertobjptr(self);
01663 assertconst( label,1 );
01664 count = ctl_serial_total( serial );
01665 ctl_xmlwrite_containertag( self, "raw", count, label );
01666 ctl_xmlwrite_indent( self );
01667 {
01668 const uint8* p = serial->begin;
01669 while( p < serial->end )
01670 {
01671 if( 0 == ((p-serial->begin)&0xf) )
01672 ctl_xmlwrite_newline( self );
01673 xml_printf( self, " %02x", (unsigned)*p );
01674 p++;
01675 }
01676 }
01677 ctl_xmlwrite_outdent( self );
01678 ctl_xmlwrite_endtag( self, "raw", label );
01679
01680 }
01688 bool raw_xml_readbytes( ctl_serial* serial, ctl_xmlread* self, const char* label )
01689 {
01690 int32 size;
01691 assertobjptr(serial);
01692 assertobjptr(self);
01693 assertconst( label,1 );
01694 if( ctl_xmlread_find( self, label ) )
01695 {
01696 if( ctl_xmlread_getattribute_int( self, CTL_LABEL_COUNT, &size ) )
01697 {
01698 ctl_sconst(char) body;
01699 ctl_xmlread_rawcontent( self, &body, true );
01700 ctl_serial_alloc( serial, size );
01701 {
01702 uint8 v;
01703 while( ctl_sconst_getxuint8(char, &body, &v ) )
01704 uint8_serial_write( &v, serial );
01705 }
01706 return true;
01707 }
01708 }
01709 return false;
01710 }
01711
01712 #else
01713 #include "unit/unit.h"
01714
01721 void Test_XMLReader(void)
01722 {
01723 const char testtext[] =
01724 "<?xml version=\"1.0\" ?>\n"
01725 "<DaScope>\n"
01726 " <Bus Length=\"shorter\"/>\n"
01727 " <!-- A Comment-->"
01728 " <contact-info> <!-- A Comment <ignore><me> -->\n"
01729 " spork <name><![CDATA[ John Doe]]></name> foon.\n\t<hole>AT&T </hole><!-- A Comment-->\n"
01730 " <!-- A Comment--> <email>spam@eggs.org</email>\n"
01731 " <test param1=\"Sporkle\" param2 = \""Mittens"\" > Test <!-- A Comment-->Text </test><!-- A Comment--> \n"
01732 " </contact-info> <!-- A Comment-->\n"
01733 "<!-- A Comment--><SPORK /> \n"
01734 " <FOON /><!-- A Comment--></DaScope>\n"
01735 ;
01736
01737 ctl_xmlread test;
01738 ctl_gstring_auto(char, buff );
01739 ctl_xmlread_init( &test, testtext, (char*)((uint8*)testtext+sizeof(testtext)), NULL, NULL );
01740
01741
01742 Test_Error( ctl_xmlread_is( &test, szconst(char,"DaScope") ) );
01743 Test_Error( ctl_xmlread_canrecurse(&test) );
01744 {
01745 ctl_xmlread xmain;
01746 Test_Error( ctl_xmlread_recurse( &xmain, &test ) );
01747 Test_Error( ctl_xmlread_getname( &xmain, &buff ) );
01748 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"Bus") ) );
01749 Test_Error( ctl_xmlread_getattribute( &xmain, &buff, szconst(char,"Length") ) );
01750 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"shorter") ) );
01751 Test_Error( ctl_xmlread_next( &xmain ) );
01752 Test_Error( ctl_xmlread_getname( &xmain, &buff ) );
01753 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"contact-info") ) );
01754 Test_Error( ctl_xmlread_canrecurse(&xmain) );
01755 {
01756 ctl_xmlread contact;
01757 Test_Error( ctl_xmlread_recurse( &contact, &xmain ) );
01758 Test_Error( !ctl_xmlread_canrecurse(&contact) );
01759 Test_Error( ctl_xmlread_getname( &contact, &buff ) );
01760 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"name") ) );
01761 Test_Error( ctl_xmlread_getname( &contact, &buff ) );
01762 Test_Error( ctl_xmlread_getcontent( &contact, &buff, true ) );
01763 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"John Doe") ) );
01764 Test_Error( ctl_xmlread_getcontent( &contact, &buff, false ) );
01765 Test_Error( !cstrcmp(char)( buff.begin, szconst(char," John Doe") ) );
01766
01767
01768 ctl_xmlread_gettextbefore( &contact, &buff, true );
01769 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"spork") ) );
01770
01771 ctl_xmlread_gettextafter( &contact, &buff, false );
01772 Test_Error( !cstrcmp(char)( buff.begin, szconst(char," foon.\n\t") ) );
01773
01774
01775 Test_Error( ctl_xmlread_next( &contact ) );
01776 Test_Error( ctl_xmlread_getname( &contact, &buff ) );
01777 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"hole") ) );
01778 Test_Error( ctl_xmlread_getcontent( &contact, &buff, true ) );
01779 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"AT&T") ) );
01780
01781
01782 Test_Error( ctl_xmlread_next( &contact ) );
01783 Test_Error( ctl_xmlread_getname( &contact, &buff ) );
01784 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"email") ) );
01785 Test_Error( ctl_xmlread_getcontent( &contact, &buff, true ) );
01786 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"spam@eggs.org") ) );
01787
01788
01789 Test_Error( ctl_xmlread_find( &contact, szconst(char,"hole") ) );
01790 Test_Error( ctl_xmlread_getname( &contact, &buff ) );
01791 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"hole") ) );
01792 Test_Error( ctl_xmlread_getcontent( &contact, &buff, true ) );
01793 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"AT&T") ) );
01794
01795
01796 Test_Error( !ctl_xmlread_find( &contact, szconst(char,"spam") ) );
01797
01798
01799 Test_Error( ctl_xmlread_find( &contact, szconst(char,"test") ) );
01800 Test_Error( ctl_xmlread_getattribute( &contact, &buff, szconst(char,"param2") ) );
01801 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"\42Mittens\42") ) );
01802 Test_Error( ctl_xmlread_getattribute( &contact, &buff, szconst(char,"param1") ) );
01803 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"Sporkle") ) );
01804 Test_Error( !ctl_xmlread_getattribute( &contact, &buff, szconst(char,"notthere") ) );
01805 Test_Error( ctl_xmlread_getcontent( &contact, &buff, true ) );
01806 Test_Error( !cstrcmp(char)( buff.begin, szconst(char,"Test Text") ) );
01807
01808
01809 Test_Error( !ctl_xmlread_find( &contact, szconst(char,"SPORK") ) );
01810 Test_Error( !ctl_xmlread_find( &contact, szconst(char,"FOON") ) );
01811 }
01812
01813 Test_Error( ctl_xmlread_find( &xmain, szconst(char,"SPORK") ) );
01814 Test_Error( ctl_xmlread_find( &xmain, szconst(char,"FOON") ) );
01815 }
01816 ctl_gstring_destroy(char, &buff );
01817 }
01818
01819 #endif