LCOV - code coverage report
Current view: top level - dom/xslt/xslt - txEXSLTFunctions.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 8 348 2.3 %
Date: 2017-07-14 16:53:18 Functions: 1 13 7.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/ArrayUtils.h"
       7             : #include "mozilla/FloatingPoint.h"
       8             : 
       9             : #include "nsIAtom.h"
      10             : #include "nsGkAtoms.h"
      11             : #include "txExecutionState.h"
      12             : #include "txExpr.h"
      13             : #include "txIXPathContext.h"
      14             : #include "txNodeSet.h"
      15             : #include "txOutputFormat.h"
      16             : #include "txRtfHandler.h"
      17             : #include "txXPathTreeWalker.h"
      18             : #include "nsPrintfCString.h"
      19             : #include "nsComponentManagerUtils.h"
      20             : #include "nsContentCID.h"
      21             : #include "nsContentCreatorFunctions.h"
      22             : #include "nsIContent.h"
      23             : #include "nsIDOMDocumentFragment.h"
      24             : #include "txMozillaXMLOutput.h"
      25             : #include "nsTextNode.h"
      26             : #include "mozilla/dom/DocumentFragment.h"
      27             : #include "prtime.h"
      28             : 
      29             : using namespace mozilla;
      30             : using namespace mozilla::dom;
      31             : 
      32             : class txStylesheetCompilerState;
      33             : 
      34             : // ------------------------------------------------------------------
      35             : // Utility functions
      36             : // ------------------------------------------------------------------
      37             : 
      38             : static nsresult
      39           0 : convertRtfToNode(txIEvalContext *aContext, txResultTreeFragment *aRtf)
      40             : {
      41             :     txExecutionState* es =
      42           0 :         static_cast<txExecutionState*>(aContext->getPrivateContext());
      43           0 :     if (!es) {
      44           0 :         NS_ERROR("Need txExecutionState!");
      45             : 
      46           0 :         return NS_ERROR_UNEXPECTED;
      47             :     }
      48             : 
      49           0 :     const txXPathNode& document = es->getSourceDocument();
      50             : 
      51           0 :     nsIDocument *doc = txXPathNativeNode::getDocument(document);
      52             :     nsCOMPtr<nsIDOMDocumentFragment> domFragment =
      53           0 :       new DocumentFragment(doc->NodeInfoManager());
      54             : 
      55           0 :     txOutputFormat format;
      56           0 :     txMozillaXMLOutput mozHandler(&format, domFragment, true);
      57             : 
      58           0 :     nsresult rv = aRtf->flushToHandler(&mozHandler);
      59           0 :     NS_ENSURE_SUCCESS(rv, rv);
      60             : 
      61           0 :     rv = mozHandler.closePrevious(true);
      62           0 :     NS_ENSURE_SUCCESS(rv, rv);
      63             : 
      64             :     // The txResultTreeFragment will own this.
      65             :     const txXPathNode* node = txXPathNativeNode::createXPathNode(domFragment,
      66           0 :                                                                  true);
      67           0 :     NS_ENSURE_TRUE(node, NS_ERROR_OUT_OF_MEMORY);
      68             : 
      69           0 :     aRtf->setNode(node);
      70             : 
      71           0 :     return NS_OK;
      72             : }
      73             : 
      74             : static nsresult
      75           0 : createTextNode(txIEvalContext *aContext, nsString& aValue,
      76             :                txXPathNode* *aResult)
      77             : {
      78             :     txExecutionState* es =
      79           0 :         static_cast<txExecutionState*>(aContext->getPrivateContext());
      80           0 :     if (!es) {
      81           0 :         NS_ERROR("Need txExecutionState!");
      82             : 
      83           0 :         return NS_ERROR_UNEXPECTED;
      84             :     }
      85             : 
      86           0 :     const txXPathNode& document = es->getSourceDocument();
      87             : 
      88           0 :     nsIDocument *doc = txXPathNativeNode::getDocument(document);
      89           0 :     nsCOMPtr<nsIContent> text = new nsTextNode(doc->NodeInfoManager());
      90             : 
      91           0 :     nsresult rv = text->SetText(aValue, false);
      92           0 :     NS_ENSURE_SUCCESS(rv, rv);
      93             : 
      94           0 :     *aResult = txXPathNativeNode::createXPathNode(text, true);
      95           0 :     NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
      96             : 
      97           0 :     return NS_OK;
      98             : }
      99             : 
     100             : static already_AddRefed<DocumentFragment>
     101           0 : createDocFragment(txIEvalContext *aContext)
     102             : {
     103             :     txExecutionState* es =
     104           0 :         static_cast<txExecutionState*>(aContext->getPrivateContext());
     105           0 :     if (!es) {
     106           0 :         NS_ERROR("Need txExecutionState!");
     107             : 
     108           0 :         return nullptr;
     109             :     }
     110             : 
     111           0 :     const txXPathNode& document = es->getSourceDocument();
     112           0 :     nsIDocument *doc = txXPathNativeNode::getDocument(document);
     113             :     RefPtr<DocumentFragment> fragment =
     114           0 :       new DocumentFragment(doc->NodeInfoManager());
     115             : 
     116           0 :     return fragment.forget();
     117             : }
     118             : 
     119             : static nsresult
     120           0 : createAndAddToResult(nsIAtom* aName, const nsAString& aValue,
     121             :                      txNodeSet* aResultSet, nsIContent* aResultHolder)
     122             : {
     123           0 :     NS_ASSERTION(aResultHolder->IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT) &&
     124             :                  aResultHolder->OwnerDoc(),
     125             :                  "invalid result-holder");
     126             : 
     127           0 :     nsIDocument* doc = aResultHolder->OwnerDoc();
     128           0 :     nsCOMPtr<Element> elem = doc->CreateElem(nsDependentAtomString(aName),
     129           0 :                                              nullptr, kNameSpaceID_None);
     130           0 :     NS_ENSURE_TRUE(elem, NS_ERROR_NULL_POINTER);
     131             : 
     132           0 :     RefPtr<nsTextNode> text = new nsTextNode(doc->NodeInfoManager());
     133             : 
     134           0 :     nsresult rv = text->SetText(aValue, false);
     135           0 :     NS_ENSURE_SUCCESS(rv, rv);
     136             : 
     137           0 :     rv = elem->AppendChildTo(text, false);
     138           0 :     NS_ENSURE_SUCCESS(rv, rv);
     139             : 
     140           0 :     rv = aResultHolder->AppendChildTo(elem, false);
     141           0 :     NS_ENSURE_SUCCESS(rv, rv);
     142             : 
     143             :     nsAutoPtr<txXPathNode> xpathNode(
     144           0 :           txXPathNativeNode::createXPathNode(elem, true));
     145           0 :     NS_ENSURE_TRUE(xpathNode, NS_ERROR_OUT_OF_MEMORY);
     146             : 
     147           0 :     aResultSet->append(*xpathNode);
     148             : 
     149           0 :     return NS_OK;
     150             : }
     151             : 
     152             : // Need to update this array if types are added to the ResultType enum in
     153             : // txAExprResult.
     154             : static const char * const sTypes[] = {
     155             :   "node-set",
     156             :   "boolean",
     157             :   "number",
     158             :   "string",
     159             :   "RTF"
     160             : };
     161             : 
     162             : // ------------------------------------------------------------------
     163             : // Function implementations
     164             : // ------------------------------------------------------------------
     165             : 
     166             : struct txEXSLTFunctionDescriptor
     167             : {
     168             :     int8_t mMinParams;
     169             :     int8_t mMaxParams;
     170             :     Expr::ResultType mReturnType;
     171             :     int32_t mNamespaceID;
     172             :     nsIAtom** mName;
     173             :     const char* mNamespaceURI;
     174             : };
     175             : 
     176             : static const char kEXSLTCommonNS[] = "http://exslt.org/common";
     177             : static const char kEXSLTSetsNS[] = "http://exslt.org/sets";
     178             : static const char kEXSLTStringsNS[] = "http://exslt.org/strings";
     179             : static const char kEXSLTMathNS[] = "http://exslt.org/math";
     180             : static const char kEXSLTDatesAndTimesNS[] = "http://exslt.org/dates-and-times";
     181             : 
     182             : // The order of this table must be the same as the
     183             : // txEXSLTFunctionCall::eType enum
     184             : static txEXSLTFunctionDescriptor descriptTable[] =
     185             : {
     186             :     { 1, 1, Expr::NODESET_RESULT, 0, &nsGkAtoms::nodeSet, kEXSLTCommonNS }, // NODE_SET
     187             :     { 1, 1, Expr::STRING_RESULT, 0, &nsGkAtoms::objectType, kEXSLTCommonNS }, // OBJECT_TYPE
     188             :     { 2, 2, Expr::NODESET_RESULT, 0, &nsGkAtoms::difference, kEXSLTSetsNS }, // DIFFERENCE
     189             :     { 1, 1, Expr::NODESET_RESULT, 0, &nsGkAtoms::distinct, kEXSLTSetsNS }, // DISTINCT
     190             :     { 2, 2, Expr::BOOLEAN_RESULT, 0, &nsGkAtoms::hasSameNode, kEXSLTSetsNS }, // HAS_SAME_NODE
     191             :     { 2, 2, Expr::NODESET_RESULT, 0, &nsGkAtoms::intersection, kEXSLTSetsNS }, // INTERSECTION
     192             :     { 2, 2, Expr::NODESET_RESULT, 0, &nsGkAtoms::leading, kEXSLTSetsNS }, // LEADING
     193             :     { 2, 2, Expr::NODESET_RESULT, 0, &nsGkAtoms::trailing, kEXSLTSetsNS }, // TRAILING
     194             :     { 1, 1, Expr::STRING_RESULT, 0, &nsGkAtoms::concat, kEXSLTStringsNS }, // CONCAT
     195             :     { 1, 2, Expr::STRING_RESULT, 0, &nsGkAtoms::split, kEXSLTStringsNS }, // SPLIT
     196             :     { 1, 2, Expr::STRING_RESULT, 0, &nsGkAtoms::tokenize, kEXSLTStringsNS }, // TOKENIZE
     197             :     { 1, 1, Expr::NUMBER_RESULT, 0, &nsGkAtoms::max, kEXSLTMathNS }, // MAX
     198             :     { 1, 1, Expr::NUMBER_RESULT, 0, &nsGkAtoms::min, kEXSLTMathNS }, // MIN
     199             :     { 1, 1, Expr::NODESET_RESULT, 0, &nsGkAtoms::highest, kEXSLTMathNS }, // HIGHEST
     200             :     { 1, 1, Expr::NODESET_RESULT, 0, &nsGkAtoms::lowest, kEXSLTMathNS }, // LOWEST
     201             :     { 0, 0, Expr::STRING_RESULT, 0, &nsGkAtoms::dateTime, kEXSLTDatesAndTimesNS }, // DATE_TIME
     202             : 
     203             : };
     204             : 
     205           0 : class txEXSLTFunctionCall : public FunctionCall
     206             : {
     207             : public:
     208             :     // The order of this enum must be the same as the descriptTable
     209             :     // table above
     210             :     enum eType {
     211             :         // Set functions
     212             :         NODE_SET,
     213             :         OBJECT_TYPE,
     214             :         DIFFERENCE,
     215             :         DISTINCT,
     216             :         HAS_SAME_NODE,
     217             :         INTERSECTION,
     218             :         LEADING,
     219             :         TRAILING,
     220             :         CONCAT,
     221             :         SPLIT,
     222             :         TOKENIZE,
     223             :         MAX,
     224             :         MIN,
     225             :         HIGHEST,
     226             :         LOWEST,
     227             :         DATE_TIME
     228             :     };
     229             : 
     230           0 :     explicit txEXSLTFunctionCall(eType aType)
     231           0 :       : mType(aType)
     232             :     {
     233           0 :     }
     234             : 
     235             :     TX_DECL_FUNCTION
     236             : 
     237             : private:
     238             :     eType mType;
     239             : };
     240             : 
     241             : nsresult
     242           0 : txEXSLTFunctionCall::evaluate(txIEvalContext *aContext,
     243             :                               txAExprResult **aResult)
     244             : {
     245           0 :     *aResult = nullptr;
     246           0 :     if (!requireParams(descriptTable[mType].mMinParams,
     247           0 :                        descriptTable[mType].mMaxParams,
     248           0 :                        aContext)) {
     249           0 :         return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;
     250             :     }
     251             : 
     252           0 :     nsresult rv = NS_OK;
     253           0 :     switch (mType) {
     254             :         case NODE_SET:
     255             :         {
     256           0 :             RefPtr<txAExprResult> exprResult;
     257           0 :             rv = mParams[0]->evaluate(aContext, getter_AddRefs(exprResult));
     258           0 :             NS_ENSURE_SUCCESS(rv, rv);
     259             : 
     260           0 :             if (exprResult->getResultType() == txAExprResult::NODESET) {
     261           0 :                 exprResult.forget(aResult);
     262             :             }
     263             :             else {
     264           0 :                 RefPtr<txNodeSet> resultSet;
     265           0 :                 rv = aContext->recycler()->
     266           0 :                     getNodeSet(getter_AddRefs(resultSet));
     267           0 :                 NS_ENSURE_SUCCESS(rv, rv);
     268             : 
     269           0 :                 if (exprResult->getResultType() ==
     270             :                     txAExprResult::RESULT_TREE_FRAGMENT) {
     271             :                     txResultTreeFragment *rtf =
     272             :                         static_cast<txResultTreeFragment*>
     273           0 :                                    (exprResult.get());
     274             : 
     275           0 :                     const txXPathNode *node = rtf->getNode();
     276           0 :                     if (!node) {
     277           0 :                         rv = convertRtfToNode(aContext, rtf);
     278           0 :                         NS_ENSURE_SUCCESS(rv, rv);
     279             : 
     280           0 :                         node = rtf->getNode();
     281             :                     }
     282             : 
     283           0 :                     resultSet->append(*node);
     284             :                 }
     285             :                 else {
     286           0 :                     nsAutoString value;
     287           0 :                     exprResult->stringValue(value);
     288             : 
     289           0 :                     nsAutoPtr<txXPathNode> node;
     290           0 :                     rv = createTextNode(aContext, value,
     291           0 :                                         getter_Transfers(node));
     292           0 :                     NS_ENSURE_SUCCESS(rv, rv);
     293             : 
     294           0 :                     resultSet->append(*node);
     295             :                 }
     296             : 
     297           0 :                 NS_ADDREF(*aResult = resultSet);
     298             :             }
     299             : 
     300           0 :             return NS_OK;
     301             :         }
     302             :         case OBJECT_TYPE:
     303             :         {
     304           0 :             RefPtr<txAExprResult> exprResult;
     305           0 :             nsresult rv = mParams[0]->evaluate(aContext,
     306           0 :                                                getter_AddRefs(exprResult));
     307           0 :             NS_ENSURE_SUCCESS(rv, rv);
     308             : 
     309           0 :             RefPtr<StringResult> strRes;
     310           0 :             rv = aContext->recycler()->getStringResult(getter_AddRefs(strRes));
     311           0 :             NS_ENSURE_SUCCESS(rv, rv);
     312             : 
     313           0 :             AppendASCIItoUTF16(sTypes[exprResult->getResultType()],
     314           0 :                                strRes->mValue);
     315             : 
     316           0 :             NS_ADDREF(*aResult = strRes);
     317             : 
     318           0 :             return NS_OK;
     319             :         }
     320             :         case DIFFERENCE:
     321             :         case INTERSECTION:
     322             :         {
     323           0 :             RefPtr<txNodeSet> nodes1;
     324           0 :             rv = evaluateToNodeSet(mParams[0], aContext,
     325           0 :                                    getter_AddRefs(nodes1));
     326           0 :             NS_ENSURE_SUCCESS(rv, rv);
     327             : 
     328           0 :             RefPtr<txNodeSet> nodes2;
     329           0 :             rv = evaluateToNodeSet(mParams[1], aContext,
     330           0 :                                    getter_AddRefs(nodes2));
     331           0 :             NS_ENSURE_SUCCESS(rv, rv);
     332             : 
     333           0 :             RefPtr<txNodeSet> resultSet;
     334           0 :             rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
     335           0 :             NS_ENSURE_SUCCESS(rv, rv);
     336             : 
     337           0 :             bool insertOnFound = mType == INTERSECTION;
     338             : 
     339           0 :             int32_t searchPos = 0;
     340           0 :             int32_t i, len = nodes1->size();
     341           0 :             for (i = 0; i < len; ++i) {
     342           0 :                 const txXPathNode& node = nodes1->get(i);
     343           0 :                 int32_t foundPos = nodes2->indexOf(node, searchPos);
     344           0 :                 if (foundPos >= 0) {
     345           0 :                     searchPos = foundPos + 1;
     346             :                 }
     347             : 
     348           0 :                 if ((foundPos >= 0) == insertOnFound) {
     349           0 :                     rv = resultSet->append(node);
     350           0 :                     NS_ENSURE_SUCCESS(rv, rv);
     351             :                 }
     352             :             }
     353             : 
     354           0 :             NS_ADDREF(*aResult = resultSet);
     355             : 
     356           0 :             return NS_OK;
     357             :         }
     358             :         case DISTINCT:
     359             :         {
     360           0 :             RefPtr<txNodeSet> nodes;
     361           0 :             rv = evaluateToNodeSet(mParams[0], aContext,
     362           0 :                                    getter_AddRefs(nodes));
     363           0 :             NS_ENSURE_SUCCESS(rv, rv);
     364             : 
     365           0 :             RefPtr<txNodeSet> resultSet;
     366           0 :             rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
     367           0 :             NS_ENSURE_SUCCESS(rv, rv);
     368             : 
     369           0 :             nsTHashtable<nsStringHashKey> hash;
     370             : 
     371           0 :             int32_t i, len = nodes->size();
     372           0 :             for (i = 0; i < len; ++i) {
     373           0 :                 nsAutoString str;
     374           0 :                 const txXPathNode& node = nodes->get(i);
     375           0 :                 txXPathNodeUtils::appendNodeValue(node, str);
     376           0 :                 if (!hash.GetEntry(str)) {
     377           0 :                     hash.PutEntry(str);
     378           0 :                     rv = resultSet->append(node);
     379           0 :                     NS_ENSURE_SUCCESS(rv, rv);
     380             :                 }
     381             :             }
     382             : 
     383           0 :             NS_ADDREF(*aResult = resultSet);
     384             : 
     385           0 :             return NS_OK;
     386             :         }
     387             :         case HAS_SAME_NODE:
     388             :         {
     389           0 :             RefPtr<txNodeSet> nodes1;
     390           0 :             rv = evaluateToNodeSet(mParams[0], aContext,
     391           0 :                                    getter_AddRefs(nodes1));
     392           0 :             NS_ENSURE_SUCCESS(rv, rv);
     393             : 
     394           0 :             RefPtr<txNodeSet> nodes2;
     395           0 :             rv = evaluateToNodeSet(mParams[1], aContext,
     396           0 :                                    getter_AddRefs(nodes2));
     397           0 :             NS_ENSURE_SUCCESS(rv, rv);
     398             : 
     399           0 :             bool found = false;
     400           0 :             int32_t i, len = nodes1->size();
     401           0 :             for (i = 0; i < len; ++i) {
     402           0 :                 if (nodes2->contains(nodes1->get(i))) {
     403           0 :                     found = true;
     404           0 :                     break;
     405             :                 }
     406             :             }
     407             : 
     408           0 :             aContext->recycler()->getBoolResult(found, aResult);
     409             : 
     410           0 :             return NS_OK;
     411             :         }
     412             :         case LEADING:
     413             :         case TRAILING:
     414             :         {
     415           0 :             RefPtr<txNodeSet> nodes1;
     416           0 :             rv = evaluateToNodeSet(mParams[0], aContext,
     417           0 :                                    getter_AddRefs(nodes1));
     418           0 :             NS_ENSURE_SUCCESS(rv, rv);
     419             : 
     420           0 :             RefPtr<txNodeSet> nodes2;
     421           0 :             rv = evaluateToNodeSet(mParams[1], aContext,
     422           0 :                                    getter_AddRefs(nodes2));
     423           0 :             NS_ENSURE_SUCCESS(rv, rv);
     424             : 
     425           0 :             if (nodes2->isEmpty()) {
     426           0 :                 *aResult = nodes1;
     427           0 :                 NS_ADDREF(*aResult);
     428             : 
     429           0 :                 return NS_OK;
     430             :             }
     431             : 
     432           0 :             RefPtr<txNodeSet> resultSet;
     433           0 :             rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
     434           0 :             NS_ENSURE_SUCCESS(rv, rv);
     435             : 
     436           0 :             int32_t end = nodes1->indexOf(nodes2->get(0));
     437           0 :             if (end >= 0) {
     438           0 :                 int32_t i = 0;
     439           0 :                 if (mType == TRAILING) {
     440           0 :                     i = end + 1;
     441           0 :                     end = nodes1->size();
     442             :                 }
     443           0 :                 for (; i < end; ++i) {
     444           0 :                     rv = resultSet->append(nodes1->get(i));
     445           0 :                     NS_ENSURE_SUCCESS(rv, rv);
     446             :                 }
     447             :             }
     448             : 
     449           0 :             NS_ADDREF(*aResult = resultSet);
     450             : 
     451           0 :             return NS_OK;
     452             :         }
     453             :         case CONCAT:
     454             :         {
     455           0 :             RefPtr<txNodeSet> nodes;
     456           0 :             rv = evaluateToNodeSet(mParams[0], aContext,
     457           0 :                                    getter_AddRefs(nodes));
     458           0 :             NS_ENSURE_SUCCESS(rv, rv);
     459             : 
     460           0 :             nsAutoString str;
     461           0 :             int32_t i, len = nodes->size();
     462           0 :             for (i = 0; i < len; ++i) {
     463           0 :                 txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
     464             :             }
     465             : 
     466           0 :             return aContext->recycler()->getStringResult(str, aResult);
     467             :         }
     468             :         case SPLIT:
     469             :         case TOKENIZE:
     470             :         {
     471             :             // Evaluate parameters
     472           0 :             nsAutoString string;
     473           0 :             rv = mParams[0]->evaluateToString(aContext, string);
     474           0 :             NS_ENSURE_SUCCESS(rv, rv);
     475             : 
     476           0 :             nsAutoString pattern;
     477           0 :             if (mParams.Length() == 2) {
     478           0 :                 rv = mParams[1]->evaluateToString(aContext, pattern);
     479           0 :                 NS_ENSURE_SUCCESS(rv, rv);
     480             :             }
     481           0 :             else if (mType == SPLIT) {
     482           0 :                 pattern.Assign(' ');
     483             :             }
     484             :             else {
     485           0 :                 pattern.AssignLiteral("\t\r\n ");
     486             :             }
     487             : 
     488             :             // Set up holders for the result
     489           0 :             RefPtr<DocumentFragment> docFrag = createDocFragment(aContext);
     490           0 :             NS_ENSURE_STATE(docFrag);
     491             : 
     492           0 :             RefPtr<txNodeSet> resultSet;
     493           0 :             rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
     494           0 :             NS_ENSURE_SUCCESS(rv, rv);
     495             : 
     496             :             uint32_t tailIndex;
     497             : 
     498             :             // Start splitting
     499           0 :             if (pattern.IsEmpty()) {
     500           0 :                 nsString::const_char_iterator start = string.BeginReading();
     501           0 :                 nsString::const_char_iterator end = string.EndReading();
     502           0 :                 for (; start < end; ++start) {
     503           0 :                     rv = createAndAddToResult(nsGkAtoms::token,
     504           0 :                                               Substring(start, start + 1),
     505           0 :                                               resultSet, docFrag);
     506           0 :                     NS_ENSURE_SUCCESS(rv, rv);
     507             :                 }
     508             : 
     509           0 :                 tailIndex = string.Length();
     510             :             }
     511           0 :             else if (mType == SPLIT) {
     512           0 :                 nsAString::const_iterator strStart, strEnd;
     513           0 :                 string.BeginReading(strStart);
     514           0 :                 string.EndReading(strEnd);
     515           0 :                 nsAString::const_iterator start = strStart, end = strEnd;
     516             : 
     517           0 :                 while (FindInReadable(pattern, start, end)) {
     518           0 :                     if (start != strStart) {
     519           0 :                         rv = createAndAddToResult(nsGkAtoms::token,
     520           0 :                                                   Substring(strStart, start),
     521           0 :                                                   resultSet, docFrag);
     522           0 :                         NS_ENSURE_SUCCESS(rv, rv);
     523             :                     }
     524           0 :                     strStart = start = end;
     525           0 :                     end = strEnd;
     526             :                 }
     527             : 
     528           0 :                 tailIndex = strStart.get() - string.get();
     529             :             }
     530             :             else {
     531           0 :                 int32_t found, start = 0;
     532           0 :                 while ((found = string.FindCharInSet(pattern, start)) !=
     533             :                        kNotFound) {
     534           0 :                     if (found != start) {
     535           0 :                         rv = createAndAddToResult(nsGkAtoms::token,
     536           0 :                                                   Substring(string, start,
     537           0 :                                                             found - start),
     538           0 :                                                   resultSet, docFrag);
     539           0 :                         NS_ENSURE_SUCCESS(rv, rv);
     540             :                     }
     541           0 :                     start = found + 1;
     542             :                 }
     543             : 
     544           0 :                 tailIndex = start;
     545             :             }
     546             : 
     547             :             // Add tail if needed
     548           0 :             if (tailIndex != (uint32_t)string.Length()) {
     549           0 :                 rv = createAndAddToResult(nsGkAtoms::token,
     550           0 :                                           Substring(string, tailIndex),
     551           0 :                                           resultSet, docFrag);
     552           0 :                 NS_ENSURE_SUCCESS(rv, rv);
     553             :             }
     554             : 
     555           0 :             NS_ADDREF(*aResult = resultSet);
     556             : 
     557           0 :             return NS_OK;
     558             :         }
     559             :         case MAX:
     560             :         case MIN:
     561             :         {
     562           0 :             RefPtr<txNodeSet> nodes;
     563           0 :             rv = evaluateToNodeSet(mParams[0], aContext,
     564           0 :                                    getter_AddRefs(nodes));
     565           0 :             NS_ENSURE_SUCCESS(rv, rv);
     566             : 
     567           0 :             if (nodes->isEmpty()) {
     568           0 :                 return aContext->recycler()->
     569           0 :                     getNumberResult(UnspecifiedNaN<double>(), aResult);
     570             :             }
     571             : 
     572           0 :             bool findMax = mType == MAX;
     573             : 
     574           0 :             double res = findMax ? mozilla::NegativeInfinity<double>() :
     575           0 :                                    mozilla::PositiveInfinity<double>();
     576           0 :             int32_t i, len = nodes->size();
     577           0 :             for (i = 0; i < len; ++i) {
     578           0 :                 nsAutoString str;
     579           0 :                 txXPathNodeUtils::appendNodeValue(nodes->get(i), str);
     580           0 :                 double val = txDouble::toDouble(str);
     581           0 :                 if (mozilla::IsNaN(val)) {
     582           0 :                     res = UnspecifiedNaN<double>();
     583           0 :                     break;
     584             :                 }
     585             : 
     586           0 :                 if (findMax ? (val > res) : (val < res)) {
     587           0 :                     res = val;
     588             :                 }
     589             :             }
     590             : 
     591           0 :             return aContext->recycler()->getNumberResult(res, aResult);
     592             :         }
     593             :         case HIGHEST:
     594             :         case LOWEST:
     595             :         {
     596           0 :             RefPtr<txNodeSet> nodes;
     597           0 :             rv = evaluateToNodeSet(mParams[0], aContext,
     598           0 :                                    getter_AddRefs(nodes));
     599           0 :             NS_ENSURE_SUCCESS(rv, rv);
     600             : 
     601           0 :             if (nodes->isEmpty()) {
     602           0 :                 NS_ADDREF(*aResult = nodes);
     603             : 
     604           0 :                 return NS_OK;
     605             :             }
     606             : 
     607           0 :             RefPtr<txNodeSet> resultSet;
     608           0 :             rv = aContext->recycler()->getNodeSet(getter_AddRefs(resultSet));
     609           0 :             NS_ENSURE_SUCCESS(rv, rv);
     610             : 
     611           0 :             bool findMax = mType == HIGHEST;
     612           0 :             double res = findMax ? mozilla::NegativeInfinity<double>() :
     613           0 :                                    mozilla::PositiveInfinity<double>();
     614           0 :             int32_t i, len = nodes->size();
     615           0 :             for (i = 0; i < len; ++i) {
     616           0 :                 nsAutoString str;
     617           0 :                 const txXPathNode& node = nodes->get(i);
     618           0 :                 txXPathNodeUtils::appendNodeValue(node, str);
     619           0 :                 double val = txDouble::toDouble(str);
     620           0 :                 if (mozilla::IsNaN(val)) {
     621           0 :                     resultSet->clear();
     622           0 :                     break;
     623             :                 }
     624           0 :                 if (findMax ? (val > res) : (val < res)) {
     625           0 :                     resultSet->clear();
     626           0 :                     res = val;
     627             :                 }
     628             : 
     629           0 :                 if (res == val) {
     630           0 :                     rv = resultSet->append(node);
     631           0 :                     NS_ENSURE_SUCCESS(rv, rv);
     632             :                 }
     633             :             }
     634             : 
     635           0 :             NS_ADDREF(*aResult = resultSet);
     636             : 
     637           0 :             return NS_OK;
     638             :         }
     639             :         case DATE_TIME:
     640             :         {
     641             :             // http://exslt.org/date/functions/date-time/
     642             : 
     643             :             PRExplodedTime prtime;
     644           0 :             PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime);
     645             : 
     646           0 :             int32_t offset = (prtime.tm_params.tp_gmt_offset +
     647           0 :               prtime.tm_params.tp_dst_offset) / 60;
     648             : 
     649           0 :             bool isneg = offset < 0;
     650           0 :             if (isneg) offset = -offset;
     651             : 
     652             :             StringResult* strRes;
     653           0 :             rv = aContext->recycler()->getStringResult(&strRes);
     654           0 :             NS_ENSURE_SUCCESS(rv, rv);
     655             : 
     656             :             // format: YYYY-MM-DDTTHH:MM:SS.sss+00:00
     657           0 :             CopyASCIItoUTF16(nsPrintfCString("%04hd-%02" PRId32 "-%02" PRId32
     658             :                                              "T%02" PRId32 ":%02" PRId32 ":%02" PRId32
     659             :                                              ".%03" PRId32 "%c%02" PRId32 ":%02" PRId32,
     660           0 :               prtime.tm_year, prtime.tm_month + 1, prtime.tm_mday,
     661             :               prtime.tm_hour, prtime.tm_min, prtime.tm_sec,
     662           0 :               prtime.tm_usec / 10000,
     663           0 :               isneg ? '-' : '+', offset / 60, offset % 60), strRes->mValue);
     664             : 
     665           0 :             *aResult = strRes;
     666             : 
     667           0 :             return NS_OK;
     668             :         }
     669             :     }
     670             : 
     671           0 :     aContext->receiveError(NS_LITERAL_STRING("Internal error"),
     672           0 :                            NS_ERROR_UNEXPECTED);
     673           0 :     return NS_ERROR_UNEXPECTED;
     674             : }
     675             : 
     676             : Expr::ResultType
     677           0 : txEXSLTFunctionCall::getReturnType()
     678             : {
     679           0 :     return descriptTable[mType].mReturnType;
     680             : }
     681             : 
     682             : bool
     683           0 : txEXSLTFunctionCall::isSensitiveTo(ContextSensitivity aContext)
     684             : {
     685           0 :     if (mType == NODE_SET || mType == SPLIT || mType == TOKENIZE) {
     686           0 :         return (aContext & PRIVATE_CONTEXT) || argsSensitiveTo(aContext);
     687             :     }
     688           0 :     return argsSensitiveTo(aContext);
     689             : }
     690             : 
     691             : #ifdef TX_TO_STRING
     692             : nsresult
     693           0 : txEXSLTFunctionCall::getNameAtom(nsIAtom **aAtom)
     694             : {
     695           0 :     NS_ADDREF(*aAtom = *descriptTable[mType].mName);
     696           0 :     return NS_OK;
     697             : }
     698             : #endif
     699             : 
     700             : extern nsresult
     701           0 : TX_ConstructEXSLTFunction(nsIAtom *aName,
     702             :                           int32_t aNamespaceID,
     703             :                           txStylesheetCompilerState* aState,
     704             :                           FunctionCall **aResult)
     705             : {
     706             :     uint32_t i;
     707           0 :     for (i = 0; i < ArrayLength(descriptTable); ++i) {
     708           0 :         txEXSLTFunctionDescriptor& desc = descriptTable[i];
     709           0 :         if (aName == *desc.mName && aNamespaceID == desc.mNamespaceID) {
     710           0 :             *aResult = new txEXSLTFunctionCall(
     711           0 :                 static_cast<txEXSLTFunctionCall::eType>(i));
     712           0 :             return NS_OK;
     713             :         }
     714             :     }
     715             : 
     716           0 :     return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
     717             : }
     718             : 
     719             : extern bool
     720           3 : TX_InitEXSLTFunction()
     721             : {
     722             :     uint32_t i;
     723          51 :     for (i = 0; i < ArrayLength(descriptTable); ++i) {
     724          48 :         txEXSLTFunctionDescriptor& desc = descriptTable[i];
     725          96 :         NS_ConvertASCIItoUTF16 namespaceURI(desc.mNamespaceURI);
     726          48 :         desc.mNamespaceID =
     727          48 :             txNamespaceManager::getNamespaceID(namespaceURI);
     728             : 
     729          48 :         if (desc.mNamespaceID == kNameSpaceID_Unknown) {
     730           0 :             return false;
     731             :         }
     732             :     }
     733             : 
     734           3 :     return true;
     735             : }

Generated by: LCOV version 1.13