LCOV - code coverage report
Current view: top level - dom/xslt/xslt - txNodeSorter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 122 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 6 0.0 %
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 "txNodeSorter.h"
       7             : #include "txExecutionState.h"
       8             : #include "txXPathResultComparator.h"
       9             : #include "nsGkAtoms.h"
      10             : #include "txNodeSetContext.h"
      11             : #include "txExpr.h"
      12             : #include "txStringUtils.h"
      13             : #include "nsQuickSort.h"
      14             : 
      15             : #include "mozilla/CheckedInt.h"
      16             : #include "mozilla/UniquePtrExtensions.h"
      17             : 
      18             : using mozilla::CheckedUint32;
      19             : using mozilla::MakeUniqueFallible;
      20             : 
      21             : /*
      22             :  * Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation
      23             :  */
      24             : 
      25           0 : txNodeSorter::txNodeSorter() : mNKeys(0)
      26             : {
      27           0 : }
      28             : 
      29           0 : txNodeSorter::~txNodeSorter()
      30             : {
      31           0 :     txListIterator iter(&mSortKeys);
      32           0 :     while (iter.hasNext()) {
      33           0 :         SortKey* key = (SortKey*)iter.next();
      34           0 :         delete key->mComparator;
      35             :         delete key;
      36             :     }
      37           0 : }
      38             : 
      39             : nsresult
      40           0 : txNodeSorter::addSortElement(Expr* aSelectExpr, Expr* aLangExpr,
      41             :                              Expr* aDataTypeExpr, Expr* aOrderExpr,
      42             :                              Expr* aCaseOrderExpr, txIEvalContext* aContext)
      43             : {
      44           0 :     nsAutoPtr<SortKey> key(new SortKey);
      45           0 :     nsresult rv = NS_OK;
      46             : 
      47             :     // Select
      48           0 :     key->mExpr = aSelectExpr;
      49             : 
      50             :     // Order
      51           0 :     bool ascending = true;
      52           0 :     if (aOrderExpr) {
      53           0 :         nsAutoString attrValue;
      54           0 :         rv = aOrderExpr->evaluateToString(aContext, attrValue);
      55           0 :         NS_ENSURE_SUCCESS(rv, rv);
      56             : 
      57           0 :         if (TX_StringEqualsAtom(attrValue, nsGkAtoms::descending)) {
      58           0 :             ascending = false;
      59             :         }
      60           0 :         else if (!TX_StringEqualsAtom(attrValue, nsGkAtoms::ascending)) {
      61             :             // XXX ErrorReport: unknown value for order attribute
      62           0 :             return NS_ERROR_XSLT_BAD_VALUE;
      63             :         }
      64             :     }
      65             : 
      66             : 
      67             :     // Create comparator depending on datatype
      68           0 :     nsAutoString dataType;
      69           0 :     if (aDataTypeExpr) {
      70           0 :         rv = aDataTypeExpr->evaluateToString(aContext, dataType);
      71           0 :         NS_ENSURE_SUCCESS(rv, rv);
      72             :     }
      73             : 
      74           0 :     if (!aDataTypeExpr || TX_StringEqualsAtom(dataType, nsGkAtoms::text)) {
      75             :         // Text comparator
      76             : 
      77             :         // Language
      78           0 :         nsAutoString lang;
      79           0 :         if (aLangExpr) {
      80           0 :             rv = aLangExpr->evaluateToString(aContext, lang);
      81           0 :             NS_ENSURE_SUCCESS(rv, rv);
      82             :         }
      83             : 
      84             :         // Case-order
      85           0 :         bool upperFirst = false;
      86           0 :         if (aCaseOrderExpr) {
      87           0 :             nsAutoString attrValue;
      88             : 
      89           0 :             rv = aCaseOrderExpr->evaluateToString(aContext, attrValue);
      90           0 :             NS_ENSURE_SUCCESS(rv, rv);
      91             : 
      92           0 :             if (TX_StringEqualsAtom(attrValue, nsGkAtoms::upperFirst)) {
      93           0 :                 upperFirst = true;
      94             :             }
      95           0 :             else if (!TX_StringEqualsAtom(attrValue,
      96             :                                           nsGkAtoms::lowerFirst)) {
      97             :                 // XXX ErrorReport: unknown value for case-order attribute
      98           0 :                 return NS_ERROR_XSLT_BAD_VALUE;
      99             :             }
     100             :         }
     101             : 
     102           0 :         key->mComparator = new txResultStringComparator(ascending,
     103             :                                                         upperFirst,
     104           0 :                                                         lang);
     105             :     }
     106           0 :     else if (TX_StringEqualsAtom(dataType, nsGkAtoms::number)) {
     107             :         // Number comparator
     108           0 :         key->mComparator = new txResultNumberComparator(ascending);
     109             :     }
     110             :     else {
     111             :         // XXX ErrorReport: unknown data-type
     112           0 :         return NS_ERROR_XSLT_BAD_VALUE;
     113             :     }
     114             : 
     115             :     // mSortKeys owns key now.
     116           0 :     rv = mSortKeys.add(key);
     117           0 :     NS_ENSURE_SUCCESS(rv, rv);
     118             : 
     119           0 :     key.forget();
     120           0 :     mNKeys++;
     121             : 
     122           0 :     return NS_OK;
     123             : }
     124             : 
     125             : nsresult
     126           0 : txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs,
     127             :                           txNodeSet** aResult)
     128             : {
     129           0 :     if (mNKeys == 0 || aNodes->isEmpty()) {
     130           0 :         RefPtr<txNodeSet> ref(aNodes);
     131           0 :         ref.forget(aResult);
     132             : 
     133           0 :         return NS_OK;
     134             :     }
     135             : 
     136           0 :     *aResult = nullptr;
     137             : 
     138           0 :     RefPtr<txNodeSet> sortedNodes;
     139           0 :     nsresult rv = aEs->recycler()->getNodeSet(getter_AddRefs(sortedNodes));
     140           0 :     NS_ENSURE_SUCCESS(rv, rv);
     141             : 
     142           0 :     txNodeSetContext* evalContext = new txNodeSetContext(aNodes, aEs);
     143           0 :     NS_ENSURE_TRUE(evalContext, NS_ERROR_OUT_OF_MEMORY);
     144             : 
     145           0 :     rv = aEs->pushEvalContext(evalContext);
     146           0 :     NS_ENSURE_SUCCESS(rv, rv);
     147             : 
     148             :     // Create and set up memoryblock for sort-values and indexarray
     149           0 :     CheckedUint32 len = aNodes->size();
     150           0 :     CheckedUint32 numSortValues = len * mNKeys;
     151           0 :     CheckedUint32 sortValuesSize = numSortValues * sizeof(txObject*);
     152           0 :     if (!sortValuesSize.isValid()) {
     153           0 :         return NS_ERROR_OUT_OF_MEMORY;
     154             :     }
     155             : 
     156           0 :     auto indexes = MakeUniqueFallible<uint32_t[]>(len.value());
     157           0 :     auto sortValues = MakeUniqueFallible<txObject*[]>(numSortValues.value());
     158           0 :     if (!indexes || !sortValues) {
     159           0 :         return NS_ERROR_OUT_OF_MEMORY;
     160             :     }
     161             : 
     162             :     uint32_t i;
     163           0 :     for (i = 0; i < len.value(); ++i) {
     164           0 :         indexes[i] = i;
     165             :     }
     166           0 :     memset(sortValues.get(), 0, sortValuesSize.value());
     167             : 
     168             :     // Sort the indexarray
     169             :     SortData sortData;
     170           0 :     sortData.mNodeSorter = this;
     171           0 :     sortData.mContext = evalContext;
     172           0 :     sortData.mSortValues = sortValues.get();
     173           0 :     sortData.mRv = NS_OK;
     174           0 :     NS_QuickSort(indexes.get(), len.value(), sizeof(uint32_t), compareNodes, &sortData);
     175             : 
     176             :     // Delete these here so we don't have to deal with them at every possible
     177             :     // failurepoint
     178           0 :     for (i = 0; i < numSortValues.value(); ++i) {
     179           0 :         delete sortValues[i];
     180             :     }
     181             : 
     182           0 :     if (NS_FAILED(sortData.mRv)) {
     183             :         // The txExecutionState owns the evalcontext so no need to handle it
     184           0 :         return sortData.mRv;
     185             :     }
     186             : 
     187             :     // Insert nodes in sorted order in new nodeset
     188           0 :     for (i = 0; i < len.value(); ++i) {
     189           0 :         rv = sortedNodes->append(aNodes->get(indexes[i]));
     190           0 :         if (NS_FAILED(rv)) {
     191             :             // The txExecutionState owns the evalcontext so no need to handle it
     192           0 :             return rv;
     193             :         }
     194             :     }
     195             : 
     196           0 :     delete aEs->popEvalContext();
     197             : 
     198           0 :     sortedNodes.forget(aResult);
     199             : 
     200           0 :     return NS_OK;
     201             : }
     202             : 
     203             : // static
     204             : int
     205           0 : txNodeSorter::compareNodes(const void* aIndexA, const void* aIndexB,
     206             :                            void* aSortData)
     207             : {
     208           0 :     SortData* sortData = static_cast<SortData*>(aSortData);
     209           0 :     NS_ENSURE_SUCCESS(sortData->mRv, -1);
     210             : 
     211           0 :     txListIterator iter(&sortData->mNodeSorter->mSortKeys);
     212           0 :     uint32_t indexA = *static_cast<const uint32_t*>(aIndexA);
     213           0 :     uint32_t indexB = *static_cast<const uint32_t*>(aIndexB);
     214           0 :     txObject** sortValuesA = sortData->mSortValues +
     215           0 :                              indexA * sortData->mNodeSorter->mNKeys;
     216           0 :     txObject** sortValuesB = sortData->mSortValues +
     217           0 :                              indexB * sortData->mNodeSorter->mNKeys;
     218             : 
     219             :     unsigned int i;
     220             :     // Step through each key until a difference is found
     221           0 :     for (i = 0; i < sortData->mNodeSorter->mNKeys; ++i) {
     222           0 :         SortKey* key = (SortKey*)iter.next();
     223             :         // Lazy create sort values
     224           0 :         if (!sortValuesA[i] &&
     225           0 :             !calcSortValue(sortValuesA[i], key, sortData, indexA)) {
     226           0 :             return -1;
     227             :         }
     228           0 :         if (!sortValuesB[i] &&
     229           0 :             !calcSortValue(sortValuesB[i], key, sortData, indexB)) {
     230           0 :             return -1;
     231             :         }
     232             : 
     233             :         // Compare node values
     234           0 :         int compRes = key->mComparator->compareValues(sortValuesA[i],
     235           0 :                                                       sortValuesB[i]);
     236           0 :         if (compRes != 0)
     237           0 :             return compRes;
     238             :     }
     239             :     // All keys have the same value for these nodes
     240             : 
     241           0 :     return indexA - indexB;
     242             : }
     243             : 
     244             : //static
     245             : bool
     246           0 : txNodeSorter::calcSortValue(txObject*& aSortValue, SortKey* aKey,
     247             :                             SortData* aSortData, uint32_t aNodeIndex)
     248             : {
     249           0 :     aSortData->mContext->setPosition(aNodeIndex + 1); // position is 1-based
     250             : 
     251           0 :     nsresult rv = aKey->mComparator->createSortableValue(aKey->mExpr,
     252           0 :                                                          aSortData->mContext,
     253           0 :                                                          aSortValue);
     254           0 :     if (NS_FAILED(rv)) {
     255           0 :         aSortData->mRv = rv;
     256           0 :         return false;
     257             :     }
     258             : 
     259           0 :     return true;
     260             : }

Generated by: LCOV version 1.13