dom/xslt/xpath/txPathExpr.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 #include "txExpr.h"
     7 #include "txNodeSet.h"
     8 #include "txNodeSetContext.h"
     9 #include "txSingleNodeContext.h"
    10 #include "txXMLUtils.h"
    11 #include "txXPathTreeWalker.h"
    13   //------------/
    14  //- PathExpr -/
    15 //------------/
    17 /**
    18  * Adds the Expr to this PathExpr
    19  * @param expr the Expr to add to this PathExpr
    20 **/
    21 nsresult
    22 PathExpr::addExpr(Expr* aExpr, PathOperator aPathOp)
    23 {
    24     NS_ASSERTION(!mItems.IsEmpty() || aPathOp == RELATIVE_OP,
    25                  "First step has to be relative in PathExpr");
    26     PathExprItem* pxi = mItems.AppendElement();
    27     if (!pxi) {
    28         return NS_ERROR_OUT_OF_MEMORY;
    29     }
    30     pxi->expr = aExpr;
    31     pxi->pathOp = aPathOp;
    33     return NS_OK;
    34 }
    36     //-----------------------------/
    37   //- Virtual methods from Expr -/
    38 //-----------------------------/
    40 /**
    41  * Evaluates this Expr based on the given context node and processor state
    42  * @param context the context node for evaluation of this Expr
    43  * @param ps the ContextState containing the stack information needed
    44  * for evaluation
    45  * @return the result of the evaluation
    46 **/
    47 nsresult
    48 PathExpr::evaluate(txIEvalContext* aContext, txAExprResult** aResult)
    49 {
    50     *aResult = nullptr;
    52     // We need to evaluate the first step with the current context since it
    53     // can depend on the context size and position. For example:
    54     // key('books', concat('book', position()))
    55     nsRefPtr<txAExprResult> res;
    56     nsresult rv = mItems[0].expr->evaluate(aContext, getter_AddRefs(res));
    57     NS_ENSURE_SUCCESS(rv, rv);
    59     NS_ENSURE_TRUE(res->getResultType() == txAExprResult::NODESET,
    60                    NS_ERROR_XSLT_NODESET_EXPECTED);
    62     nsRefPtr<txNodeSet> nodes = static_cast<txNodeSet*>
    63                                            (static_cast<txAExprResult*>
    64                                                        (res));
    65     if (nodes->isEmpty()) {
    66         res.swap(*aResult);
    68         return NS_OK;
    69     }
    70     res = nullptr; // To allow recycling
    72     // Evaluate remaining steps
    73     uint32_t i, len = mItems.Length();
    74     for (i = 1; i < len; ++i) {
    75         PathExprItem& pxi = mItems[i];
    76         nsRefPtr<txNodeSet> tmpNodes;
    77         txNodeSetContext eContext(nodes, aContext);
    78         while (eContext.hasNext()) {
    79             eContext.next();
    81             nsRefPtr<txNodeSet> resNodes;
    82             if (pxi.pathOp == DESCENDANT_OP) {
    83                 rv = aContext->recycler()->getNodeSet(getter_AddRefs(resNodes));
    84                 NS_ENSURE_SUCCESS(rv, rv);
    86                 rv = evalDescendants(pxi.expr, eContext.getContextNode(),
    87                                      &eContext, resNodes);
    88                 NS_ENSURE_SUCCESS(rv, rv);
    89             }
    90             else {
    91                 nsRefPtr<txAExprResult> res;
    92                 rv = pxi.expr->evaluate(&eContext, getter_AddRefs(res));
    93                 NS_ENSURE_SUCCESS(rv, rv);
    95                 if (res->getResultType() != txAExprResult::NODESET) {
    96                     //XXX ErrorReport: report nonnodeset error
    97                     return NS_ERROR_XSLT_NODESET_EXPECTED;
    98                 }
    99                 resNodes = static_cast<txNodeSet*>
   100                                       (static_cast<txAExprResult*>
   101                                                   (res));
   102             }
   104             if (tmpNodes) {
   105                 if (!resNodes->isEmpty()) {
   106                     nsRefPtr<txNodeSet> oldSet;
   107                     oldSet.swap(tmpNodes);
   108                     rv = aContext->recycler()->
   109                         getNonSharedNodeSet(oldSet, getter_AddRefs(tmpNodes));
   110                     NS_ENSURE_SUCCESS(rv, rv);
   112                     oldSet.swap(resNodes);
   113                     rv = aContext->recycler()->
   114                         getNonSharedNodeSet(oldSet, getter_AddRefs(resNodes));
   115                     NS_ENSURE_SUCCESS(rv, rv);
   117                     tmpNodes->addAndTransfer(resNodes);
   118                 }
   119             }
   120             else {
   121                 tmpNodes = resNodes;
   122             }
   123         }
   124         nodes = tmpNodes;
   125         if (nodes->isEmpty()) {
   126             break;
   127         }
   128     }
   130     *aResult = nodes;
   131     NS_ADDREF(*aResult);
   133     return NS_OK;
   134 } //-- evaluate
   136 /**
   137  * Selects from the descendants of the context node
   138  * all nodes that match the Expr
   139 **/
   140 nsresult
   141 PathExpr::evalDescendants(Expr* aStep, const txXPathNode& aNode,
   142                           txIMatchContext* aContext, txNodeSet* resNodes)
   143 {
   144     txSingleNodeContext eContext(aNode, aContext);
   145     nsRefPtr<txAExprResult> res;
   146     nsresult rv = aStep->evaluate(&eContext, getter_AddRefs(res));
   147     NS_ENSURE_SUCCESS(rv, rv);
   149     if (res->getResultType() != txAExprResult::NODESET) {
   150         //XXX ErrorReport: report nonnodeset error
   151         return NS_ERROR_XSLT_NODESET_EXPECTED;
   152     }
   154     txNodeSet* oldSet = static_cast<txNodeSet*>
   155                                    (static_cast<txAExprResult*>(res));
   156     nsRefPtr<txNodeSet> newSet;
   157     rv = aContext->recycler()->getNonSharedNodeSet(oldSet,
   158                                                    getter_AddRefs(newSet));
   159     NS_ENSURE_SUCCESS(rv, rv);
   161     resNodes->addAndTransfer(newSet);
   163     bool filterWS = aContext->isStripSpaceAllowed(aNode);
   165     txXPathTreeWalker walker(aNode);
   166     if (!walker.moveToFirstChild()) {
   167         return NS_OK;
   168     }
   170     do {
   171         const txXPathNode& node = walker.getCurrentPosition();
   172         if (!(filterWS && txXPathNodeUtils::isText(node) &&
   173               txXPathNodeUtils::isWhitespace(node))) {
   174             rv = evalDescendants(aStep, node, aContext, resNodes);
   175             NS_ENSURE_SUCCESS(rv, rv);
   176         }
   177     } while (walker.moveToNextSibling());
   179     return NS_OK;
   180 } //-- evalDescendants
   182 Expr::ExprType
   183 PathExpr::getType()
   184 {
   185   return PATH_EXPR;
   186 }
   188 TX_IMPL_EXPR_STUBS_BASE(PathExpr, NODESET_RESULT)
   190 Expr*
   191 PathExpr::getSubExprAt(uint32_t aPos)
   192 {
   193     return aPos < mItems.Length() ? mItems[aPos].expr.get() : nullptr;
   194 }
   195 void
   196 PathExpr::setSubExprAt(uint32_t aPos, Expr* aExpr)
   197 {
   198     NS_ASSERTION(aPos < mItems.Length(), "setting bad subexpression index");
   199     mItems[aPos].expr.forget();
   200     mItems[aPos].expr = aExpr;
   201 }
   204 bool
   205 PathExpr::isSensitiveTo(ContextSensitivity aContext)
   206 {
   207     if (mItems[0].expr->isSensitiveTo(aContext)) {
   208         return true;
   209     }
   211     // We're creating a new node/nodeset so we can ignore those bits.
   212     Expr::ContextSensitivity context =
   213         aContext & ~(Expr::NODE_CONTEXT | Expr::NODESET_CONTEXT);
   214     if (context == NO_CONTEXT) {
   215         return false;
   216     }
   218     uint32_t i, len = mItems.Length();
   219     for (i = 0; i < len; ++i) {
   220         NS_ASSERTION(!mItems[i].expr->isSensitiveTo(Expr::NODESET_CONTEXT),
   221                      "Step cannot depend on nodeset-context");
   222         if (mItems[i].expr->isSensitiveTo(context)) {
   223             return true;
   224         }
   225     }
   227     return false;
   228 }
   230 #ifdef TX_TO_STRING
   231 void
   232 PathExpr::toString(nsAString& dest)
   233 {
   234     if (!mItems.IsEmpty()) {
   235         NS_ASSERTION(mItems[0].pathOp == RELATIVE_OP,
   236                      "First step should be relative");
   237         mItems[0].expr->toString(dest);
   238     }
   240     uint32_t i, len = mItems.Length();
   241     for (i = 1; i < len; ++i) {
   242         switch (mItems[i].pathOp) {
   243             case DESCENDANT_OP:
   244                 dest.AppendLiteral("//");
   245                 break;
   246             case RELATIVE_OP:
   247                 dest.Append(char16_t('/'));
   248                 break;
   249         }
   250         mItems[i].expr->toString(dest);
   251     }
   252 }
   253 #endif

mercurial