int txResultNumberComparator::compareValues(txObject* aVal1, txObject* aVal2)
{
    double dval1 = ((NumberValue*)aVal1)->mVal;
    double dval2 = ((NumberValue*)aVal2)->mVal;

    if (MOZ_DOUBLE_IS_NaN(dval1))
        return MOZ_DOUBLE_IS_NaN(dval2) ? 0 : -mAscending;

    if (MOZ_DOUBLE_IS_NaN(dval2))
        return mAscending;

    if (dval1 == dval2)
        return 0;
    
    return (dval1 < dval2) ? -mAscending : mAscending;
}
nsresult
txStylesheet::addTemplate(txTemplateItem* aTemplate,
                          ImportFrame* aImportFrame)
{
    NS_ASSERTION(aTemplate, "missing template");

    txInstruction* instr = aTemplate->mFirstInstruction;
    nsresult rv = mTemplateInstructions.add(instr);
    NS_ENSURE_SUCCESS(rv, rv);

    // mTemplateInstructions now owns the instructions
    aTemplate->mFirstInstruction.forget();

    if (!aTemplate->mName.isNull()) {
        rv = mNamedTemplates.add(aTemplate->mName, instr);
        NS_ENSURE_TRUE(NS_SUCCEEDED(rv) || rv == NS_ERROR_XSLT_ALREADY_SET,
                       rv);
    }

    if (!aTemplate->mMatch) {
        // This is no error, see section 6 Named Templates

        return NS_OK;
    }

    // get the txList for the right mode
    nsTArray<MatchableTemplate>* templates =
        aImportFrame->mMatchableTemplates.get(aTemplate->mMode);

    if (!templates) {
        nsAutoPtr< nsTArray<MatchableTemplate> > newList(
            new nsTArray<MatchableTemplate>);
        NS_ENSURE_TRUE(newList, NS_ERROR_OUT_OF_MEMORY);

        rv = aImportFrame->mMatchableTemplates.set(aTemplate->mMode, newList);
        NS_ENSURE_SUCCESS(rv, rv);

        templates = newList.forget();
    }

    // Add the simple patterns to the list of matchable templates, according
    // to default priority
    nsAutoPtr<txPattern> simple = aTemplate->mMatch;
    nsAutoPtr<txPattern> unionPattern;
    if (simple->getType() == txPattern::UNION_PATTERN) {
        unionPattern = simple;
        simple = unionPattern->getSubPatternAt(0);
        unionPattern->setSubPatternAt(0, nullptr);
    }

    PRUint32 unionPos = 1; // only used when unionPattern is set
    while (simple) {
        double priority = aTemplate->mPrio;
        if (MOZ_DOUBLE_IS_NaN(priority)) {
            priority = simple->getDefaultPriority();
            NS_ASSERTION(!MOZ_DOUBLE_IS_NaN(priority),
                         "simple pattern without default priority");
        }

        PRUint32 i, len = templates->Length();
        for (i = 0; i < len; ++i) {
            if (priority > (*templates)[i].mPriority) {
                break;
            }
        }

        MatchableTemplate* nt = templates->InsertElementAt(i);
        NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);

        nt->mFirstInstruction = instr;
        nt->mMatch = simple;
        nt->mPriority = priority;

        if (unionPattern) {
            simple = unionPattern->getSubPatternAt(unionPos);
            if (simple) {
                unionPattern->setSubPatternAt(unionPos, nullptr);
            }
            ++unionPos;
        }
    }

    return NS_OK;
}
Beispiel #3
0
/*
 * Converts the value of the given double to a String, and places
 * The result into the destination String.
 * @return the given dest string
 */
