blob: 8d67ebccf9b2e83b10964cb3fdd118b5c964a6d1 [file] [log] [blame]
/****************************************************************************
**
** 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include "qbuiltintypes_p.h"
#include "qpatternistlocale_p.h"
#include "qvalidationerror_p.h"
#include "qabstractduration_p.h"
QT_BEGIN_NAMESPACE
using namespace QPatternist;
AbstractDuration::AbstractDuration(const bool isPos) : m_isPositive(isPos)
{
}
#define error(msg) return ValidationError::createError(msg);
#define getCapt(sym) ((captTable.sym == -1) ? QString() : capts.at(captTable.sym))
AtomicValue::Ptr AbstractDuration::create(const CaptureTable &captTable,
const QString &lexical,
bool *isPositive,
YearProperty *years,
MonthProperty *months,
DayCountProperty *days,
HourProperty *hours,
MinuteProperty *minutes,
SecondProperty *seconds,
MSecondProperty *mseconds)
{
/* We don't directly write into the arguments(eg @p years) but uses these
* because the arguments are intended for normalized values, and therefore
* can cause overflows. */
MonthCountProperty monthCount = 0;
MinuteCountProperty minCount = 0;
HourCountProperty hourCount = 0;
SecondCountProperty secCount = 0;
Q_ASSERT(isPositive);
QRegExp myExp(captTable.regExp); /* Copy, in order to stay thread safe. */
if(!myExp.exactMatch(lexical))
{
error(QString());
}
const QStringList capts(myExp.capturedTexts());
if(days)
{
if(getCapt(tDelimiter).isEmpty())
{
if((years && getCapt(year).isEmpty() && getCapt(month).isEmpty() && getCapt(day).isEmpty())
||
(!years && getCapt(day).isEmpty()))
{
error(QtXmlPatterns::tr("At least one component must be present."));
}
}
else if(getCapt(hour).isEmpty() &&
getCapt(minutes).isEmpty() &&
getCapt(seconds).isEmpty() &&
getCapt(mseconds).isEmpty())
{
error(QtXmlPatterns::tr("At least one time component must appear "
"after the %1-delimiter.")
.arg(formatKeyword("T")));
}
}
else if(getCapt(year).isEmpty() && getCapt(month).isEmpty()) /* This checks xs:yearMonthDuration. */
{
error(QtXmlPatterns::tr("At least one component must be present."));
}
/* If we got no '-', we are positive. */
*isPositive = capts.at(1).isEmpty();
if(days)
{
Q_ASSERT(hours);
Q_ASSERT(minutes);
Q_ASSERT(seconds);
Q_ASSERT(mseconds);
*days = getCapt(day).toInt();
hourCount = getCapt(hour).toInt();
minCount = getCapt(minutes).toInt();
secCount = getCapt(seconds).toInt();
const QString msecondsStr(getCapt(mseconds));
if(!msecondsStr.isEmpty())
*mseconds = msecondsStr.leftJustified(3, QLatin1Char('0')).toInt();
else
*mseconds = msecondsStr.toInt();
if(secCount > 59)
{
minCount += secCount / 60;
*seconds = secCount % 60;
}
else
*seconds = secCount;
if(minCount > 59)
{
hourCount += minCount / 60;
*minutes = minCount % 60;
}
else
*minutes = minCount;
if(hourCount > 23)
{
*days += hourCount / 24;
*hours = hourCount % 24;
}
else
*hours = hourCount;
}
if(!years)
return AtomicValue::Ptr();
/* We're supposed to handle years/months. */
Q_ASSERT(months);
*years = getCapt(year).toInt();
monthCount = getCapt(month).toInt();
if(monthCount > 11)
{
*years += monthCount / 12;
*months = monthCount % 12;
}
else
*months = monthCount;
return AtomicValue::Ptr();
}
#undef error
#undef getCapt
bool AbstractDuration::operator==(const AbstractDuration &other) const
{
if(years() == other.years()
&& months() == other.months()
&& days() == other.days()
&& hours() == other.hours()
&& minutes() == other.minutes()
&& seconds() == other.seconds()
&& mseconds() == other.mseconds())
{
if(isPositive() == other.isPositive())
return true;
else if(years() == 0
&& months() == 0
&& days() == 0
&& hours() == 0
&& minutes() == 0
&& seconds () == 0
&& mseconds() == 0)
{
return true; /* Signedness doesn't matter if all are zero. */
}
}
return false;
}
QString AbstractDuration::serializeMSeconds(const MSecondProperty mseconds)
{
QString retval;
retval.append(QLatin1Char('.'));
int div = 100;
MSecondProperty msecs = mseconds;
while(msecs > 0)
{
int d = msecs / div;
retval.append(QLatin1Char(d + '0'));
msecs = msecs % div;
div = div / 10;
}
return retval;
}
bool AbstractDuration::isPositive() const
{
return m_isPositive;
}
QT_END_NAMESPACE