Back to index

lightning-sunbird  0.9+nobinonly
nsXFormsXPathScanner.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla XForms support.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Novell, Inc.
00019  * Portions created by the Initial Developer are Copyright (C) 2004
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *  Allan Beaufour <abeaufour@novell.com>
00024  *  David Landwehr <dlandwehr@novell.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsXFormsXPathScanner.h"
00041 #include "nsXFormsXPathXMLUtil.h"
00042 
00043 nsXFormsXPathScanner::nsXFormsXPathScanner()
00044 {
00045   MOZ_COUNT_CTOR(nsXFormsXPathScanner);
00046 }
00047 
00048 nsXFormsXPathScanner::nsXFormsXPathScanner(const nsAString& aExpression)
00049 {
00050   MOZ_COUNT_CTOR(nsXFormsXPathScanner);
00051 
00052   Init(aExpression);
00053 }
00054 
00055 nsXFormsXPathScanner::~nsXFormsXPathScanner()
00056 {
00057   MOZ_COUNT_DTOR(nsXFormsXPathScanner);
00058 }
00059 
00060 void
00061 nsXFormsXPathScanner::Init(const nsAString& aExpression)
00062 {
00063   mExpression = aExpression;
00064   mSize = mExpression.Length();
00065   mLength = 0;
00066   mOffset = -1;
00067   mLast = NONE;
00068   mState = NONE;
00069 }
00070 
00071 PRInt32
00072 nsXFormsXPathScanner::Length()
00073 {
00074   return mLength;
00075 }
00076 
00077 PRInt32
00078 nsXFormsXPathScanner::Offset()
00079 {
00080   return mOffset;
00081 }
00082 
00083 nsAString&
00084 nsXFormsXPathScanner::Expression()
00085 {
00086   return mExpression;
00087 }
00088 
00089 PRUnichar
00090 nsXFormsXPathScanner::PopChar()
00091 {
00092   PRUnichar c = '\0';
00093   mLength++;
00094   if (mOffset + mLength < mSize) {
00095     c =  mExpression[mOffset + mLength];
00096   }
00097   return c;
00098 }
00099 
00100 PRUnichar
00101 nsXFormsXPathScanner::PeekChar()
00102 {
00103   return PeekChar(mOffset + mLength + 1);
00104 }
00105 
00106 PRUnichar
00107 nsXFormsXPathScanner::PeekChar(PRInt32 aOffset)
00108 {
00109   if (mSize > aOffset)
00110     return mExpression[aOffset];
00111   return '\0';
00112 }
00113 
00114 PRUnichar
00115 nsXFormsXPathScanner::NextNonWhite()
00116 {
00117   return PeekChar(GetOffsetForNonWhite());
00118 }
00119 
00120 int
00121 nsXFormsXPathScanner::GetOffsetForNonWhite()
00122 {
00123   PRInt32 co = mOffset + mLength + 1;
00124   while (nsXFormsXPathXMLUtil::IsWhitespace(PeekChar(co)))
00125     co++;
00126   return co;
00127 }
00128 
00129 PRBool
00130 nsXFormsXPathScanner::HasMoreTokens()
00131 {
00132   return mState != XPATHEOF;
00133 }
00134 
00135 nsXFormsXPathScanner::XPATHTOKEN
00136 nsXFormsXPathScanner::NextToken()
00137 {
00138   if (mState != WHITESPACE)
00139     mLast = mState;
00140   mOffset = mOffset + mLength;
00141   mLength = 0;
00142 
00143   PRUnichar c = PeekChar();
00144   if (c == '\0') {
00145     mState = XPATHEOF;
00146   } else if (nsXFormsXPathXMLUtil::IsDigit(c)) {
00147     mState = ScanNumber();
00148   } else if (c == '_' || nsXFormsXPathXMLUtil::IsLetter(c)) {
00149     mState = ScanQName();
00150   } else if (c == '"' || c == '\'') {
00151     mState = ScanLiteral();
00152   } else {
00153     switch (c) {
00154     case '(':
00155       mState = LPARAN;
00156       PopChar();
00157       break;
00158       
00159     case ')':
00160       mState = RPARAN;
00161       PopChar();
00162       break;
00163       
00164     case '[':
00165       mState = LBRACK;
00166       PopChar();
00167       break;
00168       
00169     case ']':
00170       mState = RBRACK;
00171       PopChar();
00172       break;
00173       
00174     case '@':
00175       mState = AT;
00176       PopChar();
00177       break;
00178       
00179     case ',':
00180       mState = COMMA;
00181       PopChar();
00182       break;
00183       
00184     case ':':
00185       PopChar();
00186       if (PeekChar() == ':') {
00187         mState = COLONCOLON;
00188         PopChar();
00189       } else
00190         mState = ERRORXPATHTOKEN;
00191       break;
00192       
00193     case '.':
00194       PopChar();
00195       if (PeekChar() == '.') {
00196         mState = DOTDOT;
00197         PopChar();
00198       } else if (nsXFormsXPathXMLUtil::IsDigit(PeekChar()))
00199         mState = ScanNumber();
00200       else
00201         mState = DOT;
00202       break;
00203       
00204     case '$':
00205       mState = ScanVariable();
00206       break;
00207       
00208     case '/':
00209       PopChar();
00210       if (PeekChar() == '/') {
00211         mState = SLASHSLASH;
00212         PopChar();
00213       } else
00214         mState = SLASH;
00215       break;
00216       
00217     case '|':
00218       PopChar();
00219       mState = UNION;
00220       break;
00221       
00222     case '+':
00223       PopChar();
00224       mState = PLUS;
00225       break;
00226       
00227     case '-':
00228       PopChar();
00229       mState = MINUS;
00230       break;
00231       
00232     case '=':
00233       PopChar();
00234       mState = EQUAL;
00235       break;
00236       
00237     case '!':
00238       PopChar();
00239       if (PeekChar() == '=') {
00240         mState = NOTEQUAL;
00241         PopChar();
00242       } else
00243         mState = ERRORXPATHTOKEN;
00244       break;
00245       
00246     case '<':
00247       PopChar();
00248       if (PeekChar() == '=') {
00249         mState = LEQUAL;
00250         PopChar();
00251       } else
00252         mState = LESS;
00253       break;
00254       
00255     case '>':
00256       PopChar();
00257       if (PeekChar() == '=') {
00258         mState = GEQUAL;
00259         PopChar();
00260       } else
00261         mState = GREATER;
00262       break;
00263       
00264     case '*':
00265       PopChar();
00266       mState = SolveStar();
00267       break;
00268       
00269     case '\r':
00270     case '\n':
00271     case '\t':
00272     case ' ':
00273       mState = ScanWhitespace();
00274       break;
00275       
00276     default:
00277       PopChar();
00278       mState = ERRORXPATHTOKEN;
00279     }
00280   }
00281 
00282   return mState;
00283 }
00284 
00285 PRBool
00286 nsXFormsXPathScanner::SolveDiambiguate()
00287 {
00288   return mLast != NONE && (mLast != AT && mLast != COLONCOLON && mLast != LPARAN && mLast != LBRACK &&
00289                             mLast != AND && mLast != OR && mLast != DIV && mLast != MOD && mLast != SLASH && mLast != MULTIPLYOPERATOR &&
00290                             mLast != SLASHSLASH && mLast != UNION && mLast != PLUS && mLast != MINUS && mLast != NOTEQUAL && mLast != EQUAL && mLast != LESS &&
00291                             mLast != LEQUAL && mLast != GEQUAL && mLast != GREATER && mLast != COMMA);
00292 }
00293 
00294 nsXFormsXPathScanner::XPATHTOKEN
00295 nsXFormsXPathScanner::SolveStar()
00296 {
00297   if (SolveDiambiguate())
00298     return MULTIPLYOPERATOR;
00299   return STAR;
00300 }
00301 
00302 nsXFormsXPathScanner::XPATHTOKEN
00303 nsXFormsXPathScanner::ScanNumber()
00304 {
00305   PRUnichar c = PopChar();
00306   PRBool decimal = (c == '.');
00307 
00308   while (c != '\0') {
00309     c = PeekChar();
00310     if (!decimal && c == '.') {
00311       decimal = PR_TRUE;
00312     } else if (!nsXFormsXPathXMLUtil::IsDigit(c)) {
00313       return NUMBER;
00314     }
00315     PopChar();
00316   }
00317   return NUMBER;
00318 }
00319 
00320 nsXFormsXPathScanner::XPATHTOKEN
00321 nsXFormsXPathScanner::ScanVariable()
00322 {
00323   PopChar();
00324   if (ScanQName() != ERRORXPATHTOKEN)
00325     return VARIABLE;
00326   return ERRORXPATHTOKEN;
00327 }
00328 
00329 nsXFormsXPathScanner::XPATHTOKEN
00330 nsXFormsXPathScanner::ScanWhitespace()
00331 {
00332   PRUnichar c;
00333   do {
00334     PopChar();
00335     c = PeekChar();
00336   } while (nsXFormsXPathXMLUtil::IsWhitespace(c));
00337 
00338   return WHITESPACE;
00339 }
00340 
00341 nsXFormsXPathScanner::XPATHTOKEN
00342 nsXFormsXPathScanner::ScanLiteral()
00343 {
00344   PRUnichar c = PopChar();
00345   PRUnichar p;
00346   while ((p = PeekChar()) != c && p != '\0')
00347     PopChar();
00348   if (p == '\0')
00349     return ERRORXPATHTOKEN;
00350   PopChar();
00351   return LITERAL;
00352 }
00353 
00354 nsXFormsXPathScanner::XPATHTOKEN
00355 nsXFormsXPathScanner::ScanQName()
00356 {
00357   XPATHTOKEN second = NONE;
00358   ScanNCName();
00359   if (PeekChar() == ':' && PeekChar(mOffset + mLength + 2) != ':') {
00360     PopChar();
00361     second = ScanNCName();
00362   }
00363 
00364   nsDependentSubstring image = Substring(mExpression, Offset() + 1);
00365 
00366   if (SolveDiambiguate()) {
00367     if (StringBeginsWith(image, NS_LITERAL_STRING("and")))
00368       return AND;
00369     if (StringBeginsWith(image, NS_LITERAL_STRING("or")))
00370       return OR;
00371     if (StringBeginsWith(image, NS_LITERAL_STRING("mod")))
00372       return MOD;
00373     if (StringBeginsWith(image, NS_LITERAL_STRING("div")))
00374       return DIV;
00375     return ERRORXPATHTOKEN;
00376   }
00377 
00378   PRUnichar c = NextNonWhite();
00379   if (c == '(') {
00380     if (StringBeginsWith(image, NS_LITERAL_STRING("comment")))
00381       return COMMENT;
00382     if (StringBeginsWith(image, NS_LITERAL_STRING("text")))
00383       return TEXT;
00384     if (StringBeginsWith(image, NS_LITERAL_STRING("processing-instruction")))
00385       return PI;
00386     if (StringBeginsWith(image, NS_LITERAL_STRING("node")))
00387       return NODE;
00388 
00389     return FUNCTIONNAME;
00390   }
00391 
00392   PRInt32 of = GetOffsetForNonWhite();
00393   if (PeekChar(of) == ':' && PeekChar(of + 1) == ':') {
00394     if (StringBeginsWith(image, NS_LITERAL_STRING("ancestor")))
00395       return ANCESTOR;
00396     if (StringBeginsWith(image, NS_LITERAL_STRING("ancestor-or-self")))
00397       return ANCESTOR_OR_SELF;
00398     if (StringBeginsWith(image, NS_LITERAL_STRING("attribute")))
00399       return ATTRIBUTE;
00400     if (StringBeginsWith(image, NS_LITERAL_STRING("child")))
00401       return CHILD;
00402     if (StringBeginsWith(image, NS_LITERAL_STRING("descendant")))
00403       return DESCENDANT;
00404     if (StringBeginsWith(image, NS_LITERAL_STRING("descendant-or-self")))
00405       return DESCENDANT_OR_SELF;
00406     if (StringBeginsWith(image, NS_LITERAL_STRING("following")))
00407       return FOLLOWING;
00408     if (StringBeginsWith(image, NS_LITERAL_STRING("following-sibling")))
00409       return FOLLOWING_SIBLING;
00410     if (StringBeginsWith(image, NS_LITERAL_STRING("namespace")))
00411       return NAMESPACE;
00412     if (StringBeginsWith(image, NS_LITERAL_STRING("parent")))
00413       return PARENT;
00414     if (StringBeginsWith(image, NS_LITERAL_STRING("preceding")))
00415       return PRECEDING;
00416     if (StringBeginsWith(image, NS_LITERAL_STRING("preceding-sibling")))
00417       return PRECEDING_SIBLING;
00418     if (StringBeginsWith(image, NS_LITERAL_STRING("self")))
00419       return SELF;
00420 
00421     return ERRORXPATHTOKEN;
00422   }
00423   return second != NONE ? QNAME : NCNAME;
00424 }
00425 
00426 nsXFormsXPathScanner::XPATHTOKEN
00427 nsXFormsXPathScanner::ScanNCName()
00428 {
00429   PRUnichar c = PopChar();
00430   if (c != '_' && !nsXFormsXPathXMLUtil::IsLetter(c)) {
00431     return ERRORXPATHTOKEN;
00432   }
00433     
00434   while (nsXFormsXPathXMLUtil::IsNCNameChar(PeekChar())) {
00435     PopChar();
00436   }
00437     
00438   return NCNAME;
00439 }