tag.cpp

00001 /*
00002   Copyright (c) 2005-2007 by Jakob Schroeter <js@camaya.net>
00003   This file is part of the gloox library. http://camaya.net/gloox
00004 
00005   This software is distributed under a license. The full license
00006   agreement can be found in the file LICENSE in this distribution.
00007   This software may not be copied, modified, sold or distributed
00008   other than expressed in the named license agreement.
00009 
00010   This software is distributed without any warranty.
00011 */
00012 
00013 
00014 #include "tag.h"
00015 
00016 #include <stdlib.h>
00017 
00018 #ifdef _WIN32_WCE
00019 # include <cmath>
00020 #else
00021 # include <sstream>
00022 #endif
00023 
00024 #include <algorithm>
00025 
00026 namespace gloox
00027 {
00028   Tag::Tag()
00029     : m_parent( 0 ), m_type( StanzaUndefined ), m_incoming( false ), m_valid( false )
00030   {
00031   }
00032 
00033   Tag::Tag( const std::string& name, const std::string& cdata, bool incoming )
00034     : m_name( incoming ? relax( name ) : name ),
00035       m_cdata( incoming ? relax( cdata ) : cdata ),
00036       m_parent( 0 ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
00037   {
00038     m_valid = !m_name.empty();
00039   }
00040 
00041   Tag::Tag( Tag *parent, const std::string& name, const std::string& cdata, bool incoming )
00042     : m_name( incoming ? relax( name ) : name ),
00043       m_cdata( incoming ? relax( cdata ) : cdata ),
00044       m_parent( parent ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
00045   {
00046     if( m_parent )
00047       m_parent->addChild( this );
00048     m_valid = !m_name.empty();
00049   }
00050 
00051   Tag::Tag( const std::string& name, const std::string& attrib, const std::string& value, bool incoming )
00052     : m_name( incoming ? relax( name ) : name ),
00053       m_parent( 0 ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
00054   {
00055     addAttribute( attrib, value );
00056     m_valid = !m_name.empty();
00057   }
00058 
00059   Tag::Tag( Tag *parent, const std::string& name, const std::string&  attrib, const std::string& value,
00060             bool incoming )
00061     : m_name( incoming ? relax( name ) : name ),
00062       m_parent( parent ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
00063   {
00064     if( m_parent )
00065       m_parent->addChild( this );
00066     addAttribute( attrib, value );
00067     m_valid = !m_name.empty();
00068   }
00069 
00070   Tag::~Tag()
00071   {
00072     TagList::iterator it = m_children.begin();
00073     for( ; it != m_children.end(); ++it )
00074     {
00075       delete (*it);
00076     }
00077     m_parent = 0;
00078   }
00079 
00080   bool Tag::operator==( const Tag &right ) const
00081   {
00082     if( m_name != right.m_name || m_attribs != right.m_attribs
00083          || m_children.size() != right.m_children.size() )
00084       return false;
00085 
00086     TagList::const_iterator it = m_children.begin();
00087     TagList::const_iterator it_r = right.m_children.begin();
00088     while( it != m_children.end() && it_r != right.m_children.end() && *(*it) == *(*it_r) )
00089     {
00090       ++it;
00091       ++it_r;
00092     }
00093     return it == m_children.end();
00094   }
00095 
00096   const std::string Tag::xml() const
00097   {
00098     std::string xml = "<";
00099     xml += escape( m_name );
00100     if( !m_attribs.empty() )
00101     {
00102       AttributeList::const_iterator it_a = m_attribs.begin();
00103       for( ; it_a != m_attribs.end(); ++it_a )
00104       {
00105         xml += " ";
00106         xml += escape( (*it_a).first );
00107         xml += "='";
00108         xml += escape( (*it_a).second );
00109         xml += "'";
00110       }
00111     }
00112 
00113     if( m_cdata.empty() && !m_children.size() )
00114       xml += "/>";
00115     else if( m_children.size() )
00116     {
00117       xml += ">";
00118       TagList::const_iterator it_c = m_children.begin();
00119       for( ; it_c != m_children.end(); ++it_c )
00120       {
00121         xml += (*it_c)->xml();
00122       }
00123       xml += "</";
00124       xml += escape( m_name );
00125       xml += ">";
00126     }
00127     else if( !m_cdata.empty() )
00128     {
00129       xml += ">";
00130       xml += escape( m_cdata );
00131       xml += "</";
00132       xml += escape( m_name );
00133       xml += ">";
00134     }
00135 
00136     return xml;
00137   }
00138 
00139   static const char escape_chars[] = { '&', '<', '>', '\'', '"', '<', '>',
00140   '\'', '"', '<', '>', '<', '>', '\'', '"', '<', '>', '<', '>', '\'', '"' };
00141 
00142   static const std::string escape_seqs[] = { "amp;", "lt;", "gt;", "apos;",
00143   "quot;", "#60;", "#62;", "#39;", "#34;", "#x3c;", "#x3e;", "#x3C;",
00144   "#x3E;", "#x27;", "#x22;", "#X3c;", "#X3e;", "#X3C;", "#X3E;", "#X27;",
00145   "#X22;" };
00146 
00147   static const unsigned nb_escape = sizeof(escape_chars)/sizeof(char);
00148   static const unsigned escape_size = 5;
00149 
00150   const std::string Tag::escape( std::string esc )
00151   {
00152     for( unsigned val, i = 0; i < esc.length(); ++i )
00153     {
00154       for( val = 0; val < escape_size; ++val )
00155       {
00156         if( esc[i] == escape_chars[val] )
00157         {
00158           esc[i] = '&';
00159           esc.insert( i+1, escape_seqs[val] );
00160           i += escape_seqs[val].length();
00161           break;
00162         }
00163       }
00164     }
00165     return esc;
00166   }
00167 
00168   /*
00169    * When a sequence is found, do not repack the string directly, just set
00170    * the new symbol and mark the rest for deletation (0).
00171    */
00172   const std::string Tag::relax( std::string esc )
00173   {
00174     const unsigned int l = esc.length();
00175     unsigned int p = 0;
00176     unsigned int i = 0;
00177 
00178     for( unsigned int val; i < l; ++i )
00179     {
00180       if( esc[i] != '&' )
00181         continue;
00182 
00183       for( val = 0; val < nb_escape; ++val )
00184       {
00185         if( ( i + escape_seqs[val].length() <= l )
00186         && !strncmp( esc.data()+i+1, escape_seqs[val].data(),
00187                                      escape_seqs[val].length() ) )
00188         {
00189           esc[i] = escape_chars[val];
00190           for( p=1; p <= escape_seqs[val].length(); ++p )
00191             esc[i+p] = 0;
00192           i += p-1;
00193           break;
00194         }
00195       }
00196     }
00197     if( p )
00198     {
00199       for( p = 0, i = 0; i < l; ++i )
00200       {
00201         if( esc[i] != 0 )
00202         {
00203           if( esc[p] == 0 )
00204           {
00205             esc[p] = esc[i];
00206             esc[p+1] = 0;
00207           }
00208           ++p;
00209         }
00210       }
00211       esc.resize( p );
00212     }
00213     return esc;
00214   }
00215 
00216   void Tag::addAttribute( const std::string& name, const std::string& value )
00217   {
00218     if( name.empty() || value.empty() )
00219       return;
00220 
00221     AttributeList::iterator it = m_attribs.begin();
00222     for( ; it != m_attribs.end(); ++it )
00223     {
00224       if( (*it).first == ( m_incoming ? relax( name ) : name ) )
00225       {
00226         (*it).second = m_incoming ? relax( value ) : value;
00227         return;
00228       }
00229     }
00230 
00231     m_attribs.push_back( Attribute( m_incoming ? relax( name ) : name,
00232                                     m_incoming ? relax( value ) : value ) );
00233   }
00234 
00235   void Tag::addAttribute( const std::string& name, int value )
00236   {
00237     if( !name.empty() )
00238     {
00239 #ifdef _WIN32_WCE
00240       const int len = 4 + (int)std::log10( value ) + 1;
00241       char *tmp = new char[len];
00242       sprintf( tmp, "%d", value );
00243       std::string ret( tmp, len );
00244       addAttribute( name, ret );
00245       delete[] tmp;
00246 #else
00247       std::ostringstream oss;
00248       oss << value;
00249       addAttribute( name, oss.str() );
00250 #endif
00251     }
00252   }
00253 
00254   void Tag::addAttribute( const std::string& name, long value )
00255   {
00256     if( !name.empty() )
00257     {
00258 #ifdef _WIN32_WCE
00259       const int len = 4 + (int)std::log10( value ) + 1;
00260       char *tmp = new char[len];
00261       sprintf( tmp, "%ld", value );
00262       std::string ret( tmp, len );
00263       addAttribute( name, ret );
00264       delete[] tmp;
00265 #else
00266       std::ostringstream oss;
00267       oss << value;
00268       addAttribute( name, oss.str() );
00269 #endif
00270     }
00271   }
00272 
00273   void Tag::addChild( Tag *child )
00274   {
00275     if( child )
00276     {
00277       m_children.push_back( child );
00278       child->m_parent = this;
00279     }
00280   }
00281 
00282   void Tag::addChildCopy( const Tag *child )
00283   {
00284     if( child )
00285     {
00286       Tag *t = child->clone();
00287       m_children.push_back( t );
00288       t->m_parent = this;
00289     }
00290   }
00291 
00292   const std::string Tag::findAttribute( const std::string& name ) const
00293   {
00294     AttributeList::const_iterator it = m_attribs.begin();
00295     for( ; it != m_attribs.end(); ++it )
00296       if( (*it).first == ( m_incoming ? relax( name ) : name ) )
00297         return (*it).second;
00298 
00299     return std::string();
00300   }
00301 
00302   bool Tag::hasAttribute( const std::string& name, const std::string& value ) const
00303   {
00304     if( name.empty() )
00305       return true;
00306 
00307     AttributeList::const_iterator it = m_attribs.begin();
00308     for( ; it != m_attribs.end(); ++it )
00309       if( (*it).first == ( m_incoming ? relax( name ) : name )
00310             && ( value.empty() || (*it).second == ( m_incoming ? relax( value ) : value ) ) )
00311         return true;
00312 
00313     return false;
00314   }
00315 
00316   Tag* Tag::findChild( const std::string& name ) const
00317   {
00318     TagList::const_iterator it = m_children.begin();
00319     while( it != m_children.end() && (*it)->name() != ( m_incoming ? relax( name ) : name ) )
00320       ++it;
00321     return it != m_children.end() ? (*it) : 0;
00322   }
00323 
00324   Tag* Tag::findChild( const std::string& name, const std::string& attr,
00325                        const std::string& value ) const
00326   {
00327     if( name.empty() )
00328       return 0;
00329 
00330     TagList::const_iterator it = m_children.begin();
00331     while( it != m_children.end()
00332            && ( (*it)->name() != ( m_incoming ? relax( name ) : name )
00333                 || ! (*it)->hasAttribute( attr, value ) ) )
00334       ++it;
00335     return it != m_children.end() ? (*it) : 0;
00336   }
00337 
00338   bool Tag::hasChildWithCData( const std::string& name, const std::string& cdata ) const
00339   {
00340     TagList::const_iterator it = m_children.begin();
00341     while( it != m_children.end() && ( (*it)->name() != ( m_incoming ? relax( name ) : name )
00342             || ( !cdata.empty() && (*it)->cdata() != ( m_incoming ? relax( cdata ) : cdata ) ) ) )
00343       ++it;
00344     return it != m_children.end();
00345   }
00346 
00347   Tag* Tag::findChildWithAttrib( const std::string& attr, const std::string& value ) const
00348   {
00349     TagList::const_iterator it = m_children.begin();
00350     while( it != m_children.end() && ! (*it)->hasAttribute( attr, value ) )
00351       ++it;
00352     return it != m_children.end() ? (*it) : 0;
00353   }
00354 
00355   Tag* Tag::clone() const
00356   {
00357     Tag *t = new Tag( name(), cdata(), m_incoming );
00358     t->m_attribs = m_attribs;
00359     t->m_type = m_type;
00360 
00361     Tag::TagList::const_iterator it = m_children.begin();
00362     for( ; it != m_children.end(); ++it )
00363     {
00364       t->addChild( (*it)->clone() );
00365     }
00366 
00367     return t;
00368   }
00369 
00370   Tag::TagList Tag::findChildren( const std::string& name ) const
00371   {
00372     return findChildren( m_children, name );
00373   }
00374 
00375   Tag::TagList Tag::findChildren( const Tag::TagList& list, const std::string& name ) const
00376   {
00377     Tag::TagList ret;
00378     Tag::TagList::const_iterator it = list.begin();
00379     for( ; it != list.end(); ++it )
00380     {
00381       if( (*it)->name() == ( m_incoming ? relax( name ) : name ) )
00382         ret.push_back( (*it) );
00383     }
00384     return ret;
00385   }
00386 
00387   Tag* Tag::findTag( const std::string& expression )
00388   {
00389     const Tag::TagList& l = findTagList( expression );
00390     return !l.empty() ? l.front() : 0;
00391   }
00392 
00393   Tag::TagList Tag::findTagList( const std::string& expression )
00394   {
00395     Tag::TagList l;
00396     if( expression == "/" || expression == "//" )
00397       return l;
00398 
00399     if( m_parent && expression.length() >= 2 && expression.substr( 0, 1 ) == "/"
00400                                                   && expression.substr( 1, 1 ) != "/" )
00401       return m_parent->findTagList( expression );
00402 
00403     unsigned len = 0;
00404     Tag *p = parse( expression, len );
00405 //     if( p )
00406 //       printf( "parsed tree: %s\n", p->xml().c_str() );
00407     l = evaluateTagList( p );
00408     delete p;
00409     return l;
00410   }
00411 
00412   Tag::TagList Tag::evaluateTagList( Tag *token )
00413   {
00414     Tag::TagList result;
00415     if( !token )
00416       return result;
00417 
00418 //     printf( "evaluateTagList called in Tag %s and Token %s (type: %s)\n", name().c_str(),
00419 //             token->name().c_str(), token->findAttribute( "type" ).c_str() );
00420 
00421     TokenType tokenType = (TokenType)atoi( token->findAttribute( "type" ).c_str() );
00422     switch( tokenType )
00423     {
00424       case XTUnion:
00425         add( result, evaluateUnion( token ) );
00426         break;
00427       case XTElement:
00428       {
00429 //         printf( "in XTElement, token: %s\n", token->name().c_str() );
00430         if( token->name() == name() || token->name() == "*" )
00431         {
00432 //           printf( "found %s\n", name().c_str() );
00433           const Tag::TagList& tokenChildren = token->children();
00434           if( tokenChildren.size() )
00435           {
00436             bool predicatesSucceeded = true;
00437             Tag::TagList::const_iterator cit = tokenChildren.begin();
00438             for( ; cit != tokenChildren.end(); ++cit )
00439             {
00440               if( (*cit)->hasAttribute( "predicate", "true" ) )
00441               {
00442                 predicatesSucceeded = evaluatePredicate( (*cit) );
00443                 if( !predicatesSucceeded )
00444                   return result;
00445               }
00446             }
00447 
00448             bool hasElementChildren = false;
00449             cit = tokenChildren.begin();
00450             for( ; cit != tokenChildren.end(); ++cit )
00451             {
00452               if( (*cit)->hasAttribute( "predicate", "true" ) ||
00453                   (*cit)->hasAttribute( "number", "true" ) )
00454                 continue;
00455 
00456               hasElementChildren = true;
00457 
00458 //               printf( "checking %d children of token %s\n", tokenChildren.size(), token->name().c_str() );
00459               if( !m_children.empty() )
00460               {
00461                 Tag::TagList::const_iterator it = m_children.begin();
00462                 for( ; it != m_children.end(); ++it )
00463                 {
00464                   add( result, (*it)->evaluateTagList( (*cit) ) );
00465                 }
00466               }
00467               else if( atoi( (*cit)->findAttribute( "type" ).c_str() ) == XTDoubleDot && m_parent )
00468               {
00469                 (*cit)->addAttribute( "type", XTDot );
00470                 add( result, m_parent->evaluateTagList( (*cit) ) );
00471               }
00472             }
00473 
00474             if( !hasElementChildren )
00475               result.push_back( this );
00476           }
00477           else
00478           {
00479 //             printf( "adding %s to result set\n", name().c_str() );
00480             result.push_back( this );
00481           }
00482         }
00483 //         else
00484 //           printf( "found %s != %s\n", token->name().c_str(), name().c_str() );
00485 
00486         break;
00487       }
00488       case XTDoubleSlash:
00489       {
00490 //         printf( "in XTDoubleSlash\n" );
00491         Tag *t = token->clone();
00492 //         printf( "original token: %s\ncloned token: %s\n", token->xml().c_str(), n->xml().c_str() );
00493         t->addAttribute( "type", XTElement );
00494         add( result, evaluateTagList( t ) );
00495         const Tag::TagList& res2 = allDescendants();
00496         Tag::TagList::const_iterator it = res2.begin();
00497         for( ; it != res2.end(); ++it )
00498         {
00499           add( result, (*it)->evaluateTagList( t ) );
00500         }
00501         delete t;
00502         break;
00503       }
00504       case XTDot:
00505       {
00506         const Tag::TagList& tokenChildren = token->children();
00507         if( !tokenChildren.empty() )
00508         {
00509           add( result, evaluateTagList( tokenChildren.front() ) );
00510         }
00511         else
00512           result.push_back( this );
00513         break;
00514       }
00515       case XTDoubleDot:
00516       {
00517 //         printf( "in XTDoubleDot\n" );
00518         if( m_parent )
00519         {
00520           const Tag::TagList& tokenChildren = token->children();
00521           if( tokenChildren.size() )
00522           {
00523             Tag *testtoken = tokenChildren.front();
00524             if( testtoken->name() == "*" )
00525             {
00526               add( result, m_parent->evaluateTagList( testtoken ) );
00527             }
00528             else
00529             {
00530               Tag *t = token->clone();
00531               t->addAttribute( "type", XTElement );
00532               t->m_name = m_parent->m_name;
00533               add( result, m_parent->evaluateTagList( t ) );
00534               delete t;
00535             }
00536           }
00537           else
00538           {
00539             result.push_back( m_parent );
00540           }
00541         }
00542       }
00543       case XTInteger:
00544       {
00545         const Tag::TagList& l = token->children();
00546         if( !l.size() )
00547           break;
00548 
00549         const Tag::TagList& res = evaluateTagList( l.front() );
00550 
00551         int pos = atoi( token->name().c_str() );
00552 //         printf( "checking index %d\n", pos );
00553         if( pos > 0 && pos <= (int)res.size() )
00554         {
00555           Tag::TagList::const_iterator it = res.begin();
00556           while ( --pos )
00557           {
00558             ++it;
00559           }
00560           result.push_back( *it );
00561         }
00562         break;
00563       }
00564       default:
00565         break;
00566     }
00567     return result;
00568   }
00569 
00570   bool Tag::evaluateBoolean( Tag *token )
00571   {
00572     if( !token )
00573       return false;
00574 
00575     bool result = false;
00576     TokenType tokenType = (TokenType)atoi( token->findAttribute( "type" ).c_str() );
00577     switch( tokenType )
00578     {
00579       case XTAttribute:
00580         if( token->name() == "*" && m_attribs.size() )
00581           result = true;
00582         else
00583           result = hasAttribute( token->name() );
00584         break;
00585       case XTOperatorEq:
00586         result = evaluateEquals( token );
00587         break;
00588       case XTOperatorLt:
00589         break;
00590       case XTOperatorLtEq:
00591         break;
00592       case XTOperatorGtEq:
00593         break;
00594       case XTOperatorGt:
00595         break;
00596       case XTUnion:
00597       case XTElement:
00598       {
00599         Tag *t = new Tag( "." );
00600         t->addAttribute( "type", XTDot );
00601         t->addChild( token );
00602         result = !evaluateTagList( t ).empty();
00603         t->removeChild( token );
00604         delete t;
00605         break;
00606       }
00607       default:
00608         break;
00609     }
00610 
00611     return result;
00612   }
00613 
00614   bool Tag::evaluateEquals( Tag *token )
00615   {
00616     if( !token || token->children().size() != 2 )
00617       return false;
00618 
00619     bool result = false;
00620     Tag::TagList::const_iterator it = token->children().begin();
00621     Tag *ch1 = (*it);
00622     Tag *ch2 = (*++it);
00623 
00624     TokenType tt1 = (TokenType)atoi( ch1->findAttribute( "type" ).c_str() );
00625     TokenType tt2 = (TokenType)atoi( ch2->findAttribute( "type" ).c_str() );
00626     switch( tt1 )
00627     {
00628       case XTAttribute:
00629         switch( tt2 )
00630         {
00631           case XTInteger:
00632           case XTLiteral:
00633             result = ( findAttribute( ch1->name() ) == ch2->name() );
00634             break;
00635           case XTAttribute:
00636             result = ( hasAttribute( ch1->name() ) && hasAttribute( ch2->name() ) &&
00637                       findAttribute( ch1->name() ) == findAttribute( ch2->name() ) );
00638             break;
00639           default:
00640             break;
00641         }
00642         break;
00643       case XTInteger:
00644       case XTLiteral:
00645         switch( tt2 )
00646         {
00647           case XTAttribute:
00648             result = ( ch1->name() == findAttribute( ch2->name() ) );
00649             break;
00650           case XTLiteral:
00651           case XTInteger:
00652             result = ( ch1->name() == ch2->name() );
00653             break;
00654           default:
00655             break;
00656         }
00657         break;
00658       default:
00659         break;
00660     }
00661 
00662     return result;
00663   }
00664 
00665   Tag::TagList Tag::allDescendants()
00666   {
00667     Tag::TagList result;
00668     Tag::TagList::const_iterator it = m_children.begin();
00669     for( ; it != m_children.end(); ++it )
00670     {
00671       result.push_back( (*it) );
00672       add( result, (*it)->allDescendants() );
00673     }
00674     return result;
00675   }
00676 
00677   Tag::TagList Tag::evaluateUnion( Tag *token )
00678   {
00679     Tag::TagList result;
00680     if( !token )
00681       return result;
00682 
00683     const Tag::TagList& l = token->children();
00684     Tag::TagList::const_iterator it = l.begin();
00685     for( ; it != l.end(); ++it )
00686     {
00687       add( result, evaluateTagList( (*it) ) );
00688     }
00689     return result;
00690   }
00691 
00692   void Tag::closePreviousToken( Tag** root, Tag** current, Tag::TokenType& type, std::string& tok )
00693   {
00694     if( !tok.empty() )
00695     {
00696       addToken( root, current, type, tok );
00697       type = XTElement;
00698       tok = "";
00699     }
00700   }
00701 
00702   Tag* Tag::parse( const std::string& expression, unsigned& len, Tag::TokenType border )
00703   {
00704     Tag *root = 0;
00705     Tag *current = root;
00706     std::string token;
00707 
00708 //     XPathError error = XPNoError;
00709 //     XPathState state = Init;
00710 //     int expected = 0;
00711 //     bool run = true;
00712 //     bool ws = false;
00713 
00714     Tag::TokenType type  = XTElement;
00715 
00716     char c;
00717     for( ; len < expression.length(); ++len )
00718     {
00719       c = expression[len];
00720       if( type == XTLiteralInside && c != '\'' )
00721       {
00722         token += c;
00723         continue;
00724       }
00725 
00726       switch( c )
00727       {
00728         case '/':
00729           closePreviousToken( &root, &current, type, token );
00730 
00731           if( len < expression.length()-1 && expression[len+1] == '/' )
00732           {
00733 //             addToken( &root, &current, XTDoubleSlash, "//" );
00734             type = XTDoubleSlash;
00735             ++len;
00736           }
00737 //           else
00738 //           {
00739 //             if( !current )
00740 //             addToken( &root, &current, XTSlash, "/" );
00741 //           }
00742           break;
00743         case ']':
00744           closePreviousToken( &root, &current, type, token );
00745           ++len;
00746           return root;
00747         case '[':
00748         {
00749           closePreviousToken( &root, &current, type, token );
00750           Tag *t = parse( expression, ++len, XTRightBracket );
00751           if( !addPredicate( &root, &current, t ) )
00752             delete t;
00753           break;
00754         }
00755         case '(':
00756         {
00757           closePreviousToken( &root, &current, type, token );
00758           Tag *t = parse( expression, ++len, XTRightParenthesis );
00759           if( current )
00760           {
00761 //             printf( "added %s to %s\n", t->xml().c_str(), current->xml().c_str() );
00762             t->addAttribute( "argument", "true" );
00763             current->addChild( t );
00764           }
00765           else
00766           {
00767             root = t;
00768 //             printf( "made %s new root\n", t->xml().c_str() );
00769           }
00770           break;
00771         }
00772         case ')':
00773           closePreviousToken( &root, &current, type, token );
00774           ++len;
00775           return root;
00776         case '\'':
00777           if( type == XTLiteralInside )
00778             if( expression[len - 2] == '\\' )
00779               token[token.length() - 2] = c;
00780             else
00781               type = XTLiteral;
00782           else
00783             type = XTLiteralInside;
00784           break;
00785         case '@':
00786           type = XTAttribute;
00787           break;
00788         case '.':
00789           token += c;
00790           if( token.size() == 1 )
00791           {
00792             if( len < expression.length()-1 && expression[len+1] == '.' )
00793             {
00794               type = XTDoubleDot;
00795               ++len;
00796               token += c;
00797             }
00798             else
00799             {
00800               type = XTDot;
00801             }
00802           }
00803           break;
00804         case '*':
00805 //           if( !root || ( current && ( current->tokenType() == XTSlash
00806 //                                       || current->tokenType() == XTDoubleSlash ) ) )
00807 //           {
00808 //             addToken( &root, &current, type, "*" );
00809 //             break;
00810 //           }
00811           addToken( &root, &current, type, "*" );
00812           type = XTElement;
00813           break;
00814         case '+':
00815         case '>':
00816         case '<':
00817         case '=':
00818         case '|':
00819         {
00820           closePreviousToken( &root, &current, type, token );
00821           std::string s( 1, c );
00822           Tag::TokenType ttype = getType( s );
00823           if( ttype <= border )
00824             return root;
00825           Tag *t = parse( expression, ++len, ttype );
00826           addOperator( &root, &current, t, ttype, s );
00827           if( border == XTRightBracket )
00828             return root;
00829           break;
00830         }
00831         default:
00832           token += c;
00833       }
00834     }
00835 
00836     if( !token.empty() )
00837       addToken( &root, &current, type, token );
00838 
00839 //     if( error != XPNoError )
00840 //       printf( "error: %d\n", error );
00841     return root;
00842   }
00843 
00844   void Tag::addToken( Tag **root, Tag **current, Tag::TokenType type,
00845                       const std::string& token )
00846   {
00847     Tag *t = new Tag( token );
00848     if( t->isNumber() && !t->children().size() )
00849       type = XTInteger;
00850     t->addAttribute( "type", type );
00851 
00852     if( *root )
00853     {
00854 //       printf( "new current %s, type: %d\n", token.c_str(), type );
00855       (*current)->addChild( t );
00856       *current = t;
00857     }
00858     else
00859     {
00860 //       printf( "new root %s, type: %d\n", token.c_str(), type );
00861       *current = *root = t;
00862     }
00863   }
00864 
00865   void Tag::addOperator( Tag **root, Tag **current, Tag *arg,
00866                            Tag::TokenType type, const std::string& token )
00867   {
00868     Tag *t = new Tag( token );
00869     t->addAttribute( "type", type );
00870 //     printf( "new operator: %s (arg1: %s, arg2: %s)\n", t->name().c_str(), (*root)->xml().c_str(),
00871 //                                                                           arg->xml().c_str() );
00872     t->addAttribute( "operator", "true" );
00873     t->addChild( *root );
00874     t->addChild( arg );
00875     *current = *root = t;
00876   }
00877 
00878   bool Tag::addPredicate( Tag **root, Tag **current, Tag *token )
00879   {
00880     if( !*root || !*current )
00881       return false;
00882 
00883     if( ( token->isNumber() && !token->children().size() ) || token->name() == "+" )
00884     {
00885 //       printf( "found Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
00886       if( !token->hasAttribute( "operator", "true" ) )
00887       {
00888         token->addAttribute( "type", XTInteger );
00889       }
00890       if( *root == *current )
00891       {
00892         *root = token;
00893 //         printf( "made Index new root\n" );
00894       }
00895       else
00896       {
00897         (*root)->removeChild( *current );
00898         (*root)->addChild( token );
00899 //         printf( "added Index somewhere between root and current\n" );
00900       }
00901       token->addChild( *current );
00902 //       printf( "added Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
00903     }
00904     else
00905     {
00906       token->addAttribute( "predicate", "true" );
00907       (*current)->addChild( token );
00908     }
00909 
00910     return true;
00911   }
00912 
00913   Tag::TokenType Tag::getType( const std::string& c )
00914   {
00915     if( c == "|" )
00916       return XTUnion;
00917     if( c == "<" )
00918       return XTOperatorLt;
00919     if( c == ">" )
00920       return XTOperatorGt;
00921     if( c == "*" )
00922       return XTOperatorMul;
00923     if( c == "+" )
00924       return XTOperatorPlus;
00925     if( c == "=" )
00926       return XTOperatorEq;
00927 
00928     return XTNone;
00929   }
00930 
00931   bool Tag::isWhitespace( const char c )
00932   {
00933     return ( c == 0x09 || c == 0x0a || c == 0x0d || c == 0x20 );
00934   }
00935 
00936   bool Tag::isNumber()
00937   {
00938     if( m_name.empty() )
00939       return false;
00940 
00941     std::string::size_type l = m_name.length();
00942     std::string::size_type i = 0;
00943     while( i < l && isdigit( m_name[i] ) )
00944       ++i;
00945     return i == l;
00946   }
00947 
00948   void Tag::add( Tag::TagList& one, const Tag::TagList& two )
00949   {
00950     Tag::TagList::const_iterator it = two.begin();
00951     for( ; it != two.end(); ++it )
00952       if( std::find( one.begin(), one.end(), (*it) ) == one.end() )
00953         one.push_back( (*it) );
00954   }
00955 
00956 }

Generated on Sat Nov 10 08:50:27 2007 for gloox by  doxygen 1.5.3-20071008