void txDouble::toString(double aValue, nsAString& aDest)
{

    // check for special cases

    if (MOZ_DOUBLE_IS_NaN(aValue)) {
        aDest.AppendLiteral("NaN");
        return;
    }
    if (MOZ_DOUBLE_IS_INFINITE(aValue)) {
        if (aValue < 0)
            aDest.Append(PRUnichar('-'));
        aDest.AppendLiteral("Infinity");
        return;
    }

    // Mantissa length is 17, so this is plenty
    const int buflen = 20;
    char buf[buflen];

    int intDigits, sign;
    char* endp;
    PR_dtoa(aValue, 0, 0, &intDigits, &sign, &endp, buf, buflen - 1);

    // compute length
    int32_t length = endp - buf;
    if (length > intDigits) {
        // decimal point needed
        ++length;
        if (intDigits < 1) {
            // leading zeros, -intDigits + 1
            length += 1 - intDigits;
        }
    }
    else {
        // trailing zeros, total length given by intDigits
        length = intDigits;
    }
    if (aValue < 0)
        ++length;
    // grow the string
    uint32_t oldlength = aDest.Length();
    if (!EnsureStringLength(aDest, oldlength + length))
        return; // out of memory
    nsAString::iterator dest;
    aDest.BeginWriting(dest).advance(int32_t(oldlength));
    if (aValue < 0) {
        *dest = '-'; ++dest;
    }
    int i;
    // leading zeros
    if (intDigits < 1) {
        *dest = '0'; ++dest;
        *dest = '.'; ++dest;
        for (i = 0; i > intDigits; --i) {
            *dest = '0'; ++dest;
        }
    }
    // mantissa
    int firstlen = std::min<size_t>(intDigits, endp - buf);
    for (i = 0; i < firstlen; i++) {
        *dest = buf[i]; ++dest;
    }
    if (i < endp - buf) {
        if (i > 0) {
            *dest = '.'; ++dest;
        }
        for (; i < endp - buf; i++) {
            *dest = buf[i]; ++dest;
        }
    }
    // trailing zeros
    for (; i < intDigits; i++) {
        *dest = '0'; ++dest;
    }
}
Beispiel #4
0
nsresult
txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern,
                           txPattern* aFromPattern, LevelType aLevel,
                           txIEvalContext* aContext, txList& aValues,
                           nsAString& aValueString)
{
    aValueString.Truncate();
    nsresult rv = NS_OK;

    // If the value attribute exists then use that
    if (aValueExpr) {
        nsRefPtr<txAExprResult> result;
        rv = aValueExpr->evaluate(aContext, getter_AddRefs(result));
        NS_ENSURE_SUCCESS(rv, rv);

        double value = result->numberValue();

        if (MOZ_DOUBLE_IS_INFINITE(value) || MOZ_DOUBLE_IS_NaN(value) ||
            value < 0.5) {
            txDouble::toString(value, aValueString);
            return NS_OK;
        }
        
        aValues.add(NS_INT32_TO_PTR((int32_t)floor(value + 0.5)));
        return NS_OK;
    }


    // Otherwise use count/from/level

    txPattern* countPattern = aCountPattern;
    bool ownsCountPattern = false;
    const txXPathNode& currNode = aContext->getContextNode();

    // Parse count- and from-attributes

    if (!aCountPattern) {
        ownsCountPattern = true;
        txNodeTest* nodeTest;
        uint16_t nodeType = txXPathNodeUtils::getNodeType(currNode);
        switch (nodeType) {
            case txXPathNodeType::ELEMENT_NODE:
            {
                nsCOMPtr<nsIAtom> localName =
                    txXPathNodeUtils::getLocalName(currNode);
                int32_t namespaceID = txXPathNodeUtils::getNamespaceID(currNode);
                nodeTest = new txNameTest(0, localName, namespaceID,
                                          txXPathNodeType::ELEMENT_NODE);
                break;
            }
            case txXPathNodeType::TEXT_NODE:
            case txXPathNodeType::CDATA_SECTION_NODE:
            {
                nodeTest = new txNodeTypeTest(txNodeTypeTest::TEXT_TYPE);
                break;
            }
            case txXPathNodeType::PROCESSING_INSTRUCTION_NODE:
            {
                txNodeTypeTest* typeTest;
                typeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE);
                if (typeTest) {
                    nsAutoString nodeName;
                    txXPathNodeUtils::getNodeName(currNode, nodeName);
                    typeTest->setNodeName(nodeName);
                }
                nodeTest = typeTest;
                break;
            }
            case txXPathNodeType::COMMENT_NODE:
            {
                nodeTest = new txNodeTypeTest(txNodeTypeTest::COMMENT_TYPE);
                break;
            }
            case txXPathNodeType::DOCUMENT_NODE:
            case txXPathNodeType::ATTRIBUTE_NODE:
            default:
            {
                // this won't match anything as we walk up the tree
                // but it's what the spec says to do
                nodeTest = new txNameTest(0, nsGkAtoms::_asterix, 0,
                                          nodeType);
                break;
            }
        }
        NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY);

        countPattern = new txStepPattern(nodeTest, false);
        if (!countPattern) {
            // XXX error reporting
            delete nodeTest;
            return NS_ERROR_OUT_OF_MEMORY;
        }
    }


    // Generate list of values depending on the value of the level-attribute

    // level = "single"
    if (aLevel == eLevelSingle) {
        txXPathTreeWalker walker(currNode);
        do {
            if (aFromPattern && !walker.isOnNode(currNode) &&
                aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                break;
            }

            if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
                aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
                                                            aContext)));
                break;
            }

        } while (walker.moveToParent());

        // Spec says to only match ancestors that are decendants of the
        // ancestor that matches the from-pattern, so keep going to make
        // sure that there is an ancestor that does.
        if (aFromPattern && aValues.getLength()) {
            bool hasParent;
            while ((hasParent = walker.moveToParent())) {
                if (aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                    break;
                }
            }

            if (!hasParent) {
                aValues.clear();
            }
        }
    }
    // level = "multiple"
    else if (aLevel == eLevelMultiple) {
        // find all ancestor-or-selfs that matches count until...
        txXPathTreeWalker walker(currNode);
        bool matchedFrom = false;
        do {
            if (aFromPattern && !walker.isOnNode(currNode) &&
                aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                //... we find one that matches from
                matchedFrom = true;
                break;
            }

            if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
                aValues.add(NS_INT32_TO_PTR(getSiblingCount(walker, countPattern,
                                                            aContext)));
            }
        } while (walker.moveToParent());

        // Spec says to only match ancestors that are decendants of the
        // ancestor that matches the from-pattern, so if none did then
        // we shouldn't search anything
        if (aFromPattern && !matchedFrom) {
            aValues.clear();
        }
    }
    // level = "any"
    else if (aLevel == eLevelAny) {
        int32_t value = 0;
        bool matchedFrom = false;

        txXPathTreeWalker walker(currNode);
        do {
            if (aFromPattern && !walker.isOnNode(currNode) &&
                aFromPattern->matches(walker.getCurrentPosition(), aContext)) {
                matchedFrom = true;
                break;
            }

            if (countPattern->matches(walker.getCurrentPosition(), aContext)) {
                ++value;
            }

        } while (getPrevInDocumentOrder(walker));

        // Spec says to only count nodes that follows the first node that
        // matches the from pattern. So so if none did then we shouldn't
        // count any
        if (aFromPattern && !matchedFrom) {
            value = 0;
        }

        if (value) {
            aValues.add(NS_INT32_TO_PTR(value));
        }
    }

    if (ownsCountPattern) {
        delete countPattern;
    }
    
    return NS_OK;
}
Beispiel #5
0
nsresult
Key::EncodeJSValInternal(JSContext* aCx, const jsval aVal,
                         uint8_t aTypeOffset, uint16_t aRecursionDepth)
{
  NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);

  MOZ_STATIC_ASSERT(eMaxType * MaxArrayCollapse < 256,
                    "Unable to encode jsvals.");

  if (JSVAL_IS_STRING(aVal)) {
    nsDependentJSString str;
    if (!str.init(aCx, aVal)) {
      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    }
    EncodeString(str, aTypeOffset);
    return NS_OK;
  }

  if (JSVAL_IS_INT(aVal)) {
    EncodeNumber((double)JSVAL_TO_INT(aVal), eFloat + aTypeOffset);
    return NS_OK;
  }

  if (JSVAL_IS_DOUBLE(aVal)) {
    double d = JSVAL_TO_DOUBLE(aVal);
    if (MOZ_DOUBLE_IS_NaN(d)) {
      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
    }
    EncodeNumber(d, eFloat + aTypeOffset);
    return NS_OK;
  }

  if (!JSVAL_IS_PRIMITIVE(aVal)) {
    JSObject* obj = JSVAL_TO_OBJECT(aVal);
    if (JS_IsArrayObject(aCx, obj)) {
      aTypeOffset += eMaxType;

      if (aTypeOffset == eMaxType * MaxArrayCollapse) {
        mBuffer.Append(aTypeOffset);
        aTypeOffset = 0;
      }
      NS_ASSERTION((aTypeOffset % eMaxType) == 0 &&
                   aTypeOffset < (eMaxType * MaxArrayCollapse),
                   "Wrong typeoffset");

      uint32_t length;
      if (!JS_GetArrayLength(aCx, obj, &length)) {
        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
      }

      for (uint32_t index = 0; index < length; index++) {
        jsval val;
        if (!JS_GetElement(aCx, obj, index, &val)) {
          return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
        }

        nsresult rv = EncodeJSValInternal(aCx, val, aTypeOffset,
                                          aRecursionDepth + 1);
        if (NS_FAILED(rv)) {
          return rv;
        }

        aTypeOffset = 0;
      }

      mBuffer.Append(eTerminator + aTypeOffset);

      return NS_OK;
    }

    if (JS_ObjectIsDate(aCx, obj)) {
      if (!js_DateIsValid(obj))  {
        return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
      }
      EncodeNumber(js_DateGetMsecSinceEpoch(obj), eDate + aTypeOffset);
      return NS_OK;
    }
  }

  return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
}
/*
 * Evaluates this Expr based on the given context node and processor state
 * @param context the context node for evaluation of this Expr
 * @param cs the ContextState containing the stack information needed
 * for evaluation
 * @return the result of the evaluation
 */
