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; }
/* * 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; } }
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; }
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