tag.cpp

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

Generated on Sun Apr 27 11:08:13 2008 for gloox by  doxygen 1.5.5