diff options
author | Qt by Nokia <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
---|---|---|
committer | axis <qt-info@nokia.com> | 2011-04-27 12:05:43 +0200 |
commit | e1b2c9deb5943faae2b29be6a5c006f75bb73f06 (patch) | |
tree | fc79e45367c0a8fc71185e9afc33f7503a58653c /src/xmlpatterns/functions/qstringvaluefns.cpp | |
download | qtxmlpatterns-e1b2c9deb5943faae2b29be6a5c006f75bb73f06.tar.gz |
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:
http://qt.gitorious.org/qt/pages/GitIntroductionWithQt
If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.
Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/xmlpatterns/functions/qstringvaluefns.cpp')
-rw-r--r-- | src/xmlpatterns/functions/qstringvaluefns.cpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/src/xmlpatterns/functions/qstringvaluefns.cpp b/src/xmlpatterns/functions/qstringvaluefns.cpp new file mode 100644 index 0000000..8752c7a --- /dev/null +++ b/src/xmlpatterns/functions/qstringvaluefns.cpp @@ -0,0 +1,373 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtXmlPatterns module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qabstractfloat_p.h" +#include "qatomicstring_p.h" +#include "qcommonsequencetypes_p.h" +#include "qcommonvalues_p.h" +#include "qinteger_p.h" +#include "qliteral_p.h" +#include "qpatternistlocale_p.h" +#include "qschemanumeric_p.h" + +#include "qstringvaluefns_p.h" + +QT_BEGIN_NAMESPACE + +using namespace QPatternist; + +Item ConcatFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Expression::List::const_iterator end(m_operands.constEnd()); + Expression::List::const_iterator it(m_operands.constBegin()); + QString result; + + for(; it != end; ++it) + { + Item item((*it)->evaluateSingleton(context)); + + if(item) + result += item.stringValue(); + } + + return AtomicString::fromValue(result); +} + +Item StringJoinFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + Item::Iterator::Ptr it(m_operands.first()->evaluateSequence(context)); + Q_ASSERT(it); + Item current(it->next()); + + if(!current) /* Exit early, don't evaluate the separator. */ + return CommonValues::EmptyString; + + QString result; + QString separator; + const Item isep(m_operands.at(1)->evaluateSingleton(context)); + + if(isep) + separator = isep.stringValue(); + + while(true) + { + result += current.stringValue(); + current = it->next(); + + if(!current) + break; + + result += separator; + } + + return result.isEmpty() + ? toItem(CommonValues::EmptyString) + : toItem(AtomicString::fromValue(result)); +} + +Expression::Ptr StringJoinFN::compress(const StaticContext::Ptr &context) +{ + if(m_operands.first()->staticType()->cardinality().allowsMany()) + return FunctionCall::compress(context); + else + { + if(m_operands.first()->is(IDEmptySequence)) + return wrapLiteral(CommonValues::EmptyString, context, this); + else + return m_operands.first()->compress(context); + } +} + +Item SubstringFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + Item item(m_operands.first()->evaluateSingleton(context)); + + if(!item) + return CommonValues::EmptyString; + + const QString str(item.stringValue()); + + const xsDouble dblStart = m_operands.at(1)->evaluateSingleton(context).as<Numeric>() + ->round()->toDouble(); + if(qIsNaN(dblStart)) + return CommonValues::EmptyString; + + /* XPath starts from 1, but C++ starts from 0. */ + xsInteger startingLoc = Double::fromValue(dblStart)->round()->toInteger() - 1; + + xsInteger length = 0; + if(m_operands.count() == 2) + length = str.length() - startingLoc; + else + { + const xsDouble dblLen = m_operands.at(2)->evaluateSingleton(context).as<Numeric>() + ->round()->toDouble(); + + if(qIsNaN(dblLen)) + return CommonValues::EmptyString; + + length = Double::fromValue(dblLen)->round()->toInteger(); + if(startingLoc > startingLoc + length) + return CommonValues::EmptyString; + } + + if(startingLoc < 0) + { + length = length + startingLoc; + startingLoc = 0; + } + + return AtomicString::fromValue(str.mid(startingLoc, length)); +} + +Item StringLengthFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Item item(m_operands.first()->evaluateSingleton(context)); + + /* fn:string() is re-implemented "inline" here. */ + if(item) + return Integer::fromValue(item.stringValue().length()); + else + return CommonValues::IntegerZero; +} + +NormalizeUnicodeFN::NormalizeUnicodeFN() : m_normForm(QString::NormalizationForm_C) +{ +} + +Item NormalizeSpaceFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Item arg(m_operands.first()->evaluateSingleton(context)); + + if(!arg) + return CommonValues::EmptyString; + + return toItem(AtomicString::fromValue(arg.stringValue().simplified())); +} + +Item NormalizeUnicodeFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Item arg(m_operands.first()->evaluateSingleton(context)); + + if(!arg) + return CommonValues::EmptyString; + + int normForm; + + /* The second argument has been removed, if we've already determined the form. */ + if(m_operands.count() == 1) + normForm = m_normForm; + else + { + normForm = determineNormalizationForm(context); + if(normForm == -1) + return toItem(AtomicString::fromValue(arg.stringValue())); + } + + return AtomicString::fromValue(arg.stringValue().normalized( + static_cast<QString::NormalizationForm>(normForm))); +} + +Expression::Ptr NormalizeUnicodeFN::compress(const StaticContext::Ptr &context) +{ + const Expression::Ptr me(FunctionCall::compress(context)); + if(me != this) + return me; + + Q_ASSERT(m_operands.count() == 1 || m_operands.count() == 2); + + if(m_operands.count() == 1) + m_normForm = QString::NormalizationForm_C; + else if(m_operands.last()->is(IDStringValue)) + { + m_normForm = static_cast<QString::NormalizationForm>( + determineNormalizationForm(context->dynamicContext())); + + if(m_normForm == -1) + return m_operands.first(); + + /* Remove the operand since we don't need it anymore. */ + m_operands.removeLast(); + } + + return me; +} + +int NormalizeUnicodeFN::determineNormalizationForm(const DynamicContext::Ptr &context) const +{ + const QString strRepr(m_operands.last()->evaluateSingleton(context).stringValue().trimmed().toUpper()); + + /* TODO. Put these values in a QHash for faster lookup. Keep thread safety in mind. */ + if(strRepr.isEmpty()) + return -1; + else if(strRepr == QLatin1String("NFC")) + return QString::NormalizationForm_C; + else if(strRepr == QLatin1String("NFD")) + return QString::NormalizationForm_D; + else if(strRepr == QLatin1String("NFKC")) + return QString::NormalizationForm_KC; + else if(strRepr == QLatin1String("NFKD")) + return QString::NormalizationForm_KD; + else + { + /* What form is FULLY_NORMALIZED? Is a code path available for that somewhere? */ + context->error(QtXmlPatterns::tr("The normalization form %1 is " + "unsupported. The supported forms are " + "%2, %3, %4, and %5, and none, i.e. " + "the empty string (no normalization).") + .arg(formatKeyword(strRepr)) + .arg(formatKeyword("NFC")) + .arg(formatKeyword("NFD")) + .arg(formatKeyword("NFKC")) + .arg(formatKeyword("NFKD")), + ReportContext::FOCH0003, + this); + return QString::NormalizationForm_C; /* Silence compiler warning. */ + } +} + +Item UpperCaseFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Item item(m_operands.first()->evaluateSingleton(context)); + + if(!item) + return CommonValues::EmptyString; + + return AtomicString::fromValue(item.stringValue().toUpper()); +} + +Item LowerCaseFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Item item(m_operands.first()->evaluateSingleton(context)); + + if(!item) + return CommonValues::EmptyString; + + return AtomicString::fromValue(item.stringValue().toLower()); +} + +Item TranslateFN::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Item item(m_operands.first()->evaluateSingleton(context)); + + if(!item) + return CommonValues::EmptyString; + + const QString mapString(m_operands.at(1)->evaluateSingleton(context).stringValue()); + const QString arg(item.stringValue()); + + if(mapString.isEmpty()) + return AtomicString::fromValue(arg); + + const QString transString(m_operands.at(2)->evaluateSingleton(context).stringValue()); + const int transLen = transString.length(); + const int argLen = arg.length(); + + QString result; + result.reserve(argLen); + int outI = 0; + + for(int i = 0; i < argLen; ++i) + { + const QChar argCh(arg.at(i)); + const int mapPos = mapString.indexOf(argCh); + + if(mapPos == -1) + { + result[outI] = argCh; + ++outI; + continue; + } + else if(mapPos >= transLen) + continue; + + const QChar transCh(transString.at(mapPos)); + + if(transCh.isNull()) + continue; + + result[outI] = transCh; + ++outI; + } + + result.truncate(outI); + return AtomicString::fromValue(result); +} + +EncodeString::EncodeString(const QByteArray &excludeChars, + const QByteArray &includeChars) : m_excludeChars(excludeChars), + m_includeChars(includeChars) +{ +} + +Item EncodeString::evaluateSingleton(const DynamicContext::Ptr &context) const +{ + const Item item(m_operands.first()->evaluateSingleton(context)); + + if(!item) + return CommonValues::EmptyString; + + return AtomicString::fromValue(QString::fromAscii(QUrl::toPercentEncoding(item.stringValue(), + m_excludeChars, + m_includeChars).constData())); +} + +const char *const EncodeForURIFN::include = "#!*'()"; + +EncodeForURIFN::EncodeForURIFN() : EncodeString(QByteArray(), QByteArray::fromRawData(include, 6)) +{ +} + +const char *const IriToURIFN::exclude = "#-_!~*'();?@&=+$,[]/:%"; + +IriToURIFN::IriToURIFN() : EncodeString(QByteArray::fromRawData(exclude, 22), QByteArray()) +{ +} + +const char *const EscapeHtmlURIFN::include = "?&[]%"; +const char *const EscapeHtmlURIFN::exclude = " :;=@!./+*()-,#$'"; + +EscapeHtmlURIFN::EscapeHtmlURIFN() : EncodeString(QByteArray::fromRawData(exclude, 17), + QByteArray::fromRawData(include, 6)) +{ +} + +QT_END_NAMESPACE |