Back to index

lightning-sunbird  0.9+nobinonly
StringFunctionCall.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * The MITRE Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Keith Visco <kvisco@ziplink.net> (Original Author)
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00044 #include "ExprResult.h"
00045 #include "FunctionLib.h"
00046 #include "txAtoms.h"
00047 #include "txError.h"
00048 #include "txIXPathContext.h"
00049 #include "XMLUtils.h"
00050 #include "txXPathTreeWalker.h"
00051 #include <math.h>
00052 #include "nsReadableUtils.h"
00053 
00057 StringFunctionCall::StringFunctionCall(StringFunctions aType) : mType(aType)
00058 {
00059 }
00060 
00068 nsresult
00069 StringFunctionCall::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
00070 {
00071     *aResult = nsnull;
00072 
00073     nsresult rv = NS_OK;
00074     txListIterator iter(&params);
00075     switch (mType) {
00076         case CONCAT:
00077         {
00078             if (!requireParams(2, -1, aContext))
00079                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00080                 
00081             nsRefPtr<StringResult> strRes;
00082             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
00083             NS_ENSURE_SUCCESS(rv, rv);
00084 
00085             while (iter.hasNext()) {
00086                 evaluateToString((Expr*)iter.next(), aContext, strRes->mValue);
00087             }
00088             *aResult = strRes;
00089             NS_ADDREF(*aResult);
00090 
00091             return NS_OK;
00092         }
00093         case CONTAINS:
00094         {
00095             if (!requireParams(2, 2, aContext))
00096                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00097 
00098             nsAutoString arg1, arg2;
00099             Expr* arg1Expr = (Expr*)iter.next();
00100             evaluateToString((Expr*)iter.next(), aContext, arg2);
00101             if (arg2.IsEmpty()) {
00102                 aContext->recycler()->getBoolResult(PR_TRUE, aResult);
00103             }
00104             else {
00105                 evaluateToString(arg1Expr, aContext, arg1);
00106                 aContext->recycler()->getBoolResult(arg1.Find(arg2) >= 0,
00107                                                     aResult);
00108             }
00109 
00110             return NS_OK;
00111         }
00112         case NORMALIZE_SPACE:
00113         {
00114             if (!requireParams(0, 1, aContext))
00115                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00116 
00117             nsAutoString resultStr;
00118             if (iter.hasNext())
00119                 evaluateToString((Expr*)iter.next(), aContext, resultStr);
00120             else
00121                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
00122                                                   resultStr);
00123 
00124             nsRefPtr<StringResult> strRes;
00125             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
00126             NS_ENSURE_SUCCESS(rv, rv);
00127 
00128             MBool addSpace = MB_FALSE;
00129             MBool first = MB_TRUE;
00130             strRes->mValue.SetCapacity(resultStr.Length());
00131             PRUnichar c;
00132             PRUint32 src;
00133             for (src = 0; src < resultStr.Length(); src++) {
00134                 c = resultStr.CharAt(src);
00135                 if (XMLUtils::isWhitespace(c)) {
00136                     addSpace = MB_TRUE;
00137                 }
00138                 else {
00139                     if (addSpace && !first)
00140                         strRes->mValue.Append(PRUnichar(' '));
00141 
00142                     strRes->mValue.Append(c);
00143                     addSpace = MB_FALSE;
00144                     first = MB_FALSE;
00145                 }
00146             }
00147             *aResult = strRes;
00148             NS_ADDREF(*aResult);
00149 
00150             return NS_OK;
00151         }
00152         case STARTS_WITH:
00153         {
00154             if (!requireParams(2, 2, aContext))
00155                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00156 
00157             nsAutoString arg1, arg2;
00158             Expr* arg1Expr = (Expr*)iter.next();
00159             evaluateToString((Expr*)iter.next(), aContext, arg2);
00160             if (arg2.IsEmpty()) {
00161                 aContext->recycler()->getBoolResult(PR_TRUE, aResult);
00162             }
00163             else {
00164                 evaluateToString(arg1Expr, aContext, arg1);
00165                 aContext->recycler()->getBoolResult(
00166                       StringBeginsWith(arg1, arg2), aResult);
00167             }
00168 
00169             return NS_OK;
00170         }
00171         case STRING_LENGTH:
00172         {
00173             if (!requireParams(0, 1, aContext))
00174                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00175 
00176             nsAutoString resultStr;
00177             if (iter.hasNext())
00178                 evaluateToString((Expr*)iter.next(), aContext, resultStr);
00179             else
00180                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
00181                                                   resultStr);
00182             rv = aContext->recycler()->getNumberResult(resultStr.Length(),
00183                                                        aResult);
00184             NS_ENSURE_SUCCESS(rv, rv);
00185 
00186             return NS_OK;
00187         }
00188         case SUBSTRING:
00189         {
00190             if (!requireParams(2, 3, aContext))
00191                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00192 
00193             nsAutoString src;
00194             double start, end;
00195             evaluateToString((Expr*)iter.next(), aContext, src);
00196             start = evaluateToNumber((Expr*)iter.next(), aContext);
00197 
00198             // check for NaN or +/-Inf
00199             if (Double::isNaN(start) ||
00200                 Double::isInfinite(start) ||
00201                 start >= src.Length() + 0.5) {
00202                 aContext->recycler()->getEmptyStringResult(aResult);
00203 
00204                 return NS_OK;
00205             }
00206 
00207             start = floor(start + 0.5) - 1;
00208             if (iter.hasNext()) {
00209                 end = start + evaluateToNumber((Expr*)iter.next(),
00210                                                aContext);
00211                 if (Double::isNaN(end) || end < 0) {
00212                     aContext->recycler()->getEmptyStringResult(aResult);
00213 
00214                     return NS_OK;
00215                 }
00216                 
00217                 if (end > src.Length())
00218                     end = src.Length();
00219                 else
00220                     end = floor(end + 0.5);
00221             }
00222             else {
00223                 end = src.Length();
00224             }
00225 
00226             if (start < 0)
00227                 start = 0;
00228  
00229             if (start > end) {
00230                 aContext->recycler()->getEmptyStringResult(aResult);
00231                 
00232                 return NS_OK;
00233             }
00234 
00235             return aContext->recycler()->getStringResult(
00236                   Substring(src, (PRUint32)start, (PRUint32)(end - start)),
00237                   aResult);
00238         }
00239         case SUBSTRING_AFTER:
00240         {
00241             if (!requireParams(2, 2, aContext))
00242                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00243 
00244             nsAutoString arg1, arg2;
00245             evaluateToString((Expr*)iter.next(), aContext, arg1);
00246             evaluateToString((Expr*)iter.next(), aContext, arg2);
00247             if (arg2.IsEmpty()) {
00248                 return aContext->recycler()->getStringResult(arg1, aResult);
00249             }
00250 
00251             PRInt32 idx = arg1.Find(arg2);
00252             if (idx == kNotFound) {
00253                 aContext->recycler()->getEmptyStringResult(aResult);
00254                 
00255                 return NS_OK;
00256             }
00257 
00258             PRUint32 len = arg2.Length();
00259             return aContext->recycler()->getStringResult(
00260                   Substring(arg1, idx + len, arg1.Length() - (idx + len)),
00261                   aResult);
00262         }
00263         case SUBSTRING_BEFORE:
00264         {
00265             if (!requireParams(2, 2, aContext))
00266                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00267 
00268             nsAutoString arg1, arg2;
00269             Expr* arg1Expr = (Expr*)iter.next();
00270             evaluateToString((Expr*)iter.next(), aContext, arg2);
00271             if (arg2.IsEmpty()) {
00272                 aContext->recycler()->getEmptyStringResult(aResult);
00273 
00274                 return NS_OK;
00275             }
00276 
00277             evaluateToString(arg1Expr, aContext, arg1);
00278 
00279             PRInt32 idx = arg1.Find(arg2);
00280             if (idx == kNotFound) {
00281                 aContext->recycler()->getEmptyStringResult(aResult);
00282                 
00283                 return NS_OK;
00284             }
00285 
00286             return aContext->recycler()->
00287                 getStringResult(Substring(arg1, 0, idx), aResult);
00288         }
00289         case TRANSLATE:
00290         {
00291             if (!requireParams(3, 3, aContext))
00292                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00293 
00294             nsAutoString src;
00295             evaluateToString((Expr*)iter.next(), aContext, src);
00296             if (src.IsEmpty()) {
00297                 aContext->recycler()->getEmptyStringResult(aResult);
00298 
00299                 return NS_OK;
00300             }
00301             
00302             nsRefPtr<StringResult> strRes;
00303             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
00304             NS_ENSURE_SUCCESS(rv, rv);
00305 
00306             strRes->mValue.SetCapacity(src.Length());
00307             nsAutoString oldChars, newChars;
00308             evaluateToString((Expr*)iter.next(), aContext, oldChars);
00309             evaluateToString((Expr*)iter.next(), aContext, newChars);
00310             PRUint32 i;
00311             PRInt32 newCharsLength = (PRInt32)newChars.Length();
00312             for (i = 0; i < src.Length(); i++) {
00313                 PRInt32 idx = oldChars.FindChar(src.CharAt(i));
00314                 if (idx != kNotFound) {
00315                     if (idx < newCharsLength)
00316                         strRes->mValue.Append(newChars.CharAt((PRUint32)idx));
00317                 }
00318                 else {
00319                     strRes->mValue.Append(src.CharAt(i));
00320                 }
00321             }
00322             *aResult = strRes;
00323             NS_ADDREF(*aResult);
00324 
00325             return NS_OK;
00326         }
00327         case STRING:
00328         {
00329             if (!requireParams(0, 1, aContext))
00330                 return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
00331 
00332             nsRefPtr<StringResult> strRes;
00333             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
00334             NS_ENSURE_SUCCESS(rv, rv);
00335 
00336             if (iter.hasNext())
00337                 evaluateToString((Expr*)iter.next(), aContext, strRes->mValue);
00338             else
00339                 txXPathNodeUtils::appendNodeValue(aContext->getContextNode(),
00340                                                   strRes->mValue);
00341             *aResult = strRes;
00342             NS_ADDREF(*aResult);
00343 
00344             return NS_OK;
00345         }
00346     }
00347 
00348     aContext->receiveError(NS_LITERAL_STRING("Internal error"),
00349                            NS_ERROR_UNEXPECTED);
00350     return NS_ERROR_UNEXPECTED;
00351 }
00352 
00353 #ifdef TX_TO_STRING
00354 nsresult
00355 StringFunctionCall::getNameAtom(nsIAtom** aAtom)
00356 {
00357     switch (mType) {
00358         case CONCAT:
00359         {
00360             *aAtom = txXPathAtoms::concat;
00361             break;
00362         }
00363         case CONTAINS:
00364         {
00365             *aAtom = txXPathAtoms::contains;
00366             break;
00367         }
00368         case NORMALIZE_SPACE:
00369         {
00370             *aAtom = txXPathAtoms::normalizeSpace;
00371             break;
00372         }
00373         case STARTS_WITH:
00374         {
00375             *aAtom = txXPathAtoms::startsWith;
00376             break;
00377         }
00378         case STRING:
00379         {
00380             *aAtom = txXPathAtoms::string;
00381             break;
00382         }
00383         case STRING_LENGTH:
00384         {
00385             *aAtom = txXPathAtoms::stringLength;
00386             break;
00387         }
00388         case SUBSTRING:
00389         {
00390             *aAtom = txXPathAtoms::substring;
00391             break;
00392         }
00393         case SUBSTRING_AFTER:
00394         {
00395             *aAtom = txXPathAtoms::substringAfter;
00396             break;
00397         }
00398         case SUBSTRING_BEFORE:
00399         {
00400             *aAtom = txXPathAtoms::substringBefore;
00401             break;
00402         }
00403         case TRANSLATE:
00404         {
00405             *aAtom = txXPathAtoms::translate;
00406             break;
00407         }
00408         default:
00409         {
00410             *aAtom = 0;
00411             return NS_ERROR_FAILURE;
00412         }
00413     }
00414     NS_ADDREF(*aAtom);
00415     return NS_OK;
00416 }
00417 #endif