nsresult
txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext,
                                     txAExprResult** aResult)
{
    *aResult = nullptr;
    if (!requireParams(2, 3, aContext))
        return NS_ERROR_XPATH_BAD_ARGUMENT_COUNT;

    // Get number and format
    double value;
    txExpandedName formatName;

    nsresult rv = evaluateToNumber(mParams[0], aContext, &value);
    NS_ENSURE_SUCCESS(rv, rv);

    nsAutoString formatStr;
    rv = mParams[1]->evaluateToString(aContext, formatStr);
    NS_ENSURE_SUCCESS(rv, rv);

    if (mParams.Length() == 3) {
        nsAutoString formatQName;
        rv = mParams[2]->evaluateToString(aContext, formatQName);
        NS_ENSURE_SUCCESS(rv, rv);

        rv = formatName.init(formatQName, mMappings, false);
        NS_ENSURE_SUCCESS(rv, rv);
    }

    txDecimalFormat* format = mStylesheet->getDecimalFormat(formatName);
    if (!format) {
        nsAutoString err(NS_LITERAL_STRING("unknown decimal format"));
#ifdef TX_TO_STRING
        err.AppendLiteral(" for: ");
        toString(err);
#endif
        aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG);
        return NS_ERROR_XPATH_INVALID_ARG;
    }

    // Special cases
    if (MOZ_DOUBLE_IS_NaN(value)) {
        return aContext->recycler()->getStringResult(format->mNaN, aResult);
    }

    if (value == MOZ_DOUBLE_POSITIVE_INFINITY()) {
        return aContext->recycler()->getStringResult(format->mInfinity,
                                                     aResult);
    }

    if (value == MOZ_DOUBLE_NEGATIVE_INFINITY()) {
        nsAutoString res;
        res.Append(format->mMinusSign);
        res.Append(format->mInfinity);
        return aContext->recycler()->getStringResult(res, aResult);
    }
    
    // Value is a normal finite number
    nsAutoString prefix;
    nsAutoString suffix;
    int minIntegerSize=0;
    int minFractionSize=0;
    int maxFractionSize=0;
    int multiplier=1;
    int groupSize=-1;

    uint32_t pos = 0;
    uint32_t formatLen = formatStr.Length();
    bool inQuote;

    // Get right subexpression
    inQuote = false;
    if (MOZ_DOUBLE_IS_NEGATIVE(value)) {
        while (pos < formatLen &&
               (inQuote ||
                formatStr.CharAt(pos) != format->mPatternSeparator)) {
            if (formatStr.CharAt(pos) == FORMAT_QUOTE)
                inQuote = !inQuote;
            pos++;
        }

        if (pos == formatLen) {
            pos = 0;
            prefix.Append(format->mMinusSign);
        }
        else
            pos++;
    }

    // Parse the format string
    FormatParseState pState = Prefix;
    inQuote = false;

    PRUnichar c = 0;
    while (pos < formatLen && pState != Finished) {
        c=formatStr.CharAt(pos++);

        switch (pState) {

        case Prefix:
        case Suffix:
            if (!inQuote) {
                if (c == format->mPercent) {
                    if (multiplier == 1)
                        multiplier = 100;
                    else {
                        nsAutoString err(INVALID_PARAM_VALUE);
#ifdef TX_TO_STRING
                        err.AppendLiteral(": ");
                        toString(err);
#endif
                        aContext->receiveError(err,
                                               NS_ERROR_XPATH_INVALID_ARG);
                        return NS_ERROR_XPATH_INVALID_ARG;
                    }
                }
                else if (c == format->mPerMille) {
                    if (multiplier == 1)
                        multiplier = 1000;
                    else {
                        nsAutoString err(INVALID_PARAM_VALUE);
#ifdef TX_TO_STRING
                        err.AppendLiteral(": ");
                        toString(err);
#endif
                        aContext->receiveError(err,
                                               NS_ERROR_XPATH_INVALID_ARG);
                        return NS_ERROR_XPATH_INVALID_ARG;
                    }
                }
                else if (c == format->mDecimalSeparator ||
                         c == format->mGroupingSeparator ||
                         c == format->mZeroDigit ||
                         c == format->mDigit ||
                         c == format->mPatternSeparator) {
                    pState = pState == Prefix ? IntDigit : Finished;
                    pos--;
                    break;
                }
            }

            if (c == FORMAT_QUOTE)
                inQuote = !inQuote;
            else if (pState == Prefix)
                prefix.Append(c);
            else
                suffix.Append(c);
            break;

        case IntDigit:
            if (c == format->mGroupingSeparator)
                groupSize=0;
            else if (c == format->mDigit) {
                if (groupSize >= 0)
                    groupSize++;
            }
            else {
                pState = IntZero;
                pos--;
            }
            break;

        case IntZero:
            if (c == format->mGroupingSeparator)
                groupSize = 0;
            else if (c == format->mZeroDigit) {
                if (groupSize >= 0)
                    groupSize++;
                minIntegerSize++;
            }
            else if (c == format->mDecimalSeparator) {
                pState = FracZero;
            }
            else {
                pState = Suffix;
                pos--;
            }
            break;

        case FracZero:
            if (c == format->mZeroDigit) {
                maxFractionSize++;
                minFractionSize++;
            }
            else {
                pState = FracDigit;
                pos--;
            }
            break;

        case FracDigit:
            if (c == format->mDigit)
                maxFractionSize++;
            else {
                pState = Suffix;
                pos--;
            }
            break;

        case Finished:
            break;
        }
    }

    // Did we manage to parse the entire formatstring and was it valid
    if ((c != format->mPatternSeparator && pos < formatLen) ||
        inQuote ||
        groupSize == 0) {
        nsAutoString err(INVALID_PARAM_VALUE);
#ifdef TX_TO_STRING
        err.AppendLiteral(": ");
        toString(err);
#endif
        aContext->receiveError(err, NS_ERROR_XPATH_INVALID_ARG);
        return NS_ERROR_XPATH_INVALID_ARG;
    }


    /*
     * FINALLY we're done with the parsing
     * now build the result string
     */

    value = fabs(value) * multiplier;

    // Prefix
    nsAutoString res(prefix);

    int bufsize;
    if (value > 1)
        bufsize = (int)log10(value) + 30;
    else
        bufsize = 1 + 30;

    char* buf = new char[bufsize];
    NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);

    int bufIntDigits, sign;
    char* endp;
    PR_dtoa(value, 0, 0, &bufIntDigits, &sign, &endp, buf, bufsize-1);

    int buflen = endp - buf;
    int intDigits;
    intDigits = bufIntDigits > minIntegerSize ? bufIntDigits : minIntegerSize;

    if (groupSize < 0)
        groupSize = intDigits + 10; //to simplify grouping

    // XXX We shouldn't use SetLength.
    res.SetLength(res.Length() +
                  intDigits +               // integer digits
                  1 +                       // decimal separator
                  maxFractionSize +         // fractions
                  (intDigits-1)/groupSize); // group separators

    int32_t i = bufIntDigits + maxFractionSize - 1;
    bool carry = (0 <= i+1) && (i+1 < buflen) && (buf[i+1] >= '5');
    bool hasFraction = false;

    uint32_t resPos = res.Length()-1;

    // Fractions
    for (; i >= bufIntDigits; --i) {
        int digit;
        if (i >= buflen || i < 0) {
            digit = 0;
        }
        else {
            digit = buf[i] - '0';
        }
        
        if (carry) {
            digit = (digit + 1) % 10;
            carry = digit == 0;
        }

        if (hasFraction || digit != 0 || i < bufIntDigits+minFractionSize) {
            hasFraction = true;
            res.SetCharAt((PRUnichar)(digit + format->mZeroDigit),
                          resPos--);
        }
        else {
            res.Truncate(resPos--);
        }
    }

    // Decimal separator
    if (hasFraction) {
        res.SetCharAt(format->mDecimalSeparator, resPos--);
    }
    else {
        res.Truncate(resPos--);
    }

    // Integer digits
    for (i = 0; i < intDigits; ++i) {
        int digit;
        if (bufIntDigits-i-1 >= buflen || bufIntDigits-i-1 < 0) {
            digit = 0;
        }
        else {
            digit = buf[bufIntDigits-i-1] - '0';
        }
        
        if (carry) {
            digit = (digit + 1) % 10;
            carry = digit == 0;
        }

        if (i != 0 && i%groupSize == 0) {
            res.SetCharAt(format->mGroupingSeparator, resPos--);
        }

        res.SetCharAt((PRUnichar)(digit + format->mZeroDigit), resPos--);
    }

    if (carry) {
        if (i%groupSize == 0) {
            res.Insert(format->mGroupingSeparator, resPos + 1);
        }
        res.Insert((PRUnichar)(1 + format->mZeroDigit), resPos + 1);
    }
    
    if (!hasFraction && !intDigits && !carry) {
        // If we havn't added any characters we add a '0'
        // This can only happen for formats like '##.##'
        res.Append(format->mZeroDigit);
    }

    delete [] buf;

    // Build suffix
    res.Append(suffix);

    return aContext->recycler()->getStringResult(res, aResult);
} //-- evaluate