diff options
Diffstat (limited to 'src/corelib/tools')
109 files changed, 96312 insertions, 0 deletions
diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h new file mode 100644 index 0000000000..6b870397b6 --- /dev/null +++ b/src/corelib/tools/qalgorithms.h @@ -0,0 +1,526 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QALGORITHMS_H +#define QALGORITHMS_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +/* + Warning: The contents of QAlgorithmsPrivate is not a part of the public Qt API + and may be changed from version to version or even be completely removed. +*/ +namespace QAlgorithmsPrivate { + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE void qSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan); +template <typename RandomAccessIterator, typename T> +inline void qSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy); + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE void qStableSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan); +template <typename RandomAccessIterator, typename T> +inline void qStableSortHelper(RandomAccessIterator, RandomAccessIterator, const T &); + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan); +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan); +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan); + +} + +template <typename InputIterator, typename OutputIterator> +inline OutputIterator qCopy(InputIterator begin, InputIterator end, OutputIterator dest) +{ + while (begin != end) + *dest++ = *begin++; + return dest; +} + +template <typename BiIterator1, typename BiIterator2> +inline BiIterator2 qCopyBackward(BiIterator1 begin, BiIterator1 end, BiIterator2 dest) +{ + while (begin != end) + *--dest = *--end; + return dest; +} + +template <typename InputIterator1, typename InputIterator2> +inline bool qEqual(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2) +{ + for (; first1 != last1; ++first1, ++first2) + if (!(*first1 == *first2)) + return false; + return true; +} + +template <typename ForwardIterator, typename T> +inline void qFill(ForwardIterator first, ForwardIterator last, const T &val) +{ + for (; first != last; ++first) + *first = val; +} + +template <typename Container, typename T> +inline void qFill(Container &container, const T &val) +{ + qFill(container.begin(), container.end(), val); +} + +template <typename InputIterator, typename T> +inline InputIterator qFind(InputIterator first, InputIterator last, const T &val) +{ + while (first != last && !(*first == val)) + ++first; + return first; +} + +template <typename Container, typename T> +inline typename Container::const_iterator qFind(const Container &container, const T &val) +{ + return qFind(container.constBegin(), container.constEnd(), val); +} + +template <typename InputIterator, typename T, typename Size> +inline void qCount(InputIterator first, InputIterator last, const T &value, Size &n) +{ + for (; first != last; ++first) + if (*first == value) + ++n; +} + +template <typename Container, typename T, typename Size> +inline void qCount(const Container &container, const T &value, Size &n) +{ + qCount(container.constBegin(), container.constEnd(), value, n); +} + +#ifdef qdoc +template <typename T> +LessThan qLess() +{ +} + +template <typename T> +LessThan qGreater() +{ +} +#else +template <typename T> +class qLess +{ +public: + inline bool operator()(const T &t1, const T &t2) const + { + return (t1 < t2); + } +}; + +template <typename T> +class qGreater +{ +public: + inline bool operator()(const T &t1, const T &t2) const + { + return (t2 < t1); + } +}; +#endif + +template <typename RandomAccessIterator> +inline void qSort(RandomAccessIterator start, RandomAccessIterator end) +{ + if (start != end) + QAlgorithmsPrivate::qSortHelper(start, end, *start); +} + +template <typename RandomAccessIterator, typename LessThan> +inline void qSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan) +{ + if (start != end) + QAlgorithmsPrivate::qSortHelper(start, end, *start, lessThan); +} + +template<typename Container> +inline void qSort(Container &c) +{ +#ifdef Q_CC_BOR + // Work around Borland 5.5 optimizer bug + c.detach(); +#endif + if (!c.empty()) + QAlgorithmsPrivate::qSortHelper(c.begin(), c.end(), *c.begin()); +} + +template <typename RandomAccessIterator> +inline void qStableSort(RandomAccessIterator start, RandomAccessIterator end) +{ + if (start != end) + QAlgorithmsPrivate::qStableSortHelper(start, end, *start); +} + +template <typename RandomAccessIterator, typename LessThan> +inline void qStableSort(RandomAccessIterator start, RandomAccessIterator end, LessThan lessThan) +{ + if (start != end) + QAlgorithmsPrivate::qStableSortHelper(start, end, *start, lessThan); +} + +template<typename Container> +inline void qStableSort(Container &c) +{ +#ifdef Q_CC_BOR + // Work around Borland 5.5 optimizer bug + c.detach(); +#endif + if (!c.empty()) + QAlgorithmsPrivate::qStableSortHelper(c.begin(), c.end(), *c.begin()); +} + +template <typename RandomAccessIterator, typename T> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value) +{ + // Implementation is duplicated from QAlgorithmsPrivate to keep existing code + // compiling. We have to allow using *begin and value with different types, + // and then implementing operator< for those types. + RandomAccessIterator middle; + int n = end - begin; + int half; + + while (n > 0) { + half = n >> 1; + middle = begin + half; + if (*middle < value) { + begin = middle + 1; + n -= half + 1; + } else { + n = half; + } + } + return begin; +} + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) +{ + return QAlgorithmsPrivate::qLowerBoundHelper(begin, end, value, lessThan); +} + +template <typename Container, typename T> +Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qLowerBound(const Container &container, const T &value) +{ + return QAlgorithmsPrivate::qLowerBoundHelper(container.constBegin(), container.constEnd(), value, qLess<T>()); +} + +template <typename RandomAccessIterator, typename T> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value) +{ + // Implementation is duplicated from QAlgorithmsPrivate. + RandomAccessIterator middle; + int n = end - begin; + int half; + + while (n > 0) { + half = n >> 1; + middle = begin + half; + if (value < *middle) { + n = half; + } else { + begin = middle + 1; + n -= half + 1; + } + } + return begin; +} + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) +{ + return QAlgorithmsPrivate::qUpperBoundHelper(begin, end, value, lessThan); +} + +template <typename Container, typename T> +Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qUpperBound(const Container &container, const T &value) +{ + return QAlgorithmsPrivate::qUpperBoundHelper(container.constBegin(), container.constEnd(), value, qLess<T>()); +} + +template <typename RandomAccessIterator, typename T> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value) +{ + // Implementation is duplicated from QAlgorithmsPrivate. + RandomAccessIterator it = qLowerBound(begin, end, value); + + if (it == end || value < *it) + return end; + + return it; +} + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) +{ + return QAlgorithmsPrivate::qBinaryFindHelper(begin, end, value, lessThan); +} + +template <typename Container, typename T> +Q_OUTOFLINE_TEMPLATE typename Container::const_iterator qBinaryFind(const Container &container, const T &value) +{ + return QAlgorithmsPrivate::qBinaryFindHelper(container.constBegin(), container.constEnd(), value, qLess<T>()); +} + +template <typename ForwardIterator> +Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end) +{ + while (begin != end) { + delete *begin; + ++begin; + } +} + +template <typename Container> +inline void qDeleteAll(const Container &c) +{ + qDeleteAll(c.begin(), c.end()); +} + +/* + Warning: The contents of QAlgorithmsPrivate is not a part of the public Qt API + and may be changed from version to version or even be completely removed. +*/ +namespace QAlgorithmsPrivate { + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE void qSortHelper(RandomAccessIterator start, RandomAccessIterator end, const T &t, LessThan lessThan) +{ +top: + int span = int(end - start); + if (span < 2) + return; + + --end; + RandomAccessIterator low = start, high = end - 1; + RandomAccessIterator pivot = start + span / 2; + + if (lessThan(*end, *start)) + qSwap(*end, *start); + if (span == 2) + return; + + if (lessThan(*pivot, *start)) + qSwap(*pivot, *start); + if (lessThan(*end, *pivot)) + qSwap(*end, *pivot); + if (span == 3) + return; + + qSwap(*pivot, *end); + + while (low < high) { + while (low < high && lessThan(*low, *end)) + ++low; + + while (high > low && lessThan(*end, *high)) + --high; + + if (low < high) { + qSwap(*low, *high); + ++low; + --high; + } else { + break; + } + } + + if (lessThan(*low, *end)) + ++low; + + qSwap(*end, *low); + qSortHelper(start, low, t, lessThan); + + start = low + 1; + ++end; + goto top; +} + +template <typename RandomAccessIterator, typename T> +inline void qSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy) +{ + qSortHelper(begin, end, dummy, qLess<T>()); +} + +template <typename RandomAccessIterator> +Q_OUTOFLINE_TEMPLATE void qReverse(RandomAccessIterator begin, RandomAccessIterator end) +{ + --end; + while (begin < end) + qSwap(*begin++, *end--); +} + +template <typename RandomAccessIterator> +Q_OUTOFLINE_TEMPLATE void qRotate(RandomAccessIterator begin, RandomAccessIterator middle, RandomAccessIterator end) +{ + qReverse(begin, middle); + qReverse(middle, end); + qReverse(begin, end); +} + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE void qMerge(RandomAccessIterator begin, RandomAccessIterator pivot, RandomAccessIterator end, T &t, LessThan lessThan) +{ + const int len1 = pivot - begin; + const int len2 = end - pivot; + + if (len1 == 0 || len2 == 0) + return; + + if (len1 + len2 == 2) { + if (lessThan(*(begin + 1), *(begin))) + qSwap(*begin, *(begin + 1)); + return; + } + + RandomAccessIterator firstCut; + RandomAccessIterator secondCut; + int len2Half; + if (len1 > len2) { + const int len1Half = len1 / 2; + firstCut = begin + len1Half; + secondCut = qLowerBound(pivot, end, *firstCut, lessThan); + len2Half = secondCut - pivot; + } else { + len2Half = len2 / 2; + secondCut = pivot + len2Half; + firstCut = qUpperBound(begin, pivot, *secondCut, lessThan); + } + + qRotate(firstCut, pivot, secondCut); + const RandomAccessIterator newPivot = firstCut + len2Half; + qMerge(begin, firstCut, newPivot, t, lessThan); + qMerge(newPivot, secondCut, end, t, lessThan); +} + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE void qStableSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &t, LessThan lessThan) +{ + const int span = end - begin; + if (span < 2) + return; + + const RandomAccessIterator middle = begin + span / 2; + qStableSortHelper(begin, middle, t, lessThan); + qStableSortHelper(middle, end, t, lessThan); + qMerge(begin, middle, end, t, lessThan); +} + +template <typename RandomAccessIterator, typename T> +inline void qStableSortHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &dummy) +{ + qStableSortHelper(begin, end, dummy, qLess<T>()); +} + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qLowerBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) +{ + RandomAccessIterator middle; + int n = int(end - begin); + int half; + + while (n > 0) { + half = n >> 1; + middle = begin + half; + if (lessThan(*middle, value)) { + begin = middle + 1; + n -= half + 1; + } else { + n = half; + } + } + return begin; +} + + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qUpperBoundHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) +{ + RandomAccessIterator middle; + int n = end - begin; + int half; + + while (n > 0) { + half = n >> 1; + middle = begin + half; + if (lessThan(value, *middle)) { + n = half; + } else { + begin = middle + 1; + n -= half + 1; + } + } + return begin; +} + +template <typename RandomAccessIterator, typename T, typename LessThan> +Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) +{ + RandomAccessIterator it = qLowerBoundHelper(begin, end, value, lessThan); + + if (it == end || lessThan(value, *it)) + return end; + + return it; +} + +} //namespace QAlgorithmsPrivate + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QALGORITHMS_H diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc new file mode 100644 index 0000000000..a9b7ddca7a --- /dev/null +++ b/src/corelib/tools/qalgorithms.qdoc @@ -0,0 +1,637 @@ +/**************************************************************************** +** +** 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 documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \headerfile <QtAlgorithms> + \title Generic Algorithms + \ingroup funclists + + \brief The <QtAlgorithms> header includes the generic, template-based algorithms. + + Qt provides a number of global template functions in \c + <QtAlgorithms> that work on containers and perform well-know + algorithms. You can use these algorithms with any \l {container + class} that provides STL-style iterators, including Qt's QList, + QLinkedList, QVector, QMap, and QHash classes. + + These functions have taken their inspiration from similar + functions available in the STL \c <algorithm> header. Most of them + have a direct STL equivalent; for example, qCopyBackward() is the + same as STL's copy_backward() algorithm. + + If STL is available on all your target platforms, you can use the + STL algorithms instead of their Qt counterparts. One reason why + you might want to use the STL algorithms is that STL provides + dozens and dozens of algorithms, whereas Qt only provides the most + important ones, making no attempt to duplicate functionality that + is already provided by the C++ standard. + + Most algorithms take \l {STL-style iterators} as parameters. The + algorithms are generic in the sense that they aren't bound to a + specific iterator class; you can use them with any iterators that + meet a certain set of requirements. + + Let's take the qFill() algorithm as an example. Unlike QVector, + QList has no fill() function that can be used to fill a list with + a particular value. If you need that functionality, you can use + qFill(): + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 0 + + qFill() takes a begin iterator, an end iterator, and a value. + In the example above, we pass \c list.begin() and \c list.end() + as the begin and end iterators, but this doesn't have to be + the case: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 1 + + Different algorithms can have different requirements for the + iterators they accept. For example, qFill() accepts two + \l {forward iterators}. The iterator types required are specified + for each algorithm. If an iterator of the wrong type is passed (for + example, if QList::ConstIterator is passed as an \l {output + iterator}), you will always get a compiler error, although not + necessarily a very informative one. + + Some algorithms have special requirements on the value type + stored in the containers. For example, qEqual() requires that the + value type supports operator==(), which it uses to compare items. + Similarly, qDeleteAll() requires that the value type is a + non-const pointer type (for example, QWidget *). The value type + requirements are specified for each algorithm, and the compiler + will produce an error if a requirement isn't met. + + \target binaryFind example + + The generic algorithms can be used on other container classes + than those provided by Qt and STL. The syntax of STL-style + iterators is modeled after C++ pointers, so it's possible to use + plain arrays as containers and plain pointers as iterators. A + common idiom is to use qBinaryFind() together with two static + arrays: one that contains a list of keys, and another that + contains a list of associated values. For example, the following + code will look up an HTML entity (e.g., \c &) in the \c + name_table array and return the corresponding Unicode value from + the \c value_table if the entity is recognized: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 2 + + This kind of code is for advanced users only; for most + applications, a QMap- or QHash-based approach would work just as + well: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 3 + + \section1 Types of Iterators + + The algorithms have certain requirements on the iterator types + they accept, and these are specified individually for each + function. The compiler will produce an error if a requirement + isn't met. + + \section2 Input Iterators + + An \e{input iterator} is an iterator that can be used for reading + data sequentially from a container. It must provide the following + operators: \c{==} and \c{!=} for comparing two iterators, unary + \c{*} for retrieving the value stored in the item, and prefix + \c{++} for advancing to the next item. + + The Qt containers' iterator types (const and non-const) are all + input iterators. + + \section2 Output Iterators + + An \e{output iterator} is an iterator that can be used for + writing data sequentially to a container or to some output + stream. It must provide the following operators: unary \c{*} for + writing a value (i.e., \c{*it = val}) and prefix \c{++} for + advancing to the next item. + + The Qt containers' non-const iterator types are all output + iterators. + + \section2 Forward Iterators + + A \e{forward iterator} is an iterator that meets the requirements + of both input iterators and output iterators. + + The Qt containers' non-const iterator types are all forward + iterators. + + \section2 Bidirectional Iterators + + A \e{bidirectional iterator} is an iterator that meets the + requirements of forward iterators but that in addition supports + prefix \c{--} for iterating backward. + + The Qt containers' non-const iterator types are all bidirectional + iterators. + + \section2 Random Access Iterators + + The last category, \e{random access iterators}, is the most + powerful type of iterator. It supports all the requirements of a + bidirectional iterator, and supports the following operations: + + \table + \row \i \c{i += n} \i advances iterator \c i by \c n positions + \row \i \c{i -= n} \i moves iterator \c i back by \c n positions + \row \i \c{i + n} or \c{n + i} \i returns the iterator for the item \c + n positions ahead of iterator \c i + \row \i \c{i - n} \i returns the iterator for the item \c n positions behind of iterator \c i + \row \i \c{i - j} \i returns the number of items between iterators \c i and \c j + \row \i \c{i[n]} \i same as \c{*(i + n)} + \row \i \c{i < j} \i returns true if iterator \c j comes after iterator \c i + \endtable + + QList and QVector's non-const iterator types are random access iterators. + + \sa {container classes}, <QtGlobal> +*/ + +/*! \fn OutputIterator qCopy(InputIterator begin1, InputIterator end1, OutputIterator begin2) + \relates <QtAlgorithms> + + Copies the items from range [\a begin1, \a end1) to range [\a + begin2, ...), in the order in which they appear. + + The item at position \a begin1 is assigned to that at position \a + begin2; the item at position \a begin1 + 1 is assigned to that at + position \a begin2 + 1; and so on. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 4 + + \sa qCopyBackward(), {input iterators}, {output iterators} +*/ + +/*! \fn BiIterator2 qCopyBackward(BiIterator1 begin1, BiIterator1 end1, BiIterator2 end2) + \relates <QtAlgorithms> + + Copies the items from range [\a begin1, \a end1) to range [..., + \a end2). + + The item at position \a end1 - 1 is assigned to that at position + \a end2 - 1; the item at position \a end1 - 2 is assigned to that + at position \a end2 - 2; and so on. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 5 + + \sa qCopy(), {bidirectional iterators} +*/ + +/*! \fn bool qEqual(InputIterator1 begin1, InputIterator1 end1, InputIterator2 begin2) + \relates <QtAlgorithms> + + Compares the items in the range [\a begin1, \a end1) with the + items in the range [\a begin2, ...). Returns true if all the + items compare equal; otherwise returns false. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 6 + + This function requires the item type (in the example above, + QString) to implement \c operator==(). + + \sa {input iterators} +*/ + +/*! \fn void qFill(ForwardIterator begin, ForwardIterator end, const T &value) + \relates <QtAlgorithms> + + Fills the range [\a begin, \a end) with \a value. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 7 + + \sa qCopy(), {forward iterators} +*/ + +/*! \fn void qFill(Container &container, const T &value) + \relates <QtAlgorithms> + + \overload + + This is the same as qFill(\a{container}.begin(), \a{container}.end(), \a value); +*/ + +/*! \fn InputIterator qFind(InputIterator begin, InputIterator end, const T &value) + \relates <QtAlgorithms> + + Returns an iterator to the first occurrence of \a value in a + container in the range [\a begin, \a end). Returns \a end if \a + value isn't found. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 8 + + This function requires the item type (in the example above, + QString) to implement \c operator==(). + + If the items in the range are in ascending order, you can get + faster results by using qLowerBound() or qBinaryFind() instead of + qFind(). + + \sa qBinaryFind(), {input iterators} +*/ + +/*! \fn void qFind(const Container &container, const T &value) + \relates <QtAlgorithms> + + \overload + + This is the same as qFind(\a{container}.constBegin(), \a{container}.constEnd(), value); +*/ + +/*! \fn void qCount(InputIterator begin, InputIterator end, const T &value, Size &n) + \relates <QtAlgorithms> + + Returns the number of occurrences of \a value in the range [\a begin, \a end), + which is returned in \a n. \a n is never initialized, the count is added to \a n. + It is the caller's responsibility to initialize \a n. + + Example: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 9 + + This function requires the item type (in the example above, + \c int) to implement \c operator==(). + + \sa {input iterators} +*/ + +/*! \fn void qCount(const Container &container, const T &value, Size &n) +\relates <QtAlgorithms> + +\overload + +Instead of operating on iterators, as in the other overload, this function +operates on the specified \a container to obtain the number of instances +of \a value in the variable passed as a reference in argument \a n. +*/ + +/*! \fn void qSwap(T &var1, T &var2) + \relates <QtAlgorithms> + + Exchanges the values of variables \a var1 and \a var2. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 10 +*/ + +/*! \fn void qSort(RandomAccessIterator begin, RandomAccessIterator end) + \relates <QtAlgorithms> + + Sorts the items in range [\a begin, \a end) in ascending order + using the quicksort algorithm. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 11 + + The sort algorithm is efficient on large data sets. It operates + in \l {linear-logarithmic time}, O(\e{n} log \e{n}). + + This function requires the item type (in the example above, + \c{int}) to implement \c operator<(). + + If neither of the two items is "less than" the other, the items are + taken to be equal. It is then undefined which one of the two + items will appear before the other after the sort. + + \sa qStableSort(), {random access iterators} +*/ + +/*! \fn void qSort(RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan) + \relates <QtAlgorithms> + + \overload + + Uses the \a lessThan function instead of \c operator<() to + compare the items. + + For example, here's how to sort the strings in a QStringList + in case-insensitive alphabetical order: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 12 + + To sort values in reverse order, pass + \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For + example: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 13 + + If neither of the two items is "less than" the other, the items are + taken to be equal. It is then undefined which one of the two + items will appear before the other after the sort. + + An alternative to using qSort() is to put the items to sort in a + QMap, using the sort key as the QMap key. This is often more + convenient than defining a \a lessThan function. For example, the + following code shows how to sort a list of strings case + insensitively using QMap: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 14 + + \sa QMap +*/ + +/*! \fn void qSort(Container &container) + \relates <QtAlgorithms> + + \overload + + This is the same as qSort(\a{container}.begin(), \a{container}.end()); +*/ + +/*! + \fn void qStableSort(RandomAccessIterator begin, RandomAccessIterator end) + \relates <QtAlgorithms> + + Sorts the items in range [\a begin, \a end) in ascending order + using a stable sorting algorithm. + + If neither of the two items is "less than" the other, the items are + taken to be equal. The item that appeared before the other in the + original container will still appear first after the sort. This + property is often useful when sorting user-visible data. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 15 + + The sort algorithm is efficient on large data sets. It operates + in \l {linear-logarithmic time}, O(\e{n} log \e{n}). + + This function requires the item type (in the example above, + \c{int}) to implement \c operator<(). + + \sa qSort(), {random access iterators} +*/ + +/*! + \fn void qStableSort(RandomAccessIterator begin, RandomAccessIterator end, LessThan lessThan) + \relates <QtAlgorithms> + + \overload + + Uses the \a lessThan function instead of \c operator<() to + compare the items. + + For example, here's how to sort the strings in a QStringList + in case-insensitive alphabetical order: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 16 + + Note that earlier versions of Qt allowed using a lessThan function that took its + arguments by non-const reference. From 4.3 and on this is no longer possible, + the arguments has to be passed by const reference or value. + + To sort values in reverse order, pass + \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For + example: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 17 + + If neither of the two items is "less than" the other, the items are + taken to be equal. The item that appeared before the other in the + original container will still appear first after the sort. This + property is often useful when sorting user-visible data. +*/ + +/*! + \fn void qStableSort(Container &container) + \relates <QtAlgorithms> + + \overload + + This is the same as qStableSort(\a{container}.begin(), \a{container}.end()); +*/ + +/*! \fn RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value) + \relates <QtAlgorithms> + + Performs a binary search of the range [\a begin, \a end) and + returns the position of the first ocurrence of \a value. If no + such item is found, returns the position where it should be + inserted. + + The items in the range [\a begin, \e end) must be sorted in + ascending order; see qSort(). + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 18 + + This function requires the item type (in the example above, + \c{int}) to implement \c operator<(). + + qLowerBound() can be used in conjunction with qUpperBound() to + iterate over all occurrences of the same value: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 19 + + \sa qUpperBound(), qBinaryFind() +*/ + +/*! + \fn RandomAccessIterator qLowerBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) + \relates <QtAlgorithms> + + \overload + + Uses the \a lessThan function instead of \c operator<() to + compare the items. + + Note that the items in the range must be sorted according to the order + specified by the \a lessThan object. +*/ + +/*! + \fn void qLowerBound(const Container &container, const T &value) + \relates <QtAlgorithms> + + \overload + + For read-only iteration over containers, this function is broadly equivalent to + qLowerBound(\a{container}.begin(), \a{container}.end(), value). However, since it + returns a const iterator, you cannot use it to modify the container; for example, + to insert items. +*/ + +/*! \fn RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value) + \relates <QtAlgorithms> + + Performs a binary search of the range [\a begin, \a end) and + returns the position of the one-past-the-last occurrence of \a + value. If no such item is found, returns the position where the + item should be inserted. + + The items in the range [\a begin, \e end) must be sorted in + ascending order; see qSort(). + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 20 + + This function requires the item type (in the example above, + \c{int}) to implement \c operator<(). + + qUpperBound() can be used in conjunction with qLowerBound() to + iterate over all occurrences of the same value: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 21 + + \sa qLowerBound(), qBinaryFind() +*/ + +/*! + \fn RandomAccessIterator qUpperBound(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) + \relates <QtAlgorithms> + + \overload + + Uses the \a lessThan function instead of \c operator<() to + compare the items. + + Note that the items in the range must be sorted according to the order + specified by the \a lessThan object. +*/ + +/*! + \fn void qUpperBound(const Container &container, const T &value) + \relates <QtAlgorithms> + + \overload + + This is the same as qUpperBound(\a{container}.begin(), \a{container}.end(), value); +*/ + + +/*! \fn RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value) + \relates <QtAlgorithms> + + Performs a binary search of the range [\a begin, \a end) and + returns the position of an occurrence of \a value. If there are + no occurrences of \a value, returns \a end. + + The items in the range [\a begin, \a end) must be sorted in + ascending order; see qSort(). + + If there are many occurrences of the same value, any one of them + could be returned. Use qLowerBound() or qUpperBound() if you need + finer control. + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 22 + + This function requires the item type (in the example above, + QString) to implement \c operator<(). + + See the \l{<QtAlgorithms>#binaryFind example}{detailed + description} for an example usage. + + \sa qLowerBound(), qUpperBound(), {random access iterators} +*/ + +/*! \fn RandomAccessIterator qBinaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T &value, LessThan lessThan) + \relates <QtAlgorithms> + + \overload + + Uses the \a lessThan function instead of \c operator<() to + compare the items. + + Note that the items in the range must be sorted according to the order + specified by the \a lessThan object. +*/ + +/*! + \fn void qBinaryFind(const Container &container, const T &value) + \relates <QtAlgorithms> + + \overload + + This is the same as qBinaryFind(\a{container}.begin(), \a{container}.end(), value); +*/ + + +/*! + \fn void qDeleteAll(ForwardIterator begin, ForwardIterator end) + \relates <QtAlgorithms> + + Deletes all the items in the range [\a begin, \a end) using the + C++ \c delete operator. The item type must be a pointer type (for + example, \c{QWidget *}). + + Example: + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 23 + + Notice that qDeleteAll() doesn't remove the items from the + container; it merely calls \c delete on them. In the example + above, we call clear() on the container to remove the items. + + This function can also be used to delete items stored in + associative containers, such as QMap and QHash. Only the objects + stored in each container will be deleted by this function; objects + used as keys will not be deleted. + + \sa {forward iterators} +*/ + +/*! + \fn void qDeleteAll(const Container &c) + \relates <QtAlgorithms> + + \overload + + This is the same as qDeleteAll(\a{c}.begin(), \a{c}.end()). +*/ + +/*! \fn LessThan qLess() + \relates <QtAlgorithms> + + Returns a functional object, or functor, that can be passed to qSort() + or qStableSort(). + + Example: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 24 + + \sa {qGreater()}{qGreater<T>()} +*/ + +/*! \fn LessThan qGreater() + \relates <QtAlgorithms> + + Returns a functional object, or functor, that can be passed to qSort() + or qStableSort(). + + Example: + + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 25 + + \sa {qLess()}{qLess<T>()} +*/ diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp new file mode 100644 index 0000000000..6181c82580 --- /dev/null +++ b/src/corelib/tools/qbitarray.cpp @@ -0,0 +1,738 @@ +/**************************************************************************** +** +** 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 QtCore 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 "qbitarray.h" +#include <qdatastream.h> +#include <qdebug.h> +#include <string.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QBitArray + \brief The QBitArray class provides an array of bits. + + \ingroup tools + \ingroup shared + \reentrant + + A QBitArray is an array that gives access to individual bits and + provides operators (\link operator&() AND\endlink, \link + operator|() OR\endlink, \link operator^() XOR\endlink, and \link + operator~() NOT\endlink) that work on entire arrays of bits. It + uses \l{implicit sharing} (copy-on-write) to reduce memory usage + and to avoid the needless copying of data. + + The following code constructs a QBitArray containing 200 bits + initialized to false (0): + + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 0 + + To initialize the bits to true, either pass \c true as second + argument to the constructor, or call fill() later on. + + QBitArray uses 0-based indexes, just like C++ arrays. To access + the bit at a particular index position, you can use operator[](). + On non-const bit arrays, operator[]() returns a reference to a + bit that can be used on the left side of an assignment. For + example: + + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 1 + + For technical reasons, it is more efficient to use testBit() and + setBit() to access bits in the array than operator[](). For + example: + + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 2 + + QBitArray supports \c{&} (\link operator&() AND\endlink), \c{|} + (\link operator|() OR\endlink), \c{^} (\link operator^() + XOR\endlink), \c{~} (\link operator~() NOT\endlink), as well as + \c{&=}, \c{|=}, and \c{^=}. These operators work in the same way + as the built-in C++ bitwise operators of the same name. For + example: + + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 3 + + For historical reasons, QBitArray distinguishes between a null + bit array and an empty bit array. A \e null bit array is a bit + array that is initialized using QBitArray's default constructor. + An \e empty bit array is any bit array with size 0. A null bit + array is always empty, but an empty bit array isn't necessarily + null: + + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 4 + + All functions except isNull() treat null bit arrays the same as + empty bit arrays; for example, QBitArray() compares equal to + QBitArray(0). We recommend that you always use isEmpty() and + avoid isNull(). + + \sa QByteArray, QVector +*/ + +/*! \fn QBitArray::QBitArray() + + Constructs an empty bit array. + + \sa isEmpty() +*/ + +/*! + Constructs a bit array containing \a size bits. The bits are + initialized with \a value, which defaults to false (0). +*/ +QBitArray::QBitArray(int size, bool value) +{ + if (!size) { + d.resize(0); + return; + } + d.resize(1 + (size+7)/8); + uchar* c = reinterpret_cast<uchar*>(d.data()); + memset(c, value ? 0xff : 0, d.size()); + *c = d.size()*8 - size; + if (value && size && size % 8) + *(c+1+size/8) &= (1 << (size%8)) - 1; +} + +/*! \fn int QBitArray::size() const + + Returns the number of bits stored in the bit array. + + \sa resize() +*/ + +/*! \fn int QBitArray::count() const + + Same as size(). +*/ + +/*! + If \a on is true, this function returns the number of + 1-bits stored in the bit array; otherwise the number + of 0-bits is returned. +*/ +int QBitArray::count(bool on) const +{ + int numBits = 0; + int len = size(); +#if 0 + for (int i = 0; i < len; ++i) + numBits += testBit(i); +#else + // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + const quint8 *bits = reinterpret_cast<const quint8 *>(d.data()) + 1; + while (len >= 32) { + quint32 v = quint32(bits[0]) | (quint32(bits[1]) << 8) | (quint32(bits[2]) << 16) | (quint32(bits[3]) << 24); + quint32 c = ((v & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; + c += (((v & 0xfff000) >> 12) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; + c += ((v >> 24) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; + len -= 32; + bits += 4; + numBits += int(c); + } + while (len >= 24) { + quint32 v = quint32(bits[0]) | (quint32(bits[1]) << 8) | (quint32(bits[2]) << 16); + quint32 c = ((v & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; + c += (((v & 0xfff000) >> 12) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; + len -= 24; + bits += 3; + numBits += int(c); + } + while (len >= 0) { + if (bits[len / 8] & (1 << ((len - 1) & 7))) + ++numBits; + --len; + } +#endif + return on ? numBits : size() - numBits; +} + +/*! + Resizes the bit array to \a size bits. + + If \a size is greater than the current size, the bit array is + extended to make it \a size bits with the extra bits added to the + end. The new bits are initialized to false (0). + + If \a size is less than the current size, bits are removed from + the end. + + \sa size() +*/ +void QBitArray::resize(int size) +{ + if (!size) { + d.resize(0); + } else { + int s = d.size(); + d.resize(1 + (size+7)/8); + uchar* c = reinterpret_cast<uchar*>(d.data()); + if (size > (s << 3)) + memset(c + s, 0, d.size() - s); + else if ( size % 8) + *(c+1+size/8) &= (1 << (size%8)) - 1; + *c = d.size()*8 - size; + } +} + +/*! \fn bool QBitArray::isEmpty() const + + Returns true if this bit array has size 0; otherwise returns + false. + + \sa size() +*/ + +/*! \fn bool QBitArray::isNull() const + + Returns true if this bit array is null; otherwise returns false. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 5 + + Qt makes a distinction between null bit arrays and empty bit + arrays for historical reasons. For most applications, what + matters is whether or not a bit array contains any data, + and this can be determined using isEmpty(). + + \sa isEmpty() +*/ + +/*! \fn bool QBitArray::fill(bool value, int size = -1) + + Sets every bit in the bit array to \a value, returning true if successful; + otherwise returns false. If \a size is different from -1 (the default), + the bit array is resized to \a size beforehand. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 6 + + \sa resize() +*/ + +/*! + \overload + + Sets bits at index positions \a begin up to and excluding \a end + to \a value. + + \a begin and \a end must be a valid index position in the bit + array (i.e., 0 <= \a begin <= size() and 0 <= \a end <= size()). +*/ + +void QBitArray::fill(bool value, int begin, int end) +{ + while (begin < end && begin & 0x7) + setBit(begin++, value); + int len = end - begin; + if (len <= 0) + return; + int s = len & ~0x7; + uchar *c = reinterpret_cast<uchar*>(d.data()); + memset(c + (begin >> 3) + 1, value ? 0xff : 0, s >> 3); + begin += s; + while (begin < end) + setBit(begin++, value); +} + +/*! \fn bool QBitArray::isDetached() const + + \internal +*/ + +/*! \fn void QBitArray::detach() + + \internal +*/ + +/*! \fn void QBitArray::clear() + + Clears the contents of the bit array and makes it empty. + + \sa resize(), isEmpty() +*/ + +/*! \fn void QBitArray::truncate(int pos) + + Truncates the bit array at index position \a pos. + + If \a pos is beyond the end of the array, nothing happens. + + \sa resize() +*/ + +/*! \fn bool QBitArray::toggleBit(int i) + + Inverts the value of the bit at index position \a i, returning the + previous value of that bit as either true (if it was set) or false (if + it was unset). + + If the previous value was 0, the new value will be 1. If the + previous value was 1, the new value will be 0. + + \a i must be a valid index position in the bit array (i.e., 0 <= + \a i < size()). + + \sa setBit(), clearBit() +*/ + +/*! \fn bool QBitArray::testBit(int i) const + + Returns true if the bit at index position \a i is 1; otherwise + returns false. + + \a i must be a valid index position in the bit array (i.e., 0 <= + \a i < size()). + + \sa setBit(), clearBit() +*/ + +/*! \fn bool QBitArray::setBit(int i) + + Sets the bit at index position \a i to 1. + + \a i must be a valid index position in the bit array (i.e., 0 <= + \a i < size()). + + \sa clearBit(), toggleBit() +*/ + +/*! \fn void QBitArray::setBit(int i, bool value) + + \overload + + Sets the bit at index position \a i to \a value. +*/ + +/*! \fn void QBitArray::clearBit(int i) + + Sets the bit at index position \a i to 0. + + \a i must be a valid index position in the bit array (i.e., 0 <= + \a i < size()). + + \sa setBit(), toggleBit() +*/ + +/*! \fn bool QBitArray::at(int i) const + + Returns the value of the bit at index position \a i. + + \a i must be a valid index position in the bit array (i.e., 0 <= + \a i < size()). + + \sa operator[]() +*/ + +/*! \fn QBitRef QBitArray::operator[](int i) + + Returns the bit at index position \a i as a modifiable reference. + + \a i must be a valid index position in the bit array (i.e., 0 <= + \a i < size()). + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 7 + + The return value is of type QBitRef, a helper class for QBitArray. + When you get an object of type QBitRef, you can assign to + it, and the assignment will apply to the bit in the QBitArray + from which you got the reference. + + The functions testBit(), setBit(), and clearBit() are slightly + faster. + + \sa at(), testBit(), setBit(), clearBit() +*/ + +/*! \fn bool QBitArray::operator[](int i) const + + \overload +*/ + +/*! \fn bool QBitArray::operator[](uint i) + + \overload +*/ + +/*! \fn bool QBitArray::operator[](uint i) const + + \overload +*/ + +/*! \fn QBitArray::QBitArray(const QBitArray &other) + + Constructs a copy of \a other. + + This operation takes \l{constant time}, because QBitArray is + \l{implicitly shared}. This makes returning a QBitArray from a + function very fast. If a shared instance is modified, it will be + copied (copy-on-write), and that takes \l{linear time}. + + \sa operator=() +*/ + +/*! \fn QBitArray &QBitArray::operator=(const QBitArray &other) + + Assigns \a other to this bit array and returns a reference to + this bit array. +*/ + +/*! \fn void QBitArray::swap(QBitArray &other) + \since 4.8 + + Swaps bit array \a other with this bit array. This operation is very + fast and never fails. +*/ + +/*! \fn bool QBitArray::operator==(const QBitArray &other) const + + Returns true if \a other is equal to this bit array; otherwise + returns false. + + \sa operator!=() +*/ + +/*! \fn bool QBitArray::operator!=(const QBitArray &other) const + + Returns true if \a other is not equal to this bit array; + otherwise returns false. + + \sa operator==() +*/ + +/*! + Performs the AND operation between all bits in this bit array and + \a other. Assigns the result to this bit array, and returns a + reference to it. + + The result has the length of the longest of the two bit arrays, + with any missing bits (if one array is shorter than the other) + taken to be 0. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 8 + + \sa operator&(), operator|=(), operator^=(), operator~() +*/ + +QBitArray &QBitArray::operator&=(const QBitArray &other) +{ + resize(qMax(size(), other.size())); + uchar *a1 = reinterpret_cast<uchar*>(d.data()) + 1; + const uchar *a2 = reinterpret_cast<const uchar*>(other.d.constData()) + 1; + int n = other.d.size() -1 ; + int p = d.size() - 1 - n; + while (n-- > 0) + *a1++ &= *a2++; + while (p-- > 0) + *a1++ = 0; + return *this; +} + +/*! + Performs the OR operation between all bits in this bit array and + \a other. Assigns the result to this bit array, and returns a + reference to it. + + The result has the length of the longest of the two bit arrays, + with any missing bits (if one array is shorter than the other) + taken to be 0. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 9 + + \sa operator|(), operator&=(), operator^=(), operator~() +*/ + +QBitArray &QBitArray::operator|=(const QBitArray &other) +{ + resize(qMax(size(), other.size())); + uchar *a1 = reinterpret_cast<uchar*>(d.data()) + 1; + const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1; + int n = other.d.size() - 1; + while (n-- > 0) + *a1++ |= *a2++; + return *this; +} + +/*! + Performs the XOR operation between all bits in this bit array and + \a other. Assigns the result to this bit array, and returns a + reference to it. + + The result has the length of the longest of the two bit arrays, + with any missing bits (if one array is shorter than the other) + taken to be 0. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 10 + + \sa operator^(), operator&=(), operator|=(), operator~() +*/ + +QBitArray &QBitArray::operator^=(const QBitArray &other) +{ + resize(qMax(size(), other.size())); + uchar *a1 = reinterpret_cast<uchar*>(d.data()) + 1; + const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1; + int n = other.d.size() - 1; + while (n-- > 0) + *a1++ ^= *a2++; + return *this; +} + +/*! + Returns a bit array that contains the inverted bits of this bit + array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 11 + + \sa operator&(), operator|(), operator^() +*/ + +QBitArray QBitArray::operator~() const +{ + int sz = size(); + QBitArray a(sz); + const uchar *a1 = reinterpret_cast<const uchar *>(d.constData()) + 1; + uchar *a2 = reinterpret_cast<uchar*>(a.d.data()) + 1; + int n = d.size() - 1; + + while (n-- > 0) + *a2++ = ~*a1++; + + if (sz && sz%8) + *(a2-1) &= (1 << (sz%8)) - 1; + return a; +} + +/*! + \relates QBitArray + + Returns a bit array that is the AND of the bit arrays \a a1 and \a + a2. + + The result has the length of the longest of the two bit arrays, + with any missing bits (if one array is shorter than the other) + taken to be 0. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 12 + + \sa QBitArray::operator&=(), operator|(), operator^() +*/ + +QBitArray operator&(const QBitArray &a1, const QBitArray &a2) +{ + QBitArray tmp = a1; + tmp &= a2; + return tmp; +} + +/*! + \relates QBitArray + + Returns a bit array that is the OR of the bit arrays \a a1 and \a + a2. + + The result has the length of the longest of the two bit arrays, + with any missing bits (if one array is shorter than the other) + taken to be 0. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 13 + + \sa QBitArray::operator|=(), operator&(), operator^() +*/ + +QBitArray operator|(const QBitArray &a1, const QBitArray &a2) +{ + QBitArray tmp = a1; + tmp |= a2; + return tmp; +} + +/*! + \relates QBitArray + + Returns a bit array that is the XOR of the bit arrays \a a1 and \a + a2. + + The result has the length of the longest of the two bit arrays, + with any missing bits (if one array is shorter than the other) + taken to be 0. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbitarray.cpp 14 + + \sa QBitArray::operator^=(), operator&(), operator|() +*/ + +QBitArray operator^(const QBitArray &a1, const QBitArray &a2) +{ + QBitArray tmp = a1; + tmp ^= a2; + return tmp; +} + +/*! + \class QBitRef + \reentrant + \brief The QBitRef class is an internal class, used with QBitArray. + + \internal + + The QBitRef is required by the indexing [] operator on bit arrays. + It is not for use in any other context. +*/ + +/*! \fn QBitRef::QBitRef (QBitArray& a, int i) + + Constructs a reference to element \a i in the QBitArray \a a. + This is what QBitArray::operator[] constructs its return value + with. +*/ + +/*! \fn QBitRef::operator bool() const + + Returns the value referenced by the QBitRef. +*/ + +/*! \fn bool QBitRef::operator!() const + + \internal +*/ + +/*! \fn QBitRef& QBitRef::operator= (const QBitRef& v) + + Sets the value referenced by the QBitRef to that referenced by + QBitRef \a v. +*/ + +/*! \fn QBitRef& QBitRef::operator= (bool v) + \overload + + Sets the value referenced by the QBitRef to \a v. +*/ + + +/***************************************************************************** + QBitArray stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +/*! + \relates QBitArray + + Writes bit array \a ba to stream \a out. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<(QDataStream &out, const QBitArray &ba) +{ + quint32 len = ba.size(); + out << len; + if (len > 0) + out.writeRawData(ba.d.constData() + 1, ba.d.size() - 1); + return out; +} + +/*! + \relates QBitArray + + Reads a bit array into \a ba from stream \a in. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>(QDataStream &in, QBitArray &ba) +{ + ba.clear(); + quint32 len; + in >> len; + if (len == 0) { + ba.clear(); + return in; + } + + const quint32 Step = 8 * 1024 * 1024; + quint32 totalBytes = (len + 7) / 8; + quint32 allocated = 0; + + while (allocated < totalBytes) { + int blockSize = qMin(Step, totalBytes - allocated); + ba.d.resize(allocated + blockSize + 1); + if (in.readRawData(ba.d.data() + 1 + allocated, blockSize) != blockSize) { + ba.clear(); + in.setStatus(QDataStream::ReadPastEnd); + return in; + } + allocated += blockSize; + } + + int paddingMask = ~((0x1 << (len & 0x7)) - 1); + if (paddingMask != ~0x0 && (ba.d.constData()[ba.d.size() - 1] & paddingMask)) { + ba.clear(); + in.setStatus(QDataStream::ReadCorruptData); + return in; + } + + *ba.d.data() = ba.d.size() * 8 - len; + return in; +} +#endif // QT_NO_DATASTREAM + +/*! + \fn DataPtr &QBitArray::data_ptr() + \internal +*/ + +/*! + \typedef QBitArray::DataPtr + \internal +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h new file mode 100644 index 0000000000..cec338c394 --- /dev/null +++ b/src/corelib/tools/qbitarray.h @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QBITARRAY_H +#define QBITARRAY_H + +#include <QtCore/qbytearray.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QBitRef; +class Q_CORE_EXPORT QBitArray +{ + friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QBitArray &); + friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QBitArray &); + friend Q_CORE_EXPORT uint qHash(const QBitArray &key); + QByteArray d; + +public: + inline QBitArray() {} + explicit QBitArray(int size, bool val = false); + QBitArray(const QBitArray &other) : d(other.d) {} + inline QBitArray &operator=(const QBitArray &other) { d = other.d; return *this; } +#ifdef Q_COMPILER_RVALUE_REFS + inline QBitArray &operator=(QBitArray &&other) + { qSwap(d, other.d); return *this; } +#endif + + inline void swap(QBitArray &other) { qSwap(d, other.d); } + + inline int size() const { return (d.size() << 3) - *d.constData(); } + inline int count() const { return (d.size() << 3) - *d.constData(); } + int count(bool on) const; + // ### Qt 5: Store the number of set bits separately + + inline bool isEmpty() const { return d.isEmpty(); } + inline bool isNull() const { return d.isNull(); } + + void resize(int size); + + inline void detach() { d.detach(); } + inline bool isDetached() const { return d.isDetached(); } + inline void clear() { d.clear(); } + + bool testBit(int i) const; + void setBit(int i); + void setBit(int i, bool val); + void clearBit(int i); + bool toggleBit(int i); + + bool at(int i) const; + QBitRef operator[](int i); + bool operator[](int i) const; + QBitRef operator[](uint i); + bool operator[](uint i) const; + + QBitArray& operator&=(const QBitArray &); + QBitArray& operator|=(const QBitArray &); + QBitArray& operator^=(const QBitArray &); + QBitArray operator~() const; + + inline bool operator==(const QBitArray& a) const { return d == a.d; } + inline bool operator!=(const QBitArray& a) const { return d != a.d; } + + inline bool fill(bool val, int size = -1); + void fill(bool val, int first, int last); + + inline void truncate(int pos) { if (pos < size()) resize(pos); } + +public: + typedef QByteArray::DataPtr DataPtr; + inline DataPtr &data_ptr() { return d.data_ptr(); } +}; + +inline bool QBitArray::fill(bool aval, int asize) +{ *this = QBitArray((asize < 0 ? this->size() : asize), aval); return true; } + +Q_CORE_EXPORT QBitArray operator&(const QBitArray &, const QBitArray &); +Q_CORE_EXPORT QBitArray operator|(const QBitArray &, const QBitArray &); +Q_CORE_EXPORT QBitArray operator^(const QBitArray &, const QBitArray &); + +inline bool QBitArray::testBit(int i) const +{ Q_ASSERT(i >= 0 && i < size()); + return (*(reinterpret_cast<const uchar*>(d.constData())+1+(i>>3)) & (1 << (i & 7))) != 0; } + +inline void QBitArray::setBit(int i) +{ Q_ASSERT(i >= 0 && i < size()); + *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) |= uchar(1 << (i & 7)); } + +inline void QBitArray::clearBit(int i) +{ Q_ASSERT(i >= 0 && i < size()); + *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) &= ~uchar(1 << (i & 7)); } + +inline void QBitArray::setBit(int i, bool val) +{ if (val) setBit(i); else clearBit(i); } + +inline bool QBitArray::toggleBit(int i) +{ Q_ASSERT(i >= 0 && i < size()); + uchar b = uchar(1<<(i&7)); uchar* p = reinterpret_cast<uchar*>(d.data())+1+(i>>3); + uchar c = uchar(*p&b); *p^=b; return c!=0; } + +inline bool QBitArray::operator[](int i) const { return testBit(i); } +inline bool QBitArray::operator[](uint i) const { return testBit(i); } +inline bool QBitArray::at(int i) const { return testBit(i); } + +class Q_CORE_EXPORT QBitRef +{ +private: + QBitArray& a; + int i; + inline QBitRef(QBitArray& array, int idx) : a(array), i(idx) {} + friend class QBitArray; +public: + inline operator bool() const { return a.testBit(i); } + inline bool operator!() const { return !a.testBit(i); } + QBitRef& operator=(const QBitRef& val) { a.setBit(i, val); return *this; } + QBitRef& operator=(bool val) { a.setBit(i, val); return *this; } +}; + +inline QBitRef QBitArray::operator[](int i) +{ Q_ASSERT(i >= 0); return QBitRef(*this, i); } +inline QBitRef QBitArray::operator[](uint i) +{ return QBitRef(*this, i); } + + +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QBitArray &); +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QBitArray &); +#endif + +Q_DECLARE_TYPEINFO(QBitArray, Q_MOVABLE_TYPE); +Q_DECLARE_SHARED(QBitArray) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QBITARRAY_H diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp new file mode 100644 index 0000000000..1c9b6541e3 --- /dev/null +++ b/src/corelib/tools/qbytearray.cpp @@ -0,0 +1,4394 @@ +/**************************************************************************** +** +** 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 QtCore 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 "qbytearray.h" +#include "qbytearraymatcher.h" +#include "qtools_p.h" +#include "qstring.h" +#include "qlist.h" +#include "qlocale.h" +#include "qlocale_p.h" +#include "qscopedpointer.h" +#include <qdatastream.h> + +#ifndef QT_NO_COMPRESS +#include <zlib.h> +#endif +#include <ctype.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> + +#define IS_RAW_DATA(d) ((d)->data != (d)->array) + +QT_BEGIN_NAMESPACE + + +int qFindByteArray( + const char *haystack0, int haystackLen, int from, + const char *needle0, int needleLen); + + +int qAllocMore(int alloc, int extra) +{ + if (alloc == 0 && extra == 0) + return 0; + const int page = 1 << 12; + int nalloc; + alloc += extra; + if (alloc < 1<<6) { + nalloc = (1<<3) + ((alloc >>3) << 3); + } else { + // don't do anything if the loop will overflow signed int. + if (alloc >= INT_MAX/2) + return INT_MAX; + nalloc = (alloc < page) ? 1 << 3 : page; + while (nalloc < alloc) { + if (nalloc <= 0) + return INT_MAX; + nalloc *= 2; + } + } + return nalloc - extra; +} + +/***************************************************************************** + Safe and portable C string functions; extensions to standard string.h + *****************************************************************************/ + +/*! \relates QByteArray + + Returns a duplicate string. + + Allocates space for a copy of \a src, copies it, and returns a + pointer to the copy. If \a src is 0, it immediately returns 0. + + Ownership is passed to the caller, so the returned string must be + deleted using \c delete[]. +*/ + +char *qstrdup(const char *src) +{ + if (!src) + return 0; + char *dst = new char[strlen(src) + 1]; + return qstrcpy(dst, src); +} + +/*! \relates QByteArray + + Copies all the characters up to and including the '\\0' from \a + src into \a dst and returns a pointer to \a dst. If \a src is 0, + it immediately returns 0. + + This function assumes that \a dst is large enough to hold the + contents of \a src. + + \sa qstrncpy() +*/ + +char *qstrcpy(char *dst, const char *src) +{ + if (!src) + return 0; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + int len = qstrlen(src); + // This is actually not secure!!! It will be fixed + // properly in a later release! + if (len >= 0 && strcpy_s(dst, len+1, src) == 0) + return dst; + return 0; +#else + return strcpy(dst, src); +#endif +} + +/*! \relates QByteArray + + A safe \c strncpy() function. + + Copies at most \a len bytes from \a src (stopping at \a len or the + terminating '\\0' whichever comes first) into \a dst and returns a + pointer to \a dst. Guarantees that \a dst is '\\0'-terminated. If + \a src or \a dst is 0, returns 0 immediately. + + This function assumes that \a dst is at least \a len characters + long. + + \note When compiling with Visual C++ compiler version 14.00 + (Visual C++ 2005) or later, internally the function strncpy_s + will be used. + + \sa qstrcpy() +*/ + +char *qstrncpy(char *dst, const char *src, uint len) +{ + if (!src || !dst) + return 0; +#if defined(_MSC_VER) && _MSC_VER >= 1400 + strncpy_s(dst, len, src, len-1); +#else + strncpy(dst, src, len); +#endif + if (len > 0) + dst[len-1] = '\0'; + return dst; +} + +/*! \fn uint qstrlen(const char *str) + \relates QByteArray + + A safe \c strlen() function. + + Returns the number of characters that precede the terminating '\\0', + or 0 if \a str is 0. + + \sa qstrnlen() +*/ + +/*! \fn uint qstrnlen(const char *str, uint maxlen) + \relates QByteArray + \since 4.2 + + A safe \c strnlen() function. + + Returns the number of characters that precede the terminating '\\0', but + at most \a maxlen. If \a str is 0, returns 0. + + \sa qstrlen() +*/ + +/*! + \relates QByteArray + + A safe \c strcmp() function. + + Compares \a str1 and \a str2. Returns a negative value if \a str1 + is less than \a str2, 0 if \a str1 is equal to \a str2 or a + positive value if \a str1 is greater than \a str2. + + Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + + Special case 2: Returns an arbitrary non-zero value if \a str1 is 0 + or \a str2 is 0 (but not both). + + \sa qstrncmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons} +*/ +int qstrcmp(const char *str1, const char *str2) +{ + return (str1 && str2) ? strcmp(str1, str2) + : (str1 ? 1 : (str2 ? -1 : 0)); +} + +/*! \fn int qstrncmp(const char *str1, const char *str2, uint len); + + \relates QByteArray + + A safe \c strncmp() function. + + Compares at most \a len bytes of \a str1 and \a str2. + + Returns a negative value if \a str1 is less than \a str2, 0 if \a + str1 is equal to \a str2 or a positive value if \a str1 is greater + than \a str2. + + Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + + Special case 2: Returns a random non-zero value if \a str1 is 0 + or \a str2 is 0 (but not both). + + \sa qstrcmp(), qstricmp(), qstrnicmp(), {8-bit Character Comparisons} +*/ + +/*! \relates QByteArray + + A safe \c stricmp() function. + + Compares \a str1 and \a str2 ignoring the case of the + characters. The encoding of the strings is assumed to be Latin-1. + + Returns a negative value if \a str1 is less than \a str2, 0 if \a + str1 is equal to \a str2 or a positive value if \a str1 is greater + than \a str2. + + Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + + Special case 2: Returns a random non-zero value if \a str1 is 0 + or \a str2 is 0 (but not both). + + \sa qstrcmp(), qstrncmp(), qstrnicmp(), {8-bit Character Comparisons} +*/ + +int qstricmp(const char *str1, const char *str2) +{ + register const uchar *s1 = reinterpret_cast<const uchar *>(str1); + register const uchar *s2 = reinterpret_cast<const uchar *>(str2); + int res; + uchar c; + if (!s1 || !s2) + return s1 ? 1 : (s2 ? -1 : 0); + for (; !(res = (c = QChar::toLower((ushort)*s1)) - QChar::toLower((ushort)*s2)); s1++, s2++) + if (!c) // strings are equal + break; + return res; +} + +/*! \relates QByteArray + + A safe \c strnicmp() function. + + Compares at most \a len bytes of \a str1 and \a str2 ignoring the + case of the characters. The encoding of the strings is assumed to + be Latin-1. + + Returns a negative value if \a str1 is less than \a str2, 0 if \a str1 + is equal to \a str2 or a positive value if \a str1 is greater than \a + str2. + + Special case 1: Returns 0 if \a str1 and \a str2 are both 0. + + Special case 2: Returns a random non-zero value if \a str1 is 0 + or \a str2 is 0 (but not both). + + \sa qstrcmp(), qstrncmp(), qstricmp(), {8-bit Character Comparisons} +*/ + +int qstrnicmp(const char *str1, const char *str2, uint len) +{ + register const uchar *s1 = reinterpret_cast<const uchar *>(str1); + register const uchar *s2 = reinterpret_cast<const uchar *>(str2); + int res; + uchar c; + if (!s1 || !s2) + return s1 ? 1 : (s2 ? -1 : 0); + for (; len--; s1++, s2++) { + if ((res = (c = QChar::toLower((ushort)*s1)) - QChar::toLower((ushort)*s2))) + return res; + if (!c) // strings are equal + break; + } + return 0; +} + +/*! + \internal + */ +int qstrcmp(const QByteArray &str1, const char *str2) +{ + if (!str2) + return str1.isEmpty() ? 0 : +1; + + const char *str1data = str1.constData(); + const char *str1end = str1data + str1.length(); + for ( ; str1data < str1end && *str2; ++str1data, ++str2) { + register int diff = int(uchar(*str1data)) - uchar(*str2); + if (diff) + // found a difference + return diff; + } + + // Why did we stop? + if (*str2 != '\0') + // not the null, so we stopped because str1 is shorter + return -1; + if (str1data < str1end) + // we haven't reached the end, so str1 must be longer + return +1; + return 0; +} + +/*! + \internal + */ +int qstrcmp(const QByteArray &str1, const QByteArray &str2) +{ + int l1 = str1.length(); + int l2 = str2.length(); + int ret = memcmp(str1, str2, qMin(l1, l2)); + if (ret != 0) + return ret; + + // they matched qMin(l1, l2) bytes + // so the longer one is lexically after the shorter one + return l1 - l2; +} + +// the CRC table below is created by the following piece of code +#if 0 +static void createCRC16Table() // build CRC16 lookup table +{ + register unsigned int i; + register unsigned int j; + unsigned short crc_tbl[16]; + unsigned int v0, v1, v2, v3; + for (i = 0; i < 16; i++) { + v0 = i & 1; + v1 = (i >> 1) & 1; + v2 = (i >> 2) & 1; + v3 = (i >> 3) & 1; + j = 0; +#undef SET_BIT +#define SET_BIT(x, b, v) (x) |= (v) << (b) + SET_BIT(j, 0, v0); + SET_BIT(j, 7, v0); + SET_BIT(j, 12, v0); + SET_BIT(j, 1, v1); + SET_BIT(j, 8, v1); + SET_BIT(j, 13, v1); + SET_BIT(j, 2, v2); + SET_BIT(j, 9, v2); + SET_BIT(j, 14, v2); + SET_BIT(j, 3, v3); + SET_BIT(j, 10, v3); + SET_BIT(j, 15, v3); + crc_tbl[i] = j; + } + printf("static const quint16 crc_tbl[16] = {\n"); + for (int i = 0; i < 16; i +=4) + printf(" 0x%04x, 0x%04x, 0x%04x, 0x%04x,\n", crc_tbl[i], crc_tbl[i+1], crc_tbl[i+2], crc_tbl[i+3]); + printf("};\n"); +} +#endif + +static const quint16 crc_tbl[16] = { + 0x0000, 0x1081, 0x2102, 0x3183, + 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xa50a, 0xb58b, + 0xc60c, 0xd68d, 0xe70e, 0xf78f +}; + +/*! + \relates QByteArray + + Returns the CRC-16 checksum of the first \a len bytes of \a data. + + The checksum is independent of the byte order (endianness). + + \note This function is a 16-bit cache conserving (16 entry table) + implementation of the CRC-16-CCITT algorithm. +*/ + +quint16 qChecksum(const char *data, uint len) +{ + register quint16 crc = 0xffff; + uchar c; + const uchar *p = reinterpret_cast<const uchar *>(data); + while (len--) { + c = *p++; + crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)]; + c >>= 4; + crc = ((crc >> 4) & 0x0fff) ^ crc_tbl[((crc ^ c) & 15)]; + } + return ~crc & 0xffff; +} + +/*! + \fn QByteArray qCompress(const QByteArray& data, int compressionLevel) + + \relates QByteArray + + Compresses the \a data byte array and returns the compressed data + in a new byte array. + + The \a compressionLevel parameter specifies how much compression + should be used. Valid values are between 0 and 9, with 9 + corresponding to the greatest compression (i.e. smaller compressed + data) at the cost of using a slower algorithm. Smaller values (8, + 7, ..., 1) provide successively less compression at slightly + faster speeds. The value 0 corresponds to no compression at all. + The default value is -1, which specifies zlib's default + compression. + + \sa qUncompress() +*/ + +/*! \relates QByteArray + + \overload + + Compresses the first \a nbytes of \a data and returns the + compressed data in a new byte array. +*/ + +#ifndef QT_NO_COMPRESS +QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel) +{ + if (nbytes == 0) { + return QByteArray(4, '\0'); + } + if (!data) { + qWarning("qCompress: Data is null"); + return QByteArray(); + } + if (compressionLevel < -1 || compressionLevel > 9) + compressionLevel = -1; + + ulong len = nbytes + nbytes / 100 + 13; + QByteArray bazip; + int res; + do { + bazip.resize(len + 4); + res = ::compress2((uchar*)bazip.data()+4, &len, (uchar*)data, nbytes, compressionLevel); + + switch (res) { + case Z_OK: + bazip.resize(len + 4); + bazip[0] = (nbytes & 0xff000000) >> 24; + bazip[1] = (nbytes & 0x00ff0000) >> 16; + bazip[2] = (nbytes & 0x0000ff00) >> 8; + bazip[3] = (nbytes & 0x000000ff); + break; + case Z_MEM_ERROR: + qWarning("qCompress: Z_MEM_ERROR: Not enough memory"); + bazip.resize(0); + break; + case Z_BUF_ERROR: + len *= 2; + break; + } + } while (res == Z_BUF_ERROR); + + return bazip; +} +#endif + +/*! + \fn QByteArray qUncompress(const QByteArray &data) + + \relates QByteArray + + Uncompresses the \a data byte array and returns a new byte array + with the uncompressed data. + + Returns an empty QByteArray if the input data was corrupt. + + This function will uncompress data compressed with qCompress() + from this and any earlier Qt version, back to Qt 3.1 when this + feature was added. + + \bold{Note:} If you want to use this function to uncompress external + data that was compressed using zlib, you first need to prepend a four + byte header to the byte array containing the data. The header must + contain the expected length (in bytes) of the uncompressed data, + expressed as an unsigned, big-endian, 32-bit integer. + + \sa qCompress() +*/ + +/*! \relates QByteArray + + \overload + + Uncompresses the first \a nbytes of \a data and returns a new byte + array with the uncompressed data. +*/ + +#ifndef QT_NO_COMPRESS +QByteArray qUncompress(const uchar* data, int nbytes) +{ + if (!data) { + qWarning("qUncompress: Data is null"); + return QByteArray(); + } + if (nbytes <= 4) { + if (nbytes < 4 || (data[0]!=0 || data[1]!=0 || data[2]!=0 || data[3]!=0)) + qWarning("qUncompress: Input data is corrupted"); + return QByteArray(); + } + ulong expectedSize = (data[0] << 24) | (data[1] << 16) | + (data[2] << 8) | (data[3] ); + ulong len = qMax(expectedSize, 1ul); + QScopedPointer<QByteArray::Data, QScopedPointerPodDeleter> d; + + forever { + ulong alloc = len; + if (len >= (1 << 31) - sizeof(QByteArray::Data)) { + //QByteArray does not support that huge size anyway. + qWarning("qUncompress: Input data is corrupted"); + return QByteArray(); + } + QByteArray::Data *p = static_cast<QByteArray::Data *>(qRealloc(d.data(), sizeof(QByteArray::Data) + alloc)); + if (!p) { + // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS + qWarning("qUncompress: could not allocate enough memory to uncompress data"); + return QByteArray(); + } + d.take(); // realloc was successful + d.reset(p); + + int res = ::uncompress((uchar*)d->array, &len, + (uchar*)data+4, nbytes-4); + + switch (res) { + case Z_OK: + if (len != alloc) { + if (len >= (1 << 31) - sizeof(QByteArray::Data)) { + //QByteArray does not support that huge size anyway. + qWarning("qUncompress: Input data is corrupted"); + return QByteArray(); + } + QByteArray::Data *p = static_cast<QByteArray::Data *>(qRealloc(d.data(), sizeof(QByteArray::Data) + len)); + if (!p) { + // we are not allowed to crash here when compiling with QT_NO_EXCEPTIONS + qWarning("qUncompress: could not allocate enough memory to uncompress data"); + return QByteArray(); + } + d.take(); // realloc was successful + d.reset(p); + } + d->ref = 1; + d->alloc = d->size = len; + d->data = d->array; + d->array[len] = 0; + + return QByteArray(d.take(), 0, 0); + + case Z_MEM_ERROR: + qWarning("qUncompress: Z_MEM_ERROR: Not enough memory"); + return QByteArray(); + + case Z_BUF_ERROR: + len *= 2; + continue; + + case Z_DATA_ERROR: + qWarning("qUncompress: Z_DATA_ERROR: Input data is corrupted"); + return QByteArray(); + } + } +} +#endif + +static inline bool qIsUpper(char c) +{ + return c >= 'A' && c <= 'Z'; +} + +static inline char qToLower(char c) +{ + if (c >= 'A' && c <= 'Z') + return c - 'A' + 'a'; + else + return c; +} + +QByteArray::Data QByteArray::shared_null = {Q_BASIC_ATOMIC_INITIALIZER(1), + 0, 0, shared_null.array, {0} }; +QByteArray::Data QByteArray::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), + 0, 0, shared_empty.array, {0} }; + +/*! + \class QByteArray + \brief The QByteArray class provides an array of bytes. + + \ingroup tools + \ingroup shared + \ingroup string-processing + + \reentrant + + QByteArray can be used to store both raw bytes (including '\\0's) + and traditional 8-bit '\\0'-terminated strings. Using QByteArray + is much more convenient than using \c{const char *}. Behind the + scenes, it always ensures that the data is followed by a '\\0' + terminator, and uses \l{implicit sharing} (copy-on-write) to + reduce memory usage and avoid needless copying of data. + + In addition to QByteArray, Qt also provides the QString class to + store string data. For most purposes, QString is the class you + want to use. It stores 16-bit Unicode characters, making it easy + to store non-ASCII/non-Latin-1 characters in your application. + Furthermore, QString is used throughout in the Qt API. The two + main cases where QByteArray is appropriate are when you need to + store raw binary data, and when memory conservation is critical + (e.g., with Qt for Embedded Linux). + + One way to initialize a QByteArray is simply to pass a \c{const + char *} to its constructor. For example, the following code + creates a byte array of size 5 containing the data "Hello": + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 0 + + Although the size() is 5, the byte array also maintains an extra + '\\0' character at the end so that if a function is used that + asks for a pointer to the underlying data (e.g. a call to + data()), the data pointed to is guaranteed to be + '\\0'-terminated. + + QByteArray makes a deep copy of the \c{const char *} data, so you + can modify it later without experiencing side effects. (If for + performance reasons you don't want to take a deep copy of the + character data, use QByteArray::fromRawData() instead.) + + Another approach is to set the size of the array using resize() + and to initialize the data byte per byte. QByteArray uses 0-based + indexes, just like C++ arrays. To access the byte at a particular + index position, you can use operator[](). On non-const byte + arrays, operator[]() returns a reference to a byte that can be + used on the left side of an assignment. For example: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 1 + + For read-only access, an alternative syntax is to use at(): + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 2 + + at() can be faster than operator[](), because it never causes a + \l{deep copy} to occur. + + To extract many bytes at a time, use left(), right(), or mid(). + + A QByteArray can embed '\\0' bytes. The size() function always + returns the size of the whole array, including embedded '\\0' + bytes. If you want to obtain the length of the data up to and + excluding the first '\\0' character, call qstrlen() on the byte + array. + + After a call to resize(), newly allocated bytes have undefined + values. To set all the bytes to a particular value, call fill(). + + To obtain a pointer to the actual character data, call data() or + constData(). These functions return a pointer to the beginning of the data. + The pointer is guaranteed to remain valid until a non-const function is + called on the QByteArray. It is also guaranteed that the data ends with a + '\\0' byte unless the QByteArray was created from a \l{fromRawData()}{raw + data}. This '\\0' byte is automatically provided by QByteArray and is not + counted in size(). + + QByteArray provides the following basic functions for modifying + the byte data: append(), prepend(), insert(), replace(), and + remove(). For example: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 3 + + The replace() and remove() functions' first two arguments are the + position from which to start erasing and the number of bytes that + should be erased. + + When you append() data to a non-empty array, the array will be + reallocated and the new data copied to it. You can avoid this + behavior by calling reserve(), which preallocates a certain amount + of memory. You can also call capacity() to find out how much + memory QByteArray actually allocated. Data appended to an empty + array is not copied. + + A frequent requirement is to remove whitespace characters from a + byte array ('\\n', '\\t', ' ', etc.). If you want to remove + whitespace from both ends of a QByteArray, use trimmed(). If you + want to remove whitespace from both ends and replace multiple + consecutive whitespaces with a single space character within the + byte array, use simplified(). + + If you want to find all occurrences of a particular character or + substring in a QByteArray, use indexOf() or lastIndexOf(). The + former searches forward starting from a given index position, the + latter searches backward. Both return the index position of the + character or substring if they find it; otherwise, they return -1. + For example, here's a typical loop that finds all occurrences of a + particular substring: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 4 + + If you simply want to check whether a QByteArray contains a + particular character or substring, use contains(). If you want to + find out how many times a particular character or substring + occurs in the byte array, use count(). If you want to replace all + occurrences of a particular value with another, use one of the + two-parameter replace() overloads. + + QByteArrays can be compared using overloaded operators such as + operator<(), operator<=(), operator==(), operator>=(), and so on. + The comparison is based exclusively on the numeric values + of the characters and is very fast, but is not what a human would + expect. QString::localeAwareCompare() is a better choice for + sorting user-interface strings. + + For historical reasons, QByteArray distinguishes between a null + byte array and an empty byte array. A \e null byte array is a + byte array that is initialized using QByteArray's default + constructor or by passing (const char *)0 to the constructor. An + \e empty byte array is any byte array with size 0. A null byte + array is always empty, but an empty byte array isn't necessarily + null: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 5 + + All functions except isNull() treat null byte arrays the same as + empty byte arrays. For example, data() returns a pointer to a + '\\0' character for a null byte array (\e not a null pointer), + and QByteArray() compares equal to QByteArray(""). We recommend + that you always use isEmpty() and avoid isNull(). + + \section1 Notes on Locale + + \section2 Number-String Conversions + + Functions that perform conversions between numeric data types and + strings are performed in the C locale, irrespective of the user's + locale settings. Use QString to perform locale-aware conversions + between numbers and strings. + + \section2 8-bit Character Comparisons + + In QByteArray, the notion of uppercase and lowercase and of which + character is greater than or less than another character is + locale dependent. This affects functions that support a case + insensitive option or that compare or lowercase or uppercase + their arguments. Case insensitive operations and comparisons will + be accurate if both strings contain only ASCII characters. (If \c + $LC_CTYPE is set, most Unix systems do "the right thing".) + Functions that this affects include contains(), indexOf(), + lastIndexOf(), operator<(), operator<=(), operator>(), + operator>=(), toLower() and toUpper(). + + This issue does not apply to QStrings since they represent + characters using Unicode. + + \sa QString, QBitArray +*/ + +/*! \fn QByteArray::iterator QByteArray::begin() + + \internal +*/ + +/*! \fn QByteArray::const_iterator QByteArray::begin() const + + \internal +*/ + +/*! \fn QByteArray::const_iterator QByteArray::constBegin() const + + \internal +*/ + +/*! \fn QByteArray::iterator QByteArray::end() + + \internal +*/ + +/*! \fn QByteArray::const_iterator QByteArray::end() const + + \internal +*/ + +/*! \fn QByteArray::const_iterator QByteArray::constEnd() const + + \internal +*/ + +/*! \fn void QByteArray::push_back(const QByteArray &other) + + This function is provided for STL compatibility. It is equivalent + to append(\a other). +*/ + +/*! \fn void QByteArray::push_back(const char *str) + + \overload + + Same as append(\a str). +*/ + +/*! \fn void QByteArray::push_back(char ch) + + \overload + + Same as append(\a ch). +*/ + +/*! \fn void QByteArray::push_front(const QByteArray &other) + + This function is provided for STL compatibility. It is equivalent + to prepend(\a other). +*/ + +/*! \fn void QByteArray::push_front(const char *str) + + \overload + + Same as prepend(\a str). +*/ + +/*! \fn void QByteArray::push_front(char ch) + + \overload + + Same as prepend(\a ch). +*/ + +/*! \fn QByteArray::QByteArray(const QByteArray &other) + + Constructs a copy of \a other. + + This operation takes \l{constant time}, because QByteArray is + \l{implicitly shared}. This makes returning a QByteArray from a + function very fast. If a shared instance is modified, it will be + copied (copy-on-write), taking \l{linear time}. + + \sa operator=() +*/ + +/*! \fn QByteArray::~QByteArray() + Destroys the byte array. +*/ + +/*! + Assigns \a other to this byte array and returns a reference to + this byte array. +*/ +QByteArray &QByteArray::operator=(const QByteArray & other) +{ + other.d->ref.ref(); + if (!d->ref.deref()) + qFree(d); + d = other.d; + return *this; +} + + +/*! + \overload + + Assigns \a str to this byte array. +*/ + +QByteArray &QByteArray::operator=(const char *str) +{ + Data *x; + if (!str) { + x = &shared_null; + } else if (!*str) { + x = &shared_empty; + } else { + int len = qstrlen(str); + if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1)) + realloc(len); + x = d; + memcpy(x->data, str, len + 1); // include null terminator + x->size = len; + } + x->ref.ref(); + if (!d->ref.deref()) + qFree(d); + d = x; + return *this; +} + +/*! \fn void QByteArray::swap(QByteArray &other) + \since 4.8 + + Swaps byte array \a other with this byte array. This operation is very + fast and never fails. +*/ + +/*! \fn int QByteArray::size() const + + Returns the number of bytes in this byte array. + + The last byte in the byte array is at position size() - 1. In addition, + QByteArray ensures that the byte at position size() is always '\\0', so + that you can use the return value of data() and constData() as arguments to + functions that expect '\\0'-terminated strings. If the QByteArray object + was created from a \l{fromRawData()}{raw data} that didn't include the + trailing null-termination character then QByteArray doesn't add it + automaticall unless the \l{deep copy} is created. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 6 + + \sa isEmpty(), resize() +*/ + +/*! \fn bool QByteArray::isEmpty() const + + Returns true if the byte array has size 0; otherwise returns false. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 7 + + \sa size() +*/ + +/*! \fn int QByteArray::capacity() const + + Returns the maximum number of bytes that can be stored in the + byte array without forcing a reallocation. + + The sole purpose of this function is to provide a means of fine + tuning QByteArray's memory usage. In general, you will rarely + ever need to call this function. If you want to know how many + bytes are in the byte array, call size(). + + \sa reserve(), squeeze() +*/ + +/*! \fn void QByteArray::reserve(int size) + + Attempts to allocate memory for at least \a size bytes. If you + know in advance how large the byte array will be, you can call + this function, and if you call resize() often you are likely to + get better performance. If \a size is an underestimate, the worst + that will happen is that the QByteArray will be a bit slower. + + The sole purpose of this function is to provide a means of fine + tuning QByteArray's memory usage. In general, you will rarely + ever need to call this function. If you want to change the size + of the byte array, call resize(). + + \sa squeeze(), capacity() +*/ + +/*! \fn void QByteArray::squeeze() + + Releases any memory not required to store the array's data. + + The sole purpose of this function is to provide a means of fine + tuning QByteArray's memory usage. In general, you will rarely + ever need to call this function. + + \sa reserve(), capacity() +*/ + +/*! \fn QByteArray::operator const char *() const + \fn QByteArray::operator const void *() const + + Returns a pointer to the data stored in the byte array. The + pointer can be used to access the bytes that compose the array. + The data is '\\0'-terminated. The pointer remains valid as long + as the array isn't reallocated or destroyed. + + This operator is mostly useful to pass a byte array to a function + that accepts a \c{const char *}. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_BYTEARRAY when you compile your applications. + + Note: A QByteArray can store any byte values including '\\0's, + but most functions that take \c{char *} arguments assume that the + data ends at the first '\\0' they encounter. + + \sa constData() +*/ + +/*! + \macro QT_NO_CAST_FROM_BYTEARRAY + \relates QByteArray + + Disables automatic conversions from QByteArray to + const char * or const void *. + + \sa QT_NO_CAST_TO_ASCII, QT_NO_CAST_FROM_ASCII +*/ + +/*! \fn char *QByteArray::data() + + Returns a pointer to the data stored in the byte array. The + pointer can be used to access and modify the bytes that compose + the array. The data is '\\0'-terminated, i.e. the number of + bytes in the returned character string is size() + 1 for the + '\\0' terminator. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 8 + + The pointer remains valid as long as the byte array isn't + reallocated or destroyed. For read-only access, constData() is + faster because it never causes a \l{deep copy} to occur. + + This function is mostly useful to pass a byte array to a function + that accepts a \c{const char *}. + + The following example makes a copy of the char* returned by + data(), but it will corrupt the heap and cause a crash because it + does not allocate a byte for the '\\0' at the end: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 46 + + This one allocates the correct amount of space: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 47 + + Note: A QByteArray can store any byte values including '\\0's, + but most functions that take \c{char *} arguments assume that the + data ends at the first '\\0' they encounter. + + \sa constData(), operator[]() +*/ + +/*! \fn const char *QByteArray::data() const + + \overload +*/ + +/*! \fn const char *QByteArray::constData() const + + Returns a pointer to the data stored in the byte array. The pointer can be + used to access the bytes that compose the array. The data is + '\\0'-terminated unless the QByteArray object was created from raw data. + The pointer remains valid as long as the byte array isn't reallocated or + destroyed. + + This function is mostly useful to pass a byte array to a function + that accepts a \c{const char *}. + + Note: A QByteArray can store any byte values including '\\0's, + but most functions that take \c{char *} arguments assume that the + data ends at the first '\\0' they encounter. + + \sa data(), operator[](), fromRawData() +*/ + +/*! \fn void QByteArray::detach() + + \internal +*/ + +/*! \fn bool QByteArray::isDetached() const + + \internal +*/ + +/*! \fn bool QByteArray::isSharedWith(const QByteArray &other) const + + \internal +*/ + +/*! \fn char QByteArray::at(int i) const + + Returns the character at index position \a i in the byte array. + + \a i must be a valid index position in the byte array (i.e., 0 <= + \a i < size()). + + \sa operator[]() +*/ + +/*! \fn QByteRef QByteArray::operator[](int i) + + Returns the byte at index position \a i as a modifiable reference. + + If an assignment is made beyond the end of the byte array, the + array is extended with resize() before the assignment takes + place. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 9 + + The return value is of type QByteRef, a helper class for + QByteArray. When you get an object of type QByteRef, you can use + it as if it were a char &. If you assign to it, the assignment + will apply to the character in the QByteArray from which you got + the reference. + + \sa at() +*/ + +/*! \fn char QByteArray::operator[](int i) const + + \overload + + Same as at(\a i). +*/ + +/*! \fn QByteRef QByteArray::operator[](uint i) + + \overload +*/ + +/*! \fn char QByteArray::operator[](uint i) const + + \overload +*/ + +/*! \fn QBool QByteArray::contains(const QByteArray &ba) const + + Returns true if the byte array contains an occurrence of the byte + array \a ba; otherwise returns false. + + \sa indexOf(), count() +*/ + +/*! \fn QBool QByteArray::contains(const char *str) const + + \overload + + Returns true if the byte array contains the string \a str; + otherwise returns false. +*/ + +/*! \fn QBool QByteArray::contains(char ch) const + + \overload + + Returns true if the byte array contains the character \a ch; + otherwise returns false. +*/ + +/*! + + Truncates the byte array at index position \a pos. + + If \a pos is beyond the end of the array, nothing happens. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 10 + + \sa chop(), resize(), left() +*/ +void QByteArray::truncate(int pos) +{ + if (pos < d->size) + resize(pos); +} + +/*! + + Removes \a n bytes from the end of the byte array. + + If \a n is greater than size(), the result is an empty byte + array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 11 + + \sa truncate(), resize(), left() +*/ + +void QByteArray::chop(int n) +{ + if (n > 0) + resize(d->size - n); +} + + +/*! \fn QByteArray &QByteArray::operator+=(const QByteArray &ba) + + Appends the byte array \a ba onto the end of this byte array and + returns a reference to this byte array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 12 + + Note: QByteArray is an \l{implicitly shared} class. Consequently, + if \e this is an empty QByteArray, then \e this will just share + the data held in \a ba. In this case, no copying of data is done, + taking \l{constant time}. If a shared instance is modified, it will + be copied (copy-on-write), taking \l{linear time}. + + If \e this is not an empty QByteArray, a deep copy of the data is + performed, taking \l{linear time}. + + This operation typically does not suffer from allocation overhead, + because QByteArray preallocates extra space at the end of the data + so that it may grow without reallocating for each append operation. + + \sa append(), prepend() +*/ + +/*! \fn QByteArray &QByteArray::operator+=(const QString &str) + + \overload + + Appends the string \a str onto the end of this byte array and + returns a reference to this byte array. The Unicode data is + converted into 8-bit characters using QString::toAscii(). + + If the QString contains non-ASCII Unicode characters, using this + operator can lead to loss of information. You can disable this + operator by defining \c QT_NO_CAST_TO_ASCII when you compile your + applications. You then need to call QString::toAscii() (or + QString::toLatin1() or QString::toUtf8() or QString::toLocal8Bit()) + explicitly if you want to convert the data to \c{const char *}. +*/ + +/*! \fn QByteArray &QByteArray::operator+=(const char *str) + + \overload + + Appends the string \a str onto the end of this byte array and + returns a reference to this byte array. +*/ + +/*! \fn QByteArray &QByteArray::operator+=(char ch) + + \overload + + Appends the character \a ch onto the end of this byte array and + returns a reference to this byte array. +*/ + +/*! \fn int QByteArray::length() const + + Same as size(). +*/ + +/*! \fn bool QByteArray::isNull() const + + Returns true if this byte array is null; otherwise returns false. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 13 + + Qt makes a distinction between null byte arrays and empty byte + arrays for historical reasons. For most applications, what + matters is whether or not a byte array contains any data, + and this can be determined using isEmpty(). + + \sa isEmpty() +*/ + +/*! \fn QByteArray::QByteArray() + + Constructs an empty byte array. + + \sa isEmpty() +*/ + +/*! \fn QByteArray::QByteArray(const char *str) + + Constructs a byte array initialized with the string \a str. + + QByteArray makes a deep copy of the string data. +*/ + +QByteArray::QByteArray(const char *str) +{ + if (!str) { + d = &shared_null; + } else if (!*str) { + d = &shared_empty; + } else { + int len = qstrlen(str); + d = static_cast<Data *>(qMalloc(sizeof(Data)+len)); + Q_CHECK_PTR(d); + d->ref = 0;; + d->alloc = d->size = len; + d->data = d->array; + memcpy(d->array, str, len+1); // include null terminator + } + d->ref.ref(); +} + +/*! + Constructs a byte array containing the first \a size bytes of + array \a data. + + If \a data is 0, a null byte array is constructed. + + QByteArray makes a deep copy of the string data. + + \sa fromRawData() +*/ + +QByteArray::QByteArray(const char *data, int size) +{ + if (!data) { + d = &shared_null; + } else if (size <= 0) { + d = &shared_empty; + } else { + d = static_cast<Data *>(qMalloc(sizeof(Data) + size)); + Q_CHECK_PTR(d); + d->ref = 0; + d->alloc = d->size = size; + d->data = d->array; + memcpy(d->array, data, size); + d->array[size] = '\0'; + } + d->ref.ref(); +} + +/*! + Constructs a byte array of size \a size with every byte set to + character \a ch. + + \sa fill() +*/ + +QByteArray::QByteArray(int size, char ch) +{ + if (size <= 0) { + d = &shared_null; + } else { + d = static_cast<Data *>(qMalloc(sizeof(Data)+size)); + Q_CHECK_PTR(d); + d->ref = 0; + d->alloc = d->size = size; + d->data = d->array; + d->array[size] = '\0'; + memset(d->array, ch, size); + } + d->ref.ref(); +} + +/*! + \internal + + Constructs a byte array of size \a size with uninitialized contents. +*/ + +QByteArray::QByteArray(int size, Qt::Initialization) +{ + d = static_cast<Data *>(qMalloc(sizeof(Data)+size)); + Q_CHECK_PTR(d); + d->ref = 1; + d->alloc = d->size = size; + d->data = d->array; + d->array[size] = '\0'; +} + +/*! + Sets the size of the byte array to \a size bytes. + + If \a size is greater than the current size, the byte array is + extended to make it \a size bytes with the extra bytes added to + the end. The new bytes are uninitialized. + + If \a size is less than the current size, bytes are removed from + the end. + + \sa size(), truncate() +*/ + +void QByteArray::resize(int size) +{ + if (size <= 0) { + Data *x = &shared_empty; + x->ref.ref(); + if (!d->ref.deref()) + qFree(d); + d = x; + } else if (d == &shared_null) { + // + // Optimize the idiom: + // QByteArray a; + // a.resize(sz); + // ... + // which is used in place of the Qt 3 idiom: + // QByteArray a(sz); + // + Data *x = static_cast<Data *>(qMalloc(sizeof(Data)+size)); + Q_CHECK_PTR(x); + x->ref = 1; + x->alloc = x->size = size; + x->data = x->array; + x->array[size] = '\0'; + (void) d->ref.deref(); // cannot be 0, x points to shared_null + d = x; + } else { + if (d->ref != 1 || size > d->alloc || (size < d->size && size < d->alloc >> 1)) + realloc(qAllocMore(size, sizeof(Data))); + if (d->alloc >= size) { + d->size = size; + if (d->data == d->array) { + d->array[size] = '\0'; + } + } + } +} + +/*! + Sets every byte in the byte array to character \a ch. If \a size + is different from -1 (the default), the byte array is resized to + size \a size beforehand. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 14 + + \sa resize() +*/ + +QByteArray &QByteArray::fill(char ch, int size) +{ + resize(size < 0 ? d->size : size); + if (d->size) + memset(d->data, ch, d->size); + return *this; +} + +void QByteArray::realloc(int alloc) +{ + if (d->ref != 1 || d->data != d->array) { + Data *x = static_cast<Data *>(qMalloc(sizeof(Data) + alloc)); + Q_CHECK_PTR(x); + x->size = qMin(alloc, d->size); + ::memcpy(x->array, d->data, x->size); + x->array[x->size] = '\0'; + x->ref = 1; + x->alloc = alloc; + x->data = x->array; + if (!d->ref.deref()) + qFree(d); + d = x; + } else { + Data *x = static_cast<Data *>(qRealloc(d, sizeof(Data) + alloc)); + Q_CHECK_PTR(x); + x->alloc = alloc; + x->data = x->array; + d = x; + } +} + +void QByteArray::expand(int i) +{ + resize(qMax(i + 1, d->size)); +} + +/*! + \internal + Return a QByteArray that is sure to be NUL-terminated. + + By default, all QByteArray have an extra NUL at the end, + guaranteeing that assumption. However, if QByteArray::fromRawData + is used, then the NUL is there only if the user put it there. We + can't be sure. +*/ +QByteArray QByteArray::nulTerminated() const +{ + // is this fromRawData? + if (d->data == d->array) + return *this; // no, then we're sure we're zero terminated + + QByteArray copy(*this); + copy.detach(); + return copy; +} + +/*! + Prepends the byte array \a ba to this byte array and returns a + reference to this byte array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 15 + + This is the same as insert(0, \a ba). + + Note: QByteArray is an \l{implicitly shared} class. Consequently, + if \e this is an empty QByteArray, then \e this will just share + the data held in \a ba. In this case, no copying of data is done, + taking \l{constant time}. If a shared instance is modified, it will + be copied (copy-on-write), taking \l{linear time}. + + If \e this is not an empty QByteArray, a deep copy of the data is + performed, taking \l{linear time}. + + \sa append(), insert() +*/ + +QByteArray &QByteArray::prepend(const QByteArray &ba) +{ + if ((d == &shared_null || d == &shared_empty) && !IS_RAW_DATA(ba.d)) { + *this = ba; + } else if (ba.d != &shared_null) { + QByteArray tmp = *this; + *this = ba; + append(tmp); + } + return *this; +} + +/*! + \overload + + Prepends the string \a str to this byte array. +*/ + +QByteArray &QByteArray::prepend(const char *str) +{ + return prepend(str, qstrlen(str)); +} + +/*! + \overload + \since 4.6 + + Prepends \a len bytes of the string \a str to this byte array. +*/ + +QByteArray &QByteArray::prepend(const char *str, int len) +{ + if (str) { + if (d->ref != 1 || d->size + len > d->alloc) + realloc(qAllocMore(d->size + len, sizeof(Data))); + memmove(d->data+len, d->data, d->size); + memcpy(d->data, str, len); + d->size += len; + d->data[d->size] = '\0'; + } + return *this; +} + +/*! + \overload + + Prepends the character \a ch to this byte array. +*/ + +QByteArray &QByteArray::prepend(char ch) +{ + if (d->ref != 1 || d->size + 1 > d->alloc) + realloc(qAllocMore(d->size + 1, sizeof(Data))); + memmove(d->data+1, d->data, d->size); + d->data[0] = ch; + ++d->size; + d->data[d->size] = '\0'; + return *this; +} + +/*! + Appends the byte array \a ba onto the end of this byte array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 16 + + This is the same as insert(size(), \a ba). + + Note: QByteArray is an \l{implicitly shared} class. Consequently, + if \e this is an empty QByteArray, then \e this will just share + the data held in \a ba. In this case, no copying of data is done, + taking \l{constant time}. If a shared instance is modified, it will + be copied (copy-on-write), taking \l{linear time}. + + If \e this is not an empty QByteArray, a deep copy of the data is + performed, taking \l{linear time}. + + This operation typically does not suffer from allocation overhead, + because QByteArray preallocates extra space at the end of the data + so that it may grow without reallocating for each append operation. + + \sa operator+=(), prepend(), insert() +*/ + +QByteArray &QByteArray::append(const QByteArray &ba) +{ + if ((d == &shared_null || d == &shared_empty) && !IS_RAW_DATA(ba.d)) { + *this = ba; + } else if (ba.d != &shared_null) { + if (d->ref != 1 || d->size + ba.d->size > d->alloc) + realloc(qAllocMore(d->size + ba.d->size, sizeof(Data))); + memcpy(d->data + d->size, ba.d->data, ba.d->size); + d->size += ba.d->size; + d->data[d->size] = '\0'; + } + return *this; +} + +/*! \fn QByteArray &QByteArray::append(const QString &str) + + \overload + + Appends the string \a str to this byte array. The Unicode data is + converted into 8-bit characters using QString::toAscii(). + + If the QString contains non-ASCII Unicode characters, using this + function can lead to loss of information. You can disable this + function by defining \c QT_NO_CAST_TO_ASCII when you compile your + applications. You then need to call QString::toAscii() (or + QString::toLatin1() or QString::toUtf8() or QString::toLocal8Bit()) + explicitly if you want to convert the data to \c{const char *}. +*/ + +/*! + \overload + + Appends the string \a str to this byte array. +*/ + +QByteArray& QByteArray::append(const char *str) +{ + if (str) { + int len = qstrlen(str); + if (d->ref != 1 || d->size + len > d->alloc) + realloc(qAllocMore(d->size + len, sizeof(Data))); + memcpy(d->data + d->size, str, len + 1); // include null terminator + d->size += len; + } + return *this; +} + +/*! + \overload append() + + Appends the first \a len characters of the string \a str to this byte + array and returns a reference to this byte array. + + If \a len is negative, the length of the string will be determined + automatically using qstrlen(). If \a len is zero or \a str is + null, nothing is appended to the byte array. Ensure that \a len is + \e not longer than \a str. +*/ + +QByteArray &QByteArray::append(const char *str, int len) +{ + if (len < 0) + len = qstrlen(str); + if (str && len) { + if (d->ref != 1 || d->size + len > d->alloc) + realloc(qAllocMore(d->size + len, sizeof(Data))); + memcpy(d->data + d->size, str, len); // include null terminator + d->size += len; + d->data[d->size] = '\0'; + } + return *this; +} + +/*! + \overload + + Appends the character \a ch to this byte array. +*/ + +QByteArray& QByteArray::append(char ch) +{ + if (d->ref != 1 || d->size + 1 > d->alloc) + realloc(qAllocMore(d->size + 1, sizeof(Data))); + d->data[d->size++] = ch; + d->data[d->size] = '\0'; + return *this; +} + +/*! + \internal + Inserts \a len bytes from the array \a arr at position \a pos and returns a + reference the modified byte array. +*/ +static inline QByteArray &qbytearray_insert(QByteArray *ba, + int pos, const char *arr, int len) +{ + Q_ASSERT(pos >= 0); + + if (pos < 0 || len <= 0 || arr == 0) + return *ba; + + int oldsize = ba->size(); + ba->resize(qMax(pos, oldsize) + len); + char *dst = ba->data(); + if (pos > oldsize) + ::memset(dst + oldsize, 0x20, pos - oldsize); + else + ::memmove(dst + pos + len, dst + pos, oldsize - pos); + memcpy(dst + pos, arr, len); + return *ba; +} + +/*! + Inserts the byte array \a ba at index position \a i and returns a + reference to this byte array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 17 + + \sa append(), prepend(), replace(), remove() +*/ + +QByteArray &QByteArray::insert(int i, const QByteArray &ba) +{ + QByteArray copy(ba); + return qbytearray_insert(this, i, copy.d->data, copy.d->size); +} + +/*! + \fn QByteArray &QByteArray::insert(int i, const QString &str) + + \overload + + Inserts the string \a str at index position \a i in the byte + array. The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + If \a i is greater than size(), the array is first extended using + resize(). + + If the QString contains non-ASCII Unicode characters, using this + function can lead to loss of information. You can disable this + function by defining \c QT_NO_CAST_TO_ASCII when you compile your + applications. You then need to call QString::toAscii() (or + QString::toLatin1() or QString::toUtf8() or QString::toLocal8Bit()) + explicitly if you want to convert the data to \c{const char *}. +*/ + +/*! + \overload + + Inserts the string \a str at position \a i in the byte array. + + If \a i is greater than size(), the array is first extended using + resize(). +*/ + +QByteArray &QByteArray::insert(int i, const char *str) +{ + return qbytearray_insert(this, i, str, qstrlen(str)); +} + +/*! + \overload + \since 4.6 + + Inserts \a len bytes of the string \a str at position + \a i in the byte array. + + If \a i is greater than size(), the array is first extended using + resize(). +*/ + +QByteArray &QByteArray::insert(int i, const char *str, int len) +{ + return qbytearray_insert(this, i, str, len); +} + +/*! + \overload + + Inserts character \a ch at index position \a i in the byte array. + If \a i is greater than size(), the array is first extended using + resize(). +*/ + +QByteArray &QByteArray::insert(int i, char ch) +{ + return qbytearray_insert(this, i, &ch, 1); +} + +/*! + Removes \a len bytes from the array, starting at index position \a + pos, and returns a reference to the array. + + If \a pos is out of range, nothing happens. If \a pos is valid, + but \a pos + \a len is larger than the size of the array, the + array is truncated at position \a pos. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 18 + + \sa insert(), replace() +*/ + +QByteArray &QByteArray::remove(int pos, int len) +{ + if (len <= 0 || pos >= d->size || pos < 0) + return *this; + detach(); + if (pos + len >= d->size) { + resize(pos); + } else { + memmove(d->data + pos, d->data + pos + len, d->size - pos - len); + resize(d->size - len); + } + return *this; +} + +/*! + Replaces \a len bytes from index position \a pos with the byte + array \a after, and returns a reference to this byte array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 19 + + \sa insert(), remove() +*/ + +QByteArray &QByteArray::replace(int pos, int len, const QByteArray &after) +{ + if (len == after.d->size && (pos + len <= d->size)) { + detach(); + memmove(d->data + pos, after.d->data, len*sizeof(char)); + return *this; + } else { + QByteArray copy(after); + // ### optimize me + remove(pos, len); + return insert(pos, copy); + } +} + +/*! \fn QByteArray &QByteArray::replace(int pos, int len, const char *after) + + \overload + + Replaces \a len bytes from index position \a pos with the zero terminated + string \a after. + + Notice: this can change the length of the byte array. +*/ +QByteArray &QByteArray::replace(int pos, int len, const char *after) +{ + return replace(pos,len,after,qstrlen(after)); +} + +/*! \fn QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen) + + \overload + + Replaces \a len bytes from index position \a pos with \a alen bytes + from the string \a after. \a after is allowed to have '\0' characters. + + \since 4.7 +*/ +QByteArray &QByteArray::replace(int pos, int len, const char *after, int alen) +{ + if (len == alen && (pos + len <= d->size)) { + detach(); + memcpy(d->data + pos, after, len*sizeof(char)); + return *this; + } else { + remove(pos, len); + return qbytearray_insert(this, pos, after, alen); + } +} + +// ### optimize all other replace method, by offering +// QByteArray::replace(const char *before, int blen, const char *after, int alen) + +/*! + \overload + + Replaces every occurrence of the byte array \a before with the + byte array \a after. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 20 +*/ + +QByteArray &QByteArray::replace(const QByteArray &before, const QByteArray &after) +{ + if (isNull() || before.d == after.d) + return *this; + + QByteArray aft = after; + if (after.d == d) + aft.detach(); + + return replace(before.constData(), before.size(), aft.constData(), aft.size()); +} + +/*! + \fn QByteArray &QByteArray::replace(const char *before, const QByteArray &after) + \overload + + Replaces every occurrence of the string \a before with the + byte array \a after. +*/ + +QByteArray &QByteArray::replace(const char *c, const QByteArray &after) +{ + QByteArray aft = after; + if (after.d == d) + aft.detach(); + + return replace(c, qstrlen(c), aft.constData(), aft.size()); +} + +/*! + \fn QByteArray &QByteArray::replace(const char *before, int bsize, const char *after, int asize) + \overload + + Replaces every occurrence of the string \a before with the string \a after. + Since the sizes of the strings are given by \a bsize and \a asize, they + may contain zero characters and do not need to be zero-terminated. +*/ + +QByteArray &QByteArray::replace(const char *before, int bsize, const char *after, int asize) +{ + if (isNull() || (before == after && bsize == asize)) + return *this; + + // protect against before or after being part of this + const char *a = after; + const char *b = before; + if (after >= d->data && after < d->data + d->size) { + char *copy = (char *)malloc(asize); + Q_CHECK_PTR(copy); + memcpy(copy, after, asize); + a = copy; + } + if (before >= d->data && before < d->data + d->size) { + char *copy = (char *)malloc(bsize); + Q_CHECK_PTR(copy); + memcpy(copy, before, bsize); + b = copy; + } + + QByteArrayMatcher matcher(before, bsize); + int index = 0; + int len = d->size; + char *d = data(); + + if (bsize == asize) { + if (bsize) { + while ((index = matcher.indexIn(*this, index)) != -1) { + memcpy(d + index, after, asize); + index += bsize; + } + } + } else if (asize < bsize) { + uint to = 0; + uint movestart = 0; + uint num = 0; + while ((index = matcher.indexIn(*this, index)) != -1) { + if (num) { + int msize = index - movestart; + if (msize > 0) { + memmove(d + to, d + movestart, msize); + to += msize; + } + } else { + to = index; + } + if (asize) { + memcpy(d + to, after, asize); + to += asize; + } + index += bsize; + movestart = index; + num++; + } + if (num) { + int msize = len - movestart; + if (msize > 0) + memmove(d + to, d + movestart, msize); + resize(len - num*(bsize-asize)); + } + } else { + // the most complex case. We don't want to lose performance by doing repeated + // copies and reallocs of the string. + while (index != -1) { + uint indices[4096]; + uint pos = 0; + while(pos < 4095) { + index = matcher.indexIn(*this, index); + if (index == -1) + break; + indices[pos++] = index; + index += bsize; + // avoid infinite loop + if (!bsize) + index++; + } + if (!pos) + break; + + // we have a table of replacement positions, use them for fast replacing + int adjust = pos*(asize-bsize); + // index has to be adjusted in case we get back into the loop above. + if (index != -1) + index += adjust; + int newlen = len + adjust; + int moveend = len; + if (newlen > len) { + resize(newlen); + len = newlen; + } + d = this->d->data; + + while(pos) { + pos--; + int movestart = indices[pos] + bsize; + int insertstart = indices[pos] + pos*(asize-bsize); + int moveto = insertstart + asize; + memmove(d + moveto, d + movestart, (moveend - movestart)); + if (asize) + memcpy(d + insertstart, after, asize); + moveend = movestart - bsize; + } + } + } + + if (a != after) + ::free((char *)a); + if (b != before) + ::free((char *)b); + + + return *this; +} + + +/*! + \fn QByteArray &QByteArray::replace(const QByteArray &before, const char *after) + \overload + + Replaces every occurrence of the byte array \a before with the + string \a after. +*/ + +/*! \fn QByteArray &QByteArray::replace(const QString &before, const QByteArray &after) + + \overload + + Replaces every occurrence of the string \a before with the byte + array \a after. The Unicode data is converted into 8-bit + characters using QString::toAscii(). + + If the QString contains non-ASCII Unicode characters, using this + function can lead to loss of information. You can disable this + function by defining \c QT_NO_CAST_TO_ASCII when you compile your + applications. You then need to call QString::toAscii() (or + QString::toLatin1() or QString::toUtf8() or QString::toLocal8Bit()) + explicitly if you want to convert the data to \c{const char *}. +*/ + +/*! \fn QByteArray &QByteArray::replace(const QString &before, const char *after) + \overload + + Replaces every occurrence of the string \a before with the string + \a after. +*/ + +/*! \fn QByteArray &QByteArray::replace(const char *before, const char *after) + + \overload + + Replaces every occurrence of the string \a before with the string + \a after. +*/ + +/*! + \overload + + Replaces every occurrence of the character \a before with the + byte array \a after. +*/ + +QByteArray &QByteArray::replace(char before, const QByteArray &after) +{ + char b[2] = { before, '\0' }; + QByteArray cb = fromRawData(b, 1); + return replace(cb, after); +} + +/*! \fn QByteArray &QByteArray::replace(char before, const QString &after) + + \overload + + Replaces every occurrence of the character \a before with the + string \a after. The Unicode data is converted into 8-bit + characters using QString::toAscii(). + + If the QString contains non-ASCII Unicode characters, using this + function can lead to loss of information. You can disable this + function by defining \c QT_NO_CAST_TO_ASCII when you compile your + applications. You then need to call QString::toAscii() (or + QString::toLatin1() or QString::toUtf8() or QString::toLocal8Bit()) + explicitly if you want to convert the data to \c{const char *}. +*/ + +/*! \fn QByteArray &QByteArray::replace(char before, const char *after) + + \overload + + Replaces every occurrence of the character \a before with the + string \a after. +*/ + +/*! + \overload + + Replaces every occurrence of the character \a before with the + character \a after. +*/ + +QByteArray &QByteArray::replace(char before, char after) +{ + if (d->size) { + char *i = data(); + char *e = i + d->size; + for (; i != e; ++i) + if (*i == before) + * i = after; + } + return *this; +} + +/*! + Splits the byte array into subarrays wherever \a sep occurs, and + returns the list of those arrays. If \a sep does not match + anywhere in the byte array, split() returns a single-element list + containing this byte array. +*/ + +QList<QByteArray> QByteArray::split(char sep) const +{ + QList<QByteArray> list; + int start = 0; + int end; + while ((end = indexOf(sep, start)) != -1) { + list.append(mid(start, end - start)); + start = end + 1; + } + list.append(mid(start)); + return list; +} + +/*! + \since 4.5 + + Returns a copy of this byte array repeated the specified number of \a times. + + If \a times is less than 1, an empty byte array is returned. + + Example: + + \code + QByteArray ba("ab"); + ba.repeated(4); // returns "abababab" + \endcode +*/ +QByteArray QByteArray::repeated(int times) const +{ + if (d->size == 0) + return *this; + + if (times <= 1) { + if (times == 1) + return *this; + return QByteArray(); + } + + const int resultSize = times * d->size; + + QByteArray result; + result.reserve(resultSize); + if (result.d->alloc != resultSize) + return QByteArray(); // not enough memory + + memcpy(result.d->data, d->data, d->size); + + int sizeSoFar = d->size; + char *end = result.d->data + sizeSoFar; + + const int halfResultSize = resultSize >> 1; + while (sizeSoFar <= halfResultSize) { + memcpy(end, result.d->data, sizeSoFar); + end += sizeSoFar; + sizeSoFar <<= 1; + } + memcpy(end, result.d->data, resultSize - sizeSoFar); + result.d->data[resultSize] = '\0'; + result.d->size = resultSize; + return result; +} + +#define REHASH(a) \ + if (ol_minus_1 < sizeof(uint) * CHAR_BIT) \ + hashHaystack -= (a) << ol_minus_1; \ + hashHaystack <<= 1 + +/*! + Returns the index position of the first occurrence of the byte + array \a ba in this byte array, searching forward from index + position \a from. Returns -1 if \a ba could not be found. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 21 + + \sa lastIndexOf(), contains(), count() +*/ + +int QByteArray::indexOf(const QByteArray &ba, int from) const +{ + const int ol = ba.d->size; + if (ol == 0) + return from; + if (ol == 1) + return indexOf(*ba.d->data, from); + + const int l = d->size; + if (from > d->size || ol + from > l) + return -1; + + return qFindByteArray(d->data, d->size, from, ba.d->data, ol); +} + +/*! \fn int QByteArray::indexOf(const QString &str, int from) const + + \overload + + Returns the index position of the first occurrence of the string + \a str in the byte array, searching forward from index position + \a from. Returns -1 if \a str could not be found. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + If the QString contains non-ASCII Unicode characters, using this + function can lead to loss of information. You can disable this + function by defining \c QT_NO_CAST_TO_ASCII when you compile your + applications. You then need to call QString::toAscii() (or + QString::toLatin1() or QString::toUtf8() or QString::toLocal8Bit()) + explicitly if you want to convert the data to \c{const char *}. +*/ + +/*! \fn int QByteArray::indexOf(const char *str, int from) const + + \overload + + Returns the index position of the first occurrence of the string + \a str in the byte array, searching forward from index position \a + from. Returns -1 if \a str could not be found. +*/ +int QByteArray::indexOf(const char *c, int from) const +{ + const int ol = qstrlen(c); + if (ol == 1) + return indexOf(*c, from); + + const int l = d->size; + if (from > d->size || ol + from > l) + return -1; + if (ol == 0) + return from; + + return qFindByteArray(d->data, d->size, from, c, ol); +} + +/*! + \overload + + Returns the index position of the first occurrence of the + character \a ch in the byte array, searching forward from index + position \a from. Returns -1 if \a ch could not be found. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 22 + + \sa lastIndexOf(), contains() +*/ + +int QByteArray::indexOf(char ch, int from) const +{ + if (from < 0) + from = qMax(from + d->size, 0); + if (from < d->size) { + const char *n = d->data + from - 1; + const char *e = d->data + d->size; + while (++n != e) + if (*n == ch) + return n - d->data; + } + return -1; +} + + +static int lastIndexOfHelper(const char *haystack, int l, const char *needle, int ol, int from) +{ + int delta = l - ol; + if (from < 0) + from = delta; + if (from < 0 || from > l) + return -1; + if (from > delta) + from = delta; + + const char *end = haystack; + haystack += from; + const uint ol_minus_1 = ol - 1; + const char *n = needle + ol_minus_1; + const char *h = haystack + ol_minus_1; + uint hashNeedle = 0, hashHaystack = 0; + int idx; + for (idx = 0; idx < ol; ++idx) { + hashNeedle = ((hashNeedle<<1) + *(n-idx)); + hashHaystack = ((hashHaystack<<1) + *(h-idx)); + } + hashHaystack -= *haystack; + while (haystack >= end) { + hashHaystack += *haystack; + if (hashHaystack == hashNeedle && memcmp(needle, haystack, ol) == 0) + return haystack - end; + --haystack; + REHASH(*(haystack + ol)); + } + return -1; + +} + +/*! + \fn int QByteArray::lastIndexOf(const QByteArray &ba, int from) const + + Returns the index position of the last occurrence of the byte + array \a ba in this byte array, searching backward from index + position \a from. If \a from is -1 (the default), the search + starts at the last byte. Returns -1 if \a ba could not be found. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 23 + + \sa indexOf(), contains(), count() +*/ + +int QByteArray::lastIndexOf(const QByteArray &ba, int from) const +{ + const int ol = ba.d->size; + if (ol == 1) + return lastIndexOf(*ba.d->data, from); + + return lastIndexOfHelper(d->data, d->size, ba.d->data, ol, from); +} + +/*! \fn int QByteArray::lastIndexOf(const QString &str, int from) const + + \overload + + Returns the index position of the last occurrence of the string \a + str in the byte array, searching backward from index position \a + from. If \a from is -1 (the default), the search starts at the + last (size() - 1) byte. Returns -1 if \a str could not be found. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + If the QString contains non-ASCII Unicode characters, using this + function can lead to loss of information. You can disable this + function by defining \c QT_NO_CAST_TO_ASCII when you compile your + applications. You then need to call QString::toAscii() (or + QString::toLatin1() or QString::toUtf8() or QString::toLocal8Bit()) + explicitly if you want to convert the data to \c{const char *}. +*/ + +/*! \fn int QByteArray::lastIndexOf(const char *str, int from) const + \overload + + Returns the index position of the last occurrence of the string \a + str in the byte array, searching backward from index position \a + from. If \a from is -1 (the default), the search starts at the + last (size() - 1) byte. Returns -1 if \a str could not be found. +*/ +int QByteArray::lastIndexOf(const char *str, int from) const +{ + const int ol = qstrlen(str); + if (ol == 1) + return lastIndexOf(*str, from); + + return lastIndexOfHelper(d->data, d->size, str, ol, from); +} + +/*! + \overload + + Returns the index position of the last occurrence of character \a + ch in the byte array, searching backward from index position \a + from. If \a from is -1 (the default), the search starts at the + last (size() - 1) byte. Returns -1 if \a ch could not be found. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 24 + + \sa indexOf(), contains() +*/ + +int QByteArray::lastIndexOf(char ch, int from) const +{ + if (from < 0) + from += d->size; + else if (from > d->size) + from = d->size-1; + if (from >= 0) { + const char *b = d->data; + const char *n = d->data + from + 1; + while (n-- != b) + if (*n == ch) + return n - b; + } + return -1; +} + +/*! + Returns the number of (potentially overlapping) occurrences of + byte array \a ba in this byte array. + + \sa contains(), indexOf() +*/ + +int QByteArray::count(const QByteArray &ba) const +{ + int num = 0; + int i = -1; + if (d->size > 500 && ba.d->size > 5) { + QByteArrayMatcher matcher(ba); + while ((i = matcher.indexIn(*this, i + 1)) != -1) + ++num; + } else { + while ((i = indexOf(ba, i + 1)) != -1) + ++num; + } + return num; +} + +/*! + \overload + + Returns the number of (potentially overlapping) occurrences of + string \a str in the byte array. +*/ + +int QByteArray::count(const char *str) const +{ + return count(fromRawData(str, qstrlen(str))); +} + +/*! + \overload + + Returns the number of occurrences of character \a ch in the byte + array. + + \sa contains(), indexOf() +*/ + +int QByteArray::count(char ch) const +{ + int num = 0; + const char *i = d->data + d->size; + const char *b = d->data; + while (i != b) + if (*--i == ch) + ++num; + return num; +} + +/*! \fn int QByteArray::count() const + + \overload + + Same as size(). +*/ + +/*! + Returns true if this byte array starts with byte array \a ba; + otherwise returns false. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 25 + + \sa endsWith(), left() +*/ +bool QByteArray::startsWith(const QByteArray &ba) const +{ + if (d == ba.d || ba.d->size == 0) + return true; + if (d->size < ba.d->size) + return false; + return memcmp(d->data, ba.d->data, ba.d->size) == 0; +} + +/*! \overload + + Returns true if this byte array starts with string \a str; + otherwise returns false. +*/ +bool QByteArray::startsWith(const char *str) const +{ + if (!str || !*str) + return true; + int len = qstrlen(str); + if (d->size < len) + return false; + return qstrncmp(d->data, str, len) == 0; +} + +/*! \overload + + Returns true if this byte array starts with character \a ch; + otherwise returns false. +*/ +bool QByteArray::startsWith(char ch) const +{ + if (d->size == 0) + return false; + return d->data[0] == ch; +} + +/*! + Returns true if this byte array ends with byte array \a ba; + otherwise returns false. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 26 + + \sa startsWith(), right() +*/ +bool QByteArray::endsWith(const QByteArray &ba) const +{ + if (d == ba.d || ba.d->size == 0) + return true; + if (d->size < ba.d->size) + return false; + return memcmp(d->data + d->size - ba.d->size, ba.d->data, ba.d->size) == 0; +} + +/*! \overload + + Returns true if this byte array ends with string \a str; otherwise + returns false. +*/ +bool QByteArray::endsWith(const char *str) const +{ + if (!str || !*str) + return true; + int len = qstrlen(str); + if (d->size < len) + return false; + return qstrncmp(d->data + d->size - len, str, len) == 0; +} + +/*! \overload + + Returns true if this byte array ends with character \a ch; + otherwise returns false. +*/ +bool QByteArray::endsWith(char ch) const +{ + if (d->size == 0) + return false; + return d->data[d->size - 1] == ch; +} + +/*! + Returns a byte array that contains the leftmost \a len bytes of + this byte array. + + The entire byte array is returned if \a len is greater than + size(). + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 27 + + \sa right(), mid(), startsWith(), truncate() +*/ + +QByteArray QByteArray::left(int len) const +{ + if (len >= d->size) + return *this; + if (len < 0) + len = 0; + return QByteArray(d->data, len); +} + +/*! + Returns a byte array that contains the rightmost \a len bytes of + this byte array. + + The entire byte array is returned if \a len is greater than + size(). + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 28 + + \sa endsWith(), left(), mid() +*/ + +QByteArray QByteArray::right(int len) const +{ + if (len >= d->size) + return *this; + if (len < 0) + len = 0; + return QByteArray(d->data + d->size - len, len); +} + +/*! + Returns a byte array containing \a len bytes from this byte array, + starting at position \a pos. + + If \a len is -1 (the default), or \a pos + \a len >= size(), + returns a byte array containing all bytes starting at position \a + pos until the end of the byte array. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 29 + + \sa left(), right() +*/ + +QByteArray QByteArray::mid(int pos, int len) const +{ + if (d == &shared_null || d == &shared_empty || pos >= d->size) + return QByteArray(); + if (len < 0) + len = d->size - pos; + if (pos < 0) { + len += pos; + pos = 0; + } + if (len + pos > d->size) + len = d->size - pos; + if (pos == 0 && len == d->size) + return *this; + return QByteArray(d->data + pos, len); +} + +/*! + Returns a lowercase copy of the byte array. The bytearray is + interpreted as a Latin-1 encoded string. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 30 + + \sa toUpper(), {8-bit Character Comparisons} +*/ +QByteArray QByteArray::toLower() const +{ + QByteArray s(*this); + register uchar *p = reinterpret_cast<uchar *>(s.data()); + if (p) { + while (*p) { + *p = QChar::toLower((ushort)*p); + p++; + } + } + return s; +} + +/*! + Returns an uppercase copy of the byte array. The bytearray is + interpreted as a Latin-1 encoded string. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 31 + + \sa toLower(), {8-bit Character Comparisons} +*/ + +QByteArray QByteArray::toUpper() const +{ + QByteArray s(*this); + register uchar *p = reinterpret_cast<uchar *>(s.data()); + if (p) { + while (*p) { + *p = QChar::toUpper((ushort)*p); + p++; + } + } + return s; +} + +/*! \fn void QByteArray::clear() + + Clears the contents of the byte array and makes it empty. + + \sa resize(), isEmpty() +*/ + +void QByteArray::clear() +{ + if (!d->ref.deref()) + qFree(d); + d = &shared_null; + d->ref.ref(); +} + +#if !defined(QT_NO_DATASTREAM) || (defined(QT_BOOTSTRAPPED) && !defined(QT_BUILD_QMAKE)) + +/*! \relates QByteArray + + Writes byte array \a ba to the stream \a out and returns a reference + to the stream. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator<<(QDataStream &out, const QByteArray &ba) +{ + if (ba.isNull() && out.version() >= 6) { + out << (quint32)0xffffffff; + return out; + } + return out.writeBytes(ba, ba.size()); +} + +/*! \relates QByteArray + + Reads a byte array into \a ba from the stream \a in and returns a + reference to the stream. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator>>(QDataStream &in, QByteArray &ba) +{ + ba.clear(); + quint32 len; + in >> len; + if (len == 0xffffffff) + return in; + + const quint32 Step = 1024 * 1024; + quint32 allocated = 0; + + do { + int blockSize = qMin(Step, len - allocated); + ba.resize(allocated + blockSize); + if (in.readRawData(ba.data() + allocated, blockSize) != blockSize) { + ba.clear(); + in.setStatus(QDataStream::ReadPastEnd); + return in; + } + allocated += blockSize; + } while (allocated < len); + + return in; +} +#endif // QT_NO_DATASTREAM + +/*! \fn bool QByteArray::operator==(const QString &str) const + + Returns true if this byte array is equal to string \a str; + otherwise returns false. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + The comparison is case sensitive. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. You + then need to call QString::fromAscii(), QString::fromLatin1(), + QString::fromUtf8(), or QString::fromLocal8Bit() explicitly if + you want to convert the byte array to a QString before doing the + comparison. +*/ + +/*! \fn bool QByteArray::operator!=(const QString &str) const + + Returns true if this byte array is not equal to string \a str; + otherwise returns false. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + The comparison is case sensitive. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. You + then need to call QString::fromAscii(), QString::fromLatin1(), + QString::fromUtf8(), or QString::fromLocal8Bit() explicitly if + you want to convert the byte array to a QString before doing the + comparison. +*/ + +/*! \fn bool QByteArray::operator<(const QString &str) const + + Returns true if this byte array is lexically less than string \a + str; otherwise returns false. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + The comparison is case sensitive. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. You + then need to call QString::fromAscii(), QString::fromLatin1(), + QString::fromUtf8(), or QString::fromLocal8Bit() explicitly if + you want to convert the byte array to a QString before doing the + comparison. +*/ + +/*! \fn bool QByteArray::operator>(const QString &str) const + + Returns true if this byte array is lexically greater than string + \a str; otherwise returns false. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + The comparison is case sensitive. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. You + then need to call QString::fromAscii(), QString::fromLatin1(), + QString::fromUtf8(), or QString::fromLocal8Bit() explicitly if + you want to convert the byte array to a QString before doing the + comparison. +*/ + +/*! \fn bool QByteArray::operator<=(const QString &str) const + + Returns true if this byte array is lexically less than or equal + to string \a str; otherwise returns false. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + The comparison is case sensitive. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. You + then need to call QString::fromAscii(), QString::fromLatin1(), + QString::fromUtf8(), or QString::fromLocal8Bit() explicitly if + you want to convert the byte array to a QString before doing the + comparison. +*/ + +/*! \fn bool QByteArray::operator>=(const QString &str) const + + Returns true if this byte array is greater than or equal to string + \a str; otherwise returns false. + + The Unicode data is converted into 8-bit characters using + QString::toAscii(). + + The comparison is case sensitive. + + You can disable this operator by defining \c + QT_NO_CAST_FROM_ASCII when you compile your applications. You + then need to call QString::fromAscii(), QString::fromLatin1(), + QString::fromUtf8(), or QString::fromLocal8Bit() explicitly if + you want to convert the byte array to a QString before doing the + comparison. +*/ + +/*! \fn bool operator==(const QByteArray &a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is equal to byte array \a a2; + otherwise returns false. +*/ + +/*! \fn bool operator==(const QByteArray &a1, const char *a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is equal to string \a a2; + otherwise returns false. +*/ + +/*! \fn bool operator==(const char *a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if string \a a1 is equal to byte array \a a2; + otherwise returns false. +*/ + +/*! \fn bool operator!=(const QByteArray &a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is not equal to byte array \a a2; + otherwise returns false. +*/ + +/*! \fn bool operator!=(const QByteArray &a1, const char *a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is not equal to string \a a2; + otherwise returns false. +*/ + +/*! \fn bool operator!=(const char *a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if string \a a1 is not equal to byte array \a a2; + otherwise returns false. +*/ + +/*! \fn bool operator<(const QByteArray &a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically less than byte array + \a a2; otherwise returns false. +*/ + +/*! \fn inline bool operator<(const QByteArray &a1, const char *a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically less than string + \a a2; otherwise returns false. +*/ + +/*! \fn bool operator<(const char *a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if string \a a1 is lexically less than byte array + \a a2; otherwise returns false. +*/ + +/*! \fn bool operator<=(const QByteArray &a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically less than or equal + to byte array \a a2; otherwise returns false. +*/ + +/*! \fn bool operator<=(const QByteArray &a1, const char *a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically less than or equal + to string \a a2; otherwise returns false. +*/ + +/*! \fn bool operator<=(const char *a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if string \a a1 is lexically less than or equal + to byte array \a a2; otherwise returns false. +*/ + +/*! \fn bool operator>(const QByteArray &a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically greater than byte + array \a a2; otherwise returns false. +*/ + +/*! \fn bool operator>(const QByteArray &a1, const char *a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically greater than string + \a a2; otherwise returns false. +*/ + +/*! \fn bool operator>(const char *a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if string \a a1 is lexically greater than byte array + \a a2; otherwise returns false. +*/ + +/*! \fn bool operator>=(const QByteArray &a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically greater than or + equal to byte array \a a2; otherwise returns false. +*/ + +/*! \fn bool operator>=(const QByteArray &a1, const char *a2) + \relates QByteArray + + \overload + + Returns true if byte array \a a1 is lexically greater than or + equal to string \a a2; otherwise returns false. +*/ + +/*! \fn bool operator>=(const char *a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns true if string \a a1 is lexically greater than or + equal to byte array \a a2; otherwise returns false. +*/ + +/*! \fn const QByteArray operator+(const QByteArray &a1, const QByteArray &a2) + \relates QByteArray + + Returns a byte array that is the result of concatenating byte + array \a a1 and byte array \a a2. + + \sa QByteArray::operator+=() +*/ + +/*! \fn const QByteArray operator+(const QByteArray &a1, const char *a2) + \relates QByteArray + + \overload + + Returns a byte array that is the result of concatenating byte + array \a a1 and string \a a2. +*/ + +/*! \fn const QByteArray operator+(const QByteArray &a1, char a2) + \relates QByteArray + + \overload + + Returns a byte array that is the result of concatenating byte + array \a a1 and character \a a2. +*/ + +/*! \fn const QByteArray operator+(const char *a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns a byte array that is the result of concatenating string + \a a1 and byte array \a a2. +*/ + +/*! \fn const QByteArray operator+(char a1, const QByteArray &a2) + \relates QByteArray + + \overload + + Returns a byte array that is the result of concatenating character + \a a1 and byte array \a a2. +*/ + +/*! + Returns a byte array that has whitespace removed from the start + and the end, and which has each sequence of internal whitespace + replaced with a single space. + + Whitespace means any character for which the standard C++ + isspace() function returns true. This includes the ASCII + characters '\\t', '\\n', '\\v', '\\f', '\\r', and ' '. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 32 + + \sa trimmed() +*/ +QByteArray QByteArray::simplified() const +{ + if (d->size == 0) + return *this; + QByteArray result(d->size, Qt::Uninitialized); + const char *from = d->data; + const char *fromend = from + d->size; + int outc=0; + char *to = result.d->data; + for (;;) { + while (from!=fromend && isspace(uchar(*from))) + from++; + while (from!=fromend && !isspace(uchar(*from))) + to[outc++] = *from++; + if (from!=fromend) + to[outc++] = ' '; + else + break; + } + if (outc > 0 && to[outc-1] == ' ') + outc--; + result.resize(outc); + return result; +} + +/*! + Returns a byte array that has whitespace removed from the start + and the end. + + Whitespace means any character for which the standard C++ + isspace() function returns true. This includes the ASCII + characters '\\t', '\\n', '\\v', '\\f', '\\r', and ' '. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 33 + + Unlike simplified(), trimmed() leaves internal whitespace alone. + + \sa simplified() +*/ +QByteArray QByteArray::trimmed() const +{ + if (d->size == 0) + return *this; + const char *s = d->data; + if (!isspace(uchar(*s)) && !isspace(uchar(s[d->size-1]))) + return *this; + int start = 0; + int end = d->size - 1; + while (start<=end && isspace(uchar(s[start]))) // skip white space from start + start++; + if (start <= end) { // only white space + while (end && isspace(uchar(s[end]))) // skip white space from end + end--; + } + int l = end - start + 1; + if (l <= 0) { + shared_empty.ref.ref(); + return QByteArray(&shared_empty, 0, 0); + } + return QByteArray(s+start, l); +} + +/*! + Returns a byte array of size \a width that contains this byte + array padded by the \a fill character. + + If \a truncate is false and the size() of the byte array is more + than \a width, then the returned byte array is a copy of this byte + array. + + If \a truncate is true and the size() of the byte array is more + than \a width, then any bytes in a copy of the byte array + after position \a width are removed, and the copy is returned. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 34 + + \sa rightJustified() +*/ + +QByteArray QByteArray::leftJustified(int width, char fill, bool truncate) const +{ + QByteArray result; + int len = d->size; + int padlen = width - len; + if (padlen > 0) { + result.resize(len+padlen); + if (len) + memcpy(result.d->data, d->data, len); + memset(result.d->data+len, fill, padlen); + } else { + if (truncate) + result = left(width); + else + result = *this; + } + return result; +} + +/*! + Returns a byte array of size \a width that contains the \a fill + character followed by this byte array. + + If \a truncate is false and the size of the byte array is more + than \a width, then the returned byte array is a copy of this byte + array. + + If \a truncate is true and the size of the byte array is more + than \a width, then the resulting byte array is truncated at + position \a width. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 35 + + \sa leftJustified() +*/ + +QByteArray QByteArray::rightJustified(int width, char fill, bool truncate) const +{ + QByteArray result; + int len = d->size; + int padlen = width - len; + if (padlen > 0) { + result.resize(len+padlen); + if (len) + memcpy(result.d->data+padlen, data(), len); + memset(result.d->data, fill, padlen); + } else { + if (truncate) + result = left(width); + else + result = *this; + } + return result; +} + +bool QByteArray::isNull() const { return d == &shared_null; } + + +/*! + Returns the byte array converted to a \c {long long} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +qlonglong QByteArray::toLongLong(bool *ok, int base) const +{ +#if defined(QT_CHECK_RANGE) + if (base != 0 && (base < 2 || base > 36)) { + qWarning("QByteArray::toLongLong: Invalid base %d", base); + base = 10; + } +#endif + + return QLocalePrivate::bytearrayToLongLong(nulTerminated().constData(), base, ok); +} + +/*! + Returns the byte array converted to an \c {unsigned long long} + using base \a base, which is 10 by default and must be between 2 + and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +qulonglong QByteArray::toULongLong(bool *ok, int base) const +{ +#if defined(QT_CHECK_RANGE) + if (base != 0 && (base < 2 || base > 36)) { + qWarning("QByteArray::toULongLong: Invalid base %d", base); + base = 10; + } +#endif + + return QLocalePrivate::bytearrayToUnsLongLong(nulTerminated().constData(), base, ok); +} + + +/*! + Returns the byte array converted to an \c int using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 36 + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +int QByteArray::toInt(bool *ok, int base) const +{ + qlonglong v = toLongLong(ok, base); + if (v < INT_MIN || v > INT_MAX) { + if (ok) + *ok = false; + v = 0; + } + return int(v); +} + +/*! + Returns the byte array converted to an \c {unsigned int} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +uint QByteArray::toUInt(bool *ok, int base) const +{ + qulonglong v = toULongLong(ok, base); + if (v > UINT_MAX) { + if (ok) + *ok = false; + v = 0; + } + return uint(v); +} + +/*! + \since 4.1 + + Returns the byte array converted to a \c long int using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 37 + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ +long QByteArray::toLong(bool *ok, int base) const +{ + qlonglong v = toLongLong(ok, base); + if (v < LONG_MIN || v > LONG_MAX) { + if (ok) + *ok = false; + v = 0; + } + return long(v); +} + +/*! + \since 4.1 + + Returns the byte array converted to an \c {unsigned long int} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ +ulong QByteArray::toULong(bool *ok, int base) const +{ + qulonglong v = toULongLong(ok, base); + if (v > ULONG_MAX) { + if (ok) + *ok = false; + v = 0; + } + return ulong(v); +} + +/*! + Returns the byte array converted to a \c short using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +short QByteArray::toShort(bool *ok, int base) const +{ + qlonglong v = toLongLong(ok, base); + if (v < SHRT_MIN || v > SHRT_MAX) { + if (ok) + *ok = false; + v = 0; + } + return short(v); +} + +/*! + Returns the byte array converted to an \c {unsigned short} using base \a + base, which is 10 by default and must be between 2 and 36, or 0. + + If \a base is 0, the base is determined automatically using the + following rules: If the byte array begins with "0x", it is assumed to + be hexadecimal; if it begins with "0", it is assumed to be octal; + otherwise it is assumed to be decimal. + + Returns 0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +ushort QByteArray::toUShort(bool *ok, int base) const +{ + qulonglong v = toULongLong(ok, base); + if (v > USHRT_MAX) { + if (ok) + *ok = false; + v = 0; + } + return ushort(v); +} + + +/*! + Returns the byte array converted to a \c double value. + + Returns 0.0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 38 + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +double QByteArray::toDouble(bool *ok) const +{ + return QLocalePrivate::bytearrayToDouble(nulTerminated().constData(), ok); +} + +/*! + Returns the byte array converted to a \c float value. + + Returns 0.0 if the conversion fails. + + If \a ok is not 0: if a conversion error occurs, *\a{ok} is set to + false; otherwise *\a{ok} is set to true. + + \note The conversion of the number is performed in the default C locale, + irrespective of the user's locale. + + \sa number() +*/ + +float QByteArray::toFloat(bool *ok) const +{ + return float(toDouble(ok)); +} + +/*! + Returns a copy of the byte array, encoded as Base64. + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 39 + + The algorithm used to encode Base64-encoded data is defined in \l{RFC 2045}. + + \sa fromBase64() +*/ +QByteArray QByteArray::toBase64() const +{ + const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef" + "ghijklmn" "opqrstuv" "wxyz0123" "456789+/"; + const char padchar = '='; + int padlen = 0; + + QByteArray tmp((d->size * 4) / 3 + 3, Qt::Uninitialized); + + int i = 0; + char *out = tmp.data(); + while (i < d->size) { + int chunk = 0; + chunk |= int(uchar(d->data[i++])) << 16; + if (i == d->size) { + padlen = 2; + } else { + chunk |= int(uchar(d->data[i++])) << 8; + if (i == d->size) padlen = 1; + else chunk |= int(uchar(d->data[i++])); + } + + int j = (chunk & 0x00fc0000) >> 18; + int k = (chunk & 0x0003f000) >> 12; + int l = (chunk & 0x00000fc0) >> 6; + int m = (chunk & 0x0000003f); + *out++ = alphabet[j]; + *out++ = alphabet[k]; + if (padlen > 1) *out++ = padchar; + else *out++ = alphabet[l]; + if (padlen > 0) *out++ = padchar; + else *out++ = alphabet[m]; + } + + tmp.truncate(out - tmp.data()); + return tmp; +} + +/*! + \fn QByteArray &QByteArray::setNum(int n, int base) + + Sets the byte array to the printed value of \a n in base \a base (10 + by default) and returns a reference to the byte array. The \a base can + be any value between 2 and 36. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 40 + + \note The format of the number is not localized; the default C locale + is used irrespective of the user's locale. + + \sa number(), toInt() +*/ + +/*! + \fn QByteArray &QByteArray::setNum(uint n, int base) + \overload + + \sa toUInt() +*/ + +/*! + \fn QByteArray &QByteArray::setNum(short n, int base) + \overload + + \sa toShort() +*/ + +/*! + \fn QByteArray &QByteArray::setNum(ushort n, int base) + \overload + + \sa toUShort() +*/ + +/*! + \overload + + \sa toLongLong() +*/ + +QByteArray &QByteArray::setNum(qlonglong n, int base) +{ +#if defined(QT_CHECK_RANGE) + if (base < 2 || base > 36) { + qWarning("QByteArray::setNum: Invalid base %d", base); + base = 10; + } +#endif + QLocale locale(QLocale::C); + *this = locale.d()->longLongToString(n, -1, base).toLatin1(); + return *this; +} + +/*! + \overload + + \sa toULongLong() +*/ + +QByteArray &QByteArray::setNum(qulonglong n, int base) +{ +#if defined(QT_CHECK_RANGE) + if (base < 2 || base > 36) { + qWarning("QByteArray::setNum: Invalid base %d", base); + base = 10; + } +#endif + QLocale locale(QLocale::C); + *this = locale.d()->unsLongLongToString(n, -1, base).toLatin1(); + return *this; +} + +/*! + \overload + + Sets the byte array to the printed value of \a n, formatted in format + \a f with precision \a prec, and returns a reference to the + byte array. + + The format \a f can be any of the following: + + \table + \header \i Format \i Meaning + \row \i \c e \i format as [-]9.9e[+|-]999 + \row \i \c E \i format as [-]9.9E[+|-]999 + \row \i \c f \i format as [-]9.9 + \row \i \c g \i use \c e or \c f format, whichever is the most concise + \row \i \c G \i use \c E or \c f format, whichever is the most concise + \endtable + + With 'e', 'E', and 'f', \a prec is the number of digits after the + decimal point. With 'g' and 'G', \a prec is the maximum number of + significant digits (trailing zeroes are omitted). + + \note The format of the number is not localized; the default C locale + is used irrespective of the user's locale. + + \sa toDouble() +*/ + +QByteArray &QByteArray::setNum(double n, char f, int prec) +{ + QLocalePrivate::DoubleForm form = QLocalePrivate::DFDecimal; + uint flags = 0; + + if (qIsUpper(f)) + flags = QLocalePrivate::CapitalEorX; + f = qToLower(f); + + switch (f) { + case 'f': + form = QLocalePrivate::DFDecimal; + break; + case 'e': + form = QLocalePrivate::DFExponent; + break; + case 'g': + form = QLocalePrivate::DFSignificantDigits; + break; + default: +#if defined(QT_CHECK_RANGE) + qWarning("QByteArray::setNum: Invalid format char '%c'", f); +#endif + break; + } + + QLocale locale(QLocale::C); + *this = locale.d()->doubleToString(n, prec, form, -1, flags).toLatin1(); + return *this; +} + +/*! + \fn QByteArray &QByteArray::setNum(float n, char f, int prec) + \overload + + Sets the byte array to the printed value of \a n, formatted in format + \a f with precision \a prec, and returns a reference to the + byte array. + + \note The format of the number is not localized; the default C locale + is used irrespective of the user's locale. + + \sa toFloat() +*/ + +/*! + Returns a byte array containing the string equivalent of the + number \a n to base \a base (10 by default). The \a base can be + any value between 2 and 36. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 41 + + \note The format of the number is not localized; the default C locale + is used irrespective of the user's locale. + + \sa setNum(), toInt() +*/ +QByteArray QByteArray::number(int n, int base) +{ + QByteArray s; + s.setNum(n, base); + return s; +} + +/*! + \overload + + \sa toUInt() +*/ +QByteArray QByteArray::number(uint n, int base) +{ + QByteArray s; + s.setNum(n, base); + return s; +} + +/*! + \overload + + \sa toLongLong() +*/ +QByteArray QByteArray::number(qlonglong n, int base) +{ + QByteArray s; + s.setNum(n, base); + return s; +} + +/*! + \overload + + \sa toULongLong() +*/ +QByteArray QByteArray::number(qulonglong n, int base) +{ + QByteArray s; + s.setNum(n, base); + return s; +} + +/*! + \overload + + Returns a byte array that contains the printed value of \a n, + formatted in format \a f with precision \a prec. + + Argument \a n is formatted according to the \a f format specified, + which is \c g by default, and can be any of the following: + + \table + \header \i Format \i Meaning + \row \i \c e \i format as [-]9.9e[+|-]999 + \row \i \c E \i format as [-]9.9E[+|-]999 + \row \i \c f \i format as [-]9.9 + \row \i \c g \i use \c e or \c f format, whichever is the most concise + \row \i \c G \i use \c E or \c f format, whichever is the most concise + \endtable + + With 'e', 'E', and 'f', \a prec is the number of digits after the + decimal point. With 'g' and 'G', \a prec is the maximum number of + significant digits (trailing zeroes are omitted). + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 42 + + \note The format of the number is not localized; the default C locale + is used irrespective of the user's locale. + + \sa toDouble() +*/ +QByteArray QByteArray::number(double n, char f, int prec) +{ + QByteArray s; + s.setNum(n, f, prec); + return s; +} + +/*! + Constructs a QByteArray that uses the first \a size bytes of the + \a data array. The bytes are \e not copied. The QByteArray will + contain the \a data pointer. The caller guarantees that \a data + will not be deleted or modified as long as this QByteArray and any + copies of it exist that have not been modified. In other words, + because QByteArray is an \l{implicitly shared} class and the + instance returned by this function contains the \a data pointer, + the caller must not delete \a data or modify it directly as long + as the returned QByteArray and any copies exist. However, + QByteArray does not take ownership of \a data, so the QByteArray + destructor will never delete the raw \a data, even when the + last QByteArray referring to \a data is destroyed. + + A subsequent attempt to modify the contents of the returned + QByteArray or any copy made from it will cause it to create a deep + copy of the \a data array before doing the modification. This + ensures that the raw \a data array itself will never be modified + by QByteArray. + + Here is an example of how to read data using a QDataStream on raw + data in memory without copying the raw data into a QByteArray: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 43 + + \warning A byte array created with fromRawData() is \e not + null-terminated, unless the raw data contains a 0 character at + position \a size. While that does not matter for QDataStream or + functions like indexOf(), passing the byte array to a function + accepting a \c{const char *} expected to be '\\0'-terminated will + fail. + + \sa setRawData(), data(), constData() +*/ + +QByteArray QByteArray::fromRawData(const char *data, int size) +{ + Data *x = static_cast<Data *>(qMalloc(sizeof(Data))); + Q_CHECK_PTR(x); + if (data) { + x->data = const_cast<char *>(data); + } else { + x->data = x->array; + size = 0; + } + x->ref = 1; + x->alloc = x->size = size; + *x->array = '\0'; + return QByteArray(x, 0, 0); +} + +/*! + \since 4.7 + + Resets the QByteArray to use the first \a size bytes of the + \a data array. The bytes are \e not copied. The QByteArray will + contain the \a data pointer. The caller guarantees that \a data + will not be deleted or modified as long as this QByteArray and any + copies of it exist that have not been modified. + + This function can be used instead of fromRawData() to re-use + existings QByteArray objects to save memory re-allocations. + + \sa fromRawData(), data(), constData() +*/ +QByteArray &QByteArray::setRawData(const char *data, uint size) +{ + if (d->ref != 1 || d->alloc) { + *this = fromRawData(data, size); + } else { + if (data) { + d->data = const_cast<char *>(data); + } else { + d->data = d->array; + size = 0; + } + d->alloc = d->size = size; + *d->array = '\0'; + } + return *this; +} + +/*! + Returns a decoded copy of the Base64 array \a base64. Input is not checked + for validity; invalid characters in the input are skipped, enabling the + decoding process to continue with subsequent characters. + + For example: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 44 + + The algorithm used to decode Base64-encoded data is defined in \l{RFC 2045}. + + \sa toBase64() +*/ +QByteArray QByteArray::fromBase64(const QByteArray &base64) +{ + unsigned int buf = 0; + int nbits = 0; + QByteArray tmp((base64.size() * 3) / 4, Qt::Uninitialized); + + int offset = 0; + for (int i = 0; i < base64.size(); ++i) { + int ch = base64.at(i); + int d; + + if (ch >= 'A' && ch <= 'Z') + d = ch - 'A'; + else if (ch >= 'a' && ch <= 'z') + d = ch - 'a' + 26; + else if (ch >= '0' && ch <= '9') + d = ch - '0' + 52; + else if (ch == '+') + d = 62; + else if (ch == '/') + d = 63; + else + d = -1; + + if (d != -1) { + buf = (buf << 6) | d; + nbits += 6; + if (nbits >= 8) { + nbits -= 8; + tmp[offset++] = buf >> nbits; + buf &= (1 << nbits) - 1; + } + } + } + + tmp.truncate(offset); + return tmp; +} + +/*! + Returns a decoded copy of the hex encoded array \a hexEncoded. Input is not checked + for validity; invalid characters in the input are skipped, enabling the + decoding process to continue with subsequent characters. + + For example: + + \snippet doc/src/snippets/code/src_corelib_tools_qbytearray.cpp 45 + + \sa toHex() +*/ +QByteArray QByteArray::fromHex(const QByteArray &hexEncoded) +{ + QByteArray res((hexEncoded.size() + 1)/ 2, Qt::Uninitialized); + uchar *result = (uchar *)res.data() + res.size(); + + bool odd_digit = true; + for (int i = hexEncoded.size() - 1; i >= 0; --i) { + int ch = hexEncoded.at(i); + int tmp; + if (ch >= '0' && ch <= '9') + tmp = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + tmp = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + tmp = ch - 'A' + 10; + else + continue; + if (odd_digit) { + --result; + *result = tmp; + odd_digit = false; + } else { + *result |= tmp << 4; + odd_digit = true; + } + } + + res.remove(0, result - (const uchar *)res.constData()); + return res; +} + +/*! + Returns a hex encoded copy of the byte array. The hex encoding uses the numbers 0-9 and + the letters a-f. + + \sa fromHex() +*/ +QByteArray QByteArray::toHex() const +{ + QByteArray hex(d->size * 2, Qt::Uninitialized); + char *hexData = hex.data(); + const uchar *data = (const uchar *)d->data; + for (int i = 0; i < d->size; ++i) { + int j = (data[i] >> 4) & 0xf; + if (j <= 9) + hexData[i*2] = (j + '0'); + else + hexData[i*2] = (j + 'a' - 10); + j = data[i] & 0xf; + if (j <= 9) + hexData[i*2+1] = (j + '0'); + else + hexData[i*2+1] = (j + 'a' - 10); + } + return hex; +} + +static void q_fromPercentEncoding(QByteArray *ba, char percent) +{ + if (ba->isEmpty()) + return; + + char *data = ba->data(); + const char *inputPtr = data; + + int i = 0; + int len = ba->count(); + int outlen = 0; + int a, b; + char c; + while (i < len) { + c = inputPtr[i]; + if (c == percent && i + 2 < len) { + a = inputPtr[++i]; + b = inputPtr[++i]; + + if (a >= '0' && a <= '9') a -= '0'; + else if (a >= 'a' && a <= 'f') a = a - 'a' + 10; + else if (a >= 'A' && a <= 'F') a = a - 'A' + 10; + + if (b >= '0' && b <= '9') b -= '0'; + else if (b >= 'a' && b <= 'f') b = b - 'a' + 10; + else if (b >= 'A' && b <= 'F') b = b - 'A' + 10; + + *data++ = (char)((a << 4) | b); + } else { + *data++ = c; + } + + ++i; + ++outlen; + } + + if (outlen != len) + ba->truncate(outlen); +} + +void q_fromPercentEncoding(QByteArray *ba) +{ + q_fromPercentEncoding(ba, '%'); +} + +/*! + \since 4.4 + + Returns a decoded copy of the URI/URL-style percent-encoded \a input. + The \a percent parameter allows you to replace the '%' character for + another (for instance, '_' or '='). + + For example: + \code + QByteArray text = QByteArray::fromPercentEncoding("Qt%20is%20great%33"); + text.data(); // returns "Qt is great!" + \endcode + + \sa toPercentEncoding(), QUrl::fromPercentEncoding() +*/ +QByteArray QByteArray::fromPercentEncoding(const QByteArray &input, char percent) +{ + if (input.isNull()) + return QByteArray(); // preserve null + if (input.isEmpty()) + return QByteArray(input.data(), 0); + + QByteArray tmp = input; + q_fromPercentEncoding(&tmp, percent); + return tmp; +} + +static inline bool q_strchr(const char str[], char chr) +{ + if (!str) return false; + + const char *ptr = str; + char c; + while ((c = *ptr++)) + if (c == chr) + return true; + return false; +} + +static inline char toHexHelper(char c) +{ + static const char hexnumbers[] = "0123456789ABCDEF"; + return hexnumbers[c & 0xf]; +} + +static void q_toPercentEncoding(QByteArray *ba, const char *dontEncode, const char *alsoEncode, char percent) +{ + if (ba->isEmpty()) + return; + + QByteArray input = *ba; + int len = input.count(); + const char *inputData = input.constData(); + char *output = 0; + int length = 0; + + for (int i = 0; i < len; ++i) { + unsigned char c = *inputData++; + if (((c >= 0x61 && c <= 0x7A) // ALPHA + || (c >= 0x41 && c <= 0x5A) // ALPHA + || (c >= 0x30 && c <= 0x39) // DIGIT + || c == 0x2D // - + || c == 0x2E // . + || c == 0x5F // _ + || c == 0x7E // ~ + || q_strchr(dontEncode, c)) + && !q_strchr(alsoEncode, c)) { + if (output) + output[length] = c; + ++length; + } else { + if (!output) { + // detach now + ba->resize(len*3); // worst case + output = ba->data(); + } + output[length++] = percent; + output[length++] = toHexHelper((c & 0xf0) >> 4); + output[length++] = toHexHelper(c & 0xf); + } + } + if (output) + ba->truncate(length); +} + +void q_toPercentEncoding(QByteArray *ba, const char *exclude, const char *include) +{ + q_toPercentEncoding(ba, exclude, include, '%'); +} + +void q_normalizePercentEncoding(QByteArray *ba, const char *exclude) +{ + q_fromPercentEncoding(ba, '%'); + q_toPercentEncoding(ba, exclude, 0, '%'); +} + +/*! + \since 4.4 + + Returns a URI/URL-style percent-encoded copy of this byte array. The + \a percent parameter allows you to override the default '%' + character for another. + + By default, this function will encode all characters that are not + one of the following: + + ALPHA ("a" to "z" and "A" to "Z") / DIGIT (0 to 9) / "-" / "." / "_" / "~" + + To prevent characters from being encoded pass them to \a + exclude. To force characters to be encoded pass them to \a + include. The \a percent character is always encoded. + + Example: + + \code + QByteArray text = "{a fishy string?}"; + QByteArray ba = text.toPercentEncoding("{}", "s"); + qDebug(ba.constData()); + // prints "{a fi%73hy %73tring%3F}" + \endcode + + The hex encoding uses the numbers 0-9 and the uppercase letters A-F. + + \sa fromPercentEncoding(), QUrl::toPercentEncoding() +*/ +QByteArray QByteArray::toPercentEncoding(const QByteArray &exclude, const QByteArray &include, + char percent) const +{ + if (isNull()) + return QByteArray(); // preserve null + if (isEmpty()) + return QByteArray(data(), 0); + + QByteArray include2 = include; + if (percent != '%') // the default + if ((percent >= 0x61 && percent <= 0x7A) // ALPHA + || (percent >= 0x41 && percent <= 0x5A) // ALPHA + || (percent >= 0x30 && percent <= 0x39) // DIGIT + || percent == 0x2D // - + || percent == 0x2E // . + || percent == 0x5F // _ + || percent == 0x7E) // ~ + include2 += percent; + + QByteArray result = *this; + q_toPercentEncoding(&result, exclude.nulTerminated().constData(), include2.nulTerminated().constData(), percent); + + return result; +} + +/*! \typedef QByteArray::ConstIterator + \internal +*/ + +/*! \typedef QByteArray::Iterator + \internal +*/ + +/*! \typedef QByteArray::const_iterator + \internal +*/ + +/*! \typedef QByteArray::iterator + \internal +*/ + +/*! \typedef QByteArray::const_reference + \internal +*/ + +/*! \typedef QByteArray::reference + \internal +*/ + +/*! \typedef QByteArray::value_type + \internal + */ + +/*! + \fn QByteArray::QByteArray(int size) + + Use QByteArray(int, char) instead. +*/ + + +/*! + \fn QByteArray QByteArray::leftJustify(uint width, char fill, bool truncate) const + + Use leftJustified() instead. +*/ + +/*! + \fn QByteArray QByteArray::rightJustify(uint width, char fill, bool truncate) const + + Use rightJustified() instead. +*/ + +/*! + \fn QByteArray& QByteArray::duplicate(const QByteArray& a) + + \oldcode + QByteArray bdata; + bdata.duplicate(original); + \newcode + QByteArray bdata; + bdata = original; + \endcode + + \note QByteArray uses implicit sharing so if you modify a copy, only the + copy is changed. +*/ + +/*! + \fn QByteArray& QByteArray::duplicate(const char *a, uint n) + + \overload + + \oldcode + QByteArray bdata; + bdata.duplicate(ptr, size); + \newcode + QByteArray bdata; + bdata = QByteArray(ptr, size); + \endcode + + \note QByteArray uses implicit sharing so if you modify a copy, only the + copy is changed. +*/ + +/*! + \fn void QByteArray::resetRawData(const char *data, uint n) + + Use clear() instead. +*/ + +/*! + \fn QByteArray QByteArray::lower() const + + Use toLower() instead. +*/ + +/*! + \fn QByteArray QByteArray::upper() const + + Use toUpper() instead. +*/ + +/*! + \fn QByteArray QByteArray::stripWhiteSpace() const + + Use trimmed() instead. +*/ + +/*! + \fn QByteArray QByteArray::simplifyWhiteSpace() const + + Use simplified() instead. +*/ + +/*! + \fn int QByteArray::find(char c, int from = 0) const + + Use indexOf() instead. +*/ + +/*! + \fn int QByteArray::find(const char *c, int from = 0) const + + Use indexOf() instead. +*/ + +/*! + \fn int QByteArray::find(const QByteArray &ba, int from = 0) const + + Use indexOf() instead. +*/ + +/*! + \fn int QByteArray::findRev(char c, int from = -1) const + + Use lastIndexOf() instead. +*/ + +/*! + \fn int QByteArray::findRev(const char *c, int from = -1) const + + Use lastIndexOf() instead. +*/ + +/*! + \fn int QByteArray::findRev(const QByteArray &ba, int from = -1) const + + Use lastIndexOf() instead. +*/ + +/*! + \fn int QByteArray::find(const QString &s, int from = 0) const + + Use indexOf() instead. +*/ + +/*! + \fn int QByteArray::findRev(const QString &s, int from = -1) const + + Use lastIndexOf() instead. +*/ + +/*! + \fn DataPtr &QByteArray::data_ptr() + \internal +*/ + +/*! + \typedef QByteArray::DataPtr + \internal +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h new file mode 100644 index 0000000000..0627b4e568 --- /dev/null +++ b/src/corelib/tools/qbytearray.h @@ -0,0 +1,622 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QBYTEARRAY_H +#define QBYTEARRAY_H + +#include <QtCore/qatomic.h> +#include <QtCore/qnamespace.h> + +#include <string.h> +#include <stdarg.h> + +#ifdef truncate +#error qbytearray.h must be included before any header file that defines truncate +#endif + +#if defined(Q_CC_GNU) && (__GNUC__ == 4 && __GNUC_MINOR__ == 0) +//There is a bug in GCC 4.0 that tries to instantiate template of annonymous enum +# ifdef QT_USE_FAST_OPERATOR_PLUS +# undef QT_USE_FAST_OPERATOR_PLUS +# endif +# ifdef QT_USE_FAST_CONCATENATION +# undef QT_USE_FAST_CONCATENATION +# endif +#endif + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +/***************************************************************************** + Safe and portable C string functions; extensions to standard string.h + *****************************************************************************/ + +Q_CORE_EXPORT char *qstrdup(const char *); + +inline uint qstrlen(const char *str) +{ return str ? uint(strlen(str)) : 0; } + +inline uint qstrnlen(const char *str, uint maxlen) +{ + uint length = 0; + if (str) { + while (length < maxlen && *str++) + length++; + } + return length; +} + +Q_CORE_EXPORT char *qstrcpy(char *dst, const char *src); +Q_CORE_EXPORT char *qstrncpy(char *dst, const char *src, uint len); + +Q_CORE_EXPORT int qstrcmp(const char *str1, const char *str2); +Q_CORE_EXPORT int qstrcmp(const QByteArray &str1, const QByteArray &str2); +Q_CORE_EXPORT int qstrcmp(const QByteArray &str1, const char *str2); +static inline int qstrcmp(const char *str1, const QByteArray &str2) +{ return -qstrcmp(str2, str1); } + +inline int qstrncmp(const char *str1, const char *str2, uint len) +{ + return (str1 && str2) ? strncmp(str1, str2, len) + : (str1 ? 1 : (str2 ? -1 : 0)); +} +Q_CORE_EXPORT int qstricmp(const char *, const char *); +Q_CORE_EXPORT int qstrnicmp(const char *, const char *, uint len); + +// implemented in qvsnprintf.cpp +Q_CORE_EXPORT int qvsnprintf(char *str, size_t n, const char *fmt, va_list ap); +Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt, ...); + +#ifdef QT3_SUPPORT +inline QT3_SUPPORT void *qmemmove(void *dst, const void *src, uint len) +{ return memmove(dst, src, len); } +inline QT3_SUPPORT uint cstrlen(const char *str) +{ return uint(strlen(str)); } +inline QT3_SUPPORT char *cstrcpy(char *dst, const char *src) +{ return qstrcpy(dst,src); } +inline QT3_SUPPORT int cstrcmp(const char *str1, const char *str2) +{ return strcmp(str1,str2); } +inline QT3_SUPPORT int cstrncmp(const char *str1, const char *str2, uint len) +{ return strncmp(str1,str2,len); } +#endif + +// qChecksum: Internet checksum + +Q_CORE_EXPORT quint16 qChecksum(const char *s, uint len); + +class QByteRef; +class QString; +class QDataStream; +template <typename T> class QList; + +class Q_CORE_EXPORT QByteArray +{ +private: + struct Data { + QBasicAtomicInt ref; + int alloc, size; + // ### Qt 5.0: We need to add the missing capacity bit + // (like other tool classes have), to maintain the + // reserved memory on resize. + char *data; + char array[1]; + }; + +public: + inline QByteArray(); + QByteArray(const char *); + QByteArray(const char *, int size); + QByteArray(int size, char c); + QByteArray(int size, Qt::Initialization); + inline QByteArray(const QByteArray &); + inline ~QByteArray(); + + QByteArray &operator=(const QByteArray &); + QByteArray &operator=(const char *str); +#ifdef Q_COMPILER_RVALUE_REFS + inline QByteArray &operator=(QByteArray &&other) + { qSwap(d, other.d); return *this; } +#endif + + inline void swap(QByteArray &other) { qSwap(d, other.d); } + + inline int size() const; + bool isEmpty() const; + void resize(int size); + + QByteArray &fill(char c, int size = -1); + + int capacity() const; + void reserve(int size); + void squeeze(); + +#ifndef QT_NO_CAST_FROM_BYTEARRAY + operator const char *() const; + operator const void *() const; +#endif + char *data(); + const char *data() const; + inline const char *constData() const; + inline void detach(); + bool isDetached() const; + inline bool isSharedWith(const QByteArray &other) const { return d == other.d; } + void clear(); + +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE + const char at(int i) const; + const char operator[](int i) const; + const char operator[](uint i) const; +#else + char at(int i) const; + char operator[](int i) const; + char operator[](uint i) const; +#endif + QByteRef operator[](int i); + QByteRef operator[](uint i); + + int indexOf(char c, int from = 0) const; + int indexOf(const char *c, int from = 0) const; + int indexOf(const QByteArray &a, int from = 0) const; + int lastIndexOf(char c, int from = -1) const; + int lastIndexOf(const char *c, int from = -1) const; + int lastIndexOf(const QByteArray &a, int from = -1) const; + + QBool contains(char c) const; + QBool contains(const char *a) const; + QBool contains(const QByteArray &a) const; + int count(char c) const; + int count(const char *a) const; + int count(const QByteArray &a) const; + + QByteArray left(int len) const; + QByteArray right(int len) const; + QByteArray mid(int index, int len = -1) const; + + bool startsWith(const QByteArray &a) const; + bool startsWith(char c) const; + bool startsWith(const char *c) const; + + bool endsWith(const QByteArray &a) const; + bool endsWith(char c) const; + bool endsWith(const char *c) const; + + void truncate(int pos); + void chop(int n); + + QByteArray toLower() const; + QByteArray toUpper() const; + + QByteArray trimmed() const; + QByteArray simplified() const; + QByteArray leftJustified(int width, char fill = ' ', bool truncate = false) const; + QByteArray rightJustified(int width, char fill = ' ', bool truncate = false) const; + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT QByteArray leftJustify(uint width, char aFill = ' ', bool aTruncate = false) const + { return leftJustified(int(width), aFill, aTruncate); } + inline QT3_SUPPORT QByteArray rightJustify(uint width, char aFill = ' ', bool aTruncate = false) const + { return rightJustified(int(width), aFill, aTruncate); } +#endif + + QByteArray &prepend(char c); + QByteArray &prepend(const char *s); + QByteArray &prepend(const char *s, int len); + QByteArray &prepend(const QByteArray &a); + QByteArray &append(char c); + QByteArray &append(const char *s); + QByteArray &append(const char *s, int len); + QByteArray &append(const QByteArray &a); + QByteArray &insert(int i, char c); + QByteArray &insert(int i, const char *s); + QByteArray &insert(int i, const char *s, int len); + QByteArray &insert(int i, const QByteArray &a); + QByteArray &remove(int index, int len); + QByteArray &replace(int index, int len, const char *s); + QByteArray &replace(int index, int len, const char *s, int alen); + QByteArray &replace(int index, int len, const QByteArray &s); + QByteArray &replace(char before, const char *after); + QByteArray &replace(char before, const QByteArray &after); + QByteArray &replace(const char *before, const char *after); + QByteArray &replace(const char *before, int bsize, const char *after, int asize); + QByteArray &replace(const QByteArray &before, const QByteArray &after); + QByteArray &replace(const QByteArray &before, const char *after); + QByteArray &replace(const char *before, const QByteArray &after); + QByteArray &replace(char before, char after); + QByteArray &operator+=(char c); + QByteArray &operator+=(const char *s); + QByteArray &operator+=(const QByteArray &a); + + QList<QByteArray> split(char sep) const; + + QByteArray repeated(int times) const; + +#ifndef QT_NO_CAST_TO_ASCII + QT_ASCII_CAST_WARN QByteArray &append(const QString &s); + QT_ASCII_CAST_WARN QByteArray &insert(int i, const QString &s); + QT_ASCII_CAST_WARN QByteArray &replace(const QString &before, const char *after); + QT_ASCII_CAST_WARN QByteArray &replace(char c, const QString &after); + QT_ASCII_CAST_WARN QByteArray &replace(const QString &before, const QByteArray &after); + + QT_ASCII_CAST_WARN QByteArray &operator+=(const QString &s); + QT_ASCII_CAST_WARN int indexOf(const QString &s, int from = 0) const; + QT_ASCII_CAST_WARN int lastIndexOf(const QString &s, int from = -1) const; +#endif +#ifndef QT_NO_CAST_FROM_ASCII + inline QT_ASCII_CAST_WARN bool operator==(const QString &s2) const; + inline QT_ASCII_CAST_WARN bool operator!=(const QString &s2) const; + inline QT_ASCII_CAST_WARN bool operator<(const QString &s2) const; + inline QT_ASCII_CAST_WARN bool operator>(const QString &s2) const; + inline QT_ASCII_CAST_WARN bool operator<=(const QString &s2) const; + inline QT_ASCII_CAST_WARN bool operator>=(const QString &s2) const; +#endif + + short toShort(bool *ok = 0, int base = 10) const; + ushort toUShort(bool *ok = 0, int base = 10) const; + int toInt(bool *ok = 0, int base = 10) const; + uint toUInt(bool *ok = 0, int base = 10) const; + long toLong(bool *ok = 0, int base = 10) const; + ulong toULong(bool *ok = 0, int base = 10) const; + qlonglong toLongLong(bool *ok = 0, int base = 10) const; + qulonglong toULongLong(bool *ok = 0, int base = 10) const; + float toFloat(bool *ok = 0) const; + double toDouble(bool *ok = 0) const; + QByteArray toBase64() const; + QByteArray toHex() const; + QByteArray toPercentEncoding(const QByteArray &exclude = QByteArray(), + const QByteArray &include = QByteArray(), + char percent = '%') const; + + QByteArray &setNum(short, int base = 10); + QByteArray &setNum(ushort, int base = 10); + QByteArray &setNum(int, int base = 10); + QByteArray &setNum(uint, int base = 10); + QByteArray &setNum(qlonglong, int base = 10); + QByteArray &setNum(qulonglong, int base = 10); + QByteArray &setNum(float, char f = 'g', int prec = 6); + QByteArray &setNum(double, char f = 'g', int prec = 6); + QByteArray &setRawData(const char *a, uint n); // ### Qt 5: use an int + + static QByteArray number(int, int base = 10); + static QByteArray number(uint, int base = 10); + static QByteArray number(qlonglong, int base = 10); + static QByteArray number(qulonglong, int base = 10); + static QByteArray number(double, char f = 'g', int prec = 6); + static QByteArray fromRawData(const char *, int size); + static QByteArray fromBase64(const QByteArray &base64); + static QByteArray fromHex(const QByteArray &hexEncoded); + static QByteArray fromPercentEncoding(const QByteArray &pctEncoded, char percent = '%'); + + + typedef char *iterator; + typedef const char *const_iterator; + typedef iterator Iterator; + typedef const_iterator ConstIterator; + iterator begin(); + const_iterator begin() const; + const_iterator constBegin() const; + iterator end(); + const_iterator end() const; + const_iterator constEnd() const; + + // stl compatibility + typedef const char & const_reference; + typedef char & reference; + typedef char value_type; + void push_back(char c); + void push_back(const char *c); + void push_back(const QByteArray &a); + void push_front(char c); + void push_front(const char *c); + void push_front(const QByteArray &a); + + inline int count() const { return d->size; } + int length() const { return d->size; } + bool isNull() const; + + // compatibility +#ifdef QT3_SUPPORT + QT3_SUPPORT_CONSTRUCTOR QByteArray(int size); + inline QT3_SUPPORT QByteArray& duplicate(const QByteArray& a) { *this = a; return *this; } + inline QT3_SUPPORT QByteArray& duplicate(const char *a, uint n) + { *this = QByteArray(a, n); return *this; } + inline QT3_SUPPORT void resetRawData(const char *, uint) { clear(); } + inline QT3_SUPPORT QByteArray lower() const { return toLower(); } + inline QT3_SUPPORT QByteArray upper() const { return toUpper(); } + inline QT3_SUPPORT QByteArray stripWhiteSpace() const { return trimmed(); } + inline QT3_SUPPORT QByteArray simplifyWhiteSpace() const { return simplified(); } + inline QT3_SUPPORT int find(char c, int from = 0) const { return indexOf(c, from); } + inline QT3_SUPPORT int find(const char *c, int from = 0) const { return indexOf(c, from); } + inline QT3_SUPPORT int find(const QByteArray &ba, int from = 0) const { return indexOf(ba, from); } + inline QT3_SUPPORT int findRev(char c, int from = -1) const { return lastIndexOf(c, from); } + inline QT3_SUPPORT int findRev(const char *c, int from = -1) const { return lastIndexOf(c, from); } + inline QT3_SUPPORT int findRev(const QByteArray &ba, int from = -1) const { return lastIndexOf(ba, from); } +#ifndef QT_NO_CAST_TO_ASCII + QT3_SUPPORT int find(const QString &s, int from = 0) const; + QT3_SUPPORT int findRev(const QString &s, int from = -1) const; +#endif +#endif + +private: + operator QNoImplicitBoolCast() const; + static Data shared_null; + static Data shared_empty; + Data *d; + QByteArray(Data *dd, int /*dummy*/, int /*dummy*/) : d(dd) {} + void realloc(int alloc); + void expand(int i); + QByteArray nulTerminated() const; + + friend class QByteRef; + friend class QString; + friend Q_CORE_EXPORT QByteArray qUncompress(const uchar *data, int nbytes); +public: + typedef Data * DataPtr; + inline DataPtr &data_ptr() { return d; } +}; + +inline QByteArray::QByteArray(): d(&shared_null) { d->ref.ref(); } +inline QByteArray::~QByteArray() { if (!d->ref.deref()) qFree(d); } +inline int QByteArray::size() const +{ return d->size; } + +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE +inline const char QByteArray::at(int i) const +{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } +inline const char QByteArray::operator[](int i) const +{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } +inline const char QByteArray::operator[](uint i) const +{ Q_ASSERT(i < uint(size())); return d->data[i]; } +#else +inline char QByteArray::at(int i) const +{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } +inline char QByteArray::operator[](int i) const +{ Q_ASSERT(i >= 0 && i < size()); return d->data[i]; } +inline char QByteArray::operator[](uint i) const +{ Q_ASSERT(i < uint(size())); return d->data[i]; } +#endif + +inline bool QByteArray::isEmpty() const +{ return d->size == 0; } +#ifndef QT_NO_CAST_FROM_BYTEARRAY +inline QByteArray::operator const char *() const +{ return d->data; } +inline QByteArray::operator const void *() const +{ return d->data; } +#endif +inline char *QByteArray::data() +{ detach(); return d->data; } +inline const char *QByteArray::data() const +{ return d->data; } +inline const char *QByteArray::constData() const +{ return d->data; } +inline void QByteArray::detach() +{ if (d->ref != 1 || d->data != d->array) realloc(d->size); } +inline bool QByteArray::isDetached() const +{ return d->ref == 1; } +inline QByteArray::QByteArray(const QByteArray &a) : d(a.d) +{ d->ref.ref(); } +#ifdef QT3_SUPPORT +inline QByteArray::QByteArray(int aSize) : d(&shared_null) +{ d->ref.ref(); if (aSize > 0) fill('\0', aSize); } +#endif + +inline int QByteArray::capacity() const +{ return d->alloc; } + +inline void QByteArray::reserve(int asize) +{ if (d->ref != 1 || asize > d->alloc) realloc(asize); } + +inline void QByteArray::squeeze() +{ if (d->size < d->alloc) realloc(d->size); } + +class Q_CORE_EXPORT QByteRef { + QByteArray &a; + int i; + inline QByteRef(QByteArray &array, int idx) + : a(array),i(idx) {} + friend class QByteArray; +public: +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE + inline operator const char() const + { return i < a.d->size ? a.d->data[i] : char(0); } +#else + inline operator char() const + { return i < a.d->size ? a.d->data[i] : char(0); } +#endif + inline QByteRef &operator=(char c) + { if (i >= a.d->size) a.expand(i); else a.detach(); + a.d->data[i] = c; return *this; } + inline QByteRef &operator=(const QByteRef &c) + { if (i >= a.d->size) a.expand(i); else a.detach(); + a.d->data[i] = c.a.d->data[c.i]; return *this; } + inline bool operator==(char c) const + { return a.d->data[i] == c; } + inline bool operator!=(char c) const + { return a.d->data[i] != c; } + inline bool operator>(char c) const + { return a.d->data[i] > c; } + inline bool operator>=(char c) const + { return a.d->data[i] >= c; } + inline bool operator<(char c) const + { return a.d->data[i] < c; } + inline bool operator<=(char c) const + { return a.d->data[i] <= c; } +}; + +inline QByteRef QByteArray::operator[](int i) +{ Q_ASSERT(i >= 0); return QByteRef(*this, i); } +inline QByteRef QByteArray::operator[](uint i) +{ return QByteRef(*this, i); } +inline QByteArray::iterator QByteArray::begin() +{ detach(); return d->data; } +inline QByteArray::const_iterator QByteArray::begin() const +{ return d->data; } +inline QByteArray::const_iterator QByteArray::constBegin() const +{ return d->data; } +inline QByteArray::iterator QByteArray::end() +{ detach(); return d->data + d->size; } +inline QByteArray::const_iterator QByteArray::end() const +{ return d->data + d->size; } +inline QByteArray::const_iterator QByteArray::constEnd() const +{ return d->data + d->size; } +inline QByteArray &QByteArray::operator+=(char c) +{ return append(c); } +inline QByteArray &QByteArray::operator+=(const char *s) +{ return append(s); } +inline QByteArray &QByteArray::operator+=(const QByteArray &a) +{ return append(a); } +inline void QByteArray::push_back(char c) +{ append(c); } +inline void QByteArray::push_back(const char *c) +{ append(c); } +inline void QByteArray::push_back(const QByteArray &a) +{ append(a); } +inline void QByteArray::push_front(char c) +{ prepend(c); } +inline void QByteArray::push_front(const char *c) +{ prepend(c); } +inline void QByteArray::push_front(const QByteArray &a) +{ prepend(a); } +inline QBool QByteArray::contains(const QByteArray &a) const +{ return QBool(indexOf(a) != -1); } +inline QBool QByteArray::contains(char c) const +{ return QBool(indexOf(c) != -1); } +inline bool operator==(const QByteArray &a1, const QByteArray &a2) +{ return (a1.size() == a2.size()) && (memcmp(a1.constData(), a2.constData(), a1.size())==0); } +inline bool operator==(const QByteArray &a1, const char *a2) +{ return a2 ? qstrcmp(a1,a2) == 0 : a1.isEmpty(); } +inline bool operator==(const char *a1, const QByteArray &a2) +{ return a1 ? qstrcmp(a1,a2) == 0 : a2.isEmpty(); } +inline bool operator!=(const QByteArray &a1, const QByteArray &a2) +{ return !(a1==a2); } +inline bool operator!=(const QByteArray &a1, const char *a2) +{ return a2 ? qstrcmp(a1,a2) != 0 : !a1.isEmpty(); } +inline bool operator!=(const char *a1, const QByteArray &a2) +{ return a1 ? qstrcmp(a1,a2) != 0 : !a2.isEmpty(); } +inline bool operator<(const QByteArray &a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) < 0; } + inline bool operator<(const QByteArray &a1, const char *a2) +{ return qstrcmp(a1, a2) < 0; } +inline bool operator<(const char *a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) < 0; } +inline bool operator<=(const QByteArray &a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) <= 0; } +inline bool operator<=(const QByteArray &a1, const char *a2) +{ return qstrcmp(a1, a2) <= 0; } +inline bool operator<=(const char *a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) <= 0; } +inline bool operator>(const QByteArray &a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) > 0; } +inline bool operator>(const QByteArray &a1, const char *a2) +{ return qstrcmp(a1, a2) > 0; } +inline bool operator>(const char *a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) > 0; } +inline bool operator>=(const QByteArray &a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) >= 0; } +inline bool operator>=(const QByteArray &a1, const char *a2) +{ return qstrcmp(a1, a2) >= 0; } +inline bool operator>=(const char *a1, const QByteArray &a2) +{ return qstrcmp(a1, a2) >= 0; } +#ifndef QT_USE_FAST_OPERATOR_PLUS +# ifndef QT_USE_FAST_CONCATENATION +inline const QByteArray operator+(const QByteArray &a1, const QByteArray &a2) +{ return QByteArray(a1) += a2; } +inline const QByteArray operator+(const QByteArray &a1, const char *a2) +{ return QByteArray(a1) += a2; } +inline const QByteArray operator+(const QByteArray &a1, char a2) +{ return QByteArray(a1) += a2; } +inline const QByteArray operator+(const char *a1, const QByteArray &a2) +{ return QByteArray(a1) += a2; } +inline const QByteArray operator+(char a1, const QByteArray &a2) +{ return QByteArray(&a1, 1) += a2; } +# endif // QT_USE_FAST_CONCATENATION +#endif // QT_USE_FAST_OPERATOR_PLUS +inline QBool QByteArray::contains(const char *c) const +{ return QBool(indexOf(c) != -1); } +inline QByteArray &QByteArray::replace(char before, const char *c) +{ return replace(&before, 1, c, qstrlen(c)); } +inline QByteArray &QByteArray::replace(const QByteArray &before, const char *c) +{ return replace(before.constData(), before.size(), c, qstrlen(c)); } +inline QByteArray &QByteArray::replace(const char *before, const char *after) +{ return replace(before, qstrlen(before), after, qstrlen(after)); } + +inline QByteArray &QByteArray::setNum(short n, int base) +{ return setNum(qlonglong(n), base); } +inline QByteArray &QByteArray::setNum(ushort n, int base) +{ return setNum(qulonglong(n), base); } +inline QByteArray &QByteArray::setNum(int n, int base) +{ return setNum(qlonglong(n), base); } +inline QByteArray &QByteArray::setNum(uint n, int base) +{ return setNum(qulonglong(n), base); } +inline QByteArray &QByteArray::setNum(float n, char f, int prec) +{ return setNum(double(n),f,prec); } + + +#if !defined(QT_NO_DATASTREAM) || (defined(QT_BOOTSTRAPPED) && !defined(QT_BUILD_QMAKE)) +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QByteArray &); +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QByteArray &); +#endif + +#ifndef QT_NO_COMPRESS +Q_CORE_EXPORT QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel = -1); +Q_CORE_EXPORT QByteArray qUncompress(const uchar* data, int nbytes); +inline QByteArray qCompress(const QByteArray& data, int compressionLevel = -1) +{ return qCompress(reinterpret_cast<const uchar *>(data.constData()), data.size(), compressionLevel); } +inline QByteArray qUncompress(const QByteArray& data) +{ return qUncompress(reinterpret_cast<const uchar*>(data.constData()), data.size()); } +#endif + +Q_DECLARE_TYPEINFO(QByteArray, Q_MOVABLE_TYPE); +Q_DECLARE_SHARED(QByteArray) + +QT_END_NAMESPACE + +QT_END_HEADER + +#ifdef QT_USE_FAST_CONCATENATION +#include <QtCore/qstring.h> +#endif + +#endif // QBYTEARRAY_H diff --git a/src/corelib/tools/qbytearraymatcher.cpp b/src/corelib/tools/qbytearraymatcher.cpp new file mode 100644 index 0000000000..bc99760ddc --- /dev/null +++ b/src/corelib/tools/qbytearraymatcher.cpp @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** 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 QtCore 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 "qbytearraymatcher.h" + +#include <limits.h> + +QT_BEGIN_NAMESPACE + +static inline void bm_init_skiptable(const uchar *cc, int len, uchar *skiptable) +{ + int l = qMin(len, 255); + memset(skiptable, l, 256*sizeof(uchar)); + cc += len - l; + while (l--) + skiptable[*cc++] = l; +} + +static inline int bm_find(const uchar *cc, int l, int index, const uchar *puc, uint pl, + const uchar *skiptable) +{ + if (pl == 0) + return index > l ? -1 : index; + const uint pl_minus_one = pl - 1; + + register const uchar *current = cc + index + pl_minus_one; + const uchar *end = cc + l; + while (current < end) { + uint skip = skiptable[*current]; + if (!skip) { + // possible match + while (skip < pl) { + if (*(current - skip) != puc[pl_minus_one - skip]) + break; + skip++; + } + if (skip > pl_minus_one) // we have a match + return (current - cc) - skip + 1; + + // in case we don't have a match we are a bit inefficient as we only skip by one + // when we have the non matching char in the string. + if (skiptable[*(current - skip)] == pl) + skip = pl - skip; + else + skip = 1; + } + if (current > end - skip) + break; + current += skip; + } + return -1; // not found +} + +/*! \class QByteArrayMatcher + \brief The QByteArrayMatcher class holds a sequence of bytes that + can be quickly matched in a byte array. + + \ingroup tools + \ingroup string-processing + + This class is useful when you have a sequence of bytes that you + want to repeatedly match against some byte arrays (perhaps in a + loop), or when you want to search for the same sequence of bytes + multiple times in the same byte array. Using a matcher object and + indexIn() is faster than matching a plain QByteArray with + QByteArray::indexOf() if repeated matching takes place. This + class offers no benefit if you are doing one-off byte array + matches. + + Create the QByteArrayMatcher with the QByteArray you want to + search for. Then call indexIn() on the QByteArray that you want to + search. + + \sa QByteArray, QStringMatcher +*/ + +/*! + Constructs an empty byte array matcher that won't match anything. + Call setPattern() to give it a pattern to match. +*/ +QByteArrayMatcher::QByteArrayMatcher() + : d(0) +{ + p.p = 0; + p.l = 0; + qMemSet(p.q_skiptable, 0, sizeof(p.q_skiptable)); +} + +/*! + Constructs a byte array matcher from \a pattern. \a pattern + has the given \a length. \a pattern must remain in scope, but + the destructor does not delete \a pattern. + */ +QByteArrayMatcher::QByteArrayMatcher(const char *pattern, int length) + : d(0) +{ + p.p = reinterpret_cast<const uchar *>(pattern); + p.l = length; + bm_init_skiptable(p.p, p.l, p.q_skiptable); +} + +/*! + Constructs a byte array matcher that will search for \a pattern. + Call indexIn() to perform a search. +*/ +QByteArrayMatcher::QByteArrayMatcher(const QByteArray &pattern) + : d(0), q_pattern(pattern) +{ + p.p = reinterpret_cast<const uchar *>(pattern.constData()); + p.l = pattern.size(); + bm_init_skiptable(p.p, p.l, p.q_skiptable); +} + +/*! + Copies the \a other byte array matcher to this byte array matcher. +*/ +QByteArrayMatcher::QByteArrayMatcher(const QByteArrayMatcher &other) + : d(0) +{ + operator=(other); +} + +/*! + Destroys the byte array matcher. +*/ +QByteArrayMatcher::~QByteArrayMatcher() +{ +} + +/*! + Assigns the \a other byte array matcher to this byte array matcher. +*/ +QByteArrayMatcher &QByteArrayMatcher::operator=(const QByteArrayMatcher &other) +{ + q_pattern = other.q_pattern; + memcpy(&p, &other.p, sizeof(p)); + return *this; +} + +/*! + Sets the byte array that this byte array matcher will search for + to \a pattern. + + \sa pattern(), indexIn() +*/ +void QByteArrayMatcher::setPattern(const QByteArray &pattern) +{ + q_pattern = pattern; + p.p = reinterpret_cast<const uchar *>(pattern.constData()); + p.l = pattern.size(); + bm_init_skiptable(p.p, p.l, p.q_skiptable); +} + +/*! + Searches the byte array \a ba, from byte position \a from (default + 0, i.e. from the first byte), for the byte array pattern() that + was set in the constructor or in the most recent call to + setPattern(). Returns the position where the pattern() matched in + \a ba, or -1 if no match was found. +*/ +int QByteArrayMatcher::indexIn(const QByteArray &ba, int from) const +{ + if (from < 0) + from = 0; + return bm_find(reinterpret_cast<const uchar *>(ba.constData()), ba.size(), from, + p.p, p.l, p.q_skiptable); +} + +/*! + Searches the char string \a str, which has length \a len, from + byte position \a from (default 0, i.e. from the first byte), for + the byte array pattern() that was set in the constructor or in the + most recent call to setPattern(). Returns the position where the + pattern() matched in \a str, or -1 if no match was found. +*/ +int QByteArrayMatcher::indexIn(const char *str, int len, int from) const +{ + if (from < 0) + from = 0; + return bm_find(reinterpret_cast<const uchar *>(str), len, from, + p.p, p.l, p.q_skiptable); +} + +/*! + \fn QByteArray QByteArrayMatcher::pattern() const + + Returns the byte array pattern that this byte array matcher will + search for. + + \sa setPattern() +*/ + + +static int findChar(const char *str, int len, char ch, int from) +{ + const uchar *s = (const uchar *)str; + uchar c = (uchar)ch; + if (from < 0) + from = qMax(from + len, 0); + if (from < len) { + const uchar *n = s + from - 1; + const uchar *e = s + len; + while (++n != e) + if (*n == c) + return n - s; + } + return -1; +} + +/*! \internal + */ +static int qFindByteArrayBoyerMoore( + const char *haystack, int haystackLen, int haystackOffset, + const char *needle, int needleLen) +{ + uchar skiptable[256]; + bm_init_skiptable((const uchar *)needle, needleLen, skiptable); + if (haystackOffset < 0) + haystackOffset = 0; + return bm_find((const uchar *)haystack, haystackLen, haystackOffset, + (const uchar *)needle, needleLen, skiptable); +} + +#define REHASH(a) \ + if (sl_minus_1 < sizeof(uint) * CHAR_BIT) \ + hashHaystack -= (a) << sl_minus_1; \ + hashHaystack <<= 1 + +/*! \internal + */ +int qFindByteArray( + const char *haystack0, int haystackLen, int from, + const char *needle, int needleLen) +{ + const int l = haystackLen; + const int sl = needleLen; + if (from < 0) + from += l; + if (uint(sl + from) > (uint)l) + return -1; + if (!sl) + return from; + if (!l) + return -1; + + if (sl == 1) + return findChar(haystack0, haystackLen, needle[0], from); + + /* + We use the Boyer-Moore algorithm in cases where the overhead + for the skip table should pay off, otherwise we use a simple + hash function. + */ + if (l > 500 && sl > 5) + return qFindByteArrayBoyerMoore(haystack0, haystackLen, from, + needle, needleLen); + + /* + We use some hashing for efficiency's sake. Instead of + comparing strings, we compare the hash value of str with that + of a part of this QString. Only if that matches, we call memcmp(). + */ + const char *haystack = haystack0 + from; + const char *end = haystack0 + (l - sl); + const uint sl_minus_1 = sl - 1; + uint hashNeedle = 0, hashHaystack = 0; + int idx; + for (idx = 0; idx < sl; ++idx) { + hashNeedle = ((hashNeedle<<1) + needle[idx]); + hashHaystack = ((hashHaystack<<1) + haystack[idx]); + } + hashHaystack -= *(haystack + sl_minus_1); + + while (haystack <= end) { + hashHaystack += *(haystack + sl_minus_1); + if (hashHaystack == hashNeedle && *needle == *haystack + && memcmp(needle, haystack, sl) == 0) + return haystack - haystack0; + + REHASH(*haystack); + ++haystack; + } + return -1; +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h new file mode 100644 index 0000000000..444089a00a --- /dev/null +++ b/src/corelib/tools/qbytearraymatcher.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QBYTEARRAYMATCHER_H +#define QBYTEARRAYMATCHER_H + +#include <QtCore/qbytearray.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QByteArrayMatcherPrivate; + +class Q_CORE_EXPORT QByteArrayMatcher +{ +public: + QByteArrayMatcher(); + explicit QByteArrayMatcher(const QByteArray &pattern); + explicit QByteArrayMatcher(const char *pattern, int length); + QByteArrayMatcher(const QByteArrayMatcher &other); + ~QByteArrayMatcher(); + + QByteArrayMatcher &operator=(const QByteArrayMatcher &other); + + void setPattern(const QByteArray &pattern); + + int indexIn(const QByteArray &ba, int from = 0) const; + int indexIn(const char *str, int len, int from = 0) const; + inline QByteArray pattern() const + { + if (q_pattern.isNull()) + return QByteArray(reinterpret_cast<const char*>(p.p), p.l); + return q_pattern; + } + +private: + QByteArrayMatcherPrivate *d; + QByteArray q_pattern; +#ifdef Q_CC_RVCT +// explicitly allow anonymous unions for RVCT to prevent compiler warnings +# pragma push +# pragma anon_unions +#endif + struct Data { + uchar q_skiptable[256]; + const uchar *p; + int l; + }; + union { + uint dummy[256]; + Data p; + }; +#ifdef Q_CC_RVCT +# pragma pop +#endif +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QBYTEARRAYMATCHER_H diff --git a/src/corelib/tools/qbytedata_p.h b/src/corelib/tools/qbytedata_p.h new file mode 100644 index 0000000000..45c576d2e9 --- /dev/null +++ b/src/corelib/tools/qbytedata_p.h @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QBYTEDATA_H +#define QBYTEDATA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qbytearray.h> + +QT_BEGIN_NAMESPACE + +// this class handles a list of QByteArrays. It is a variant of QRingBuffer +// that avoid malloc/realloc/memcpy. +class QByteDataBuffer +{ +private: + QList<QByteArray> buffers; + qint64 bufferCompleteSize; +public: + QByteDataBuffer() : bufferCompleteSize(0) + { + } + + ~QByteDataBuffer() + { + clear(); + } + + inline void append(QByteDataBuffer& other) + { + if (other.isEmpty()) + return; + + buffers.append(other.buffers); + bufferCompleteSize += other.byteAmount(); + } + + + inline void append(const QByteArray& bd) + { + if (bd.isEmpty()) + return; + + buffers.append(bd); + bufferCompleteSize += bd.size(); + } + + inline void prepend(QByteArray& bd) + { + if (bd.isEmpty()) + return; + + buffers.prepend(bd); + bufferCompleteSize += bd.size(); + } + + // return the first QByteData. User of this function has to qFree() its .data! + // preferably use this function to read data. + inline QByteArray read() + { + bufferCompleteSize -= buffers.first().size(); + return buffers.takeFirst(); + } + + // return everything. User of this function has to qFree() its .data! + // avoid to use this, it might malloc and memcpy. + inline QByteArray readAll() + { + return read(byteAmount()); + } + + // return amount. User of this function has to qFree() its .data! + // avoid to use this, it might malloc and memcpy. + inline QByteArray read(qint64 amount) + { + amount = qMin(byteAmount(), amount); + QByteArray byteData; + byteData.resize(amount); + read(byteData.data(), byteData.size()); + return byteData; + } + + // return amount bytes. User of this function has to qFree() its .data! + // avoid to use this, it will memcpy. + qint64 read(char* dst, qint64 amount) + { + amount = qMin(amount, byteAmount()); + qint64 originalAmount = amount; + char *writeDst = dst; + + while (amount > 0) { + QByteArray first = buffers.takeFirst(); + if (amount >= first.size()) { + // take it completely + bufferCompleteSize -= first.size(); + amount -= first.size(); + memcpy(writeDst, first.constData(), first.size()); + writeDst += first.size(); + first.clear(); + } else { + // take a part of it & it is the last one to take + bufferCompleteSize -= amount; + memcpy(writeDst, first.constData(), amount); + + qint64 newFirstSize = first.size() - amount; + QByteArray newFirstData; + newFirstData.resize(newFirstSize); + memcpy(newFirstData.data(), first.constData() + amount, newFirstSize); + buffers.prepend(newFirstData); + + amount = 0; + first.clear(); + } + } + + return originalAmount; + } + + inline char getChar() + { + char c; + read(&c, 1); + return c; + } + + inline void clear() + { + buffers.clear(); + bufferCompleteSize = 0; + } + + // The byte count of all QByteArrays + inline qint64 byteAmount() const + { + return bufferCompleteSize; + } + + // the number of QByteArrays + inline qint64 bufferCount() const + { + return buffers.length(); + } + + inline bool isEmpty() const + { + return byteAmount() == 0; + } + + inline qint64 sizeNextBlock() const + { + if(buffers.isEmpty()) + return 0; + else + return buffers.first().size(); + } + + inline QByteArray& operator[](int i) + { + return buffers[i]; + } + + inline bool canReadLine() const { + for (int i = 0; i < buffers.length(); i++) + if (buffers.at(i).contains('\n')) + return true; + return false; + } +}; + +QT_END_NAMESPACE + +#endif // QBYTEDATA_H diff --git a/src/corelib/tools/qcache.h b/src/corelib/tools/qcache.h new file mode 100644 index 0000000000..7f6b86919f --- /dev/null +++ b/src/corelib/tools/qcache.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QCACHE_H +#define QCACHE_H + +#include <QtCore/qhash.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template <class Key, class T> +class QCache +{ + struct Node { + inline Node() : keyPtr(0) {} + inline Node(T *data, int cost) + : keyPtr(0), t(data), c(cost), p(0), n(0) {} + const Key *keyPtr; T *t; int c; Node *p,*n; + }; + Node *f, *l; + QHash<Key, Node> hash; + void *unused; // ### Qt5: remove + int mx, total; + + inline void unlink(Node &n) { + if (n.p) n.p->n = n.n; + if (n.n) n.n->p = n.p; + if (l == &n) l = n.p; + if (f == &n) f = n.n; + total -= n.c; + T *obj = n.t; + hash.remove(*n.keyPtr); + delete obj; + } + inline T *relink(const Key &key) { + typename QHash<Key, Node>::iterator i = hash.find(key); + if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd()) + return 0; + + Node &n = *i; + if (f != &n) { + if (n.p) n.p->n = n.n; + if (n.n) n.n->p = n.p; + if (l == &n) l = n.p; + n.p = 0; + n.n = f; + f->p = &n; + f = &n; + } + return n.t; + } + + Q_DISABLE_COPY(QCache) + +public: + inline explicit QCache(int maxCost = 100); +#ifdef QT3_SUPPORT + inline QT3_SUPPORT_CONSTRUCTOR QCache(int maxCost, int /* dummy */) + : f(0), l(0), mx(maxCost), total(0) {} +#endif + inline ~QCache() { clear(); } + + inline int maxCost() const { return mx; } + void setMaxCost(int m); + inline int totalCost() const { return total; } + + inline int size() const { return hash.size(); } + inline int count() const { return hash.size(); } + inline bool isEmpty() const { return hash.isEmpty(); } + inline QList<Key> keys() const { return hash.keys(); } + + void clear(); + + bool insert(const Key &key, T *object, int cost = 1); + T *object(const Key &key) const; + inline bool contains(const Key &key) const { return hash.contains(key); } + T *operator[](const Key &key) const; + + bool remove(const Key &key); + T *take(const Key &key); + +private: + void trim(int m); + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT T *find(const Key &key) const { return object(key); } +#endif + +}; + +template <class Key, class T> +inline QCache<Key, T>::QCache(int amaxCost) + : f(0), l(0), unused(0), mx(amaxCost), total(0) {} + +template <class Key, class T> +inline void QCache<Key,T>::clear() +{ while (f) { delete f->t; f = f->n; } + hash.clear(); l = 0; total = 0; } + +template <class Key, class T> +inline void QCache<Key,T>::setMaxCost(int m) +{ mx = m; trim(mx); } + +template <class Key, class T> +inline T *QCache<Key,T>::object(const Key &key) const +{ return const_cast<QCache<Key,T>*>(this)->relink(key); } + +template <class Key, class T> +inline T *QCache<Key,T>::operator[](const Key &key) const +{ return object(key); } + +template <class Key, class T> +inline bool QCache<Key,T>::remove(const Key &key) +{ + typename QHash<Key, Node>::iterator i = hash.find(key); + if (typename QHash<Key, Node>::const_iterator(i) == hash.constEnd()) { + return false; + } else { + unlink(*i); + return true; + } +} + +template <class Key, class T> +inline T *QCache<Key,T>::take(const Key &key) +{ + typename QHash<Key, Node>::iterator i = hash.find(key); + if (i == hash.end()) + return 0; + + Node &n = *i; + T *t = n.t; + n.t = 0; + unlink(n); + return t; +} + +template <class Key, class T> +bool QCache<Key,T>::insert(const Key &akey, T *aobject, int acost) +{ + remove(akey); + if (acost > mx) { + delete aobject; + return false; + } + trim(mx - acost); + Node sn(aobject, acost); + typename QHash<Key, Node>::iterator i = hash.insert(akey, sn); + total += acost; + Node *n = &i.value(); + n->keyPtr = &i.key(); + if (f) f->p = n; + n->n = f; + f = n; + if (!l) l = f; + return true; +} + +template <class Key, class T> +void QCache<Key,T>::trim(int m) +{ + Node *n = l; + while (n && total > m) { + Node *u = n; + n = n->p; + if (qIsDetached(*u->t)) + unlink(*u); + } +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCACHE_H diff --git a/src/corelib/tools/qcache.qdoc b/src/corelib/tools/qcache.qdoc new file mode 100644 index 0000000000..9e12c92c1c --- /dev/null +++ b/src/corelib/tools/qcache.qdoc @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** 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 documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QCache + \brief The QCache class is a template class that provides a cache. + + \ingroup tools + \ingroup shared + + \reentrant + + QCache\<Key, T\> defines a cache that stores objects of type T + associated with keys of type Key. For example, here's the + definition of a cache that stores objects of type Employee + associated with an integer key: + + \snippet doc/src/snippets/code/doc_src_qcache.cpp 0 + + Here's how to insert an object in the cache: + + \snippet doc/src/snippets/code/doc_src_qcache.cpp 1 + + The advantage of using QCache over some other key-based data + structure (such as QMap or QHash) is that QCache automatically + takes ownership of the objects that are inserted into the cache and + deletes them to make room for new objects, if necessary. When + inserting an object into the cache, you can specify a \e{cost}, + which should bear some approximate relationship to the amount of + memory taken by the object. When the sum of all objects' costs + (totalCost()) exceeds the cache's limit (maxCost()), QCache starts + deleting objects in the cache to keep under the limit, starting with + less recently accessed objects. + + By default, QCache's maxCost() is 100. You can specify a + different value in the QCache constructor: + + \snippet doc/src/snippets/code/doc_src_qcache.cpp 2 + + Each time you call insert(), you can specify a cost as third + argument (after the key and a pointer to the object to insert). + After the call, the inserted object is owned by the QCache, which + may delete it at any time to make room for other objects. + + To look up objects in the cache, use object() or + operator[](). This function looks up an object by its key, and + returns either a pointer to the cached object (which is owned by + the cache) or 0. + + If you want to remove an object from the cache for a particular key, + call remove(). This will also delete the object. If you want to + remove an object from the cache without the QCache deleting it, use + take(). + + \sa QPixmapCache, QHash, QMap +*/ + +/*! \fn QCache::QCache(int maxCost = 100) + + Constructs a cache whose contents will never have a total cost + greater than \a maxCost. +*/ + +/*! \fn QCache::~QCache() + + Destroys the cache. Deletes all the objects in the cache. +*/ + +/*! \fn int QCache::maxCost() const + + Returns the maximum allowed total cost of the cache. + + \sa setMaxCost(), totalCost() +*/ + +/*! \fn void QCache::setMaxCost(int cost) + + Sets the maximum allowed total cost of the cache to \a cost. If + the current total cost is greater than \a cost, some objects are + deleted immediately. + + \sa maxCost(), totalCost() +*/ + +/*! \fn int QCache::totalCost() const + + Returns the total cost of the objects in the cache. + + This value is normally below maxCost(), but QCache makes an + exception for Qt's \l{implicitly shared} classes. If a cached + object shares its internal data with another instance, QCache may + keep the object lying around, possibly contributing to making + totalCost() larger than maxCost(). + + \sa setMaxCost() +*/ + +/*! \fn int QCache::size() const + + Returns the number of objects in the cache. + + \sa isEmpty() +*/ + +/*! \fn int QCache::count() const + + Same as size(). +*/ + +/*! \fn bool QCache::isEmpty() const + + Returns true if the cache contains no objects; otherwise + returns false. + + \sa size() +*/ + +/*! \fn QList<Key> QCache::keys() const + + Returns a list of the keys in the cache. +*/ + +/*! \fn void QCache::clear(); + + Deletes all the objects in the cache. + + \sa remove(), take() +*/ + + +/*! \fn bool QCache::insert(const Key &key, T *object, int cost = 1) + + Inserts \a object into the cache with key \a key and + associated cost \a cost. Any object with the same key already in + the cache will be removed. + + After this call, \a object is owned by the QCache and may be + deleted at any time. In particular, if \a cost is greater than + maxCost(), the object will be deleted immediately. + + The function returns true if the object was inserted into the + cache; otherwise it returns false. + + \sa take(), remove() +*/ + +/*! \fn T *QCache::object(const Key &key) const + + Returns the object associated with key \a key, or 0 if the key does + not exist in the cache. + + \warning The returned object is owned by QCache and may be + deleted at any time. + + \sa take(), remove() +*/ + +/*! \fn bool QCache::contains(const Key &key) const + + Returns true if the cache contains an object associated with key \a + key; otherwise returns false. + + \sa take(), remove() +*/ + +/*! \fn T *QCache::operator[](const Key &key) const + + Returns the object associated with key \a key, or 0 if the key does + not exist in the cache. + + This is the same as object(). + + \warning The returned object is owned by QCache and may be + deleted at any time. +*/ + +/*! \fn bool QCache::remove(const Key &key) + + Deletes the object associated with key \a key. Returns true if the + object was found in the cache; otherwise returns false. + + \sa take(), clear() +*/ + +/*! \fn T *QCache::take(const Key &key) + + Takes the object associated with key \a key out of the cache + without deleting it. Returns a pointer to the object taken out, or + 0 if the key does not exist in the cache. + + The ownership of the returned object is passed to the caller. + + \sa remove() +*/ + +/*! + \fn QCache::QCache(int maxCost, int dummy) + + Use QCache(int) instead. +*/ + +/*! + \fn T *QCache::find(const Key &key) const + + Use object() instead. +*/ diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp new file mode 100644 index 0000000000..a9030074b3 --- /dev/null +++ b/src/corelib/tools/qchar.cpp @@ -0,0 +1,1654 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +// Don't define it while compiling this module, or USERS of Qt will +// not be able to link. +#ifdef QT_NO_CAST_FROM_ASCII +# undef QT_NO_CAST_FROM_ASCII +#endif +#ifdef QT_NO_CAST_TO_ASCII +# undef QT_NO_CAST_TO_ASCII +#endif +#include "qchar.h" + +#include "qdatastream.h" +#include "qtextcodec.h" + +#include "qunicodetables_p.h" +#include "qunicodetables.cpp" + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_CODEC_FOR_C_STRINGS +# ifdef QT_NO_TEXTCODEC +# define QT_NO_CODEC_FOR_C_STRINGS +# endif +#endif + +#define FLAG(x) (1 << (x)) + +/*! + \class QLatin1Char + \brief The QLatin1Char class provides an 8-bit ASCII/Latin-1 character. + + \ingroup string-processing + + This class is only useful to avoid the codec for C strings business + in the QChar(ch) constructor. You can avoid it by writing + QChar(ch, 0). + + \sa QChar, QLatin1String, QString +*/ + +/*! + \fn const char QLatin1Char::toLatin1() const + + Converts a Latin-1 character to an 8-bit ASCII representation of + the character. +*/ + +/*! + \fn const ushort QLatin1Char::unicode() const + + Converts a Latin-1 character to an 16-bit-encoded Unicode representation + of the character. +*/ + +/*! + \fn QLatin1Char::QLatin1Char(char c) + + Constructs a Latin-1 character for \a c. This constructor should be + used when the encoding of the input character is known to be Latin-1. +*/ + +/*! + \class QChar + \brief The QChar class provides a 16-bit Unicode character. + + \ingroup string-processing + \reentrant + + In Qt, Unicode characters are 16-bit entities without any markup + or structure. This class represents such an entity. It is + lightweight, so it can be used everywhere. Most compilers treat + it like a \c{unsigned short}. + + QChar provides a full complement of testing/classification + functions, converting to and from other formats, converting from + composed to decomposed Unicode, and trying to compare and + case-convert if you ask it to. + + The classification functions include functions like those in the + standard C++ header \<cctype\> (formerly \<ctype.h\>), but + operating on the full range of Unicode characters. They all + return true if the character is a certain type of character; + otherwise they return false. These classification functions are + isNull() (returns true if the character is '\\0'), isPrint() + (true if the character is any sort of printable character, + including whitespace), isPunct() (any sort of punctation), + isMark() (Unicode Mark), isLetter() (a letter), isNumber() (any + sort of numeric character, not just 0-9), isLetterOrNumber(), and + isDigit() (decimal digits). All of these are wrappers around + category() which return the Unicode-defined category of each + character. + + QChar also provides direction(), which indicates the "natural" + writing direction of this character. The joining() function + indicates how the character joins with its neighbors (needed + mostly for Arabic) and finally hasMirrored(), which indicates + whether the character needs to be mirrored when it is printed in + its "unnatural" writing direction. + + Composed Unicode characters (like \aring) can be converted to + decomposed Unicode ("a" followed by "ring above") by using + decomposition(). + + In Unicode, comparison is not necessarily possible and case + conversion is very difficult at best. Unicode, covering the + "entire" world, also includes most of the world's case and + sorting problems. operator==() and friends will do comparison + based purely on the numeric Unicode value (code point) of the + characters, and toUpper() and toLower() will do case changes when + the character has a well-defined uppercase/lowercase equivalent. + For locale-dependent comparisons, use + QString::localeAwareCompare(). + + The conversion functions include unicode() (to a scalar), + toLatin1() (to scalar, but converts all non-Latin-1 characters to + 0), row() (gives the Unicode row), cell() (gives the Unicode + cell), digitValue() (gives the integer value of any of the + numerous digit characters), and a host of constructors. + + QChar provides constructors and cast operators that make it easy + to convert to and from traditional 8-bit \c{char}s. If you + defined \c QT_NO_CAST_FROM_ASCII and \c QT_NO_CAST_TO_ASCII, as + explained in the QString documentation, you will need to + explicitly call fromAscii() or fromLatin1(), or use QLatin1Char, + to construct a QChar from an 8-bit \c char, and you will need to + call toAscii() or toLatin1() to get the 8-bit value back. + + \sa QString, Unicode, QLatin1Char +*/ + +/*! + \enum QChar::UnicodeVersion + + Specifies which version of the \l{http://www.unicode.org/}{Unicode standard} + introduced a certain character. + + \value Unicode_1_1 Version 1.1 + \value Unicode_2_0 Version 2.0 + \value Unicode_2_1_2 Version 2.1.2 + \value Unicode_3_0 Version 3.0 + \value Unicode_3_1 Version 3.1 + \value Unicode_3_2 Version 3.2 + \value Unicode_4_0 Version 4.0 + \value Unicode_4_1 Version 4.1 + \value Unicode_5_0 Version 5.0 + \value Unicode_Unassigned The value is not assigned to any character + in version 5.0 of Unicode. + + \sa unicodeVersion() +*/ + +/*! + \enum QChar::Category + + This enum maps the Unicode character categories. + + The following characters are normative in Unicode: + + \value Mark_NonSpacing Unicode class name Mn + + \value Mark_SpacingCombining Unicode class name Mc + + \value Mark_Enclosing Unicode class name Me + + \value Number_DecimalDigit Unicode class name Nd + + \value Number_Letter Unicode class name Nl + + \value Number_Other Unicode class name No + + \value Separator_Space Unicode class name Zs + + \value Separator_Line Unicode class name Zl + + \value Separator_Paragraph Unicode class name Zp + + \value Other_Control Unicode class name Cc + + \value Other_Format Unicode class name Cf + + \value Other_Surrogate Unicode class name Cs + + \value Other_PrivateUse Unicode class name Co + + \value Other_NotAssigned Unicode class name Cn + + + The following categories are informative in Unicode: + + \value Letter_Uppercase Unicode class name Lu + + \value Letter_Lowercase Unicode class name Ll + + \value Letter_Titlecase Unicode class name Lt + + \value Letter_Modifier Unicode class name Lm + + \value Letter_Other Unicode class name Lo + + \value Punctuation_Connector Unicode class name Pc + + \value Punctuation_Dash Unicode class name Pd + + \value Punctuation_Open Unicode class name Ps + + \value Punctuation_Close Unicode class name Pe + + \value Punctuation_InitialQuote Unicode class name Pi + + \value Punctuation_FinalQuote Unicode class name Pf + + \value Punctuation_Other Unicode class name Po + + \value Symbol_Math Unicode class name Sm + + \value Symbol_Currency Unicode class name Sc + + \value Symbol_Modifier Unicode class name Sk + + \value Symbol_Other Unicode class name So + + \value NoCategory Qt cannot find an appropriate category for the character. + + \omitvalue Punctuation_Dask + + \sa category() +*/ + +/*! + \enum QChar::Direction + + This enum type defines the Unicode direction attributes. See the + \l{http://www.unicode.org/}{Unicode Standard} for a description + of the values. + + In order to conform to C/C++ naming conventions "Dir" is prepended + to the codes used in the Unicode Standard. + + \value DirAL + \value DirAN + \value DirB + \value DirBN + \value DirCS + \value DirEN + \value DirES + \value DirET + \value DirL + \value DirLRE + \value DirLRO + \value DirNSM + \value DirON + \value DirPDF + \value DirR + \value DirRLE + \value DirRLO + \value DirS + \value DirWS + + \sa direction() +*/ + +/*! + \enum QChar::Decomposition + + This enum type defines the Unicode decomposition attributes. See + the \l{http://www.unicode.org/}{Unicode Standard} for a + description of the values. + + \value NoDecomposition + \value Canonical + \value Circle + \value Compat + \value Final + \value Font + \value Fraction + \value Initial + \value Isolated + \value Medial + \value Narrow + \value NoBreak + \value Small + \value Square + \value Sub + \value Super + \value Vertical + \value Wide + + \omitvalue Single + + \sa decomposition() +*/ + +/*! + \enum QChar::Joining + + This enum type defines the Unicode joining attributes. See the + \l{http://www.unicode.org/}{Unicode Standard} for a description + of the values. + + \value Center + \value Dual + \value OtherJoining + \value Right + + \sa joining() +*/ + +/*! + \enum QChar::CombiningClass + + \internal + + This enum type defines names for some of the Unicode combining + classes. See the \l{http://www.unicode.org/}{Unicode Standard} + for a description of the values. + + \value Combining_Above + \value Combining_AboveAttached + \value Combining_AboveLeft + \value Combining_AboveLeftAttached + \value Combining_AboveRight + \value Combining_AboveRightAttached + \value Combining_Below + \value Combining_BelowAttached + \value Combining_BelowLeft + \value Combining_BelowLeftAttached + \value Combining_BelowRight + \value Combining_BelowRightAttached + \value Combining_DoubleAbove + \value Combining_DoubleBelow + \value Combining_IotaSubscript + \value Combining_Left + \value Combining_LeftAttached + \value Combining_Right + \value Combining_RightAttached +*/ + +/*! + \enum QChar::SpecialCharacter + + \value Null A QChar with this value isNull(). + \value Nbsp Non-breaking space. + \value ReplacementCharacter The character shown when a font has no glyph + for a certain codepoint. A special question mark character is often + used. Codecs use this codepoint when input data cannot be + represented in Unicode. + \value ObjectReplacementCharacter Used to represent an object such as an + image when such objects cannot be presented. + \value ByteOrderMark + \value ByteOrderSwapped + \value ParagraphSeparator + \value LineSeparator + + \omitvalue null + \omitvalue replacement + \omitvalue byteOrderMark + \omitvalue byteOrderSwapped + \omitvalue nbsp +*/ + +/*! + \fn void QChar::setCell(uchar cell) + \internal +*/ + +/*! + \fn void QChar::setRow(uchar row) + \internal +*/ + +/*! + \fn QChar::QChar() + + Constructs a null QChar ('\\0'). + + \sa isNull() +*/ + +/*! + \fn QChar::QChar(QLatin1Char ch) + + Constructs a QChar corresponding to ASCII/Latin-1 character \a ch. +*/ + +/*! + \fn QChar::QChar(SpecialCharacter ch) + + Constructs a QChar for the predefined character value \a ch. +*/ + +/*! + Constructs a QChar corresponding to ASCII/Latin-1 character \a + ch. +*/ +QChar::QChar(char ch) +{ +#ifndef QT_NO_CODEC_FOR_C_STRINGS + if (QTextCodec::codecForCStrings()) + // ##### + ucs = QTextCodec::codecForCStrings()->toUnicode(&ch, 1).at(0).unicode(); + else +#endif + ucs = uchar(ch); +} + +/*! + Constructs a QChar corresponding to ASCII/Latin-1 character \a ch. +*/ +QChar::QChar(uchar ch) +{ +#ifndef QT_NO_CODEC_FOR_C_STRINGS + if (QTextCodec::codecForCStrings()) { + // ##### + char c = char(ch); + ucs = QTextCodec::codecForCStrings()->toUnicode(&c, 1).at(0).unicode(); + } else +#endif + ucs = ch; +} + +/*! + \fn QChar::QChar(uchar cell, uchar row) + + Constructs a QChar for Unicode cell \a cell in row \a row. + + \sa cell(), row() +*/ + +/*! + \fn QChar::QChar(ushort code) + + Constructs a QChar for the character with Unicode code point \a + code. +*/ + + +/*! + \fn QChar::QChar(short code) + + Constructs a QChar for the character with Unicode code point \a + code. +*/ + + +/*! + \fn QChar::QChar(uint code) + + Constructs a QChar for the character with Unicode code point \a + code. +*/ + + +/*! + \fn QChar::QChar(int code) + + Constructs a QChar for the character with Unicode code point \a + code. +*/ + + +/*! + \fn bool QChar::isNull() const + + Returns true if the character is the Unicode character 0x0000 + ('\\0'); otherwise returns false. +*/ + +/*! + \fn uchar QChar::cell() const + + Returns the cell (least significant byte) of the Unicode + character. + + \sa row() +*/ + +/*! + \fn uchar QChar::row() const + + Returns the row (most significant byte) of the Unicode character. + + \sa cell() +*/ + +/*! + Returns true if the character is a printable character; otherwise + returns false. This is any character not of category Cc or Cn. + + Note that this gives no indication of whether the character is + available in a particular font. +*/ +bool QChar::isPrint() const +{ + const int test = FLAG(Other_Control) | + FLAG(Other_NotAssigned); + return !(FLAG(qGetProp(ucs)->category) & test); +} + +/*! + Returns true if the character is a separator character + (Separator_* categories); otherwise returns false. +*/ +bool QChar::isSpace() const +{ + if(ucs >= 9 && ucs <=13) + return true; + const int test = FLAG(Separator_Space) | + FLAG(Separator_Line) | + FLAG(Separator_Paragraph); + return FLAG(qGetProp(ucs)->category) & test; +} + +/*! + Returns true if the character is a mark (Mark_* categories); + otherwise returns false. + + See QChar::Category for more information regarding marks. +*/ +bool QChar::isMark() const +{ + const int test = FLAG(Mark_NonSpacing) | + FLAG(Mark_SpacingCombining) | + FLAG(Mark_Enclosing); + return FLAG(qGetProp(ucs)->category) & test; +} + +/*! + Returns true if the character is a punctuation mark (Punctuation_* + categories); otherwise returns false. +*/ +bool QChar::isPunct() const +{ + const int test = FLAG(Punctuation_Connector) | + FLAG(Punctuation_Dash) | + FLAG(Punctuation_Open) | + FLAG(Punctuation_Close) | + FLAG(Punctuation_InitialQuote) | + FLAG(Punctuation_FinalQuote) | + FLAG(Punctuation_Other); + return FLAG(qGetProp(ucs)->category) & test; +} + +/*! + Returns true if the character is a letter (Letter_* categories); + otherwise returns false. +*/ +bool QChar::isLetter() const +{ + const int test = FLAG(Letter_Uppercase) | + FLAG(Letter_Lowercase) | + FLAG(Letter_Titlecase) | + FLAG(Letter_Modifier) | + FLAG(Letter_Other); + return FLAG(qGetProp(ucs)->category) & test; +} + +/*! + Returns true if the character is a number (Number_* categories, + not just 0-9); otherwise returns false. + + \sa isDigit() +*/ +bool QChar::isNumber() const +{ + const int test = FLAG(Number_DecimalDigit) | + FLAG(Number_Letter) | + FLAG(Number_Other); + return FLAG(qGetProp(ucs)->category) & test; +} + +/*! + Returns true if the character is a letter or number (Letter_* or + Number_* categories); otherwise returns false. +*/ +bool QChar::isLetterOrNumber() const +{ + const int test = FLAG(Letter_Uppercase) | + FLAG(Letter_Lowercase) | + FLAG(Letter_Titlecase) | + FLAG(Letter_Modifier) | + FLAG(Letter_Other) | + FLAG(Number_DecimalDigit) | + FLAG(Number_Letter) | + FLAG(Number_Other); + return FLAG(qGetProp(ucs)->category) & test; +} + + +/*! + Returns true if the character is a decimal digit + (Number_DecimalDigit); otherwise returns false. +*/ +bool QChar::isDigit() const +{ + return (qGetProp(ucs)->category == Number_DecimalDigit); +} + + +/*! + Returns true if the character is a symbol (Symbol_* categories); + otherwise returns false. +*/ +bool QChar::isSymbol() const +{ + const int test = FLAG(Symbol_Math) | + FLAG(Symbol_Currency) | + FLAG(Symbol_Modifier) | + FLAG(Symbol_Other); + return FLAG(qGetProp(ucs)->category) & test; +} + +/*! + \fn bool QChar::isHighSurrogate() const + + Returns true if the QChar is the high part of a utf16 surrogate + (ie. if its code point is between 0xd800 and 0xdbff, inclusive). +*/ + +/*! + \fn bool QChar::isLowSurrogate() const + + Returns true if the QChar is the low part of a utf16 surrogate + (ie. if its code point is between 0xdc00 and 0xdfff, inclusive). +*/ + +/*! + \fn static bool QChar::isHighSurrogate(uint ucs4) + \since 4.7 + + Returns true if the UCS-4-encoded character specified by \a ucs4 + is the high part of a utf16 surrogate + (ie. if its code point is between 0xd800 and 0xdbff, inclusive). +*/ + +/*! + \fn static bool QChar::isLowSurrogate(uint ucs4) + \since 4.7 + + Returns true if the UCS-4-encoded character specified by \a ucs4 + is the low part of a utf16 surrogate + (ie. if its code point is between 0xdc00 and 0xdfff, inclusive). +*/ + +/*! + \fn static bool QChar::requiresSurrogates(uint ucs4) + \since 4.7 + + Returns true if the UCS-4-encoded character specified by \a ucs4 + can be split into the high and low parts of a utf16 surrogate + (ie. if its code point is greater than or equals to 0x10000). +*/ + +/*! + \fn static uint QChar::surrogateToUcs4(ushort high, ushort low) + + Converts a UTF16 surrogate pair with the given \a high and \a low values + to its UCS-4 code point. +*/ + +/*! + \fn static uint QChar::surrogateToUcs4(QChar high, QChar low) + + Converts a utf16 surrogate pair (\a high, \a low) to its ucs4 code point. +*/ + +/*! + \fn static ushort QChar::highSurrogate(uint ucs4) + + Returns the high surrogate value of a ucs4 code point. + The returned result is undefined if \a ucs4 is smaller than 0x10000. +*/ + +/*! + \fn static ushort QChar::lowSurrogate(uint ucs4) + + Returns the low surrogate value of a ucs4 code point. + The returned result is undefined if \a ucs4 is smaller than 0x10000. +*/ + +/*! + Returns the numeric value of the digit, or -1 if the character is + not a digit. +*/ +int QChar::digitValue() const +{ + return qGetProp(ucs)->digitValue; +} + +/*! + \overload + Returns the numeric value of the digit, specified by the UCS-2-encoded + character, \a ucs2, or -1 if the character is not a digit. +*/ +int QChar::digitValue(ushort ucs2) +{ + return qGetProp(ucs2)->digitValue; +} + +/*! + \overload + Returns the numeric value of the digit specified by the UCS-4-encoded + character, \a ucs4, or -1 if the character is not a digit. +*/ +int QChar::digitValue(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return 0; + return qGetProp(ucs4)->digitValue; +} + +/*! + Returns the character's category. +*/ +QChar::Category QChar::category() const +{ + return (QChar::Category) qGetProp(ucs)->category; +} + +/*! + \overload + \since 4.3 + Returns the category of the UCS-4-encoded character specified by \a ucs4. +*/ +QChar::Category QChar::category(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return QChar::NoCategory; + return (QChar::Category) qGetProp(ucs4)->category; +} + +/*! + \overload + Returns the category of the UCS-2-encoded character specified by \a ucs2. +*/ +QChar::Category QChar::category(ushort ucs2) +{ + return (QChar::Category) qGetProp(ucs2)->category; +} + + +/*! + Returns the character's direction. +*/ +QChar::Direction QChar::direction() const +{ + return (QChar::Direction) qGetProp(ucs)->direction; +} + +/*! + \overload + Returns the direction of the UCS-4-encoded character specified by \a ucs4. +*/ +QChar::Direction QChar::direction(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return QChar::DirL; + return (QChar::Direction) qGetProp(ucs4)->direction; +} + +/*! + \overload + Returns the direction of the UCS-2-encoded character specified by \a ucs2. +*/ +QChar::Direction QChar::direction(ushort ucs2) +{ + return (QChar::Direction) qGetProp(ucs2)->direction; +} + +/*! + Returns information about the joining properties of the character + (needed for certain languages such as Arabic). +*/ +QChar::Joining QChar::joining() const +{ + return (QChar::Joining) qGetProp(ucs)->joining; +} + +/*! + \overload + Returns information about the joining properties of the UCS-4-encoded + character specified by \a ucs4 (needed for certain languages such as + Arabic). +*/ +QChar::Joining QChar::joining(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return QChar::OtherJoining; + return (QChar::Joining) qGetProp(ucs4)->joining; +} + +/*! + \overload + Returns information about the joining properties of the UCS-2-encoded + character specified by \a ucs2 (needed for certain languages such as + Arabic). +*/ +QChar::Joining QChar::joining(ushort ucs2) +{ + return (QChar::Joining) qGetProp(ucs2)->joining; +} + + +/*! + Returns true if the character should be reversed if the text + direction is reversed; otherwise returns false. + + Same as (ch.mirroredChar() != ch). + + \sa mirroredChar() +*/ +bool QChar::hasMirrored() const +{ + return qGetProp(ucs)->mirrorDiff != 0; +} + +/*! + \fn bool QChar::isLower() const + + Returns true if the character is a lowercase letter, i.e. + category() is Letter_Lowercase. + + \sa isUpper(), toLower(), toUpper() +*/ + +/*! + \fn bool QChar::isUpper() const + + Returns true if the character is an uppercase letter, i.e. + category() is Letter_Uppercase. + + \sa isLower(), toUpper(), toLower() +*/ + +/*! + \fn bool QChar::isTitleCase() const + \since 4.3 + + Returns true if the character is a titlecase letter, i.e. + category() is Letter_Titlecase. + + \sa isLower(), toUpper(), toLower(), toTitleCase() +*/ + +/*! + Returns the mirrored character if this character is a mirrored + character; otherwise returns the character itself. + + \sa hasMirrored() +*/ +QChar QChar::mirroredChar() const +{ + return ucs + qGetProp(ucs)->mirrorDiff; +} + +/*! + \overload + Returns the mirrored character if the UCS-4-encoded character specified + by \a ucs4 is a mirrored character; otherwise returns the character itself. + + \sa hasMirrored() +*/ +uint QChar::mirroredChar(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return ucs4; + return ucs4 + qGetProp(ucs4)->mirrorDiff; +} + +/*! + \overload + Returns the mirrored character if the UCS-2-encoded character specified + by \a ucs2 is a mirrored character; otherwise returns the character itself. + + \sa hasMirrored() +*/ +ushort QChar::mirroredChar(ushort ucs2) +{ + return ucs2 + qGetProp(ucs2)->mirrorDiff; +} + + +enum { + Hangul_SBase = 0xac00, + Hangul_LBase = 0x1100, + Hangul_VBase = 0x1161, + Hangul_TBase = 0x11a7, + Hangul_SCount = 11172, + Hangul_LCount = 19, + Hangul_VCount = 21, + Hangul_TCount = 28, + Hangul_NCount = 21*28 +}; + +// buffer has to have a length of 3. It's needed for Hangul decomposition +static const unsigned short * QT_FASTCALL decompositionHelper + (uint ucs4, int *length, int *tag, unsigned short *buffer) +{ + *length = 0; + if (ucs4 > UNICODE_LAST_CODEPOINT) + return 0; + if (ucs4 >= Hangul_SBase && ucs4 < Hangul_SBase + Hangul_SCount) { + int SIndex = ucs4 - Hangul_SBase; + buffer[0] = Hangul_LBase + SIndex / Hangul_NCount; // L + buffer[1] = Hangul_VBase + (SIndex % Hangul_NCount) / Hangul_TCount; // V + buffer[2] = Hangul_TBase + SIndex % Hangul_TCount; // T + *length = buffer[2] == Hangul_TBase ? 2 : 3; + *tag = QChar::Canonical; + return buffer; + } + + const unsigned short index = GET_DECOMPOSITION_INDEX(ucs4); + if (index == 0xffff) + return 0; + const unsigned short *decomposition = uc_decomposition_map+index; + *tag = (*decomposition) & 0xff; + *length = (*decomposition) >> 8; + return decomposition+1; +} + +/*! + Decomposes a character into its parts. Returns an empty string if + no decomposition exists. +*/ +QString QChar::decomposition() const +{ + return decomposition(ucs); +} + +/*! + \overload + Decomposes the UCS-4-encoded character specified by \a ucs4 into its + constituent parts. Returns an empty string if no decomposition exists. +*/ +QString QChar::decomposition(uint ucs4) +{ + unsigned short buffer[3]; + int length; + int tag; + const unsigned short *d = decompositionHelper(ucs4, &length, &tag, buffer); + return QString::fromUtf16(d, length); +} + +/*! + Returns the tag defining the composition of the character. Returns + QChar::Single if no decomposition exists. +*/ +QChar::Decomposition QChar::decompositionTag() const +{ + return decompositionTag(ucs); +} + +/*! + \overload + Returns the tag defining the composition of the UCS-4-encoded character + specified by \a ucs4. Returns QChar::Single if no decomposition exists. +*/ +QChar::Decomposition QChar::decompositionTag(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return QChar::NoDecomposition; + const unsigned short index = GET_DECOMPOSITION_INDEX(ucs4); + if (index == 0xffff) + return QChar::NoDecomposition; + return (QChar::Decomposition)(uc_decomposition_map[index] & 0xff); +} + +/*! + Returns the combining class for the character as defined in the + Unicode standard. This is mainly useful as a positioning hint for + marks attached to a base character. + + The Qt text rendering engine uses this information to correctly + position non-spacing marks around a base character. +*/ +unsigned char QChar::combiningClass() const +{ + return (unsigned char) qGetProp(ucs)->combiningClass; +} + +/*! + \overload + Returns the combining class for the UCS-4-encoded character specified by + \a ucs4, as defined in the Unicode standard. +*/ +unsigned char QChar::combiningClass(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return 0; + return (unsigned char) qGetProp(ucs4)->combiningClass; +} + +/*! + \overload + Returns the combining class for the UCS-2-encoded character specified by + \a ucs2, as defined in the Unicode standard. +*/ +unsigned char QChar::combiningClass(ushort ucs2) +{ + return (unsigned char) qGetProp(ucs2)->combiningClass; +} + +/*! + Returns the Unicode version that introduced this character. +*/ +QChar::UnicodeVersion QChar::unicodeVersion() const +{ + return (QChar::UnicodeVersion) qGetProp(ucs)->unicodeVersion; +} + +/*! + \overload + Returns the Unicode version that introduced the character specified in + its UCS-4-encoded form as \a ucs4. +*/ +QChar::UnicodeVersion QChar::unicodeVersion(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return QChar::Unicode_Unassigned; + return (QChar::UnicodeVersion) qGetProp(ucs4)->unicodeVersion; +} + +/*! + \overload + Returns the Unicode version that introduced the character specified in + its UCS-2-encoded form as \a ucs2. +*/ +QChar::UnicodeVersion QChar::unicodeVersion(ushort ucs2) +{ + return (QChar::UnicodeVersion) qGetProp(ucs2)->unicodeVersion; +} + +/*! + \since 4.8 + + Returns the most recent supported Unicode version. +*/ +QChar::UnicodeVersion QChar::currentUnicodeVersion() +{ + return UNICODE_DATA_VERSION; +} + +/*! + Returns the lowercase equivalent if the character is uppercase or titlecase; + otherwise returns the character itself. +*/ +QChar QChar::toLower() const +{ + const QUnicodeTables::Properties *p = qGetProp(ucs); + if (!p->lowerCaseSpecial) + return ucs + p->lowerCaseDiff; + return ucs; +} + +/*! + \overload + Returns the lowercase equivalent of the UCS-4-encoded character specified + by \a ucs4 if the character is uppercase or titlecase; otherwise returns + the character itself. +*/ +uint QChar::toLower(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return ucs4; + const QUnicodeTables::Properties *p = qGetProp(ucs4); + if (!p->lowerCaseSpecial) + return ucs4 + p->lowerCaseDiff; + return ucs4; +} + +/*! + \overload + Returns the lowercase equivalent of the UCS-2-encoded character specified + by \a ucs2 if the character is uppercase or titlecase; otherwise returns + the character itself. +*/ +ushort QChar::toLower(ushort ucs2) +{ + const QUnicodeTables::Properties *p = qGetProp(ucs2); + if (!p->lowerCaseSpecial) + return ucs2 + p->lowerCaseDiff; + return ucs2; +} + +/*! + Returns the uppercase equivalent if the character is lowercase or titlecase; + otherwise returns the character itself. +*/ +QChar QChar::toUpper() const +{ + const QUnicodeTables::Properties *p = qGetProp(ucs); + if (!p->upperCaseSpecial) + return ucs + p->upperCaseDiff; + return ucs; +} + +/*! + \overload + Returns the uppercase equivalent of the UCS-4-encoded character specified + by \a ucs4 if the character is lowercase or titlecase; otherwise returns + the character itself. +*/ +uint QChar::toUpper(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return ucs4; + const QUnicodeTables::Properties *p = qGetProp(ucs4); + if (!p->upperCaseSpecial) + return ucs4 + p->upperCaseDiff; + return ucs4; +} + +/*! + \overload + Returns the uppercase equivalent of the UCS-2-encoded character specified + by \a ucs2 if the character is lowercase or titlecase; otherwise returns + the character itself. +*/ +ushort QChar::toUpper(ushort ucs2) +{ + const QUnicodeTables::Properties *p = qGetProp(ucs2); + if (!p->upperCaseSpecial) + return ucs2 + p->upperCaseDiff; + return ucs2; +} + +/*! + Returns the title case equivalent if the character is lowercase or uppercase; + otherwise returns the character itself. +*/ +QChar QChar::toTitleCase() const +{ + const QUnicodeTables::Properties *p = qGetProp(ucs); + if (!p->titleCaseSpecial) + return ucs + p->titleCaseDiff; + return ucs; +} + +/*! + \overload + Returns the title case equivalent of the UCS-4-encoded character specified + by \a ucs4 if the character is lowercase or uppercase; otherwise returns + the character itself. +*/ +uint QChar::toTitleCase(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return ucs4; + const QUnicodeTables::Properties *p = qGetProp(ucs4); + if (!p->titleCaseSpecial) + return ucs4 + p->titleCaseDiff; + return ucs4; +} + +/*! + \overload + Returns the title case equivalent of the UCS-2-encoded character specified + by \a ucs2 if the character is lowercase or uppercase; otherwise returns + the character itself. +*/ +ushort QChar::toTitleCase(ushort ucs2) +{ + const QUnicodeTables::Properties *p = qGetProp(ucs2); + if (!p->titleCaseSpecial) + return ucs2 + p->titleCaseDiff; + return ucs2; +} + + +static inline uint foldCase(const ushort *ch, const ushort *start) +{ + uint c = *ch; + if (QChar(c).isLowSurrogate() && ch > start && QChar(*(ch - 1)).isHighSurrogate()) + c = QChar::surrogateToUcs4(*(ch - 1), c); + return *ch + qGetProp(c)->caseFoldDiff; +} + +static inline uint foldCase(uint ch, uint &last) +{ + uint c = ch; + if (QChar(c).isLowSurrogate() && QChar(last).isHighSurrogate()) + c = QChar::surrogateToUcs4(last, c); + last = ch; + return ch + qGetProp(c)->caseFoldDiff; +} + +static inline ushort foldCase(ushort ch) +{ + return ch + qGetProp(ch)->caseFoldDiff; +} + +/*! + Returns the case folded equivalent of the character. For most Unicode characters this + is the same as toLowerCase(). +*/ +QChar QChar::toCaseFolded() const +{ + return ucs + qGetProp(ucs)->caseFoldDiff; +} + +/*! + \overload + Returns the case folded equivalent of the UCS-4-encoded character specified + by \a ucs4. For most Unicode characters this is the same as toLowerCase(). +*/ +uint QChar::toCaseFolded(uint ucs4) +{ + if (ucs4 > UNICODE_LAST_CODEPOINT) + return ucs4; + return ucs4 + qGetProp(ucs4)->caseFoldDiff; +} + +/*! + \overload + Returns the case folded equivalent of the UCS-2-encoded character specified + by \a ucs2. For most Unicode characters this is the same as toLowerCase(). +*/ +ushort QChar::toCaseFolded(ushort ucs2) +{ + return ucs2 + qGetProp(ucs2)->caseFoldDiff; +} + + +/*! + \fn char QChar::latin1() const + + Use toLatin1() instead. +*/ + +/*! + \fn char QChar::ascii() const + + Use toAscii() instead. +*/ + +/*! + \fn char QChar::toLatin1() const + + Returns the Latin-1 character equivalent to the QChar, or 0. This + is mainly useful for non-internationalized software. + + \sa toAscii(), unicode(), QTextCodec::codecForCStrings() +*/ + +/*! + \fn char QChar::toAscii() const + Returns the character value of the QChar obtained using the current + codec used to read C strings, or 0 if the character is not representable + using this codec. The default codec handles Latin-1 encoded text, + but this can be changed to assist developers writing source code using + other encodings. + + The main purpose of this function is to preserve ASCII characters used + in C strings. This is mainly useful for developers of non-internationalized + software. + + \sa toLatin1(), unicode(), QTextCodec::codecForCStrings() +*/ +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE +const char QChar::toAscii() const +#else +char QChar::toAscii() const +#endif +{ +#ifndef QT_NO_CODEC_FOR_C_STRINGS + if (QTextCodec::codecForCStrings()) + // ##### + return QTextCodec::codecForCStrings()->fromUnicode(QString(*this)).at(0); +#endif + return ucs > 0xff ? 0 : char(ucs); +} + +/*! + \fn QChar QChar::fromLatin1(char c) + + Converts the Latin-1 character \a c to its equivalent QChar. This + is mainly useful for non-internationalized software. + + \sa fromAscii(), unicode(), QTextCodec::codecForCStrings() +*/ + +/*! + Converts the ASCII character \a c to its equivalent QChar. This + is mainly useful for non-internationalized software. + + An alternative is to use QLatin1Char. + + \sa fromLatin1(), unicode(), QTextCodec::codecForCStrings() +*/ +QChar QChar::fromAscii(char c) +{ +#ifndef QT_NO_CODEC_FOR_C_STRINGS + if (QTextCodec::codecForCStrings()) + // ##### + return QTextCodec::codecForCStrings()->toUnicode(&c, 1).at(0).unicode(); +#endif + return QChar(ushort((uchar)c)); +} + +#ifndef QT_NO_DATASTREAM +/*! + \relates QChar + + Writes the char \a chr to the stream \a out. + + \sa {Serializing Qt Data Types} +*/ +QDataStream &operator<<(QDataStream &out, const QChar &chr) +{ + out << quint16(chr.unicode()); + return out; +} + +/*! + \relates QChar + + Reads a char from the stream \a in into char \a chr. + + \sa {Serializing Qt Data Types} +*/ +QDataStream &operator>>(QDataStream &in, QChar &chr) +{ + quint16 u; + in >> u; + chr.unicode() = ushort(u); + return in; +} +#endif // QT_NO_DATASTREAM + +/*! + \fn ushort & QChar::unicode() + + Returns a reference to the numeric Unicode value of the QChar. +*/ + +/*! + \fn ushort QChar::unicode() const + + \overload +*/ + +/***************************************************************************** + Documentation of QChar related functions + *****************************************************************************/ + +/*! + \fn bool operator==(QChar c1, QChar c2) + + \relates QChar + + Returns true if \a c1 and \a c2 are the same Unicode character; + otherwise returns false. +*/ + +/*! + \fn int operator!=(QChar c1, QChar c2) + + \relates QChar + + Returns true if \a c1 and \a c2 are not the same Unicode + character; otherwise returns false. +*/ + +/*! + \fn int operator<=(QChar c1, QChar c2) + + \relates QChar + + Returns true if the numeric Unicode value of \a c1 is less than + or equal to that of \a c2; otherwise returns false. +*/ + +/*! + \fn int operator>=(QChar c1, QChar c2) + + \relates QChar + + Returns true if the numeric Unicode value of \a c1 is greater than + or equal to that of \a c2; otherwise returns false. +*/ + +/*! + \fn int operator<(QChar c1, QChar c2) + + \relates QChar + + Returns true if the numeric Unicode value of \a c1 is less than + that of \a c2; otherwise returns false. +*/ + +/*! + \fn int operator>(QChar c1, QChar c2) + + \relates QChar + + Returns true if the numeric Unicode value of \a c1 is greater than + that of \a c2; otherwise returns false. +*/ + +/*! + \fn bool QChar::mirrored() const + + Use hasMirrored() instead. +*/ + +/*! + \fn QChar QChar::lower() const + + Use toLower() instead. +*/ + +/*! + \fn QChar QChar::upper() const + + Use toUpper() instead. +*/ + +/*! + \fn bool QChar::networkOrdered() + + See if QSysInfo::ByteOrder == QSysInfo::BigEndian instead. +*/ + + +// --------------------------------------------------------------------------- + + +static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion version, int from) +{ + unsigned short buffer[3]; + + QString &s = *str; + + const unsigned short *utf16 = reinterpret_cast<unsigned short *>(s.data()); + const unsigned short *uc = utf16 + s.length(); + while (uc != utf16 + from) { + uint ucs4 = *(--uc); + if (QChar(ucs4).isLowSurrogate() && uc != utf16) { + ushort high = *(uc - 1); + if (QChar(high).isHighSurrogate()) { + --uc; + ucs4 = QChar::surrogateToUcs4(high, ucs4); + } + } + if (QChar::unicodeVersion(ucs4) > version) + continue; + int length; + int tag; + const unsigned short *d = decompositionHelper(ucs4, &length, &tag, buffer); + if (!d || (canonical && tag != QChar::Canonical)) + continue; + + int pos = uc - utf16; + s.replace(pos, QChar::requiresSurrogates(ucs4) ? 2 : 1, reinterpret_cast<const QChar *>(d), length); + // since the insert invalidates the pointers and we do decomposition recursive + utf16 = reinterpret_cast<unsigned short *>(s.data()); + uc = utf16 + pos + length; + } +} + + +struct UCS2Pair { + ushort u1; + ushort u2; +}; + +inline bool operator<(ushort u1, const UCS2Pair &ligature) +{ return u1 < ligature.u1; } +inline bool operator<(const UCS2Pair &ligature, ushort u1) +{ return ligature.u1 < u1; } + +static ushort ligatureHelper(ushort u1, ushort u2) +{ + // hangul L-V pair + int LIndex = u1 - Hangul_LBase; + if (0 <= LIndex && LIndex < Hangul_LCount) { + int VIndex = u2 - Hangul_VBase; + if (0 <= VIndex && VIndex < Hangul_VCount) + return Hangul_SBase + (LIndex * Hangul_VCount + VIndex) * Hangul_TCount; + } + + // hangul LV-T pair + int SIndex = u1 - Hangul_SBase; + if (0 <= SIndex && SIndex < Hangul_SCount && (SIndex % Hangul_TCount) == 0) { + int TIndex = u2 - Hangul_TBase; + if (0 <= TIndex && TIndex <= Hangul_TCount) + return u1 + TIndex; + } + + const unsigned short index = GET_LIGATURE_INDEX(u2); + if (index == 0xffff) + return 0; + const unsigned short *ligatures = uc_ligature_map+index; + ushort length = *ligatures++; + { + const UCS2Pair *data = reinterpret_cast<const UCS2Pair *>(ligatures); + const UCS2Pair *r = qBinaryFind(data, data + length, u1); + if (r != data + length) + return r->u2; + } + + return 0; +} + +static void composeHelper(QString *str, int from) +{ + QString &s = *str; + + if (s.length() - from < 2) + return; + + // the loop can partly ignore high Unicode as all ligatures are in the BMP + int starter = 0; + int lastCombining = 0; + int pos = from; + while (pos < s.length()) { + uint uc = s.at(pos).unicode(); + if (QChar(uc).isHighSurrogate() && pos < s.length()-1) { + ushort low = s.at(pos+1).unicode(); + if (QChar(low).isLowSurrogate()) { + uc = QChar::surrogateToUcs4(uc, low); + ++pos; + } + } + int combining = QChar::combiningClass(uc); + if (starter == pos - 1 || combining > lastCombining) { + // allowed to form ligature with S + QChar ligature = ligatureHelper(s.at(starter).unicode(), uc); + if (ligature.unicode()) { + s[starter] = ligature; + s.remove(pos, 1); + continue; + } + } + if (!combining) + starter = pos; + lastCombining = combining; + ++pos; + } +} + + +static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, int from) +{ + QString &s = *str; + const int l = s.length()-1; + int pos = from; + while (pos < l) { + int p2 = pos+1; + uint u1 = s.at(pos).unicode(); + if (QChar(u1).isHighSurrogate()) { + ushort low = s.at(p2).unicode(); + if (QChar(low).isLowSurrogate()) { + u1 = QChar::surrogateToUcs4(u1, low); + if (p2 >= l) + break; + ++p2; + } + } + uint u2 = s.at(p2).unicode(); + if (QChar(u2).isHighSurrogate() && p2 < l) { + ushort low = s.at(p2+1).unicode(); + if (QChar(low).isLowSurrogate()) { + u2 = QChar::surrogateToUcs4(u2, low); + ++p2; + } + } + + ushort c2 = 0; + { + const QUnicodeTables::Properties *p = qGetProp(u2); + if ((QChar::UnicodeVersion)p->unicodeVersion <= version) + c2 = p->combiningClass; + } + if (c2 == 0) { + pos = p2+1; + continue; + } + + ushort c1 = 0; + { + const QUnicodeTables::Properties *p = qGetProp(u1); + if ((QChar::UnicodeVersion)p->unicodeVersion <= version) + c1 = p->combiningClass; + } + + if (c1 > c2) { + QChar *uc = s.data(); + int p = pos; + // exchange characters + if (!QChar::requiresSurrogates(u2)) { + uc[p++] = u2; + } else { + uc[p++] = QChar::highSurrogate(u2); + uc[p++] = QChar::lowSurrogate(u2); + } + if (!QChar::requiresSurrogates(u1)) { + uc[p++] = u1; + } else { + uc[p++] = QChar::highSurrogate(u1); + uc[p++] = QChar::lowSurrogate(u1); + } + if (pos > 0) + --pos; + if (pos > 0 && s.at(pos).isLowSurrogate()) + --pos; + } else { + ++pos; + if (QChar::requiresSurrogates(u1)) + ++pos; + } + } +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h new file mode 100644 index 0000000000..508053671c --- /dev/null +++ b/src/corelib/tools/qchar.h @@ -0,0 +1,404 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QCHAR_H +#define QCHAR_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QString; + +struct QLatin1Char +{ +public: + inline explicit QLatin1Char(char c) : ch(c) {} +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE + inline const char toLatin1() const { return ch; } + inline const ushort unicode() const { return ushort(uchar(ch)); } +#else + inline char toLatin1() const { return ch; } + inline ushort unicode() const { return ushort(uchar(ch)); } +#endif + +private: + char ch; +}; + + +class Q_CORE_EXPORT QChar { +public: + QChar(); +#ifndef QT_NO_CAST_FROM_ASCII + QT_ASCII_CAST_WARN_CONSTRUCTOR QChar(char c); + QT_ASCII_CAST_WARN_CONSTRUCTOR QChar(uchar c); +#endif + QChar(QLatin1Char ch); + QChar(uchar c, uchar r); + inline QChar(ushort rc) : ucs(rc){} + QChar(short rc); + QChar(uint rc); + QChar(int rc); + enum SpecialCharacter { + Null = 0x0000, + Nbsp = 0x00a0, + ReplacementCharacter = 0xfffd, + ObjectReplacementCharacter = 0xfffc, + ByteOrderMark = 0xfeff, + ByteOrderSwapped = 0xfffe, +#ifdef QT3_SUPPORT + null = Null, + replacement = ReplacementCharacter, + byteOrderMark = ByteOrderMark, + byteOrderSwapped = ByteOrderSwapped, + nbsp = Nbsp, +#endif + ParagraphSeparator = 0x2029, + LineSeparator = 0x2028 + }; + QChar(SpecialCharacter sc); + + // Unicode information + + enum Category + { + NoCategory, // ### Qt 5: replace with Other_NotAssigned + + Mark_NonSpacing, // Mn + Mark_SpacingCombining, // Mc + Mark_Enclosing, // Me + + Number_DecimalDigit, // Nd + Number_Letter, // Nl + Number_Other, // No + + Separator_Space, // Zs + Separator_Line, // Zl + Separator_Paragraph, // Zp + + Other_Control, // Cc + Other_Format, // Cf + Other_Surrogate, // Cs + Other_PrivateUse, // Co + Other_NotAssigned, // Cn + + Letter_Uppercase, // Lu + Letter_Lowercase, // Ll + Letter_Titlecase, // Lt + Letter_Modifier, // Lm + Letter_Other, // Lo + + Punctuation_Connector, // Pc + Punctuation_Dash, // Pd + Punctuation_Open, // Ps + Punctuation_Close, // Pe + Punctuation_InitialQuote, // Pi + Punctuation_FinalQuote, // Pf + Punctuation_Other, // Po + + Symbol_Math, // Sm + Symbol_Currency, // Sc + Symbol_Modifier, // Sk + Symbol_Other, // So + + Punctuation_Dask = Punctuation_Dash // ### Qt 5: remove + }; + + enum Direction + { + DirL, DirR, DirEN, DirES, DirET, DirAN, DirCS, DirB, DirS, DirWS, DirON, + DirLRE, DirLRO, DirAL, DirRLE, DirRLO, DirPDF, DirNSM, DirBN + }; + + enum Decomposition + { + NoDecomposition, + Canonical, + Font, + NoBreak, + Initial, + Medial, + Final, + Isolated, + Circle, + Super, + Sub, + Vertical, + Wide, + Narrow, + Small, + Square, + Compat, + Fraction + +#ifdef QT3_SUPPORT + , Single = NoDecomposition +#endif + }; + + enum Joining + { + OtherJoining, Dual, Right, Center + }; + + enum CombiningClass + { + Combining_BelowLeftAttached = 200, + Combining_BelowAttached = 202, + Combining_BelowRightAttached = 204, + Combining_LeftAttached = 208, + Combining_RightAttached = 210, + Combining_AboveLeftAttached = 212, + Combining_AboveAttached = 214, + Combining_AboveRightAttached = 216, + + Combining_BelowLeft = 218, + Combining_Below = 220, + Combining_BelowRight = 222, + Combining_Left = 224, + Combining_Right = 226, + Combining_AboveLeft = 228, + Combining_Above = 230, + Combining_AboveRight = 232, + + Combining_DoubleBelow = 233, + Combining_DoubleAbove = 234, + Combining_IotaSubscript = 240 + }; + + enum UnicodeVersion { + Unicode_Unassigned, // ### Qt 5: assign with some constantly big value + Unicode_1_1, + Unicode_2_0, + Unicode_2_1_2, + Unicode_3_0, + Unicode_3_1, + Unicode_3_2, + Unicode_4_0, + Unicode_4_1, + Unicode_5_0 + }; + // ****** WHEN ADDING FUNCTIONS, CONSIDER ADDING TO QCharRef TOO + + Category category() const; + Direction direction() const; + Joining joining() const; + bool hasMirrored() const; + unsigned char combiningClass() const; + + QChar mirroredChar() const; + QString decomposition() const; + Decomposition decompositionTag() const; + + int digitValue() const; + QChar toLower() const; + QChar toUpper() const; + QChar toTitleCase() const; + QChar toCaseFolded() const; + + UnicodeVersion unicodeVersion() const; + +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE + const char toAscii() const; + inline const char toLatin1() const; + inline const ushort unicode() const { return ucs; } +#else + char toAscii() const; + inline char toLatin1() const; + inline ushort unicode() const { return ucs; } +#endif +#ifdef Q_NO_PACKED_REFERENCE + inline ushort &unicode() { return const_cast<ushort&>(ucs); } +#else + inline ushort &unicode() { return ucs; } +#endif + + static QChar fromAscii(char c); + static QChar fromLatin1(char c); + + inline bool isNull() const { return ucs == 0; } + bool isPrint() const; + bool isPunct() const; + bool isSpace() const; + bool isMark() const; + bool isLetter() const; + bool isNumber() const; + bool isLetterOrNumber() const; + bool isDigit() const; + bool isSymbol() const; + inline bool isLower() const { return category() == Letter_Lowercase; } + inline bool isUpper() const { return category() == Letter_Uppercase; } + inline bool isTitleCase() const { return category() == Letter_Titlecase; } + + inline bool isHighSurrogate() const { + return ((ucs & 0xfc00) == 0xd800); + } + inline bool isLowSurrogate() const { + return ((ucs & 0xfc00) == 0xdc00); + } + + inline uchar cell() const { return uchar(ucs & 0xff); } + inline uchar row() const { return uchar((ucs>>8)&0xff); } + inline void setCell(uchar cell); + inline void setRow(uchar row); + + static inline bool isHighSurrogate(uint ucs4) { + return ((ucs4 & 0xfffffc00) == 0xd800); + } + static inline bool isLowSurrogate(uint ucs4) { + return ((ucs4 & 0xfffffc00) == 0xdc00); + } + static inline bool requiresSurrogates(uint ucs4) { + return (ucs4 >= 0x10000); + } + static inline uint surrogateToUcs4(ushort high, ushort low) { + return (uint(high)<<10) + low - 0x35fdc00; + } + static inline uint surrogateToUcs4(QChar high, QChar low) { + return (uint(high.ucs)<<10) + low.ucs - 0x35fdc00; + } + static inline ushort highSurrogate(uint ucs4) { + return ushort((ucs4>>10) + 0xd7c0); + } + static inline ushort lowSurrogate(uint ucs4) { + return ushort(ucs4%0x400 + 0xdc00); + } + + static Category QT_FASTCALL category(uint ucs4); + static Category QT_FASTCALL category(ushort ucs2); + static Direction QT_FASTCALL direction(uint ucs4); + static Direction QT_FASTCALL direction(ushort ucs2); + static Joining QT_FASTCALL joining(uint ucs4); + static Joining QT_FASTCALL joining(ushort ucs2); + static unsigned char QT_FASTCALL combiningClass(uint ucs4); + static unsigned char QT_FASTCALL combiningClass(ushort ucs2); + + static uint QT_FASTCALL mirroredChar(uint ucs4); + static ushort QT_FASTCALL mirroredChar(ushort ucs2); + static Decomposition QT_FASTCALL decompositionTag(uint ucs4); + + static int QT_FASTCALL digitValue(uint ucs4); + static int QT_FASTCALL digitValue(ushort ucs2); + static uint QT_FASTCALL toLower(uint ucs4); + static ushort QT_FASTCALL toLower(ushort ucs2); + static uint QT_FASTCALL toUpper(uint ucs4); + static ushort QT_FASTCALL toUpper(ushort ucs2); + static uint QT_FASTCALL toTitleCase(uint ucs4); + static ushort QT_FASTCALL toTitleCase(ushort ucs2); + static uint QT_FASTCALL toCaseFolded(uint ucs4); + static ushort QT_FASTCALL toCaseFolded(ushort ucs2); + + static UnicodeVersion QT_FASTCALL unicodeVersion(uint ucs4); + static UnicodeVersion QT_FASTCALL unicodeVersion(ushort ucs2); + + static UnicodeVersion QT_FASTCALL currentUnicodeVersion(); + + static QString QT_FASTCALL decomposition(uint ucs4); + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT bool mirrored() const { return hasMirrored(); } + inline QT3_SUPPORT QChar lower() const { return toLower(); } + inline QT3_SUPPORT QChar upper() const { return toUpper(); } + static inline QT3_SUPPORT bool networkOrdered() { + return QSysInfo::ByteOrder == QSysInfo::BigEndian; + } +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE + inline QT3_SUPPORT const char latin1() const { return toLatin1(); } + inline QT3_SUPPORT const char ascii() const { return toAscii(); } +#else + inline QT3_SUPPORT char latin1() const { return toLatin1(); } + inline QT3_SUPPORT char ascii() const { return toAscii(); } +#endif +#endif + +private: +#ifdef QT_NO_CAST_FROM_ASCII + QChar(char c); + QChar(uchar c); +#endif + ushort ucs; +}; + +Q_DECLARE_TYPEINFO(QChar, Q_MOVABLE_TYPE); + +inline QChar::QChar() : ucs(0) {} + +#ifdef Q_COMPILER_MANGLES_RETURN_TYPE +inline const char QChar::toLatin1() const { return ucs > 0xff ? '\0' : char(ucs); } +#else +inline char QChar::toLatin1() const { return ucs > 0xff ? '\0' : char(ucs); } +#endif +inline QChar QChar::fromLatin1(char c) { return QChar(ushort(uchar(c))); } + +inline QChar::QChar(uchar c, uchar r) : ucs(ushort((r << 8) | c)){} +inline QChar::QChar(short rc) : ucs(ushort(rc)){} +inline QChar::QChar(uint rc) : ucs(ushort(rc & 0xffff)){} +inline QChar::QChar(int rc) : ucs(ushort(rc & 0xffff)){} +inline QChar::QChar(SpecialCharacter s) : ucs(ushort(s)) {} +inline QChar::QChar(QLatin1Char ch) : ucs(ch.unicode()) {} + +inline void QChar::setCell(uchar acell) +{ ucs = ushort((ucs & 0xff00) + acell); } +inline void QChar::setRow(uchar arow) +{ ucs = ushort((ushort(arow)<<8) + (ucs&0xff)); } + +inline bool operator==(QChar c1, QChar c2) { return c1.unicode() == c2.unicode(); } +inline bool operator!=(QChar c1, QChar c2) { return c1.unicode() != c2.unicode(); } +inline bool operator<=(QChar c1, QChar c2) { return c1.unicode() <= c2.unicode(); } +inline bool operator>=(QChar c1, QChar c2) { return c1.unicode() >= c2.unicode(); } +inline bool operator<(QChar c1, QChar c2) { return c1.unicode() < c2.unicode(); } +inline bool operator>(QChar c1, QChar c2) { return c1.unicode() > c2.unicode(); } + +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QChar &); +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QChar &); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCHAR_H diff --git a/src/corelib/tools/qcontainerfwd.h b/src/corelib/tools/qcontainerfwd.h new file mode 100644 index 0000000000..28f8a6f1a3 --- /dev/null +++ b/src/corelib/tools/qcontainerfwd.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QCONTAINERFWD_H +#define QCONTAINERFWD_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +template <class Key, class T> class QCache; +template <class Key, class T> class QHash; +template <class T> class QLinkedList; +template <class T> class QList; +template <class Key, class T> class QMap; +template <class Key, class T> class QMultiHash; +template <class Key, class T> class QMultiMap; +template <class T1, class T2> struct QPair; +template <class T> class QQueue; +template <class T> class QSet; +template <class T> class QStack; +template<class T, int Prealloc = 256> class QVarLengthArray; +template <class T> class QVector; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCONTAINERFWD_H diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp new file mode 100644 index 0000000000..8e1c4c49a2 --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -0,0 +1,474 @@ +/**************************************************************************** +** +** 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 QtCore 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 "qcontiguouscache.h" +#ifdef QT_QCONTIGUOUSCACHE_DEBUG +#include <QDebug> +#endif + +QT_BEGIN_NAMESPACE + +#ifdef QT_QCONTIGUOUSCACHE_DEBUG +void QContiguousCacheData::dump() const +{ + qDebug() << "capacity:" << alloc; + qDebug() << "count:" << count; + qDebug() << "start:" << start; + qDebug() << "offset:" << offset; +} +#endif + +QContiguousCacheData *QContiguousCacheData::allocate(int size, int alignment) +{ + return static_cast<QContiguousCacheData *>(qMallocAligned(size, alignment)); +} + +void QContiguousCacheData::free(QContiguousCacheData *data) +{ + qFreeAligned(data); +} + +/*! \class QContiguousCache + \brief The QContiguousCache class is a template class that provides a contiguous cache. + \ingroup tools + \ingroup shared + \reentrant + \since 4.6 + + The QContiguousCache class provides an efficient way of caching items for + display in a user interface view. Unlike QCache, it adds a restriction + that elements within the cache are contiguous. This has the advantage + of matching how user interface views most commonly request data, as + a set of rows localized around the current scrolled position. This + restriction allows the cache to consume less memory and processor + cycles than QCache. The QContiguousCache class also can provide + an upper bound on memory usage via setCapacity(). + + The simplest way of using a contiguous cache is to use the append() + and prepend(). + +\code +MyRecord record(int row) const +{ + Q_ASSERT(row >= 0 && row < count()); + + while(row > cache.lastIndex()) + cache.append(slowFetchRecord(cache.lastIndex()+1)); + while(row < cache.firstIndex()) + cache.prepend(slowFetchRecord(cache.firstIndex()-1)); + + return cache.at(row); +} +\endcode + + If the cache is full then the item at the opposite end of the cache from + where the new item is appended or prepended will be removed. + + This usage can be further optimized by using the insert() function + in the case where the requested row is a long way from the currently cached + items. If there is a gap between where the new item is inserted and the currently + cached items then the existing cached items are first removed to retain + the contiguous nature of the cache. Hence it is important to take some care then + when using insert() in order to avoid unwanted clearing of the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Calling prepend() such that the first index would become less + than 0 or append() such that the last index would become greater + than INT_MAX can result in the indexes of the cache being invalid. + When the cache indexes are invalid it is important to call + normalizeIndexes() before calling any of containsIndex(), firstIndex(), + lastIndex(), at() or \l{QContiguousCache::operator[]()}{operator[]()}. + Calling these functions when the cache has invalid indexes will result in + undefined behavior. The indexes can be checked by using areIndexesValid() + + In most cases the indexes will not exceed 0 to INT_MAX, and + normalizeIndexes() will not need to be used. + + See the \l{Contiguous Cache Example}{Contiguous Cache} example. +*/ + +/*! \fn QContiguousCache::QContiguousCache(int capacity) + + Constructs a cache with the given \a capacity. + + \sa setCapacity() +*/ + +/*! \fn QContiguousCache::QContiguousCache(const QContiguousCache<T> &other) + + Constructs a copy of \a other. + + This operation takes \l{constant time}, because QContiguousCache is + \l{implicitly shared}. This makes returning a QContiguousCache from a + function very fast. If a shared instance is modified, it will be + copied (copy-on-write), and that takes \l{linear time}. + + \sa operator=() +*/ + +/*! \fn QContiguousCache::~QContiguousCache() + + Destroys the cache. +*/ + +/*! \fn void QContiguousCache::detach() + \internal +*/ + +/*! \fn bool QContiguousCache::isDetached() const + \internal +*/ + +/*! \fn void QContiguousCache::setSharable(bool sharable) + \internal +*/ + +/*! \typedef QContiguousCache::value_type + \internal + */ + +/*! \typedef QContiguousCache::pointer + \internal + */ + +/*! \typedef QContiguousCache::const_pointer + \internal + */ + +/*! \typedef QContiguousCache::reference + \internal + */ + +/*! \typedef QContiguousCache::const_reference + \internal + */ + +/*! \typedef QContiguousCache::difference_type + \internal + */ + +/*! \typedef QContiguousCache::size_type + \internal + */ + +/*! \fn QContiguousCache<T> &QContiguousCache::operator=(const QContiguousCache<T> &other) + + Assigns \a other to this cache and returns a reference to this cache. +*/ + +/*! \fn void QContiguousCache::swap(QContiguousCache<T> &other) + \since 4.8 + + Swaps cache \a other with this cache. This operation is very + fast and never fails. +*/ + +/*! \fn bool QContiguousCache::operator==(const QContiguousCache<T> &other) const + + Returns true if \a other is equal to this cache; otherwise returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator!=() +*/ + +/*! \fn bool QContiguousCache::operator!=(const QContiguousCache<T> &other) const + + Returns true if \a other is not equal to this cache; otherwise + returns false. + + Two caches are considered equal if they contain the same values at the same + indexes. This function requires the value type to implement the \c operator==(). + + \sa operator==() +*/ + +/*! \fn int QContiguousCache::capacity() const + + Returns the number of items the cache can store before it is full. + When a cache contains a number of items equal to its capacity, adding new + items will cause items farthest from the added item to be removed. + + \sa setCapacity(), size() +*/ + +/*! \fn int QContiguousCache::count() const + + Same as size(). +*/ + +/*! \fn int QContiguousCache::size() const + + Returns the number of items contained within the cache. + + \sa capacity() +*/ + +/*! \fn bool QContiguousCache::isEmpty() const + + Returns true if no items are stored within the cache. + + \sa size(), capacity() +*/ + +/*! \fn bool QContiguousCache::isFull() const + + Returns true if the number of items stored within the cache is equal + to the capacity of the cache. + + \sa size(), capacity() +*/ + +/*! \fn int QContiguousCache::available() const + + Returns the number of items that can be added to the cache before it becomes full. + + \sa size(), capacity(), isFull() +*/ + +/*! \fn void QContiguousCache::clear() + + Removes all items from the cache. The capacity is unchanged. +*/ + +/*! \fn void QContiguousCache::setCapacity(int size) + + Sets the capacity of the cache to the given \a size. A cache can hold a + number of items equal to its capacity. When inserting, appending or prepending + items to the cache, if the cache is already full then the item farthest from + the added item will be removed. + + If the given \a size is smaller than the current count of items in the cache + then only the last \a size items from the cache will remain. + + \sa capacity(), isFull() +*/ + +/*! \fn const T &QContiguousCache::at(int i) const + + Returns the item at index position \a i in the cache. \a i must + be a valid index position in the cache (i.e, firstIndex() <= \a i <= lastIndex()). + + The indexes in the cache refer to the number of positions the item is from the + first item appended into the cache. That is to say a cache with a capacity of + 100, that has had 150 items appended will have a valid index range of + 50 to 149. This allows inserting and retrieving items into the cache based + on a theoretical infinite list + + \sa firstIndex(), lastIndex(), insert(), operator[]() +*/ + +/*! \fn T &QContiguousCache::operator[](int i) + + Returns the item at index position \a i as a modifiable reference. If + the cache does not contain an item at the given index position \a i + then it will first insert an empty item at that position. + + In most cases it is better to use either at() or insert(). + + \note This non-const overload of operator[] requires QContiguousCache + to make a deep copy. Use at() for read-only access to a non-const + QContiguousCache. + + \sa insert(), at() +*/ + +/*! \fn const T &QContiguousCache::operator[](int i) const + + \overload + + Same as at(\a i). +*/ + +/*! \fn void QContiguousCache::append(const T &value) + + Inserts \a value at the end of the cache. If the cache is already full + the item at the start of the cache will be removed. + + \sa prepend(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::prepend(const T &value) + + Inserts \a value at the start of the cache. If the cache is already full + the item at the end of the cache will be removed. + + \sa append(), insert(), isFull() +*/ + +/*! \fn void QContiguousCache::insert(int i, const T &value) + + Inserts the \a value at the index position \a i. If the cache already contains + an item at \a i then that value is replaced. If \a i is either one more than + lastIndex() or one less than firstIndex() it is the equivalent to an append() + or a prepend(). + + If the given index \a i is not within the current range of the cache nor adjacent + to the bounds of the cache's index range, the cache is first cleared before + inserting the item. At this point the cache will have a size of 1. It is + worthwhile taking effort to insert items in an order that starts adjacent + to the current index range for the cache. + + The range of valid indexes for the QContiguousCache class are from + 0 to INT_MAX. Inserting outside of this range has undefined behavior. + + + \sa prepend(), append(), isFull(), firstIndex(), lastIndex() +*/ + +/*! \fn bool QContiguousCache::containsIndex(int i) const + + Returns true if the cache's index range includes the given index \a i. + + \sa firstIndex(), lastIndex() +*/ + +/*! \fn int QContiguousCache::firstIndex() const + + Returns the first valid index in the cache. The index will be invalid if the + cache is empty. + + \sa capacity(), size(), lastIndex() +*/ + +/*! \fn int QContiguousCache::lastIndex() const + + Returns the last valid index in the cache. The index will be invalid if the cache is empty. + + \sa capacity(), size(), firstIndex() +*/ + + +/*! \fn T &QContiguousCache::first() + + Returns a reference to the first item in the cache. This function + assumes that the cache isn't empty. + + \sa last(), isEmpty() +*/ + +/*! \fn T &QContiguousCache::last() + + Returns a reference to the last item in the cache. This function + assumes that the cache isn't empty. + + \sa first(), isEmpty() +*/ + +/*! \fn const T& QContiguousCache::first() const + + \overload +*/ + +/*! \fn const T& QContiguousCache::last() const + + \overload +*/ + +/*! \fn void QContiguousCache::removeFirst() + + Removes the first item from the cache. This function assumes that + the cache isn't empty. + + \sa removeLast() +*/ + +/*! \fn void QContiguousCache::removeLast() + + Removes the last item from the cache. This function assumes that + the cache isn't empty. + + \sa removeFirst() +*/ + +/*! \fn T QContiguousCache::takeFirst() + + Removes the first item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeFirst() is more efficient. + + \sa takeLast(), removeFirst() +*/ + +/*! \fn T QContiguousCache::takeLast() + + Removes the last item in the cache and returns it. This function + assumes that the cache isn't empty. + + If you don't use the return value, removeLast() is more efficient. + + \sa takeFirst(), removeLast() +*/ + +/*! \fn void QContiguousCache::normalizeIndexes() + + Moves the first index and last index of the cache + such that they point to valid indexes. The function does not modify + the contents of the cache or the ordering of elements within the cache. + + It is provided so that index overflows can be corrected when using the + cache as a circular buffer. + + \code + QContiguousCache<int> cache(10); + cache.insert(INT_MAX, 1); // cache contains one value and has valid indexes, INT_MAX to INT_MAX + cache.append(2); // cache contains two values but does not have valid indexes. + cache.normalizeIndexes(); // cache has two values, 1 and 2. New first index will be in the range of 0 to capacity(). + \endcode + + \sa areIndexesValid(), append(), prepend() +*/ + +/*! \fn bool QContiguousCache::areIndexesValid() const + + Returns whether the indexes for items stored in the cache are valid. + Indexes can become invalid if items are appended after the index position + INT_MAX or prepended before the index position 0. This is only expected + to occur in very long lived circular buffer style usage of the + contiguous cache. Indexes can be made valid again by calling + normalizeIndexs(). + + \sa normalizeIndexes(), append(), prepend() +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h new file mode 100644 index 0000000000..7880c2e411 --- /dev/null +++ b/src/corelib/tools/qcontiguouscache.h @@ -0,0 +1,466 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QCONTIGUOUSCACHE_H +#define QCONTIGUOUSCACHE_H + +#include <QtCore/qatomic.h> +#include <limits.h> +#include <new> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#undef QT_QCONTIGUOUSCACHE_DEBUG +QT_MODULE(Core) + + +struct Q_CORE_EXPORT QContiguousCacheData +{ + QBasicAtomicInt ref; + int alloc; + int count; + int start; + int offset; + uint sharable : 1; + uint reserved : 31; + + // total is 24 bytes (HP-UX aCC: 40 bytes) + // the next entry is already aligned to 8 bytes + // there will be an 8 byte gap here if T requires 16-byte alignment + // (such as long double on 64-bit platforms, __int128, __float128) + + static QContiguousCacheData *allocate(int size, int alignment); + static void free(QContiguousCacheData *data); + +#ifdef QT_QCONTIGUOUSCACHE_DEBUG + void dump() const; +#endif +}; + +template <typename T> +struct QContiguousCacheTypedData: private QContiguousCacheData +{ + // private inheritance to avoid aliasing warningss + T array[1]; + + static inline void free(QContiguousCacheTypedData *data) { QContiguousCacheData::free(data); } +}; + +template<typename T> +class QContiguousCache { + typedef QContiguousCacheTypedData<T> Data; + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; }; +public: + // STL compatibility + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef qptrdiff difference_type; + typedef int size_type; + + explicit QContiguousCache(int capacity = 0); + QContiguousCache(const QContiguousCache<T> &v) : d(v.d) { d->ref.ref(); if (!d->sharable) detach_helper(); } + + inline ~QContiguousCache() { if (!d) return; if (!d->ref.deref()) free(p); } + + inline void detach() { if (d->ref != 1) detach_helper(); } + inline bool isDetached() const { return d->ref == 1; } + inline void setSharable(bool sharable) { if (!sharable) detach(); d->sharable = sharable; } + + QContiguousCache<T> &operator=(const QContiguousCache<T> &other); +#ifdef Q_COMPILER_RVALUE_REFS + inline QContiguousCache<T> &operator=(QContiguousCache<T> &&other) + { qSwap(d, other.d); return *this; } +#endif + inline void swap(QContiguousCache<T> &other) { qSwap(d, other.d); } + bool operator==(const QContiguousCache<T> &other) const; + inline bool operator!=(const QContiguousCache<T> &other) const { return !(*this == other); } + + inline int capacity() const {return d->alloc; } + inline int count() const { return d->count; } + inline int size() const { return d->count; } + + inline bool isEmpty() const { return d->count == 0; } + inline bool isFull() const { return d->count == d->alloc; } + inline int available() const { return d->alloc - d->count; } + + void clear(); + void setCapacity(int size); + + const T &at(int pos) const; + T &operator[](int i); + const T &operator[](int i) const; + + void append(const T &value); + void prepend(const T &value); + void insert(int pos, const T &value); + + inline bool containsIndex(int pos) const { return pos >= d->offset && pos - d->offset < d->count; } + inline int firstIndex() const { return d->offset; } + inline int lastIndex() const { return d->offset + d->count - 1; } + + inline const T &first() const { Q_ASSERT(!isEmpty()); return p->array[d->start]; } + inline const T &last() const { Q_ASSERT(!isEmpty()); return p->array[(d->start + d->count -1) % d->alloc]; } + inline T &first() { Q_ASSERT(!isEmpty()); detach(); return p->array[d->start]; } + inline T &last() { Q_ASSERT(!isEmpty()); detach(); return p->array[(d->start + d->count -1) % d->alloc]; } + + void removeFirst(); + T takeFirst(); + void removeLast(); + T takeLast(); + + inline bool areIndexesValid() const + { return d->offset >= 0 && d->offset < INT_MAX - d->count && (d->offset % d->alloc) == d->start; } + + inline void normalizeIndexes() { d->offset = d->start; } + +#ifdef QT_QCONTIGUOUSCACHE_DEBUG + void dump() const { p->dump(); } +#endif +private: + void detach_helper(); + + QContiguousCacheData *malloc(int aalloc); + void free(Data *x); + int sizeOfTypedData() { + // this is more or less the same as sizeof(Data), except that it doesn't + // count the padding at the end + return reinterpret_cast<const char *>(&(reinterpret_cast<const Data *>(this))->array[1]) - reinterpret_cast<const char *>(this); + } + int alignOfTypedData() const + { +#ifdef Q_ALIGNOF + return qMax<int>(sizeof(void*), Q_ALIGNOF(Data)); +#else + return 0; +#endif + } +}; + +template <typename T> +void QContiguousCache<T>::detach_helper() +{ + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; + + x.d = malloc(d->alloc); + x.d->ref = 1; + x.d->count = d->count; + x.d->start = d->start; + x.d->offset = d->offset; + x.d->alloc = d->alloc; + x.d->sharable = true; + x.d->reserved = 0; + + T *dest = x.p->array + x.d->start; + T *src = p->array + d->start; + int oldcount = x.d->count; + while (oldcount--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + dest++; + if (dest == x.p->array + x.d->alloc) + dest = x.p->array; + src++; + if (src == p->array + d->alloc) + src = p->array; + } + + if (!d->ref.deref()) + free(p); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::setCapacity(int asize) +{ + if (asize == d->alloc) + return; + detach(); + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; + x.d = malloc(asize); + x.d->alloc = asize; + x.d->count = qMin(d->count, asize); + x.d->offset = d->offset + d->count - x.d->count; + if(asize) + x.d->start = x.d->offset % x.d->alloc; + else + x.d->start = 0; + + int oldcount = x.d->count; + if(oldcount) + { + T *dest = x.p->array + (x.d->start + x.d->count-1) % x.d->alloc; + T *src = p->array + (d->start + d->count-1) % d->alloc; + while (oldcount--) { + if (QTypeInfo<T>::isComplex) { + new (dest) T(*src); + } else { + *dest = *src; + } + if (dest == x.p->array) + dest = x.p->array + x.d->alloc; + dest--; + if (src == p->array) + src = p->array + d->alloc; + src--; + } + } + /* free old */ + free(p); + d = x.d; +} + +template <typename T> +void QContiguousCache<T>::clear() +{ + if (d->ref == 1) { + if (QTypeInfo<T>::isComplex) { + int oldcount = d->count; + T * i = p->array + d->start; + T * e = p->array + d->alloc; + while (oldcount--) { + i->~T(); + i++; + if (i == e) + i = p->array; + } + } + d->count = d->start = d->offset = 0; + } else { + union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; + x.d = malloc(d->alloc); + x.d->ref = 1; + x.d->alloc = d->alloc; + x.d->count = x.d->start = x.d->offset = 0; + x.d->sharable = true; + if (!d->ref.deref()) free(p); + d = x.d; + } +} + +template <typename T> +inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc) +{ + return QContiguousCacheData::allocate(sizeOfTypedData() + (aalloc - 1) * sizeof(T), alignOfTypedData()); +} + +template <typename T> +QContiguousCache<T>::QContiguousCache(int cap) +{ + d = malloc(cap); + d->ref = 1; + d->alloc = cap; + d->count = d->start = d->offset = 0; + d->sharable = true; +} + +template <typename T> +QContiguousCache<T> &QContiguousCache<T>::operator=(const QContiguousCache<T> &other) +{ + other.d->ref.ref(); + if (!d->ref.deref()) + free(d); + d = other.d; + if (!d->sharable) + detach_helper(); + return *this; +} + +template <typename T> +bool QContiguousCache<T>::operator==(const QContiguousCache<T> &other) const +{ + if (other.d == d) + return true; + if (other.d->start != d->start + || other.d->count != d->count + || other.d->offset != d->offset + || other.d->alloc != d->alloc) + return false; + for (int i = firstIndex(); i <= lastIndex(); ++i) + if (!(at(i) == other.at(i))) + return false; + return true; +} + +template <typename T> +void QContiguousCache<T>::free(Data *x) +{ + if (QTypeInfo<T>::isComplex) { + int oldcount = d->count; + T * i = p->array + d->start; + T * e = p->array + d->alloc; + while (oldcount--) { + i->~T(); + i++; + if (i == e) + i = p->array; + } + } + x->free(x); +} +template <typename T> +void QContiguousCache<T>::append(const T &value) +{ + detach(); + if (QTypeInfo<T>::isComplex) { + if (d->count == d->alloc) + (p->array + (d->start+d->count) % d->alloc)->~T(); + new (p->array + (d->start+d->count) % d->alloc) T(value); + } else { + p->array[(d->start+d->count) % d->alloc] = value; + } + + if (d->count == d->alloc) { + d->start++; + d->start %= d->alloc; + d->offset++; + } else { + d->count++; + } +} + +template<typename T> +void QContiguousCache<T>::prepend(const T &value) +{ + detach(); + if (d->start) + d->start--; + else + d->start = d->alloc-1; + d->offset--; + + if (d->count != d->alloc) + d->count++; + else + if (d->count == d->alloc) + (p->array + d->start)->~T(); + + if (QTypeInfo<T>::isComplex) + new (p->array + d->start) T(value); + else + p->array[d->start] = value; +} + +template<typename T> +void QContiguousCache<T>::insert(int pos, const T &value) +{ + Q_ASSERT_X(pos >= 0 && pos < INT_MAX, "QContiguousCache<T>::insert", "index out of range"); + detach(); + if (containsIndex(pos)) { + if(QTypeInfo<T>::isComplex) + new (p->array + pos % d->alloc) T(value); + else + p->array[pos % d->alloc] = value; + } else if (pos == d->offset-1) + prepend(value); + else if (pos == d->offset+d->count) + append(value); + else { + // we don't leave gaps. + clear(); + d->offset = pos; + d->start = pos % d->alloc; + d->count = 1; + if (QTypeInfo<T>::isComplex) + new (p->array + d->start) T(value); + else + p->array[d->start] = value; + } +} + +template <typename T> +inline const T &QContiguousCache<T>::at(int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; } +template <typename T> +inline const T &QContiguousCache<T>::operator[](int pos) const +{ Q_ASSERT_X(pos >= d->offset && pos - d->offset < d->count, "QContiguousCache<T>::at", "index out of range"); return p->array[pos % d->alloc]; } + +template <typename T> +inline T &QContiguousCache<T>::operator[](int pos) +{ + detach(); + if (!containsIndex(pos)) + insert(pos, T()); + return p->array[pos % d->alloc]; +} + +template <typename T> +inline void QContiguousCache<T>::removeFirst() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (p->array + d->start)->~T(); + d->start = (d->start + 1) % d->alloc; + d->offset++; +} + +template <typename T> +inline void QContiguousCache<T>::removeLast() +{ + Q_ASSERT(d->count > 0); + detach(); + d->count--; + if (QTypeInfo<T>::isComplex) + (p->array + (d->start + d->count) % d->alloc)->~T(); +} + +template <typename T> +inline T QContiguousCache<T>::takeFirst() +{ T t = first(); removeFirst(); return t; } + +template <typename T> +inline T QContiguousCache<T>::takeLast() +{ T t = last(); removeLast(); return t; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp new file mode 100644 index 0000000000..630e390563 --- /dev/null +++ b/src/corelib/tools/qcryptographichash.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** 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 QtCore 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 <qcryptographichash.h> + +#ifdef Q_OS_SYMBIAN +#define _MD5_H_ // Needed to disable system header +#endif + +#include "../../3rdparty/md5/md5.h" +#include "../../3rdparty/md5/md5.cpp" +#include "../../3rdparty/md4/md4.h" +#include "../../3rdparty/md4/md4.cpp" +#include "../../3rdparty/sha1/sha1.cpp" + + +QT_BEGIN_NAMESPACE + +class QCryptographicHashPrivate +{ +public: + QCryptographicHash::Algorithm method; + union { + MD5Context md5Context; + md4_context md4Context; + Sha1State sha1Context; + }; + QByteArray result; +}; + +/*! + \class QCryptographicHash + + \brief The QCryptographicHash class provides a way to generate cryptographic hashes. + + \since 4.3 + + \ingroup tools + \reentrant + + QCryptographicHash can be used to generate cryptographic hashes of binary or text data. + + Currently MD4, MD5, and SHA-1 are supported. +*/ + +/*! + \enum QCryptographicHash::Algorithm + + \value Md4 Generate an MD4 hash sum + \value Md5 Generate an MD5 hash sum + \value Sha1 Generate an SHA1 hash sum +*/ + +/*! + Constructs an object that can be used to create a cryptographic hash from data using \a method. +*/ +QCryptographicHash::QCryptographicHash(Algorithm method) + : d(new QCryptographicHashPrivate) +{ + d->method = method; + reset(); +} + +/*! + Destroys the object. +*/ +QCryptographicHash::~QCryptographicHash() +{ + delete d; +} + +/*! + Resets the object. +*/ +void QCryptographicHash::reset() +{ + switch (d->method) { + case Md4: + md4_init(&d->md4Context); + break; + case Md5: + MD5Init(&d->md5Context); + break; + case Sha1: + sha1InitState(&d->sha1Context); + break; + } + d->result.clear(); +} + +/*! + Adds the first \a length chars of \a data to the cryptographic + hash. +*/ +void QCryptographicHash::addData(const char *data, int length) +{ + switch (d->method) { + case Md4: + md4_update(&d->md4Context, (const unsigned char *)data, length); + break; + case Md5: + MD5Update(&d->md5Context, (const unsigned char *)data, length); + break; + case Sha1: + sha1Update(&d->sha1Context, (const unsigned char *)data, length); + break; + } + d->result.clear(); +} + +/*! + \overload addData() +*/ +void QCryptographicHash::addData(const QByteArray &data) +{ + addData(data.constData(), data.length()); +} + +/*! + Returns the final hash value. + + \sa QByteArray::toHex() +*/ +QByteArray QCryptographicHash::result() const +{ + if (!d->result.isEmpty()) + return d->result; + + switch (d->method) { + case Md4: { + md4_context copy = d->md4Context; + d->result.resize(MD4_RESULTLEN); + md4_final(©, (unsigned char *)d->result.data()); + break; + } + case Md5: { + MD5Context copy = d->md5Context; + d->result.resize(16); + MD5Final(©, (unsigned char *)d->result.data()); + break; + } + case Sha1: { + Sha1State copy = d->sha1Context; + d->result.resize(20); + sha1FinalizeState(©); + sha1ToHash(©, (unsigned char *)d->result.data()); + } + } + return d->result; +} + +/*! + Returns the hash of \a data using \a method. +*/ +QByteArray QCryptographicHash::hash(const QByteArray &data, Algorithm method) +{ + QCryptographicHash hash(method); + hash.addData(data); + return hash.result(); +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qcryptographichash.h b/src/corelib/tools/qcryptographichash.h new file mode 100644 index 0000000000..8506961882 --- /dev/null +++ b/src/corelib/tools/qcryptographichash.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QCRYPTOGRAPHICSHASH_H +#define QCRYPTOGRAPHICSHASH_H + +#include <QtCore/qbytearray.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class QCryptographicHashPrivate; + +class Q_CORE_EXPORT QCryptographicHash +{ +public: + enum Algorithm { + Md4, + Md5, + Sha1 + }; + + QCryptographicHash(Algorithm method); + ~QCryptographicHash(); + + void reset(); + + void addData(const char *data, int length); + void addData(const QByteArray &data); + + QByteArray result() const; + + static QByteArray hash(const QByteArray &data, Algorithm method); +private: + Q_DISABLE_COPY(QCryptographicHash) + QCryptographicHashPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp new file mode 100644 index 0000000000..a3a8884374 --- /dev/null +++ b/src/corelib/tools/qdatetime.cpp @@ -0,0 +1,5881 @@ +/**************************************************************************** +** +** 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 QtCore 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 "qplatformdefs.h" +#include "private/qdatetime_p.h" + +#include "qdatastream.h" +#include "qset.h" +#include "qlocale.h" +#include "qdatetime.h" +#include "qregexp.h" +#include "qdebug.h" +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +#include <qt_windows.h> +#endif +#ifndef Q_WS_WIN +#include <locale.h> +#endif + +#include <time.h> +#if defined(Q_OS_WINCE) +#include "qfunctions_wince.h" +#endif + +//#define QDATETIMEPARSER_DEBUG +#if defined (QDATETIMEPARSER_DEBUG) && !defined(QT_NO_DEBUG_STREAM) +# define QDTPDEBUG qDebug() << QString("%1:%2").arg(__FILE__).arg(__LINE__) +# define QDTPDEBUGN qDebug +#else +# define QDTPDEBUG if (false) qDebug() +# define QDTPDEBUGN if (false) qDebug +#endif + +#if defined(Q_WS_MAC) +#include <private/qcore_mac_p.h> +#endif + +#if defined(Q_OS_SYMBIAN) +#include <e32std.h> +#endif + +QT_BEGIN_NAMESPACE + +enum { + FIRST_YEAR = -4713, + FIRST_MONTH = 1, + FIRST_DAY = 2, // ### Qt 5: make FIRST_DAY = 1, by support jd == 0 as valid + SECS_PER_DAY = 86400, + MSECS_PER_DAY = 86400000, + SECS_PER_HOUR = 3600, + MSECS_PER_HOUR = 3600000, + SECS_PER_MIN = 60, + MSECS_PER_MIN = 60000, + JULIAN_DAY_FOR_EPOCH = 2440588 // result of julianDayFromGregorianDate(1970, 1, 1) +}; + +static inline QDate fixedDate(int y, int m, int d) +{ + QDate result(y, m, 1); + result.setDate(y, m, qMin(d, result.daysInMonth())); + return result; +} + +static inline uint julianDayFromGregorianDate(int year, int month, int day) +{ + // Gregorian calendar starting from October 15, 1582 + // Algorithm from Henry F. Fliegel and Thomas C. Van Flandern + return (1461 * (year + 4800 + (month - 14) / 12)) / 4 + + (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12 + - (3 * ((year + 4900 + (month - 14) / 12) / 100)) / 4 + + day - 32075; +} + +static uint julianDayFromDate(int year, int month, int day) +{ + if (year < 0) + ++year; + + if (year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15)))) { + return julianDayFromGregorianDate(year, month, day); + } else if (year < 1582 || (year == 1582 && (month < 10 || (month == 10 && day <= 4)))) { + // Julian calendar until October 4, 1582 + // Algorithm from Frequently Asked Questions about Calendars by Claus Toendering + int a = (14 - month) / 12; + return (153 * (month + (12 * a) - 3) + 2) / 5 + + (1461 * (year + 4800 - a)) / 4 + + day - 32083; + } else { + // the day following October 4, 1582 is October 15, 1582 + return 0; + } +} + +static void getDateFromJulianDay(uint julianDay, int *year, int *month, int *day) +{ + int y, m, d; + + if (julianDay >= 2299161) { + // Gregorian calendar starting from October 15, 1582 + // This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern + qulonglong ell, n, i, j; + ell = qulonglong(julianDay) + 68569; + n = (4 * ell) / 146097; + ell = ell - (146097 * n + 3) / 4; + i = (4000 * (ell + 1)) / 1461001; + ell = ell - (1461 * i) / 4 + 31; + j = (80 * ell) / 2447; + d = ell - (2447 * j) / 80; + ell = j / 11; + m = j + 2 - (12 * ell); + y = 100 * (n - 49) + i + ell; + } else { + // Julian calendar until October 4, 1582 + // Algorithm from Frequently Asked Questions about Calendars by Claus Toendering + julianDay += 32082; + int dd = (4 * julianDay + 3) / 1461; + int ee = julianDay - (1461 * dd) / 4; + int mm = ((5 * ee) + 2) / 153; + d = ee - (153 * mm + 2) / 5 + 1; + m = mm + 3 - 12 * (mm / 10); + y = dd - 4800 + (mm / 10); + if (y <= 0) + --y; + } + if (year) + *year = y; + if (month) + *month = m; + if (day) + *day = d; +} + + +static const char monthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +#ifndef QT_NO_TEXTDATE +static const char * const qt_shortMonthNames[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +#endif +#ifndef QT_NO_DATESTRING +static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* dd = 0); +#endif + +/***************************************************************************** + QDate member functions + *****************************************************************************/ + +/*! + \since 4.5 + + \enum QDate::MonthNameType + + This enum describes the types of the string representation used + for the month name. + + \value DateFormat This type of name can be used for date-to-string formatting. + \value StandaloneFormat This type is used when you need to enumerate months or weekdays. + Usually standalone names are represented in singular forms with + capitalized first letter. +*/ + +/*! + \class QDate + \reentrant + \brief The QDate class provides date functions. + + + A QDate object contains a calendar date, i.e. year, month, and day + numbers, in the Gregorian calendar. (see \l{QDate G and J} {Use of + Gregorian and Julian Calendars} for dates prior to 15 October + 1582). It can read the current date from the system clock. It + provides functions for comparing dates, and for manipulating + dates. For example, it is possible to add and subtract days, + months, and years to dates. + + A QDate object is typically created either by giving the year, + month, and day numbers explicitly. Note that QDate interprets two + digit years as is, i.e., years 0 - 99. A QDate can also be + constructed with the static function currentDate(), which creates + a QDate object containing the system clock's date. An explicit + date can also be set using setDate(). The fromString() function + returns a QDate given a string and a date format which is used to + interpret the date within the string. + + The year(), month(), and day() functions provide access to the + year, month, and day numbers. Also, dayOfWeek() and dayOfYear() + functions are provided. The same information is provided in + textual format by the toString(), shortDayName(), longDayName(), + shortMonthName(), and longMonthName() functions. + + QDate provides a full set of operators to compare two QDate + objects where smaller means earlier, and larger means later. + + You can increment (or decrement) a date by a given number of days + using addDays(). Similarly you can use addMonths() and addYears(). + The daysTo() function returns the number of days between two + dates. + + The daysInMonth() and daysInYear() functions return how many days + there are in this date's month and year, respectively. The + isLeapYear() function indicates whether a date is in a leap year. + + \section1 + + \target QDate G and J + \section2 Use of Gregorian and Julian Calendars + + QDate uses the Gregorian calendar in all locales, beginning + on the date 15 October 1582. For dates up to and including 4 + October 1582, the Julian calendar is used. This means there is a + 10-day gap in the internal calendar between the 4th and the 15th + of October 1582. When you use QDateTime for dates in that epoch, + the day after 4 October 1582 is 15 October 1582, and the dates in + the gap are invalid. + + The Julian to Gregorian changeover date used here is the date when + the Gregorian calendar was first introduced, by Pope Gregory + XIII. That change was not universally accepted and some localities + only executed it at a later date (if at all). QDateTime + doesn't take any of these historical facts into account. If an + application must support a locale-specific dating system, it must + do so on its own, remembering to convert the dates using the + Julian day. + + \section2 No Year 0 + + There is no year 0. Dates in that year are considered invalid. The + year -1 is the year "1 before Christ" or "1 before current era." + The day before 0001-01-01 is December 31st, 1 BCE. + + \section2 Range of Valid Dates + + The range of valid dates is from January 2nd, 4713 BCE, to + sometime in the year 11 million CE. The Julian Day returned by + QDate::toJulianDay() is a number in the contiguous range from 1 to + \e{overflow}, even across QDateTime's "date holes". It is suitable + for use in applications that must convert a QDateTime to a date in + another calendar system, e.g., Hebrew, Islamic or Chinese. + + \sa QTime, QDateTime, QDateEdit, QDateTimeEdit, QCalendarWidget +*/ + +/*! + \fn QDate::QDate() + + Constructs a null date. Null dates are invalid. + + \sa isNull(), isValid() +*/ + +/*! + Constructs a date with year \a y, month \a m and day \a d. + + If the specified date is invalid, the date is not set and + isValid() returns false. A date before 2 January 4713 B.C. is + considered invalid. + + \warning Years 0 to 99 are interpreted as is, i.e., years + 0-99. + + \sa isValid() +*/ + +QDate::QDate(int y, int m, int d) +{ + setDate(y, m, d); +} + + +/*! + \fn bool QDate::isNull() const + + Returns true if the date is null; otherwise returns false. A null + date is invalid. + + \note The behavior of this function is equivalent to isValid(). + + \sa isValid() +*/ + + +/*! + Returns true if this date is valid; otherwise returns false. + + \sa isNull() +*/ + +bool QDate::isValid() const +{ + return !isNull(); +} + + +/*! + Returns the year of this date. Negative numbers indicate years + before 1 A.D. = 1 C.E., such that year -44 is 44 B.C. + + \sa month(), day() +*/ + +int QDate::year() const +{ + int y; + getDateFromJulianDay(jd, &y, 0, 0); + return y; +} + +/*! + Returns the number corresponding to the month of this date, using + the following convention: + + \list + \i 1 = "January" + \i 2 = "February" + \i 3 = "March" + \i 4 = "April" + \i 5 = "May" + \i 6 = "June" + \i 7 = "July" + \i 8 = "August" + \i 9 = "September" + \i 10 = "October" + \i 11 = "November" + \i 12 = "December" + \endlist + + \sa year(), day() +*/ + +int QDate::month() const +{ + int m; + getDateFromJulianDay(jd, 0, &m, 0); + return m; +} + +/*! + Returns the day of the month (1 to 31) of this date. + + \sa year(), month(), dayOfWeek() +*/ + +int QDate::day() const +{ + int d; + getDateFromJulianDay(jd, 0, 0, &d); + return d; +} + +/*! + Returns the weekday (1 to 7) for this date. + + \sa day(), dayOfYear(), Qt::DayOfWeek +*/ + +int QDate::dayOfWeek() const +{ + return (jd % 7) + 1; +} + +/*! + Returns the day of the year (1 to 365 or 366 on leap years) for + this date. + + \sa day(), dayOfWeek() +*/ + +int QDate::dayOfYear() const +{ + return jd - julianDayFromDate(year(), 1, 1) + 1; +} + +/*! + Returns the number of days in the month (28 to 31) for this date. + + \sa day(), daysInYear() +*/ + +int QDate::daysInMonth() const +{ + int y, m, d; + getDateFromJulianDay(jd, &y, &m, &d); + if (m == 2 && isLeapYear(y)) + return 29; + else + return monthDays[m]; +} + +/*! + Returns the number of days in the year (365 or 366) for this date. + + \sa day(), daysInMonth() +*/ + +int QDate::daysInYear() const +{ + int y, m, d; + getDateFromJulianDay(jd, &y, &m, &d); + return isLeapYear(y) ? 366 : 365; +} + +/*! + Returns the week number (1 to 53), and stores the year in + *\a{yearNumber} unless \a yearNumber is null (the default). + + Returns 0 if the date is invalid. + + In accordance with ISO 8601, weeks start on Monday and the first + Thursday of a year is always in week 1 of that year. Most years + have 52 weeks, but some have 53. + + *\a{yearNumber} is not always the same as year(). For example, 1 + January 2000 has week number 52 in the year 1999, and 31 December + 2002 has week number 1 in the year 2003. + + \legalese + Copyright (c) 1989 The Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms are permitted + provided that the above copyright notice and this paragraph are + duplicated in all such forms and that any documentation, + advertising materials, and other materials related to such + distribution and use acknowledge that the software was developed + by the University of California, Berkeley. The name of the + University may not be used to endorse or promote products derived + from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + \sa isValid() +*/ + +int QDate::weekNumber(int *yearNumber) const +{ + if (!isValid()) + return 0; + + int year = QDate::year(); + int yday = dayOfYear() - 1; + int wday = dayOfWeek(); + if (wday == 7) + wday = 0; + int w; + + for (;;) { + int len; + int bot; + int top; + + len = isLeapYear(year) ? 366 : 365; + /* + ** What yday (-3 ... 3) does + ** the ISO year begin on? + */ + bot = ((yday + 11 - wday) % 7) - 3; + /* + ** What yday does the NEXT + ** ISO year begin on? + */ + top = bot - (len % 7); + if (top < -3) + top += 7; + top += len; + if (yday >= top) { + ++year; + w = 1; + break; + } + if (yday >= bot) { + w = 1 + ((yday - bot) / 7); + break; + } + --year; + yday += isLeapYear(year) ? 366 : 365; + } + if (yearNumber != 0) + *yearNumber = year; + return w; +} + +#ifndef QT_NO_TEXTDATE +/*! + \since 4.5 + + Returns the short name of the \a month for the representation specified + by \a type. + + The months are enumerated using the following convention: + + \list + \i 1 = "Jan" + \i 2 = "Feb" + \i 3 = "Mar" + \i 4 = "Apr" + \i 5 = "May" + \i 6 = "Jun" + \i 7 = "Jul" + \i 8 = "Aug" + \i 9 = "Sep" + \i 10 = "Oct" + \i 11 = "Nov" + \i 12 = "Dec" + \endlist + + The month names will be localized according to the system's locale + settings. + + \sa toString(), longMonthName(), shortDayName(), longDayName() +*/ + +QString QDate::shortMonthName(int month, QDate::MonthNameType type) +{ + if (month < 1 || month > 12) { + month = 1; + } + switch (type) { + case QDate::DateFormat: + return QLocale::system().monthName(month, QLocale::ShortFormat); + case QDate::StandaloneFormat: + return QLocale::system().standaloneMonthName(month, QLocale::ShortFormat); + default: + break; + } + return QString(); +} + +/*! + Returns the short version of the name of the \a month. The + returned name is in normal type which can be used for date formatting. + + \sa toString(), longMonthName(), shortDayName(), longDayName() + */ + +QString QDate::shortMonthName(int month) +{ + return shortMonthName(month, QDate::DateFormat); +} + +/*! + \since 4.5 + + Returns the long name of the \a month for the representation specified + by \a type. + + The months are enumerated using the following convention: + + \list + \i 1 = "January" + \i 2 = "February" + \i 3 = "March" + \i 4 = "April" + \i 5 = "May" + \i 6 = "June" + \i 7 = "July" + \i 8 = "August" + \i 9 = "September" + \i 10 = "October" + \i 11 = "November" + \i 12 = "December" + \endlist + + The month names will be localized according to the system's locale + settings. + + \sa toString(), shortMonthName(), shortDayName(), longDayName() +*/ + +QString QDate::longMonthName(int month, MonthNameType type) +{ + if (month < 1 || month > 12) { + month = 1; + } + switch (type) { + case QDate::DateFormat: + return QLocale::system().monthName(month, QLocale::LongFormat); + case QDate::StandaloneFormat: + return QLocale::system().standaloneMonthName(month, QLocale::LongFormat); + default: + break; + } + return QString(); +} + +/*! + Returns the long version of the name of the \a month. The + returned name is in normal type which can be used for date formatting. + + \sa toString(), shortMonthName(), shortDayName(), longDayName() + */ + +QString QDate::longMonthName(int month) +{ + if (month < 1 || month > 12) { + month = 1; + } + return QLocale::system().monthName(month, QLocale::LongFormat); +} + +/*! + \since 4.5 + + Returns the short name of the \a weekday for the representation specified + by \a type. + + The days are enumerated using the following convention: + + \list + \i 1 = "Mon" + \i 2 = "Tue" + \i 3 = "Wed" + \i 4 = "Thu" + \i 5 = "Fri" + \i 6 = "Sat" + \i 7 = "Sun" + \endlist + + The day names will be localized according to the system's locale + settings. + + \sa toString(), shortMonthName(), longMonthName(), longDayName() +*/ + +QString QDate::shortDayName(int weekday, MonthNameType type) +{ + if (weekday < 1 || weekday > 7) { + weekday = 1; + } + switch (type) { + case QDate::DateFormat: + return QLocale::system().dayName(weekday, QLocale::ShortFormat); + case QDate::StandaloneFormat: + return QLocale::system().standaloneDayName(weekday, QLocale::ShortFormat); + default: + break; + } + return QString(); +} + +/*! + Returns the short version of the name of the \a weekday. The + returned name is in normal type which can be used for date formatting. + + \sa toString(), longDayName(), shortMonthName(), longMonthName() + */ + +QString QDate::shortDayName(int weekday) +{ + if (weekday < 1 || weekday > 7) { + weekday = 1; + } + return QLocale::system().dayName(weekday, QLocale::ShortFormat); +} + +/*! + \since 4.5 + + Returns the long name of the \a weekday for the representation specified + by \a type. + + The days are enumerated using the following convention: + + \list + \i 1 = "Monday" + \i 2 = "Tuesday" + \i 3 = "Wednesday" + \i 4 = "Thursday" + \i 5 = "Friday" + \i 6 = "Saturday" + \i 7 = "Sunday" + \endlist + + The day names will be localized according to the system's locale + settings. + + \sa toString(), shortDayName(), shortMonthName(), longMonthName() +*/ + +QString QDate::longDayName(int weekday, MonthNameType type) +{ + if (weekday < 1 || weekday > 7) { + weekday = 1; + } + switch (type) { + case QDate::DateFormat: + return QLocale::system().dayName(weekday, QLocale::LongFormat); + case QDate::StandaloneFormat: + return QLocale::system().standaloneDayName(weekday, QLocale::LongFormat); + default: + break; + } + return QLocale::system().dayName(weekday, QLocale::LongFormat); +} + +/*! + Returns the long version of the name of the \a weekday. The + returned name is in normal type which can be used for date formatting. + + \sa toString(), shortDayName(), shortMonthName(), longMonthName() + */ + +QString QDate::longDayName(int weekday) +{ + if (weekday < 1 || weekday > 7) { + weekday = 1; + } + return QLocale::system().dayName(weekday, QLocale::LongFormat); +} +#endif //QT_NO_TEXTDATE + +#ifndef QT_NO_DATESTRING + +/*! + \fn QString QDate::toString(Qt::DateFormat format) const + + \overload + + Returns the date as a string. The \a format parameter determines + the format of the string. + + If the \a format is Qt::TextDate, the string is formatted in + the default way. QDate::shortDayName() and QDate::shortMonthName() + are used to generate the string, so the day and month names will + be localized names. An example of this formatting is + "Sat May 20 1995". + + If the \a format is Qt::ISODate, the string format corresponds + to the ISO 8601 extended specification for representations of + dates and times, taking the form YYYY-MM-DD, where YYYY is the + year, MM is the month of the year (between 01 and 12), and DD is + the day of the month between 01 and 31. + + If the \a format is Qt::SystemLocaleShortDate or + Qt::SystemLocaleLongDate, the string format depends on the locale + settings of the system. Identical to calling + QLocale::system().toString(date, QLocale::ShortFormat) or + QLocale::system().toString(date, QLocale::LongFormat). + + If the \a format is Qt::DefaultLocaleShortDate or + Qt::DefaultLocaleLongDate, the string format depends on the + default application locale. This is the locale set with + QLocale::setDefault(), or the system locale if no default locale + has been set. Identical to calling QLocale().toString(date, + QLocale::ShortFormat) or QLocale().toString(date, + QLocale::LongFormat). + + If the date is invalid, an empty string will be returned. + + \warning The Qt::ISODate format is only valid for years in the + range 0 to 9999. This restriction may apply to locale-aware + formats as well, depending on the locale settings. + + \sa shortDayName(), shortMonthName() +*/ +QString QDate::toString(Qt::DateFormat f) const +{ + if (!isValid()) + return QString(); + int y, m, d; + getDateFromJulianDay(jd, &y, &m, &d); + switch (f) { + case Qt::SystemLocaleDate: + case Qt::SystemLocaleShortDate: + case Qt::SystemLocaleLongDate: + return QLocale::system().toString(*this, f == Qt::SystemLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat); + case Qt::LocaleDate: + case Qt::DefaultLocaleShortDate: + case Qt::DefaultLocaleLongDate: + return QLocale().toString(*this, f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat); + default: +#ifndef QT_NO_TEXTDATE + case Qt::TextDate: + { + return QString::fromLatin1("%0 %1 %2 %3") + .arg(shortDayName(dayOfWeek())) + .arg(shortMonthName(m)) + .arg(d) + .arg(y); + } +#endif + case Qt::ISODate: + { + if (year() < 0 || year() > 9999) + return QString(); + QString month(QString::number(m).rightJustified(2, QLatin1Char('0'))); + QString day(QString::number(d).rightJustified(2, QLatin1Char('0'))); + return QString::number(y) + QLatin1Char('-') + month + QLatin1Char('-') + day; + } + } +} + +/*! + Returns the date as a string. The \a format parameter determines + the format of the result string. + + These expressions may be used: + + \table + \header \i Expression \i Output + \row \i d \i the day as number without a leading zero (1 to 31) + \row \i dd \i the day as number with a leading zero (01 to 31) + \row \i ddd + \i the abbreviated localized day name (e.g. 'Mon' to 'Sun'). + Uses QDate::shortDayName(). + \row \i dddd + \i the long localized day name (e.g. 'Monday' to 'Sunday'). + Uses QDate::longDayName(). + \row \i M \i the month as number without a leading zero (1 to 12) + \row \i MM \i the month as number with a leading zero (01 to 12) + \row \i MMM + \i the abbreviated localized month name (e.g. 'Jan' to 'Dec'). + Uses QDate::shortMonthName(). + \row \i MMMM + \i the long localized month name (e.g. 'January' to 'December'). + Uses QDate::longMonthName(). + \row \i yy \i the year as two digit number (00 to 99) + \row \i yyyy \i the year as four digit number. If the year is negative, + a minus sign is prepended in addition. + \endtable + + All other input characters will be ignored. Any sequence of characters that + are enclosed in singlequotes will be treated as text and not be used as an + expression. Two consecutive singlequotes ("''") are replaced by a singlequote + in the output. + + Example format strings (assuming that the QDate is the 20 July + 1969): + + \table + \header \o Format \o Result + \row \o dd.MM.yyyy \o 20.07.1969 + \row \o ddd MMMM d yy \o Sun July 20 69 + \row \o 'The day is' dddd \o The day is Sunday + \endtable + + If the datetime is invalid, an empty string will be returned. + + \warning The Qt::ISODate format is only valid for years in the + range 0 to 9999. This restriction may apply to locale-aware + formats as well, depending on the locale settings. + + \sa QDateTime::toString() QTime::toString() + +*/ +QString QDate::toString(const QString& format) const +{ + if (year() > 9999) + return QString(); + return fmtDateTime(format, 0, this); +} +#endif //QT_NO_DATESTRING + +/*! + \obsolete + + Sets the date's year \a y, month \a m, and day \a d. + + If \a y is in the range 0 to 99, it is interpreted as 1900 to + 1999. + + Use setDate() instead. +*/ + +bool QDate::setYMD(int y, int m, int d) +{ + if (uint(y) <= 99) + y += 1900; + return setDate(y, m, d); +} + +/*! + \since 4.2 + + Sets the date's \a year, \a month, and \a day. Returns true if + the date is valid; otherwise returns false. + + If the specified date is invalid, the QDate object is set to be + invalid. Any date before 2 January 4713 B.C. is considered + invalid. + + \sa isValid() +*/ +bool QDate::setDate(int year, int month, int day) +{ + if (!isValid(year, month, day)) { + jd = 0; + } else { + jd = julianDayFromDate(year, month, day); + } + return jd != 0; +} + +/*! + \since 4.5 + + Extracts the date's year, month, and day, and assigns them to + *\a year, *\a month, and *\a day. The pointers may be null. + + \sa year(), month(), day(), isValid() +*/ +void QDate::getDate(int *year, int *month, int *day) +{ + getDateFromJulianDay(jd, year, month, day); +} + +/*! + Returns a QDate object containing a date \a ndays later than the + date of this object (or earlier if \a ndays is negative). + + \sa addMonths() addYears() daysTo() +*/ + +QDate QDate::addDays(int ndays) const +{ + QDate d; + // this is basically "d.jd = jd + ndays" with checks for integer overflow + if (ndays >= 0) + d.jd = (jd + ndays >= jd) ? jd + ndays : 0; + else + d.jd = (jd + ndays < jd) ? jd + ndays : 0; + return d; +} + +/*! + Returns a QDate object containing a date \a nmonths later than the + date of this object (or earlier if \a nmonths is negative). + + \note If the ending day/month combination does not exist in the + resulting month/year, this function will return a date that is the + latest valid date. + + \warning QDate has a date hole around the days introducing the + Gregorian calendar (the days 5 to 14 October 1582, inclusive, do + not exist). If the calculation ends in one of those days, QDate + will return either October 4 or October 15. + + \sa addDays() addYears() +*/ + +QDate QDate::addMonths(int nmonths) const +{ + if (!isValid()) + return QDate(); + if (!nmonths) + return *this; + + int old_y, y, m, d; + getDateFromJulianDay(jd, &y, &m, &d); + old_y = y; + + bool increasing = nmonths > 0; + + while (nmonths != 0) { + if (nmonths < 0 && nmonths + 12 <= 0) { + y--; + nmonths+=12; + } else if (nmonths < 0) { + m+= nmonths; + nmonths = 0; + if (m <= 0) { + --y; + m += 12; + } + } else if (nmonths - 12 >= 0) { + y++; + nmonths -= 12; + } else if (m == 12) { + y++; + m = 0; + } else { + m += nmonths; + nmonths = 0; + if (m > 12) { + ++y; + m -= 12; + } + } + } + + // was there a sign change? + if ((old_y > 0 && y <= 0) || + (old_y < 0 && y >= 0)) + // yes, adjust the date by +1 or -1 years + y += increasing ? +1 : -1; + + // did we end up in the Gregorian/Julian conversion hole? + if (y == 1582 && m == 10 && d > 4 && d < 15) + d = increasing ? 15 : 4; + + return fixedDate(y, m, d); +} + +/*! + Returns a QDate object containing a date \a nyears later than the + date of this object (or earlier if \a nyears is negative). + + \note If the ending day/month combination does not exist in the + resulting year (i.e., if the date was Feb 29 and the final year is + not a leap year), this function will return a date that is the + latest valid date (that is, Feb 28). + + \sa addDays(), addMonths() +*/ + +QDate QDate::addYears(int nyears) const +{ + if (!isValid()) + return QDate(); + + int y, m, d; + getDateFromJulianDay(jd, &y, &m, &d); + + int old_y = y; + y += nyears; + + // was there a sign change? + if ((old_y > 0 && y <= 0) || + (old_y < 0 && y >= 0)) + // yes, adjust the date by +1 or -1 years + y += nyears > 0 ? +1 : -1; + + return fixedDate(y, m, d); +} + +/*! + Returns the number of days from this date to \a d (which is + negative if \a d is earlier than this date). + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 0 + + \sa addDays() +*/ + +int QDate::daysTo(const QDate &d) const +{ + return d.jd - jd; +} + + +/*! + \fn bool QDate::operator==(const QDate &d) const + + Returns true if this date is equal to \a d; otherwise returns + false. + +*/ + +/*! + \fn bool QDate::operator!=(const QDate &d) const + + Returns true if this date is different from \a d; otherwise + returns false. +*/ + +/*! + \fn bool QDate::operator<(const QDate &d) const + + Returns true if this date is earlier than \a d; otherwise returns + false. +*/ + +/*! + \fn bool QDate::operator<=(const QDate &d) const + + Returns true if this date is earlier than or equal to \a d; + otherwise returns false. +*/ + +/*! + \fn bool QDate::operator>(const QDate &d) const + + Returns true if this date is later than \a d; otherwise returns + false. +*/ + +/*! + \fn bool QDate::operator>=(const QDate &d) const + + Returns true if this date is later than or equal to \a d; + otherwise returns false. +*/ + +/*! + \fn QDate::currentDate() + Returns the current date, as reported by the system clock. + + \sa QTime::currentTime(), QDateTime::currentDateTime() +*/ + +#ifndef QT_NO_DATESTRING +/*! + \fn QDate QDate::fromString(const QString &string, Qt::DateFormat format) + + Returns the QDate represented by the \a string, using the + \a format given, or an invalid date if the string cannot be + parsed. + + Note for Qt::TextDate: It is recommended that you use the + English short month names (e.g. "Jan"). Although localized month + names can also be used, they depend on the user's locale settings. +*/ +QDate QDate::fromString(const QString& s, Qt::DateFormat f) +{ + if (s.isEmpty()) + return QDate(); + + switch (f) { + case Qt::ISODate: + { + int year(s.mid(0, 4).toInt()); + int month(s.mid(5, 2).toInt()); + int day(s.mid(8, 2).toInt()); + if (year && month && day) + return QDate(year, month, day); + } + break; + case Qt::SystemLocaleDate: + case Qt::SystemLocaleShortDate: + case Qt::SystemLocaleLongDate: + return fromString(s, QLocale::system().dateFormat(f == Qt::SystemLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat)); + case Qt::LocaleDate: + case Qt::DefaultLocaleShortDate: + case Qt::DefaultLocaleLongDate: + return fromString(s, QLocale().dateFormat(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat)); + default: +#ifndef QT_NO_TEXTDATE + case Qt::TextDate: { + QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts); + + if (parts.count() != 4) { + return QDate(); + } + + QString monthName = parts.at(1); + int month = -1; + // Assume that English monthnames are the default + for (int i = 0; i < 12; ++i) { + if (monthName == QLatin1String(qt_shortMonthNames[i])) { + month = i + 1; + break; + } + } + // If English names can't be found, search the localized ones + if (month == -1) { + for (int i = 1; i <= 12; ++i) { + if (monthName == QDate::shortMonthName(i)) { + month = i; + break; + } + } + } + if (month < 1 || month > 12) { + return QDate(); + } + + bool ok; + int day = parts.at(2).toInt(&ok); + if (!ok) { + return QDate(); + } + + int year = parts.at(3).toInt(&ok); + if (!ok) { + return QDate(); + } + + return QDate(year, month, day); + } +#else + break; +#endif + } + return QDate(); +} + +/*! + \fn QDate::fromString(const QString &string, const QString &format) + + Returns the QDate represented by the \a string, using the \a + format given, or an invalid date if the string cannot be parsed. + + These expressions may be used for the format: + + \table + \header \i Expression \i Output + \row \i d \i The day as a number without a leading zero (1 to 31) + \row \i dd \i The day as a number with a leading zero (01 to 31) + \row \i ddd + \i The abbreviated localized day name (e.g. 'Mon' to 'Sun'). + Uses QDate::shortDayName(). + \row \i dddd + \i The long localized day name (e.g. 'Monday' to 'Sunday'). + Uses QDate::longDayName(). + \row \i M \i The month as a number without a leading zero (1 to 12) + \row \i MM \i The month as a number with a leading zero (01 to 12) + \row \i MMM + \i The abbreviated localized month name (e.g. 'Jan' to 'Dec'). + Uses QDate::shortMonthName(). + \row \i MMMM + \i The long localized month name (e.g. 'January' to 'December'). + Uses QDate::longMonthName(). + \row \i yy \i The year as two digit number (00 to 99) + \row \i yyyy \i The year as four digit number. If the year is negative, + a minus sign is prepended in addition. + \endtable + + All other input characters will be treated as text. Any sequence + of characters that are enclosed in single quotes will also be + treated as text and will not be used as an expression. For example: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 1 + + If the format is not satisfied, an invalid QDate is returned. The + expressions that don't expect leading zeroes (d, M) will be + greedy. This means that they will use two digits even if this + will put them outside the accepted range of values and leaves too + few digits for other sections. For example, the following format + string could have meant January 30 but the M will grab two + digits, resulting in an invalid date: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 2 + + For any field that is not represented in the format the following + defaults are used: + + \table + \header \i Field \i Default value + \row \i Year \i 1900 + \row \i Month \i 1 + \row \i Day \i 1 + \endtable + + The following examples demonstrate the default values: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 3 + + \sa QDateTime::fromString(), QTime::fromString(), QDate::toString(), + QDateTime::toString(), QTime::toString() +*/ + +QDate QDate::fromString(const QString &string, const QString &format) +{ + QDate date; +#ifndef QT_BOOTSTRAPPED + QDateTimeParser dt(QVariant::Date, QDateTimeParser::FromString); + if (dt.parseFormat(format)) + dt.fromString(string, &date, 0); +#else + Q_UNUSED(string); + Q_UNUSED(format); +#endif + return date; +} +#endif // QT_NO_DATESTRING + +/*! + \overload + + Returns true if the specified date (\a year, \a month, and \a + day) is valid; otherwise returns false. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 4 + + \sa isNull(), setDate() +*/ + +bool QDate::isValid(int year, int month, int day) +{ + if (year < FIRST_YEAR + || (year == FIRST_YEAR && + (month < FIRST_MONTH + || (month == FIRST_MONTH && day < FIRST_DAY))) + || year == 0) // there is no year 0 in the Julian calendar + return false; + + // passage from Julian to Gregorian calendar + if (year == 1582 && month == 10 && day > 4 && day < 15) + return 0; + + return (day > 0 && month > 0 && month <= 12) && + (day <= monthDays[month] || (day == 29 && month == 2 && isLeapYear(year))); +} + +/*! + \fn bool QDate::isLeapYear(int year) + + Returns true if the specified \a year is a leap year; otherwise + returns false. +*/ + +bool QDate::isLeapYear(int y) +{ + if (y < 1582) { + if ( y < 1) { // No year 0 in Julian calendar, so -1, -5, -9 etc are leap years + ++y; + } + return y % 4 == 0; + } else { + return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0; + } +} + +/*! + \internal + + This function has a confusing name and shouldn't be part of the + API anyway, since we have toJulian() and fromJulian(). + ### Qt 5: remove it +*/ +uint QDate::gregorianToJulian(int y, int m, int d) +{ + return julianDayFromDate(y, m, d); +} + +/*! + \internal + + This function has a confusing name and shouldn't be part of the + API anyway, since we have toJulian() and fromJulian(). + ### Qt 5: remove it +*/ +void QDate::julianToGregorian(uint jd, int &y, int &m, int &d) +{ + getDateFromJulianDay(jd, &y, &m, &d); +} + +/*! \fn static QDate QDate::fromJulianDay(int jd) + + Converts the Julian day \a jd to a QDate. + + \sa toJulianDay() +*/ + +/*! \fn int QDate::toJulianDay() const + + Converts the date to a Julian day. + + \sa fromJulianDay() +*/ + +/***************************************************************************** + QTime member functions + *****************************************************************************/ + +/*! + \class QTime + \reentrant + + \brief The QTime class provides clock time functions. + + + A QTime object contains a clock time, i.e. the number of hours, + minutes, seconds, and milliseconds since midnight. It can read the + current time from the system clock and measure a span of elapsed + time. It provides functions for comparing times and for + manipulating a time by adding a number of milliseconds. + + QTime uses the 24-hour clock format; it has no concept of AM/PM. + Unlike QDateTime, QTime knows nothing about time zones or + daylight savings time (DST). + + A QTime object is typically created either by giving the number + of hours, minutes, seconds, and milliseconds explicitly, or by + using the static function currentTime(), which creates a QTime + object that contains the system's local time. Note that the + accuracy depends on the accuracy of the underlying operating + system; not all systems provide 1-millisecond accuracy. + + The hour(), minute(), second(), and msec() functions provide + access to the number of hours, minutes, seconds, and milliseconds + of the time. The same information is provided in textual format by + the toString() function. + + QTime provides a full set of operators to compare two QTime + objects. One time is considered smaller than another if it is + earlier than the other. + + The time a given number of seconds or milliseconds later than a + given time can be found using the addSecs() or addMSecs() + functions. Correspondingly, the number of seconds or milliseconds + between two times can be found using secsTo() or msecsTo(). + + QTime can be used to measure a span of elapsed time using the + start(), restart(), and elapsed() functions. + + \sa QDate, QDateTime +*/ + +/*! + \fn QTime::QTime() + + Constructs a null time object. A null time can be a QTime(0, 0, 0, 0) + (i.e., midnight) object, except that isNull() returns true and isValid() + returns false. + + \sa isNull(), isValid() +*/ + +/*! + Constructs a time with hour \a h, minute \a m, seconds \a s and + milliseconds \a ms. + + \a h must be in the range 0 to 23, \a m and \a s must be in the + range 0 to 59, and \a ms must be in the range 0 to 999. + + \sa isValid() +*/ + +QTime::QTime(int h, int m, int s, int ms) +{ + setHMS(h, m, s, ms); +} + + +/*! + \fn bool QTime::isNull() const + + Returns true if the time is null (i.e., the QTime object was + constructed using the default constructor); otherwise returns + false. A null time is also an invalid time. + + \sa isValid() +*/ + +/*! + Returns true if the time is valid; otherwise returns false. For example, + the time 23:30:55.746 is valid, but 24:12:30 is invalid. + + \sa isNull() +*/ + +bool QTime::isValid() const +{ + return mds > NullTime && mds < MSECS_PER_DAY; +} + + +/*! + Returns the hour part (0 to 23) of the time. + + \sa minute(), second(), msec() +*/ + +int QTime::hour() const +{ + return ds() / MSECS_PER_HOUR; +} + +/*! + Returns the minute part (0 to 59) of the time. + + \sa hour(), second(), msec() +*/ + +int QTime::minute() const +{ + return (ds() % MSECS_PER_HOUR) / MSECS_PER_MIN; +} + +/*! + Returns the second part (0 to 59) of the time. + + \sa hour(), minute(), msec() +*/ + +int QTime::second() const +{ + return (ds() / 1000)%SECS_PER_MIN; +} + +/*! + Returns the millisecond part (0 to 999) of the time. + + \sa hour(), minute(), second() +*/ + +int QTime::msec() const +{ + return ds() % 1000; +} + +#ifndef QT_NO_DATESTRING +/*! + \overload + + Returns the time as a string. Milliseconds are not included. The + \a format parameter determines the format of the string. + + If \a format is Qt::TextDate, the string format is HH:MM:SS; e.g. 1 + second before midnight would be "23:59:59". + + If \a format is Qt::ISODate, the string format corresponds to the + ISO 8601 extended specification for representations of dates, + which is also HH:MM:SS. (However, contrary to ISO 8601, dates + before 15 October 1582 are handled as Julian dates, not Gregorian + dates. See \l{QDate G and J} {Use of Gregorian and Julian + Calendars}. This might change in a future version of Qt.) + + If the \a format is Qt::SystemLocaleShortDate or + Qt::SystemLocaleLongDate, the string format depends on the locale + settings of the system. Identical to calling + QLocale::system().toString(time, QLocale::ShortFormat) or + QLocale::system().toString(time, QLocale::LongFormat). + + If the \a format is Qt::DefaultLocaleShortDate or + Qt::DefaultLocaleLongDate, the string format depends on the + default application locale. This is the locale set with + QLocale::setDefault(), or the system locale if no default locale + has been set. Identical to calling QLocale().toString(time, + QLocale::ShortFormat) or QLocale().toString(time, + QLocale::LongFormat). + + If the time is invalid, an empty string will be returned. +*/ + +QString QTime::toString(Qt::DateFormat format) const +{ + if (!isValid()) + return QString(); + + switch (format) { + case Qt::SystemLocaleDate: + case Qt::SystemLocaleShortDate: + case Qt::SystemLocaleLongDate: + return QLocale::system().toString(*this, format == Qt::SystemLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat); + case Qt::LocaleDate: + case Qt::DefaultLocaleShortDate: + case Qt::DefaultLocaleLongDate: + return QLocale().toString(*this, format == Qt::DefaultLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat); + + default: + case Qt::ISODate: + case Qt::TextDate: + return QString::fromLatin1("%1:%2:%3") + .arg(hour(), 2, 10, QLatin1Char('0')) + .arg(minute(), 2, 10, QLatin1Char('0')) + .arg(second(), 2, 10, QLatin1Char('0')); + } +} + +/*! + Returns the time as a string. The \a format parameter determines + the format of the result string. + + These expressions may be used: + + \table + \header \i Expression \i Output + \row \i h + \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) + \row \i hh + \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) + \row \i H + \i the hour without a leading zero (0 to 23, even with AM/PM display) + \row \i HH + \i the hour with a leading zero (00 to 23, even with AM/PM display) + \row \i m \i the minute without a leading zero (0 to 59) + \row \i mm \i the minute with a leading zero (00 to 59) + \row \i s \i the second without a leading zero (0 to 59) + \row \i ss \i the second with a leading zero (00 to 59) + \row \i z \i the milliseconds without leading zeroes (0 to 999) + \row \i zzz \i the milliseconds with leading zeroes (000 to 999) + \row \i AP or A + \i use AM/PM display. \e AP will be replaced by either "AM" or "PM". + \row \i ap or a + \i use am/pm display. \e ap will be replaced by either "am" or "pm". + \row \i t \i the timezone (for example "CEST") + \endtable + + All other input characters will be ignored. Any sequence of characters that + are enclosed in singlequotes will be treated as text and not be used as an + expression. Two consecutive singlequotes ("''") are replaced by a singlequote + in the output. + + Example format strings (assuming that the QTime is 14:13:09.042) + + \table + \header \i Format \i Result + \row \i hh:mm:ss.zzz \i 14:13:09.042 + \row \i h:m:s ap \i 2:13:9 pm + \row \i H:m:s a \i 14:13:9 pm + \endtable + + If the datetime is invalid, an empty string will be returned. + If \a format is empty, the default format "hh:mm:ss" is used. + + \sa QDate::toString() QDateTime::toString() +*/ +QString QTime::toString(const QString& format) const +{ + return fmtDateTime(format, this, 0); +} +#endif //QT_NO_DATESTRING +/*! + Sets the time to hour \a h, minute \a m, seconds \a s and + milliseconds \a ms. + + \a h must be in the range 0 to 23, \a m and \a s must be in the + range 0 to 59, and \a ms must be in the range 0 to 999. + Returns true if the set time is valid; otherwise returns false. + + \sa isValid() +*/ + +bool QTime::setHMS(int h, int m, int s, int ms) +{ +#if defined(Q_OS_WINCE) + startTick = NullTime; +#endif + if (!isValid(h,m,s,ms)) { + mds = NullTime; // make this invalid + return false; + } + mds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms; + return true; +} + +/*! + Returns a QTime object containing a time \a s seconds later + than the time of this object (or earlier if \a s is negative). + + Note that the time will wrap if it passes midnight. + + Example: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 5 + + \sa addMSecs(), secsTo(), QDateTime::addSecs() +*/ + +QTime QTime::addSecs(int s) const +{ + return addMSecs(s * 1000); +} + +/*! + Returns the number of seconds from this time to \a t. + If \a t is earlier than this time, the number of seconds returned + is negative. + + Because QTime measures time within a day and there are 86400 + seconds in a day, the result is always between -86400 and 86400. + + secsTo() does not take into account any milliseconds. + + \sa addSecs(), QDateTime::secsTo() +*/ + +int QTime::secsTo(const QTime &t) const +{ + return (t.ds() - ds()) / 1000; +} + +/*! + Returns a QTime object containing a time \a ms milliseconds later + than the time of this object (or earlier if \a ms is negative). + + Note that the time will wrap if it passes midnight. See addSecs() + for an example. + + \sa addSecs(), msecsTo(), QDateTime::addMSecs() +*/ + +QTime QTime::addMSecs(int ms) const +{ + QTime t; + if (ms < 0) { + // % not well-defined for -ve, but / is. + int negdays = (MSECS_PER_DAY - ms) / MSECS_PER_DAY; + t.mds = (ds() + ms + negdays * MSECS_PER_DAY) % MSECS_PER_DAY; + } else { + t.mds = (ds() + ms) % MSECS_PER_DAY; + } +#if defined(Q_OS_WINCE) + if (startTick > NullTime) + t.startTick = (startTick + ms) % MSECS_PER_DAY; +#endif + return t; +} + +/*! + Returns the number of milliseconds from this time to \a t. + If \a t is earlier than this time, the number of milliseconds returned + is negative. + + Because QTime measures time within a day and there are 86400 + seconds in a day, the result is always between -86400000 and + 86400000 ms. + + \sa secsTo(), addMSecs(), QDateTime::msecsTo() +*/ + +int QTime::msecsTo(const QTime &t) const +{ +#if defined(Q_OS_WINCE) + // GetLocalTime() for Windows CE has no milliseconds resolution + if (t.startTick > NullTime && startTick > NullTime) + return t.startTick - startTick; + else +#endif + return t.ds() - ds(); +} + + +/*! + \fn bool QTime::operator==(const QTime &t) const + + Returns true if this time is equal to \a t; otherwise returns false. +*/ + +/*! + \fn bool QTime::operator!=(const QTime &t) const + + Returns true if this time is different from \a t; otherwise returns false. +*/ + +/*! + \fn bool QTime::operator<(const QTime &t) const + + Returns true if this time is earlier than \a t; otherwise returns false. +*/ + +/*! + \fn bool QTime::operator<=(const QTime &t) const + + Returns true if this time is earlier than or equal to \a t; + otherwise returns false. +*/ + +/*! + \fn bool QTime::operator>(const QTime &t) const + + Returns true if this time is later than \a t; otherwise returns false. +*/ + +/*! + \fn bool QTime::operator>=(const QTime &t) const + + Returns true if this time is later than or equal to \a t; + otherwise returns false. +*/ + +/*! + \fn QTime::currentTime() + + Returns the current time as reported by the system clock. + + Note that the accuracy depends on the accuracy of the underlying + operating system; not all systems provide 1-millisecond accuracy. +*/ + +#ifndef QT_NO_DATESTRING +/*! + \fn QTime QTime::fromString(const QString &string, Qt::DateFormat format) + + Returns the time represented in the \a string as a QTime using the + \a format given, or an invalid time if this is not possible. + + Note that fromString() uses a "C" locale encoded string to convert + milliseconds to a float value. If the default locale is not "C", + this may result in two conversion attempts (if the conversion + fails for the default locale). This should be considered an + implementation detail. +*/ +QTime QTime::fromString(const QString& s, Qt::DateFormat f) +{ + if (s.isEmpty()) { + QTime t; + t.mds = NullTime; + return t; + } + + switch (f) { + case Qt::SystemLocaleDate: + case Qt::SystemLocaleShortDate: + case Qt::SystemLocaleLongDate: + return fromString(s, QLocale::system().timeFormat(f == Qt::SystemLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat)); + case Qt::LocaleDate: + case Qt::DefaultLocaleShortDate: + case Qt::DefaultLocaleLongDate: + return fromString(s, QLocale().timeFormat(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat)); + default: + { + bool ok = true; + const int hour(s.mid(0, 2).toInt(&ok)); + if (!ok) + return QTime(); + const int minute(s.mid(3, 2).toInt(&ok)); + if (!ok) + return QTime(); + const int second(s.mid(6, 2).toInt(&ok)); + if (!ok) + return QTime(); + const QString msec_s(QLatin1String("0.") + s.mid(9, 4)); + const float msec(msec_s.toFloat(&ok)); + if (!ok) + return QTime(hour, minute, second, 0); + return QTime(hour, minute, second, qMin(qRound(msec * 1000.0), 999)); + } + } +} + +/*! + \fn QTime::fromString(const QString &string, const QString &format) + + Returns the QTime represented by the \a string, using the \a + format given, or an invalid time if the string cannot be parsed. + + These expressions may be used for the format: + + \table + \header \i Expression \i Output + \row \i h + \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) + \row \i hh + \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) + \row \i m \i the minute without a leading zero (0 to 59) + \row \i mm \i the minute with a leading zero (00 to 59) + \row \i s \i the second without a leading zero (0 to 59) + \row \i ss \i the second with a leading zero (00 to 59) + \row \i z \i the milliseconds without leading zeroes (0 to 999) + \row \i zzz \i the milliseconds with leading zeroes (000 to 999) + \row \i AP + \i interpret as an AM/PM time. \e AP must be either "AM" or "PM". + \row \i ap + \i Interpret as an AM/PM time. \e ap must be either "am" or "pm". + \endtable + + All other input characters will be treated as text. Any sequence + of characters that are enclosed in single quotes will also be + treated as text and not be used as an expression. + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 6 + + If the format is not satisfied an invalid QTime is returned. + Expressions that do not expect leading zeroes to be given (h, m, s + and z) are greedy. This means that they will use two digits even if + this puts them outside the range of accepted values and leaves too + few digits for other sections. For example, the following string + could have meant 00:07:10, but the m will grab two digits, resulting + in an invalid time: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 7 + + Any field that is not represented in the format will be set to zero. + For example: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 8 + + \sa QDateTime::fromString() QDate::fromString() QDate::toString() + QDateTime::toString() QTime::toString() +*/ + +QTime QTime::fromString(const QString &string, const QString &format) +{ + QTime time; +#ifndef QT_BOOTSTRAPPED + QDateTimeParser dt(QVariant::Time, QDateTimeParser::FromString); + if (dt.parseFormat(format)) + dt.fromString(string, 0, &time); +#else + Q_UNUSED(string); + Q_UNUSED(format); +#endif + return time; +} + +#endif // QT_NO_DATESTRING + + +/*! + \overload + + Returns true if the specified time is valid; otherwise returns + false. + + The time is valid if \a h is in the range 0 to 23, \a m and + \a s are in the range 0 to 59, and \a ms is in the range 0 to 999. + + Example: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 9 +*/ + +bool QTime::isValid(int h, int m, int s, int ms) +{ + return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000; +} + + +/*! + Sets this time to the current time. This is practical for timing: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 10 + + \sa restart(), elapsed(), currentTime() +*/ + +void QTime::start() +{ + *this = currentTime(); +} + +/*! + Sets this time to the current time and returns the number of + milliseconds that have elapsed since the last time start() or + restart() was called. + + This function is guaranteed to be atomic and is thus very handy + for repeated measurements. Call start() to start the first + measurement, and restart() for each later measurement. + + Note that the counter wraps to zero 24 hours after the last call + to start() or restart(). + + \warning If the system's clock setting has been changed since the + last time start() or restart() was called, the result is + undefined. This can happen when daylight savings time is turned on + or off. + + \sa start(), elapsed(), currentTime() +*/ + +int QTime::restart() +{ + QTime t = currentTime(); + int n = msecsTo(t); + if (n < 0) // passed midnight + n += 86400*1000; + *this = t; + return n; +} + +/*! + Returns the number of milliseconds that have elapsed since the + last time start() or restart() was called. + + Note that the counter wraps to zero 24 hours after the last call + to start() or restart. + + Note that the accuracy depends on the accuracy of the underlying + operating system; not all systems provide 1-millisecond accuracy. + + \warning If the system's clock setting has been changed since the + last time start() or restart() was called, the result is + undefined. This can happen when daylight savings time is turned on + or off. + + \sa start(), restart() +*/ + +int QTime::elapsed() const +{ + int n = msecsTo(currentTime()); + if (n < 0) // passed midnight + n += 86400 * 1000; + return n; +} + + +/***************************************************************************** + QDateTime member functions + *****************************************************************************/ + +/*! + \class QDateTime + \reentrant + \brief The QDateTime class provides date and time functions. + + + A QDateTime object contains a calendar date and a clock time (a + "datetime"). It is a combination of the QDate and QTime classes. + It can read the current datetime from the system clock. It + provides functions for comparing datetimes and for manipulating a + datetime by adding a number of seconds, days, months, or years. + + A QDateTime object is typically created either by giving a date + and time explicitly in the constructor, or by using the static + function currentDateTime() that returns a QDateTime object set + to the system clock's time. The date and time can be changed with + setDate() and setTime(). A datetime can also be set using the + setTime_t() function that takes a POSIX-standard "number of + seconds since 00:00:00 on January 1, 1970" value. The fromString() + function returns a QDateTime, given a string and a date format + used to interpret the date within the string. + + The date() and time() functions provide access to the date and + time parts of the datetime. The same information is provided in + textual format by the toString() function. + + QDateTime provides a full set of operators to compare two + QDateTime objects where smaller means earlier and larger means + later. + + You can increment (or decrement) a datetime by a given number of + milliseconds using addMSecs(), seconds using addSecs(), or days + using addDays(). Similarly you can use addMonths() and addYears(). + The daysTo() function returns the number of days between two datetimes, + secsTo() returns the number of seconds between two datetimes, and + msecsTo() returns the number of milliseconds between two datetimes. + + QDateTime can store datetimes as \l{Qt::LocalTime}{local time} or + as \l{Qt::UTC}{UTC}. QDateTime::currentDateTime() returns a + QDateTime expressed as local time; use toUTC() to convert it to + UTC. You can also use timeSpec() to find out if a QDateTime + object stores a UTC time or a local time. Operations such as + addSecs() and secsTo() are aware of daylight saving time (DST). + + \note QDateTime does not account for leap seconds. + + \section1 + + \target QDateTime G and J + \section2 Use of Gregorian and Julian Calendars + + QDate uses the Gregorian calendar in all locales, beginning + on the date 15 October 1582. For dates up to and including 4 + October 1582, the Julian calendar is used. This means there is a + 10-day gap in the internal calendar between the 4th and the 15th + of October 1582. When you use QDateTime for dates in that epoch, + the day after 4 October 1582 is 15 October 1582, and the dates in + the gap are invalid. + + The Julian to Gregorian changeover date used here is the date when + the Gregorian calendar was first introduced, by Pope Gregory + XIII. That change was not universally accepted and some localities + only executed it at a later date (if at all). QDateTime + doesn't take any of these historical facts into account. If an + application must support a locale-specific dating system, it must + do so on its own, remembering to convert the dates using the + Julian day. + + \section2 No Year 0 + + There is no year 0. Dates in that year are considered invalid. The + year -1 is the year "1 before Christ" or "1 before current era." + The day before 0001-01-01 is December 31st, 1 BCE. + + \section2 Range of Valid Dates + + The range of valid dates is from January 2nd, 4713 BCE, to + sometime in the year 11 million CE. The Julian Day returned by + QDate::toJulianDay() is a number in the contiguous range from 1 to + \e{overflow}, even across QDateTime's "date holes". It is suitable + for use in applications that must convert a QDateTime to a date in + another calendar system, e.g., Hebrew, Islamic or Chinese. + + The Gregorian calendar was introduced in different places around + the world on different dates. QDateTime uses QDate to store the + date, so it uses the Gregorian calendar for all locales, beginning + on the date 15 October 1582. For dates up to and including 4 + October 1582, QDateTime uses the Julian calendar. This means + there is a 10-day gap in the QDateTime calendar between the 4th + and the 15th of October 1582. When you use QDateTime for dates in + that epoch, the day after 4 October 1582 is 15 October 1582, and + the dates in the gap are invalid. + + \section2 + Use of System Timezone + + QDateTime uses the system's time zone information to determine the + offset of local time from UTC. If the system is not configured + correctly or not up-to-date, QDateTime will give wrong results as + well. + + \section2 Daylight Savings Time (DST) + + QDateTime takes into account the system's time zone information + when dealing with DST. On modern Unix systems, this means it + applies the correct historical DST data whenever possible. On + Windows and Windows CE, where the system doesn't support + historical DST data, historical accuracy is not maintained with + respect to DST. + + The range of valid dates taking DST into account is 1970-01-01 to + the present, and rules are in place for handling DST correctly + until 2037-12-31, but these could change. For dates falling + outside that range, QDateTime makes a \e{best guess} using the + rules for year 1970 or 2037, but we can't guarantee accuracy. This + means QDateTime doesn't take into account changes in a locale's + time zone before 1970, even if the system's time zone database + supports that information. + + \sa QDate QTime QDateTimeEdit +*/ + +/*! + Constructs a null datetime (i.e. null date and null time). A null + datetime is invalid, since the date is invalid. + + \sa isValid() +*/ +QDateTime::QDateTime() + : d(new QDateTimePrivate) +{ +} + + +/*! + Constructs a datetime with the given \a date, a valid + time(00:00:00.000), and sets the timeSpec() to Qt::LocalTime. +*/ + +QDateTime::QDateTime(const QDate &date) + : d(new QDateTimePrivate) +{ + d->date = date; + d->time = QTime(0, 0, 0); +} + +/*! + Constructs a datetime with the given \a date and \a time, using + the time specification defined by \a spec. + + If \a date is valid and \a time is not, the time will be set to midnight. +*/ + +QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec) + : d(new QDateTimePrivate) +{ + d->date = date; + d->time = date.isValid() && !time.isValid() ? QTime(0, 0, 0) : time; + d->spec = (spec == Qt::UTC) ? QDateTimePrivate::UTC : QDateTimePrivate::LocalUnknown; +} + +/*! + Constructs a copy of the \a other datetime. +*/ + +QDateTime::QDateTime(const QDateTime &other) + : d(other.d) +{ +} + +/*! + Destroys the datetime. +*/ +QDateTime::~QDateTime() +{ +} + +/*! + Makes a copy of the \a other datetime and returns a reference to the + copy. +*/ + +QDateTime &QDateTime::operator=(const QDateTime &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if both the date and the time are null; otherwise + returns false. A null datetime is invalid. + + \sa QDate::isNull(), QTime::isNull(), isValid() +*/ + +bool QDateTime::isNull() const +{ + return d->date.isNull() && d->time.isNull(); +} + +/*! + Returns true if both the date and the time are valid; otherwise + returns false. + + \sa QDate::isValid(), QTime::isValid() +*/ + +bool QDateTime::isValid() const +{ + return d->date.isValid() && d->time.isValid(); +} + +/*! + Returns the date part of the datetime. + + \sa setDate(), time(), timeSpec() +*/ + +QDate QDateTime::date() const +{ + return d->date; +} + +/*! + Returns the time part of the datetime. + + \sa setTime(), date(), timeSpec() +*/ + +QTime QDateTime::time() const +{ + return d->time; +} + +/*! + Returns the time specification of the datetime. + + \sa setTimeSpec(), date(), time(), Qt::TimeSpec +*/ + +Qt::TimeSpec QDateTime::timeSpec() const +{ + switch(d->spec) + { + case QDateTimePrivate::UTC: + return Qt::UTC; + case QDateTimePrivate::OffsetFromUTC: + return Qt::OffsetFromUTC; + default: + return Qt::LocalTime; + } +} + +/*! + Sets the date part of this datetime to \a date. + If no time is set, it is set to midnight. + + \sa date(), setTime(), setTimeSpec() +*/ + +void QDateTime::setDate(const QDate &date) +{ + detach(); + d->date = date; + if (d->spec == QDateTimePrivate::LocalStandard + || d->spec == QDateTimePrivate::LocalDST) + d->spec = QDateTimePrivate::LocalUnknown; + if (date.isValid() && !d->time.isValid()) + d->time = QTime(0, 0, 0); +} + +/*! + Sets the time part of this datetime to \a time. + + \sa time(), setDate(), setTimeSpec() +*/ + +void QDateTime::setTime(const QTime &time) +{ + detach(); + if (d->spec == QDateTimePrivate::LocalStandard + || d->spec == QDateTimePrivate::LocalDST) + d->spec = QDateTimePrivate::LocalUnknown; + d->time = time; +} + +/*! + Sets the time specification used in this datetime to \a spec. + + \sa timeSpec(), setDate(), setTime(), Qt::TimeSpec +*/ + +void QDateTime::setTimeSpec(Qt::TimeSpec spec) +{ + detach(); + + switch(spec) + { + case Qt::UTC: + d->spec = QDateTimePrivate::UTC; + break; + case Qt::OffsetFromUTC: + d->spec = QDateTimePrivate::OffsetFromUTC; + break; + default: + d->spec = QDateTimePrivate::LocalUnknown; + break; + } +} + +qint64 toMSecsSinceEpoch_helper(qint64 jd, int msecs) +{ + qint64 days = jd - JULIAN_DAY_FOR_EPOCH; + qint64 retval = (days * MSECS_PER_DAY) + msecs; + return retval; +} + +/*! + \since 4.7 + + Returns the datetime as the number of milliseconds that have passed + since 1970-01-01T00:00:00.000, Coordinated Universal Time (Qt::UTC). + + On systems that do not support time zones, this function will + behave as if local time were Qt::UTC. + + The behavior for this function is undefined if the datetime stored in + this object is not valid. However, for all valid dates, this function + returns a unique value. + + \sa toTime_t(), setMSecsSinceEpoch() +*/ +qint64 QDateTime::toMSecsSinceEpoch() const +{ + QDate utcDate; + QTime utcTime; + d->getUTC(utcDate, utcTime); + + return toMSecsSinceEpoch_helper(utcDate.jd, utcTime.ds()); +} + +/*! + Returns the datetime as the number of seconds that have passed + since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC). + + On systems that do not support time zones, this function will + behave as if local time were Qt::UTC. + + \note This function returns a 32-bit unsigned integer, so it does not + support dates before 1970, but it does support dates after + 2038-01-19T03:14:06, which may not be valid time_t values. Be careful + when passing those time_t values to system functions, which could + interpret them as negative dates. + + If the date is outside the range 1970-01-01T00:00:00 to + 2106-02-07T06:28:14, this function returns -1 cast to an unsigned integer + (i.e., 0xFFFFFFFF). + + To get an extended range, use toMSecsSinceEpoch(). + + \sa toMSecsSinceEpoch(), setTime_t() +*/ + +uint QDateTime::toTime_t() const +{ + qint64 retval = toMSecsSinceEpoch() / 1000; + if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF)) + return uint(-1); + return uint(retval); +} + +/*! + \since 4.7 + + Sets the date and time given the number of milliseconds,\a msecs, that have + passed since 1970-01-01T00:00:00.000, Coordinated Universal Time + (Qt::UTC). On systems that do not support time zones this function + will behave as if local time were Qt::UTC. + + Note that there are possible values for \a msecs that lie outside the + valid range of QDateTime, both negative and positive. The behavior of + this function is undefined for those values. + + \sa toMSecsSinceEpoch(), setTime_t() +*/ +void QDateTime::setMSecsSinceEpoch(qint64 msecs) +{ + detach(); + + QDateTimePrivate::Spec oldSpec = d->spec; + + int ddays = msecs / MSECS_PER_DAY; + msecs %= MSECS_PER_DAY; + if (msecs < 0) { + // negative + --ddays; + msecs += MSECS_PER_DAY; + } + + d->date = QDate(1970, 1, 1).addDays(ddays); + d->time = QTime().addMSecs(msecs); + d->spec = QDateTimePrivate::UTC; + + if (oldSpec != QDateTimePrivate::UTC) + d->spec = d->getLocal(d->date, d->time); +} + +/*! + \fn void QDateTime::setTime_t(uint seconds) + + Sets the date and time given the number of \a seconds that have + passed since 1970-01-01T00:00:00, Coordinated Universal Time + (Qt::UTC). On systems that do not support time zones this function + will behave as if local time were Qt::UTC. + + \sa toTime_t() +*/ + +void QDateTime::setTime_t(uint secsSince1Jan1970UTC) +{ + detach(); + + QDateTimePrivate::Spec oldSpec = d->spec; + + d->date = QDate(1970, 1, 1).addDays(secsSince1Jan1970UTC / SECS_PER_DAY); + d->time = QTime().addSecs(secsSince1Jan1970UTC % SECS_PER_DAY); + d->spec = QDateTimePrivate::UTC; + + if (oldSpec != QDateTimePrivate::UTC) + d->spec = d->getLocal(d->date, d->time); +} + +#ifndef QT_NO_DATESTRING +/*! + \fn QString QDateTime::toString(Qt::DateFormat format) const + + \overload + + Returns the datetime as a string in the \a format given. + + If the \a format is Qt::TextDate, the string is formatted in + the default way. QDate::shortDayName(), QDate::shortMonthName(), + and QTime::toString() are used to generate the string, so the + day and month names will be localized names. An example of this + formatting is "Wed May 20 03:40:13 1998". + + If the \a format is Qt::ISODate, the string format corresponds + to the ISO 8601 extended specification for representations of + dates and times, taking the form YYYY-MM-DDTHH:MM:SS. + + If the \a format is Qt::SystemLocaleShortDate or + Qt::SystemLocaleLongDate, the string format depends on the locale + settings of the system. Identical to calling + QLocale::system().toString(datetime, QLocale::ShortFormat) or + QLocale::system().toString(datetime, QLocale::LongFormat). + + If the \a format is Qt::DefaultLocaleShortDate or + Qt::DefaultLocaleLongDate, the string format depends on the + default application locale. This is the locale set with + QLocale::setDefault(), or the system locale if no default locale + has been set. Identical to calling QLocale().toString(datetime, + QLocale::ShortFormat) or QLocale().toString(datetime, + QLocale::LongFormat). + + If the datetime is invalid, an empty string will be returned. + + \warning The Qt::ISODate format is only valid for years in the + range 0 to 9999. This restriction may apply to locale-aware + formats as well, depending on the locale settings. + + \sa QDate::toString() QTime::toString() Qt::DateFormat +*/ + +QString QDateTime::toString(Qt::DateFormat f) const +{ + QString buf; + if (!isValid()) + return buf; + + if (f == Qt::ISODate) { + buf = d->date.toString(Qt::ISODate); + if (buf.isEmpty()) + return QString(); // failed to convert + buf += QLatin1Char('T'); + buf += d->time.toString(Qt::ISODate); + } +#ifndef QT_NO_TEXTDATE + else if (f == Qt::TextDate) { +#ifndef Q_WS_WIN + buf = d->date.shortDayName(d->date.dayOfWeek()); + buf += QLatin1Char(' '); + buf += d->date.shortMonthName(d->date.month()); + buf += QLatin1Char(' '); + buf += QString::number(d->date.day()); +#else + wchar_t out[255]; + GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILDATE, out, 255); + QString winstr = QString::fromWCharArray(out); + switch (winstr.toInt()) { + case 1: + buf = d->date.shortDayName(d->date.dayOfWeek()); + buf += QLatin1Char(' '); + buf += QString::number(d->date.day()); + buf += QLatin1String(". "); + buf += d->date.shortMonthName(d->date.month()); + break; + default: + buf = d->date.shortDayName(d->date.dayOfWeek()); + buf += QLatin1Char(' '); + buf += d->date.shortMonthName(d->date.month()); + buf += QLatin1Char(' '); + buf += QString::number(d->date.day()); + } +#endif + buf += QLatin1Char(' '); + buf += d->time.toString(); + buf += QLatin1Char(' '); + buf += QString::number(d->date.year()); + } +#endif + else { + buf = d->date.toString(f); + if (buf.isEmpty()) + return QString(); // failed to convert + buf += QLatin1Char(' '); + buf += d->time.toString(f); + } + + return buf; +} + +/*! + Returns the datetime as a string. The \a format parameter + determines the format of the result string. + + These expressions may be used for the date: + + \table + \header \i Expression \i Output + \row \i d \i the day as number without a leading zero (1 to 31) + \row \i dd \i the day as number with a leading zero (01 to 31) + \row \i ddd + \i the abbreviated localized day name (e.g. 'Mon' to 'Sun'). + Uses QDate::shortDayName(). + \row \i dddd + \i the long localized day name (e.g. 'Monday' to 'Qt::Sunday'). + Uses QDate::longDayName(). + \row \i M \i the month as number without a leading zero (1-12) + \row \i MM \i the month as number with a leading zero (01-12) + \row \i MMM + \i the abbreviated localized month name (e.g. 'Jan' to 'Dec'). + Uses QDate::shortMonthName(). + \row \i MMMM + \i the long localized month name (e.g. 'January' to 'December'). + Uses QDate::longMonthName(). + \row \i yy \i the year as two digit number (00-99) + \row \i yyyy \i the year as four digit number + \endtable + + These expressions may be used for the time: + + \table + \header \i Expression \i Output + \row \i h + \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) + \row \i hh + \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) + \row \i m \i the minute without a leading zero (0 to 59) + \row \i mm \i the minute with a leading zero (00 to 59) + \row \i s \i the second without a leading zero (0 to 59) + \row \i ss \i the second with a leading zero (00 to 59) + \row \i z \i the milliseconds without leading zeroes (0 to 999) + \row \i zzz \i the milliseconds with leading zeroes (000 to 999) + \row \i AP + \i use AM/PM display. \e AP will be replaced by either "AM" or "PM". + \row \i ap + \i use am/pm display. \e ap will be replaced by either "am" or "pm". + \endtable + + All other input characters will be ignored. Any sequence of characters that + are enclosed in singlequotes will be treated as text and not be used as an + expression. Two consecutive singlequotes ("''") are replaced by a singlequote + in the output. + + Example format strings (assumed that the QDateTime is 21 May 2001 + 14:13:09): + + \table + \header \i Format \i Result + \row \i dd.MM.yyyy \i 21.05.2001 + \row \i ddd MMMM d yy \i Tue May 21 01 + \row \i hh:mm:ss.zzz \i 14:13:09.042 + \row \i h:m:s ap \i 2:13:9 pm + \endtable + + If the datetime is invalid, an empty string will be returned. + + \sa QDate::toString() QTime::toString() +*/ +QString QDateTime::toString(const QString& format) const +{ + return fmtDateTime(format, &d->time, &d->date); +} +#endif //QT_NO_DATESTRING + +/*! + Returns a QDateTime object containing a datetime \a ndays days + later than the datetime of this object (or earlier if \a ndays is + negative). + + \sa daysTo(), addMonths(), addYears(), addSecs() +*/ + +QDateTime QDateTime::addDays(int ndays) const +{ + return QDateTime(d->date.addDays(ndays), d->time, timeSpec()); +} + +/*! + Returns a QDateTime object containing a datetime \a nmonths months + later than the datetime of this object (or earlier if \a nmonths + is negative). + + \sa daysTo(), addDays(), addYears(), addSecs() +*/ + +QDateTime QDateTime::addMonths(int nmonths) const +{ + return QDateTime(d->date.addMonths(nmonths), d->time, timeSpec()); +} + +/*! + Returns a QDateTime object containing a datetime \a nyears years + later than the datetime of this object (or earlier if \a nyears is + negative). + + \sa daysTo(), addDays(), addMonths(), addSecs() +*/ + +QDateTime QDateTime::addYears(int nyears) const +{ + return QDateTime(d->date.addYears(nyears), d->time, timeSpec()); +} + +QDateTime QDateTimePrivate::addMSecs(const QDateTime &dt, qint64 msecs) +{ + QDate utcDate; + QTime utcTime; + dt.d->getUTC(utcDate, utcTime); + + addMSecs(utcDate, utcTime, msecs); + + return QDateTime(utcDate, utcTime, Qt::UTC).toTimeSpec(dt.timeSpec()); +} + +/*! + Adds \a msecs to utcDate and \a utcTime as appropriate. It is assumed that + utcDate and utcTime are adjusted to UTC. + + \since 4.5 + \internal + */ +void QDateTimePrivate::addMSecs(QDate &utcDate, QTime &utcTime, qint64 msecs) +{ + uint dd = utcDate.jd; + int tt = utcTime.ds(); + int sign = 1; + if (msecs < 0) { + msecs = -msecs; + sign = -1; + } + if (msecs >= int(MSECS_PER_DAY)) { + dd += sign * (msecs / MSECS_PER_DAY); + msecs %= MSECS_PER_DAY; + } + + tt += sign * msecs; + if (tt < 0) { + tt = MSECS_PER_DAY - tt - 1; + dd -= tt / MSECS_PER_DAY; + tt = tt % MSECS_PER_DAY; + tt = MSECS_PER_DAY - tt - 1; + } else if (tt >= int(MSECS_PER_DAY)) { + dd += tt / MSECS_PER_DAY; + tt = tt % MSECS_PER_DAY; + } + + utcDate.jd = dd; + utcTime.mds = tt; +} + +/*! + Returns a QDateTime object containing a datetime \a s seconds + later than the datetime of this object (or earlier if \a s is + negative). + + \sa addMSecs(), secsTo(), addDays(), addMonths(), addYears() +*/ + +QDateTime QDateTime::addSecs(int s) const +{ + return d->addMSecs(*this, qint64(s) * 1000); +} + +/*! + Returns a QDateTime object containing a datetime \a msecs miliseconds + later than the datetime of this object (or earlier if \a msecs is + negative). + + \sa addSecs(), msecsTo(), addDays(), addMonths(), addYears() +*/ +QDateTime QDateTime::addMSecs(qint64 msecs) const +{ + return d->addMSecs(*this, msecs); +} + +/*! + Returns the number of days from this datetime to the \a other + datetime. If the \a other datetime is earlier than this datetime, + the value returned is negative. + + \sa addDays(), secsTo(), msecsTo() +*/ + +int QDateTime::daysTo(const QDateTime &other) const +{ + return d->date.daysTo(other.d->date); +} + +/*! + Returns the number of seconds from this datetime to the \a other + datetime. If the \a other datetime is earlier than this datetime, + the value returned is negative. + + Before performing the comparison, the two datetimes are converted + to Qt::UTC to ensure that the result is correct if one of the two + datetimes has daylight saving time (DST) and the other doesn't. + + Example: + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 11 + + \sa addSecs(), daysTo(), QTime::secsTo() +*/ + +int QDateTime::secsTo(const QDateTime &other) const +{ + QDate date1, date2; + QTime time1, time2; + + d->getUTC(date1, time1); + other.d->getUTC(date2, time2); + + return (date1.daysTo(date2) * SECS_PER_DAY) + time1.secsTo(time2); +} + +/*! + Returns the number of milliseconds from this datetime to the \a other + datetime. If the \a other datetime is earlier than this datetime, + the value returned is negative. + + Before performing the comparison, the two datetimes are converted + to Qt::UTC to ensure that the result is correct if one of the two + datetimes has daylight saving time (DST) and the other doesn't. + + \sa addMSecs(), daysTo(), QTime::msecsTo() +*/ + +qint64 QDateTime::msecsTo(const QDateTime &other) const +{ + QDate selfDate; + QDate otherDate; + QTime selfTime; + QTime otherTime; + + d->getUTC(selfDate, selfTime); + other.d->getUTC(otherDate, otherTime); + + return (static_cast<qint64>(selfDate.daysTo(otherDate)) * static_cast<qint64>(MSECS_PER_DAY)) + + static_cast<qint64>(selfTime.msecsTo(otherTime)); +} + + +/*! + \fn QDateTime QDateTime::toTimeSpec(Qt::TimeSpec specification) const + + Returns a copy of this datetime configured to use the given time + \a specification. + + \sa timeSpec(), toUTC(), toLocalTime() +*/ + +QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const +{ + if ((d->spec == QDateTimePrivate::UTC) == (spec == Qt::UTC)) + return *this; + + QDateTime ret; + if (spec == Qt::UTC) { + d->getUTC(ret.d->date, ret.d->time); + ret.d->spec = QDateTimePrivate::UTC; + } else { + ret.d->spec = d->getLocal(ret.d->date, ret.d->time); + } + return ret; +} + +/*! + Returns true if this datetime is equal to the \a other datetime; + otherwise returns false. + + \sa operator!=() +*/ + +bool QDateTime::operator==(const QDateTime &other) const +{ + if (d->spec == other.d->spec && d->utcOffset == other.d->utcOffset) + return d->time == other.d->time && d->date == other.d->date; + else { + QDate date1, date2; + QTime time1, time2; + + d->getUTC(date1, time1); + other.d->getUTC(date2, time2); + return time1 == time2 && date1 == date2; + } +} + +/*! + \fn bool QDateTime::operator!=(const QDateTime &other) const + + Returns true if this datetime is different from the \a other + datetime; otherwise returns false. + + Two datetimes are different if either the date, the time, or the + time zone components are different. + + \sa operator==() +*/ + +/*! + Returns true if this datetime is earlier than the \a other + datetime; otherwise returns false. +*/ + +bool QDateTime::operator<(const QDateTime &other) const +{ + if (d->spec == other.d->spec && d->spec != QDateTimePrivate::OffsetFromUTC) { + if (d->date != other.d->date) + return d->date < other.d->date; + return d->time < other.d->time; + } else { + QDate date1, date2; + QTime time1, time2; + d->getUTC(date1, time1); + other.d->getUTC(date2, time2); + if (date1 != date2) + return date1 < date2; + return time1 < time2; + } +} + +/*! + \fn bool QDateTime::operator<=(const QDateTime &other) const + + Returns true if this datetime is earlier than or equal to the + \a other datetime; otherwise returns false. +*/ + +/*! + \fn bool QDateTime::operator>(const QDateTime &other) const + + Returns true if this datetime is later than the \a other datetime; + otherwise returns false. +*/ + +/*! + \fn bool QDateTime::operator>=(const QDateTime &other) const + + Returns true if this datetime is later than or equal to the + \a other datetime; otherwise returns false. +*/ + +/*! + \fn QDateTime QDateTime::currentDateTime() + Returns the current datetime, as reported by the system clock, in + the local time zone. + + \sa currentDateTimeUtc(), QDate::currentDate(), QTime::currentTime(), toTimeSpec() +*/ + +/*! + \fn QDateTime QDateTime::currentDateTimeUtc() + \since 4.7 + Returns the current datetime, as reported by the system clock, in + UTC. + + \sa currentDateTime(), QDate::currentDate(), QTime::currentTime(), toTimeSpec() +*/ + +/*! + \fn qint64 QDateTime::currentMSecsSinceEpoch() + \since 4.7 + + Returns the number of milliseconds since 1970-01-01T00:00:00 Universal + Coordinated Time. This number is like the POSIX time_t variable, but + expressed in milliseconds instead. + + \sa currentDateTime(), currentDateTimeUtc(), toTime_t(), toTimeSpec() +*/ + +static inline uint msecsFromDecomposed(int hour, int minute, int sec, int msec = 0) +{ + return MSECS_PER_HOUR * hour + MSECS_PER_MIN * minute + 1000 * sec + msec; +} + +#if defined(Q_OS_WIN) +QDate QDate::currentDate() +{ + QDate d; + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + GetLocalTime(&st); + d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay); + return d; +} + +QTime QTime::currentTime() +{ + QTime ct; + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + GetLocalTime(&st); + ct.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); +#if defined(Q_OS_WINCE) + ct.startTick = GetTickCount() % MSECS_PER_DAY; +#endif + return ct; +} + +QDateTime QDateTime::currentDateTime() +{ + QDate d; + QTime t; + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + GetLocalTime(&st); + d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay); + t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + return QDateTime(d, t); +} + +QDateTime QDateTime::currentDateTimeUtc() +{ + QDate d; + QTime t; + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + GetSystemTime(&st); + d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay); + t.mds = msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); + return QDateTime(d, t, Qt::UTC); +} + +qint64 QDateTime::currentMSecsSinceEpoch() +{ + QDate d; + QTime t; + SYSTEMTIME st; + memset(&st, 0, sizeof(SYSTEMTIME)); + GetSystemTime(&st); + + return msecsFromDecomposed(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds) + + qint64(julianDayFromGregorianDate(st.wYear, st.wMonth, st.wDay) + - julianDayFromGregorianDate(1970, 1, 1)) * Q_INT64_C(86400000); +} + +#elif defined(Q_OS_SYMBIAN) +QDate QDate::currentDate() +{ + QDate d; + TTime localTime; + localTime.HomeTime(); + TDateTime localDateTime = localTime.DateTime(); + // months and days are zero indexed + d.jd = julianDayFromDate(localDateTime.Year(), localDateTime.Month() + 1, localDateTime.Day() + 1 ); + return d; +} + +QTime QTime::currentTime() +{ + QTime ct; + TTime localTime; + localTime.HomeTime(); + TDateTime localDateTime = localTime.DateTime(); + ct.mds = msecsFromDecomposed(localDateTime.Hour(), localDateTime.Minute(), + localDateTime.Second(), localDateTime.MicroSecond() / 1000); + return ct; +} + +QDateTime QDateTime::currentDateTime() +{ + QDate d; + QTime ct; + TTime localTime; + localTime.HomeTime(); + TDateTime localDateTime = localTime.DateTime(); + // months and days are zero indexed + d.jd = julianDayFromDate(localDateTime.Year(), localDateTime.Month() + 1, localDateTime.Day() + 1); + ct.mds = msecsFromDecomposed(localDateTime.Hour(), localDateTime.Minute(), + localDateTime.Second(), localDateTime.MicroSecond() / 1000); + return QDateTime(d, ct); +} + +QDateTime QDateTime::currentDateTimeUtc() +{ + QDate d; + QTime ct; + TTime gmTime; + gmTime.UniversalTime(); + TDateTime gmtDateTime = gmTime.DateTime(); + // months and days are zero indexed + d.jd = julianDayFromDate(gmtDateTime.Year(), gmtDateTime.Month() + 1, gmtDateTime.Day() + 1); + ct.mds = msecsFromDecomposed(gmtDateTime.Hour(), gmtDateTime.Minute(), + gmtDateTime.Second(), gmtDateTime.MicroSecond() / 1000); + return QDateTime(d, ct, Qt::UTC); +} + +qint64 QDateTime::currentMSecsSinceEpoch() +{ + QDate d; + QTime ct; + TTime gmTime; + gmTime.UniversalTime(); + TDateTime gmtDateTime = gmTime.DateTime(); + + // according to the documentation, the value is: + // "a date and time as a number of microseconds since midnight, January 1st, 0 AD nominal Gregorian" + qint64 value = gmTime.Int64(); + + // whereas 1970-01-01T00:00:00 is (in the same representation): + // ((1970 * 365) + (1970 / 4) - (1970 / 100) + (1970 / 400) - 13) * 86400 * 1000000 + static const qint64 unixEpoch = Q_INT64_C(0xdcddb30f2f8000); + + return (value - unixEpoch) / 1000; +} + +#elif defined(Q_OS_UNIX) +QDate QDate::currentDate() +{ + QDate d; + // posix compliant system + time_t ltime; + time(<ime); + struct tm *t = 0; + +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant version of localtime() where available + tzset(); + struct tm res; + t = localtime_r(<ime, &res); +#else + t = localtime(<ime); +#endif // !QT_NO_THREAD && _POSIX_THREAD_SAFE_FUNCTIONS + + d.jd = julianDayFromDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday); + return d; +} + +QTime QTime::currentTime() +{ + QTime ct; + // posix compliant system + struct timeval tv; + gettimeofday(&tv, 0); + time_t ltime = tv.tv_sec; + struct tm *t = 0; + +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant version of localtime() where available + tzset(); + struct tm res; + t = localtime_r(<ime, &res); +#else + t = localtime(<ime); +#endif + Q_CHECK_PTR(t); + + ct.mds = msecsFromDecomposed(t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000); + return ct; +} + +QDateTime QDateTime::currentDateTime() +{ + // posix compliant system + // we have milliseconds + struct timeval tv; + gettimeofday(&tv, 0); + time_t ltime = tv.tv_sec; + struct tm *t = 0; + +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant version of localtime() where available + tzset(); + struct tm res; + t = localtime_r(<ime, &res); +#else + t = localtime(<ime); +#endif + + QDateTime dt; + dt.d->time.mds = msecsFromDecomposed(t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000); + + dt.d->date.jd = julianDayFromDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday); + dt.d->spec = t->tm_isdst > 0 ? QDateTimePrivate::LocalDST : + t->tm_isdst == 0 ? QDateTimePrivate::LocalStandard : + QDateTimePrivate::LocalUnknown; + return dt; +} + +QDateTime QDateTime::currentDateTimeUtc() +{ + // posix compliant system + // we have milliseconds + struct timeval tv; + gettimeofday(&tv, 0); + time_t ltime = tv.tv_sec; + struct tm *t = 0; + +#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant version of localtime() where available + struct tm res; + t = gmtime_r(<ime, &res); +#else + t = gmtime(<ime); +#endif + + QDateTime dt; + dt.d->time.mds = msecsFromDecomposed(t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec / 1000); + + dt.d->date.jd = julianDayFromDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday); + dt.d->spec = QDateTimePrivate::UTC; + return dt; +} + +qint64 QDateTime::currentMSecsSinceEpoch() +{ + // posix compliant system + // we have milliseconds + struct timeval tv; + gettimeofday(&tv, 0); + return qint64(tv.tv_sec) * Q_INT64_C(1000) + tv.tv_usec / 1000; +} + +#else +#error "What system is this?" +#endif + +/*! + \since 4.2 + + Returns a datetime whose date and time are the number of \a seconds + that have passed since 1970-01-01T00:00:00, Coordinated Universal + Time (Qt::UTC). On systems that do not support time zones, the time + will be set as if local time were Qt::UTC. + + \sa toTime_t(), setTime_t() +*/ +QDateTime QDateTime::fromTime_t(uint seconds) +{ + QDateTime d; + d.setTime_t(seconds); + return d; +} + +/*! + \since 4.7 + + Returns a datetime whose date and time are the number of milliseconds, \a msecs, + that have passed since 1970-01-01T00:00:00.000, Coordinated Universal + Time (Qt::UTC). On systems that do not support time zones, the time + will be set as if local time were Qt::UTC. + + Note that there are possible values for \a msecs that lie outside the valid + range of QDateTime, both negative and positive. The behavior of this + function is undefined for those values. + + \sa toTime_t(), setTime_t() +*/ +QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs) +{ + QDateTime d; + d.setMSecsSinceEpoch(msecs); + return d; +} + +/*! + \since 4.4 + \internal + + Sets the offset from UTC to \a seconds, and also sets timeSpec() to + Qt::OffsetFromUTC. + + The maximum and minimum offset is 14 positive or negative hours. If + \a seconds is larger or smaller than that, the result is undefined. + + 0 as offset is identical to UTC. Therefore, if \a seconds is 0, the + timeSpec() will be set to Qt::UTC. Hence the UTC offset always + relates to UTC, and can never relate to local time. + + \sa isValid(), utcOffset() + */ +void QDateTime::setUtcOffset(int seconds) +{ + detach(); + + /* The motivation to also setting d->spec is to ensure that the QDateTime + * instance stay in well-defined states all the time, instead of that + * we instruct the user to ensure it. */ + if(seconds == 0) + d->spec = QDateTimePrivate::UTC; + else + d->spec = QDateTimePrivate::OffsetFromUTC; + + /* Even if seconds is 0 we assign it to utcOffset. */ + d->utcOffset = seconds; +} + +/*! + \since 4.4 + \internal + + Returns the UTC offset in seconds. If the timeSpec() isn't + Qt::OffsetFromUTC, 0 is returned. However, since 0 is a valid UTC + offset the return value of this function cannot be used to determine + whether a utcOffset() is used or is valid, timeSpec() must be + checked. + + Likewise, if this QDateTime() is invalid or if timeSpec() isn't + Qt::OffsetFromUTC, 0 is returned. + + The UTC offset only applies if the timeSpec() is Qt::OffsetFromUTC. + + \sa isValid(), setUtcOffset() + */ +int QDateTime::utcOffset() const +{ + if(isValid() && d->spec == QDateTimePrivate::OffsetFromUTC) + return d->utcOffset; + else + return 0; +} + +#ifndef QT_NO_DATESTRING + +static int fromShortMonthName(const QString &monthName) +{ + // Assume that English monthnames are the default + for (int i = 0; i < 12; ++i) { + if (monthName == QLatin1String(qt_shortMonthNames[i])) + return i + 1; + } + // If English names can't be found, search the localized ones + for (int i = 1; i <= 12; ++i) { + if (monthName == QDate::shortMonthName(i)) + return i; + } + return -1; +} + +/*! + \fn QDateTime QDateTime::fromString(const QString &string, Qt::DateFormat format) + + Returns the QDateTime represented by the \a string, using the + \a format given, or an invalid datetime if this is not possible. + + Note for Qt::TextDate: It is recommended that you use the + English short month names (e.g. "Jan"). Although localized month + names can also be used, they depend on the user's locale settings. +*/ +QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) +{ + if (s.isEmpty()) { + return QDateTime(); + } + + switch (f) { + case Qt::ISODate: { + QString tmp = s; + Qt::TimeSpec ts = Qt::LocalTime; + const QDate date = QDate::fromString(tmp.left(10), Qt::ISODate); + if (tmp.size() == 10) + return QDateTime(date); + + tmp = tmp.mid(11); + + // Recognize UTC specifications + if (tmp.endsWith(QLatin1Char('Z'))) { + ts = Qt::UTC; + tmp.chop(1); + } + + // Recognize timezone specifications + QRegExp rx(QLatin1String("[+-]")); + if (tmp.contains(rx)) { + int idx = tmp.indexOf(rx); + QString tmp2 = tmp.mid(idx); + tmp = tmp.left(idx); + bool ok = true; + int ntzhour = 1; + int ntzminute = 3; + if ( tmp2.indexOf(QLatin1Char(':')) == 3 ) + ntzminute = 4; + const int tzhour(tmp2.mid(ntzhour, 2).toInt(&ok)); + const int tzminute(tmp2.mid(ntzminute, 2).toInt(&ok)); + QTime tzt(tzhour, tzminute); + int utcOffset = (tzt.hour() * 60 + tzt.minute()) * 60; + if ( utcOffset != 0 ) { + ts = Qt::OffsetFromUTC; + QDateTime dt(date, QTime::fromString(tmp, Qt::ISODate), ts); + dt.setUtcOffset( utcOffset * (tmp2.startsWith(QLatin1Char('-')) ? -1 : 1) ); + return dt; + } + } + return QDateTime(date, QTime::fromString(tmp, Qt::ISODate), ts); + } + case Qt::SystemLocaleDate: + case Qt::SystemLocaleShortDate: + case Qt::SystemLocaleLongDate: + return fromString(s, QLocale::system().dateTimeFormat(f == Qt::SystemLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat)); + case Qt::LocaleDate: + case Qt::DefaultLocaleShortDate: + case Qt::DefaultLocaleLongDate: + return fromString(s, QLocale().dateTimeFormat(f == Qt::DefaultLocaleLongDate ? QLocale::LongFormat + : QLocale::ShortFormat)); +#if !defined(QT_NO_TEXTDATE) + case Qt::TextDate: { + QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts); + + if ((parts.count() < 5) || (parts.count() > 6)) { + return QDateTime(); + } + + // Accept "Sun Dec 1 13:02:00 1974" and "Sun 1. Dec 13:02:00 1974" + int month = -1, day = -1; + bool ok; + + month = fromShortMonthName(parts.at(1)); + if (month != -1) { + day = parts.at(2).toInt(&ok); + if (!ok) + day = -1; + } + + if (month == -1 || day == -1) { + // first variant failed, lets try the other + month = fromShortMonthName(parts.at(2)); + if (month != -1) { + QString dayStr = parts.at(1); + if (dayStr.endsWith(QLatin1Char('.'))) { + dayStr.chop(1); + day = dayStr.toInt(&ok); + if (!ok) + day = -1; + } else { + day = -1; + } + } + } + + if (month == -1 || day == -1) { + // both variants failed, give up + return QDateTime(); + } + + int year; + QStringList timeParts = parts.at(3).split(QLatin1Char(':')); + if ((timeParts.count() == 3) || (timeParts.count() == 2)) { + year = parts.at(4).toInt(&ok); + if (!ok) + return QDateTime(); + } else { + timeParts = parts.at(4).split(QLatin1Char(':')); + if ((timeParts.count() != 3) && (timeParts.count() != 2)) + return QDateTime(); + year = parts.at(3).toInt(&ok); + if (!ok) + return QDateTime(); + } + + int hour = timeParts.at(0).toInt(&ok); + if (!ok) { + return QDateTime(); + } + + int minute = timeParts.at(1).toInt(&ok); + if (!ok) { + return QDateTime(); + } + + int second = (timeParts.count() > 2) ? timeParts.at(2).toInt(&ok) : 0; + if (!ok) { + return QDateTime(); + } + + QDate date(year, month, day); + QTime time(hour, minute, second); + + if (parts.count() == 5) + return QDateTime(date, time, Qt::LocalTime); + + QString tz = parts.at(5); + if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive)) + return QDateTime(); + QDateTime dt(date, time, Qt::UTC); + if (tz.length() > 3) { + int tzoffset = 0; + QChar sign = tz.at(3); + if ((sign != QLatin1Char('+')) + && (sign != QLatin1Char('-'))) { + return QDateTime(); + } + int tzhour = tz.mid(4, 2).toInt(&ok); + if (!ok) + return QDateTime(); + int tzminute = tz.mid(6).toInt(&ok); + if (!ok) + return QDateTime(); + tzoffset = (tzhour*60 + tzminute) * 60; + if (sign == QLatin1Char('-')) + tzoffset = -tzoffset; + dt.setUtcOffset(tzoffset); + } + return dt.toLocalTime(); + } +#endif //QT_NO_TEXTDATE + } + + return QDateTime(); +} + +/*! + \fn QDateTime::fromString(const QString &string, const QString &format) + + Returns the QDateTime represented by the \a string, using the \a + format given, or an invalid datetime if the string cannot be parsed. + + These expressions may be used for the date part of the format string: + + \table + \header \i Expression \i Output + \row \i d \i the day as number without a leading zero (1 to 31) + \row \i dd \i the day as number with a leading zero (01 to 31) + \row \i ddd + \i the abbreviated localized day name (e.g. 'Mon' to 'Sun'). + Uses QDate::shortDayName(). + \row \i dddd + \i the long localized day name (e.g. 'Monday' to 'Sunday'). + Uses QDate::longDayName(). + \row \i M \i the month as number without a leading zero (1-12) + \row \i MM \i the month as number with a leading zero (01-12) + \row \i MMM + \i the abbreviated localized month name (e.g. 'Jan' to 'Dec'). + Uses QDate::shortMonthName(). + \row \i MMMM + \i the long localized month name (e.g. 'January' to 'December'). + Uses QDate::longMonthName(). + \row \i yy \i the year as two digit number (00-99) + \row \i yyyy \i the year as four digit number + \endtable + + \note Unlike the other version of this function, day and month names must + be given in the user's local language. It is only possible to use the English + names if the user's language is English. + + These expressions may be used for the time part of the format string: + + \table + \header \i Expression \i Output + \row \i h + \i the hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display) + \row \i hh + \i the hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display) + \row \i H + \i the hour without a leading zero (0 to 23, even with AM/PM display) + \row \i HH + \i the hour with a leading zero (00 to 23, even with AM/PM display) + \row \i m \i the minute without a leading zero (0 to 59) + \row \i mm \i the minute with a leading zero (00 to 59) + \row \i s \i the second without a leading zero (0 to 59) + \row \i ss \i the second with a leading zero (00 to 59) + \row \i z \i the milliseconds without leading zeroes (0 to 999) + \row \i zzz \i the milliseconds with leading zeroes (000 to 999) + \row \i AP or A + \i interpret as an AM/PM time. \e AP must be either "AM" or "PM". + \row \i ap or a + \i Interpret as an AM/PM time. \e ap must be either "am" or "pm". + \endtable + + All other input characters will be treated as text. Any sequence + of characters that are enclosed in singlequotes will also be + treated as text and not be used as an expression. + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 12 + + If the format is not satisfied an invalid QDateTime is returned. + The expressions that don't have leading zeroes (d, M, h, m, s, z) will be + greedy. This means that they will use two digits even if this will + put them outside the range and/or leave too few digits for other + sections. + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 13 + + This could have meant 1 January 00:30.00 but the M will grab + two digits. + + For any field that is not represented in the format the following + defaults are used: + + \table + \header \i Field \i Default value + \row \i Year \i 1900 + \row \i Month \i 1 (January) + \row \i Day \i 1 + \row \i Hour \i 0 + \row \i Minute \i 0 + \row \i Second \i 0 + \endtable + + For example: + + \snippet doc/src/snippets/code/src_corelib_tools_qdatetime.cpp 14 + + \sa QDate::fromString() QTime::fromString() QDate::toString() + QDateTime::toString() QTime::toString() +*/ + +QDateTime QDateTime::fromString(const QString &string, const QString &format) +{ +#ifndef QT_BOOTSTRAPPED + QTime time; + QDate date; + + QDateTimeParser dt(QVariant::DateTime, QDateTimeParser::FromString); + if (dt.parseFormat(format) && dt.fromString(string, &date, &time)) + return QDateTime(date, time); +#else + Q_UNUSED(string); + Q_UNUSED(format); +#endif + return QDateTime(QDate(), QTime(-1, -1, -1)); +} + +#endif // QT_NO_DATESTRING +/*! + \fn QDateTime QDateTime::toLocalTime() const + + Returns a datetime containing the date and time information in + this datetime, but specified using the Qt::LocalTime definition. + + \sa toTimeSpec() +*/ + +/*! + \fn QDateTime QDateTime::toUTC() const + + Returns a datetime containing the date and time information in + this datetime, but specified using the Qt::UTC definition. + + \sa toTimeSpec() +*/ + +/*! \internal + */ +void QDateTime::detach() +{ + d.detach(); +} + +/***************************************************************************** + Date/time stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +/*! + \relates QDate + + Writes the \a date to stream \a out. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator<<(QDataStream &out, const QDate &date) +{ + return out << (quint32)(date.jd); +} + +/*! + \relates QDate + + Reads a date from stream \a in into the \a date. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator>>(QDataStream &in, QDate &date) +{ + quint32 jd; + in >> jd; + date.jd = jd; + return in; +} + +/*! + \relates QTime + + Writes \a time to stream \a out. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator<<(QDataStream &out, const QTime &time) +{ + return out << quint32(time.mds); +} + +/*! + \relates QTime + + Reads a time from stream \a in into the given \a time. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator>>(QDataStream &in, QTime &time) +{ + quint32 ds; + in >> ds; + time.mds = int(ds); + return in; +} + +/*! + \relates QDateTime + + Writes \a dateTime to the \a out stream. + + \sa {Serializing Qt Data Types} +*/ +QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime) +{ + out << dateTime.d->date << dateTime.d->time; + if (out.version() >= 7) + out << (qint8)dateTime.d->spec; + return out; +} + +/*! + \relates QDateTime + + Reads a datetime from the stream \a in into \a dateTime. + + \sa {Serializing Qt Data Types} +*/ + +QDataStream &operator>>(QDataStream &in, QDateTime &dateTime) +{ + dateTime.detach(); + + qint8 ts = (qint8)QDateTimePrivate::LocalUnknown; + in >> dateTime.d->date >> dateTime.d->time; + if (in.version() >= 7) + in >> ts; + dateTime.d->spec = (QDateTimePrivate::Spec)ts; + return in; +} +#endif // QT_NO_DATASTREAM + + +/*! + \fn QString QDate::monthName(int month) + + Use shortMonthName() instead. +*/ + +/*! + \fn QString QDate::dayName(int weekday) + + Use shortDayName() instead. +*/ + +/*! + \fn bool QDate::leapYear(int year) + + Use isLeapYear() instead. +*/ + +/*! + \fn QDate QDate::currentDate(Qt::TimeSpec spec) + + If \a spec is Qt::LocalTime, use the currentDate() overload that + takes no parameters instead; otherwise, use + QDateTime::currentDateTime(). + + \oldcode + QDate localDate = QDate::currentDate(Qt::LocalTime); + QDate utcDate = QDate::currentDate(Qt::UTC); + \newcode + QDate localDate = QDate::currentDate(); + QDate utcDate = QDateTime::currentDateTime().toUTC().date(); + \endcode + + \sa QDateTime::toUTC() +*/ + +/*! + \fn QTime QTime::currentTime(Qt::TimeSpec specification) + + Returns the current time for the given \a specification. + + To replace uses of this function where the \a specification is Qt::LocalTime, + use the currentDate() overload that takes no parameters instead; otherwise, + use QDateTime::currentDateTime() and convert the result to a UTC measurement. + + \oldcode + QTime localTime = QTime::currentTime(Qt::LocalTime); + QTime utcTime = QTime::currentTime(Qt::UTC); + \newcode + QTime localTime = QTime::currentTime(); + QTime utcTime = QTimeTime::currentDateTime().toUTC().time(); + \endcode + + \sa QDateTime::toUTC() +*/ + +/*! + \fn void QDateTime::setTime_t(uint secsSince1Jan1970UTC, Qt::TimeSpec spec) + + Use the single-argument overload of setTime_t() instead. +*/ + +/*! + \fn QDateTime QDateTime::currentDateTime(Qt::TimeSpec spec) + + Use the currentDateTime() overload that takes no parameters + instead. +*/ + +// checks if there is an unqoted 'AP' or 'ap' in the string +static bool hasUnquotedAP(const QString &f) +{ + const QLatin1Char quote('\''); + bool inquote = false; + const int max = f.size(); + for (int i=0; i<max; ++i) { + if (f.at(i) == quote) { + inquote = !inquote; + } else if (!inquote && f.at(i).toUpper() == QLatin1Char('A')) { + return true; + } + } + return false; +} + +#ifndef QT_NO_DATESTRING +/***************************************************************************** + Some static function used by QDate, QTime and QDateTime +*****************************************************************************/ + +// Replaces tokens by their value. See QDateTime::toString() for a list of valid tokens +static QString getFmtString(const QString& f, const QTime* dt = 0, const QDate* dd = 0, bool am_pm = false) +{ + if (f.isEmpty()) + return QString(); + + QString buf = f; + int removed = 0; + + if (dt) { + if (f.startsWith(QLatin1String("hh")) || f.startsWith(QLatin1String("HH"))) { + const bool hour12 = f.at(0) == QLatin1Char('h') && am_pm; + if (hour12 && dt->hour() > 12) + buf = QString::number(dt->hour() - 12).rightJustified(2, QLatin1Char('0'), true); + else if (hour12 && dt->hour() == 0) + buf = QLatin1String("12"); + else + buf = QString::number(dt->hour()).rightJustified(2, QLatin1Char('0'), true); + removed = 2; + } else if (f.at(0) == QLatin1Char('h') || f.at(0) == QLatin1Char('H')) { + const bool hour12 = f.at(0) == QLatin1Char('h') && am_pm; + if (hour12 && dt->hour() > 12) + buf = QString::number(dt->hour() - 12); + else if (hour12 && dt->hour() == 0) + buf = QLatin1String("12"); + else + buf = QString::number(dt->hour()); + removed = 1; + } else if (f.startsWith(QLatin1String("mm"))) { + buf = QString::number(dt->minute()).rightJustified(2, QLatin1Char('0'), true); + removed = 2; + } else if (f.at(0) == (QLatin1Char('m'))) { + buf = QString::number(dt->minute()); + removed = 1; + } else if (f.startsWith(QLatin1String("ss"))) { + buf = QString::number(dt->second()).rightJustified(2, QLatin1Char('0'), true); + removed = 2; + } else if (f.at(0) == QLatin1Char('s')) { + buf = QString::number(dt->second()); + } else if (f.startsWith(QLatin1String("zzz"))) { + buf = QString::number(dt->msec()).rightJustified(3, QLatin1Char('0'), true); + removed = 3; + } else if (f.at(0) == QLatin1Char('z')) { + buf = QString::number(dt->msec()); + removed = 1; + } else if (f.at(0).toUpper() == QLatin1Char('A')) { + const bool upper = f.at(0) == QLatin1Char('A'); + buf = dt->hour() < 12 ? QLatin1String("am") : QLatin1String("pm"); + if (upper) + buf = buf.toUpper(); + if (f.size() > 1 && f.at(1).toUpper() == QLatin1Char('P') && + f.at(0).isUpper() == f.at(1).isUpper()) { + removed = 2; + } else { + removed = 1; + } + } + } + + if (dd) { + if (f.startsWith(QLatin1String("dddd"))) { + buf = dd->longDayName(dd->dayOfWeek()); + removed = 4; + } else if (f.startsWith(QLatin1String("ddd"))) { + buf = dd->shortDayName(dd->dayOfWeek()); + removed = 3; + } else if (f.startsWith(QLatin1String("dd"))) { + buf = QString::number(dd->day()).rightJustified(2, QLatin1Char('0'), true); + removed = 2; + } else if (f.at(0) == QLatin1Char('d')) { + buf = QString::number(dd->day()); + removed = 1; + } else if (f.startsWith(QLatin1String("MMMM"))) { + buf = dd->longMonthName(dd->month()); + removed = 4; + } else if (f.startsWith(QLatin1String("MMM"))) { + buf = dd->shortMonthName(dd->month()); + removed = 3; + } else if (f.startsWith(QLatin1String("MM"))) { + buf = QString::number(dd->month()).rightJustified(2, QLatin1Char('0'), true); + removed = 2; + } else if (f.at(0) == QLatin1Char('M')) { + buf = QString::number(dd->month()); + removed = 1; + } else if (f.startsWith(QLatin1String("yyyy"))) { + const int year = dd->year(); + buf = QString::number(qAbs(year)).rightJustified(4, QLatin1Char('0')); + if(year > 0) + removed = 4; + else + { + buf.prepend(QLatin1Char('-')); + removed = 5; + } + + } else if (f.startsWith(QLatin1String("yy"))) { + buf = QString::number(dd->year()).right(2).rightJustified(2, QLatin1Char('0')); + removed = 2; + } + } + if (removed == 0 || removed >= f.size()) { + return buf; + } + + return buf + getFmtString(f.mid(removed), dt, dd, am_pm); +} + +// Parses the format string and uses getFmtString to get the values for the tokens. Ret +static QString fmtDateTime(const QString& f, const QTime* dt, const QDate* dd) +{ + const QLatin1Char quote('\''); + if (f.isEmpty()) + return QString(); + if (dt && !dt->isValid()) + return QString(); + if (dd && !dd->isValid()) + return QString(); + + const bool ap = hasUnquotedAP(f); + + QString buf; + QString frm; + QChar status(QLatin1Char('0')); + + for (int i = 0; i < (int)f.length(); ++i) { + if (f.at(i) == quote) { + if (status == quote) { + if (i > 0 && f.at(i - 1) == quote) + buf += QLatin1Char('\''); + status = QLatin1Char('0'); + } else { + if (!frm.isEmpty()) { + buf += getFmtString(frm, dt, dd, ap); + frm.clear(); + } + status = quote; + } + } else if (status == quote) { + buf += f.at(i); + } else if (f.at(i) == status) { + if ((ap) && ((f.at(i) == QLatin1Char('P')) || (f.at(i) == QLatin1Char('p')))) + status = QLatin1Char('0'); + frm += f.at(i); + } else { + buf += getFmtString(frm, dt, dd, ap); + frm.clear(); + if ((f.at(i) == QLatin1Char('h')) || (f.at(i) == QLatin1Char('m')) + || (f.at(i) == QLatin1Char('H')) + || (f.at(i) == QLatin1Char('s')) || (f.at(i) == QLatin1Char('z'))) { + status = f.at(i); + frm += f.at(i); + } else if ((f.at(i) == QLatin1Char('d')) || (f.at(i) == QLatin1Char('M')) || (f.at(i) == QLatin1Char('y'))) { + status = f.at(i); + frm += f.at(i); + } else if ((ap) && (f.at(i) == QLatin1Char('A'))) { + status = QLatin1Char('P'); + frm += f.at(i); + } else if((ap) && (f.at(i) == QLatin1Char('a'))) { + status = QLatin1Char('p'); + frm += f.at(i); + } else { + buf += f.at(i); + status = QLatin1Char('0'); + } + } + } + + buf += getFmtString(frm, dt, dd, ap); + + return buf; +} +#endif // QT_NO_DATESTRING + +#ifdef Q_OS_WIN +static const int LowerYear = 1980; +#else +static const int LowerYear = 1970; +#endif +static const int UpperYear = 2037; + +static QDate adjustDate(QDate date) +{ + QDate lowerLimit(LowerYear, 1, 2); + QDate upperLimit(UpperYear, 12, 30); + + if (date > lowerLimit && date < upperLimit) + return date; + + int month = date.month(); + int day = date.day(); + + // neither 1970 nor 2037 are leap years, so make sure date isn't Feb 29 + if (month == 2 && day == 29) + --day; + + if (date < lowerLimit) + date.setDate(LowerYear, month, day); + else + date.setDate(UpperYear, month, day); + + return date; +} + +static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time) +{ + QDate fakeDate = adjustDate(date); + + // won't overflow because of fakeDate + time_t secsSince1Jan1970UTC = toMSecsSinceEpoch_helper(fakeDate.toJulianDay(), QTime().msecsTo(time)) / 1000; + tm *brokenDown = 0; + +#if defined(Q_OS_WINCE) + tm res; + FILETIME utcTime = time_tToFt(secsSince1Jan1970UTC); + FILETIME resultTime; + FileTimeToLocalFileTime(&utcTime , &resultTime); + SYSTEMTIME sysTime; + FileTimeToSystemTime(&resultTime , &sysTime); + + res.tm_sec = sysTime.wSecond; + res.tm_min = sysTime.wMinute; + res.tm_hour = sysTime.wHour; + res.tm_mday = sysTime.wDay; + res.tm_mon = sysTime.wMonth - 1; + res.tm_year = sysTime.wYear - 1900; + brokenDown = &res; +#elif defined(Q_OS_SYMBIAN) + // months and days are zero index based + _LIT(KUnixEpoch, "19700000:000000.000000"); + TTimeIntervalSeconds utcOffset = User::UTCOffset(); + TTimeIntervalSeconds tTimeIntervalSecsSince1Jan1970UTC(secsSince1Jan1970UTC); + TTime epochTTime; + TInt err = epochTTime.Set(KUnixEpoch); + tm res; + if(err == KErrNone) { + TTime utcTTime = epochTTime + tTimeIntervalSecsSince1Jan1970UTC; + utcTTime = utcTTime + utcOffset; + TDateTime utcDateTime = utcTTime.DateTime(); + res.tm_sec = utcDateTime.Second(); + res.tm_min = utcDateTime.Minute(); + res.tm_hour = utcDateTime.Hour(); + res.tm_mday = utcDateTime.Day() + 1; // non-zero based index for tm struct + res.tm_mon = utcDateTime.Month(); + res.tm_year = utcDateTime.Year() - 1900; + res.tm_isdst = 0; + brokenDown = &res; + } +#elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant version of localtime() where available + tzset(); + tm res; + brokenDown = localtime_r(&secsSince1Jan1970UTC, &res); +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + tm res; + if (!_localtime64_s(&res, &secsSince1Jan1970UTC)) + brokenDown = &res; +#else + brokenDown = localtime(&secsSince1Jan1970UTC); +#endif + if (!brokenDown) { + date = QDate(1970, 1, 1); + time = QTime(); + return QDateTimePrivate::LocalUnknown; + } else { + int deltaDays = fakeDate.daysTo(date); + date = QDate(brokenDown->tm_year + 1900, brokenDown->tm_mon + 1, brokenDown->tm_mday); + time = QTime(brokenDown->tm_hour, brokenDown->tm_min, brokenDown->tm_sec, time.msec()); + date = date.addDays(deltaDays); + if (brokenDown->tm_isdst > 0) + return QDateTimePrivate::LocalDST; + else if (brokenDown->tm_isdst < 0) + return QDateTimePrivate::LocalUnknown; + else + return QDateTimePrivate::LocalStandard; + } +} + +static void localToUtc(QDate &date, QTime &time, int isdst) +{ + if (!date.isValid()) + return; + + QDate fakeDate = adjustDate(date); + + tm localTM; + localTM.tm_sec = time.second(); + localTM.tm_min = time.minute(); + localTM.tm_hour = time.hour(); + localTM.tm_mday = fakeDate.day(); + localTM.tm_mon = fakeDate.month() - 1; + localTM.tm_year = fakeDate.year() - 1900; + localTM.tm_isdst = (int)isdst; +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + time_t secsSince1Jan1970UTC = (toMSecsSinceEpoch_helper(fakeDate.toJulianDay(), QTime().msecsTo(time)) / 1000); +#else +#if defined(Q_OS_WIN) + _tzset(); +#endif + time_t secsSince1Jan1970UTC = mktime(&localTM); +#endif + tm *brokenDown = 0; +#if defined(Q_OS_WINCE) + tm res; + FILETIME localTime = time_tToFt(secsSince1Jan1970UTC); + SYSTEMTIME sysTime; + FileTimeToSystemTime(&localTime, &sysTime); + FILETIME resultTime; + LocalFileTimeToFileTime(&localTime , &resultTime); + FileTimeToSystemTime(&resultTime , &sysTime); + res.tm_sec = sysTime.wSecond; + res.tm_min = sysTime.wMinute; + res.tm_hour = sysTime.wHour; + res.tm_mday = sysTime.wDay; + res.tm_mon = sysTime.wMonth - 1; + res.tm_year = sysTime.wYear - 1900; + res.tm_isdst = (int)isdst; + brokenDown = &res; +#elif defined(Q_OS_SYMBIAN) + // months and days are zero index based + _LIT(KUnixEpoch, "19700000:000000.000000"); + TTimeIntervalSeconds utcOffset = TTimeIntervalSeconds(0 - User::UTCOffset().Int()); + TTimeIntervalSeconds tTimeIntervalSecsSince1Jan1970UTC(secsSince1Jan1970UTC); + TTime epochTTime; + TInt err = epochTTime.Set(KUnixEpoch); + tm res; + if(err == KErrNone) { + TTime utcTTime = epochTTime + tTimeIntervalSecsSince1Jan1970UTC; + utcTTime = utcTTime + utcOffset; + TDateTime utcDateTime = utcTTime.DateTime(); + res.tm_sec = utcDateTime.Second(); + res.tm_min = utcDateTime.Minute(); + res.tm_hour = utcDateTime.Hour(); + res.tm_mday = utcDateTime.Day() + 1; // non-zero based index for tm struct + res.tm_mon = utcDateTime.Month(); + res.tm_year = utcDateTime.Year() - 1900; + res.tm_isdst = (int)isdst; + brokenDown = &res; + } +#elif !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + // use the reentrant version of gmtime() where available + tm res; + brokenDown = gmtime_r(&secsSince1Jan1970UTC, &res); +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + tm res; + if (!_gmtime64_s(&res, &secsSince1Jan1970UTC)) + brokenDown = &res; +#else + brokenDown = gmtime(&secsSince1Jan1970UTC); +#endif // !QT_NO_THREAD && _POSIX_THREAD_SAFE_FUNCTIONS + if (!brokenDown) { + date = QDate(1970, 1, 1); + time = QTime(); + } else { + int deltaDays = fakeDate.daysTo(date); + date = QDate(brokenDown->tm_year + 1900, brokenDown->tm_mon + 1, brokenDown->tm_mday); + time = QTime(brokenDown->tm_hour, brokenDown->tm_min, brokenDown->tm_sec, time.msec()); + date = date.addDays(deltaDays); + } +} + +QDateTimePrivate::Spec QDateTimePrivate::getLocal(QDate &outDate, QTime &outTime) const +{ + outDate = date; + outTime = time; + if (spec == QDateTimePrivate::UTC) + return utcToLocal(outDate, outTime); + return spec; +} + +void QDateTimePrivate::getUTC(QDate &outDate, QTime &outTime) const +{ + outDate = date; + outTime = time; + const bool isOffset = spec == QDateTimePrivate::OffsetFromUTC; + + if (spec != QDateTimePrivate::UTC && !isOffset) + localToUtc(outDate, outTime, (int)spec); + + if (isOffset) + addMSecs(outDate, outTime, -(qint64(utcOffset) * 1000)); +} + +#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING) +QDebug operator<<(QDebug dbg, const QDate &date) +{ + dbg.nospace() << "QDate(" << date.toString() << ')'; + return dbg.space(); +} + +QDebug operator<<(QDebug dbg, const QTime &time) +{ + dbg.nospace() << "QTime(" << time.toString() << ')'; + return dbg.space(); +} + +QDebug operator<<(QDebug dbg, const QDateTime &date) +{ + dbg.nospace() << "QDateTime(" << date.toString() << ')'; + return dbg.space(); +} +#endif + +#ifndef QT_BOOTSTRAPPED + +/*! + \internal + Gets the digit from a datetime. E.g. + + QDateTime var(QDate(2004, 02, 02)); + int digit = getDigit(var, Year); + // digit = 2004 +*/ + +int QDateTimeParser::getDigit(const QDateTime &t, int index) const +{ + if (index < 0 || index >= sectionNodes.size()) { +#ifndef QT_NO_DATESTRING + qWarning("QDateTimeParser::getDigit() Internal error (%s %d)", + qPrintable(t.toString()), index); +#else + qWarning("QDateTimeParser::getDigit() Internal error (%d)", index); +#endif + return -1; + } + const SectionNode &node = sectionNodes.at(index); + switch (node.type) { + case Hour24Section: case Hour12Section: return t.time().hour(); + case MinuteSection: return t.time().minute(); + case SecondSection: return t.time().second(); + case MSecSection: return t.time().msec(); + case YearSection2Digits: + case YearSection: return t.date().year(); + case MonthSection: return t.date().month(); + case DaySection: return t.date().day(); + case DayOfWeekSection: return t.date().day(); + case AmPmSection: return t.time().hour() > 11 ? 1 : 0; + + default: break; + } + +#ifndef QT_NO_DATESTRING + qWarning("QDateTimeParser::getDigit() Internal error 2 (%s %d)", + qPrintable(t.toString()), index); +#else + qWarning("QDateTimeParser::getDigit() Internal error 2 (%d)", index); +#endif + return -1; +} + +/*! + \internal + Sets a digit in a datetime. E.g. + + QDateTime var(QDate(2004, 02, 02)); + int digit = getDigit(var, Year); + // digit = 2004 + setDigit(&var, Year, 2005); + digit = getDigit(var, Year); + // digit = 2005 +*/ + +bool QDateTimeParser::setDigit(QDateTime &v, int index, int newVal) const +{ + if (index < 0 || index >= sectionNodes.size()) { +#ifndef QT_NO_DATESTRING + qWarning("QDateTimeParser::setDigit() Internal error (%s %d %d)", + qPrintable(v.toString()), index, newVal); +#else + qWarning("QDateTimeParser::setDigit() Internal error (%d %d)", index, newVal); +#endif + return false; + } + const SectionNode &node = sectionNodes.at(index); + + int year, month, day, hour, minute, second, msec; + year = v.date().year(); + month = v.date().month(); + day = v.date().day(); + hour = v.time().hour(); + minute = v.time().minute(); + second = v.time().second(); + msec = v.time().msec(); + + switch (node.type) { + case Hour24Section: case Hour12Section: hour = newVal; break; + case MinuteSection: minute = newVal; break; + case SecondSection: second = newVal; break; + case MSecSection: msec = newVal; break; + case YearSection2Digits: + case YearSection: year = newVal; break; + case MonthSection: month = newVal; break; + case DaySection: + case DayOfWeekSection: + if (newVal > 31) { + // have to keep legacy behavior. setting the + // date to 32 should return false. Setting it + // to 31 for february should return true + return false; + } + day = newVal; + break; + case AmPmSection: hour = (newVal == 0 ? hour % 12 : (hour % 12) + 12); break; + default: + qWarning("QDateTimeParser::setDigit() Internal error (%s)", + qPrintable(sectionName(node.type))); + break; + } + + if (!(node.type & (DaySection|DayOfWeekSection))) { + if (day < cachedDay) + day = cachedDay; + const int max = QDate(year, month, 1).daysInMonth(); + if (day > max) { + day = max; + } + } + if (QDate::isValid(year, month, day) && QTime::isValid(hour, minute, second, msec)) { + v = QDateTime(QDate(year, month, day), QTime(hour, minute, second, msec), spec); + return true; + } + return false; +} + + + +/*! + \ + + Returns the absolute maximum for a section +*/ + +int QDateTimeParser::absoluteMax(int s, const QDateTime &cur) const +{ + const SectionNode &sn = sectionNode(s); + switch (sn.type) { + case Hour24Section: + case Hour12Section: return 23; // this is special-cased in + // parseSection. We want it to be + // 23 for the stepBy case. + case MinuteSection: + case SecondSection: return 59; + case MSecSection: return 999; + case YearSection2Digits: + case YearSection: return 9999; // sectionMaxSize will prevent + // people from typing in a larger + // number in count == 2 sections. + // stepBy() will work on real years anyway + case MonthSection: return 12; + case DaySection: + case DayOfWeekSection: return cur.isValid() ? cur.date().daysInMonth() : 31; + case AmPmSection: return 1; + default: break; + } + qWarning("QDateTimeParser::absoluteMax() Internal error (%s)", + qPrintable(sectionName(sn.type))); + return -1; +} + +/*! + \internal + + Returns the absolute minimum for a section +*/ + +int QDateTimeParser::absoluteMin(int s) const +{ + const SectionNode &sn = sectionNode(s); + switch (sn.type) { + case Hour24Section: + case Hour12Section: + case MinuteSection: + case SecondSection: + case MSecSection: + case YearSection2Digits: + case YearSection: return 0; + case MonthSection: + case DaySection: + case DayOfWeekSection: return 1; + case AmPmSection: return 0; + default: break; + } + qWarning("QDateTimeParser::absoluteMin() Internal error (%s, %0x)", + qPrintable(sectionName(sn.type)), sn.type); + return -1; +} + +/*! + \internal + + Returns the sectionNode for the Section \a s. +*/ + +const QDateTimeParser::SectionNode &QDateTimeParser::sectionNode(int sectionIndex) const +{ + if (sectionIndex < 0) { + switch (sectionIndex) { + case FirstSectionIndex: + return first; + case LastSectionIndex: + return last; + case NoSectionIndex: + return none; + } + } else if (sectionIndex < sectionNodes.size()) { + return sectionNodes.at(sectionIndex); + } + + qWarning("QDateTimeParser::sectionNode() Internal error (%d)", + sectionIndex); + return none; +} + +QDateTimeParser::Section QDateTimeParser::sectionType(int sectionIndex) const +{ + return sectionNode(sectionIndex).type; +} + + +/*! + \internal + + Returns the starting position for section \a s. +*/ + +int QDateTimeParser::sectionPos(int sectionIndex) const +{ + return sectionPos(sectionNode(sectionIndex)); +} + +int QDateTimeParser::sectionPos(const SectionNode &sn) const +{ + switch (sn.type) { + case FirstSection: return 0; + case LastSection: return displayText().size() - 1; + default: break; + } + if (sn.pos == -1) { + qWarning("QDateTimeParser::sectionPos Internal error (%s)", qPrintable(sectionName(sn.type))); + return -1; + } + return sn.pos; +} + + +/*! + \internal helper function for parseFormat. removes quotes that are + not escaped and removes the escaping on those that are escaped + +*/ + +static QString unquote(const QString &str) +{ + const QChar quote(QLatin1Char('\'')); + const QChar slash(QLatin1Char('\\')); + const QChar zero(QLatin1Char('0')); + QString ret; + QChar status(zero); + const int max = str.size(); + for (int i=0; i<max; ++i) { + if (str.at(i) == quote) { + if (status != quote) { + status = quote; + } else if (!ret.isEmpty() && str.at(i - 1) == slash) { + ret[ret.size() - 1] = quote; + } else { + status = zero; + } + } else { + ret += str.at(i); + } + } + return ret; +} +/*! + \internal + + Parses the format \a newFormat. If successful, returns true and + sets up the format. Else keeps the old format and returns false. + +*/ + +static inline int countRepeat(const QString &str, int index, int maxCount) +{ + int count = 1; + const QChar ch(str.at(index)); + const int max = qMin(index + maxCount, str.size()); + while (index + count < max && str.at(index + count) == ch) { + ++count; + } + return count; +} + +static inline void appendSeparator(QStringList *list, const QString &string, int from, int size, int lastQuote) +{ + QString str(string.mid(from, size)); + if (lastQuote >= from) + str = unquote(str); + list->append(str); +} + + +bool QDateTimeParser::parseFormat(const QString &newFormat) +{ + const QLatin1Char quote('\''); + const QLatin1Char slash('\\'); + const QLatin1Char zero('0'); + if (newFormat == displayFormat && !newFormat.isEmpty()) { + return true; + } + + QDTPDEBUGN("parseFormat: %s", newFormat.toLatin1().constData()); + + QVector<SectionNode> newSectionNodes; + Sections newDisplay = 0; + QStringList newSeparators; + int i, index = 0; + int add = 0; + QChar status(zero); + const int max = newFormat.size(); + int lastQuote = -1; + for (i = 0; i<max; ++i) { + if (newFormat.at(i) == quote) { + lastQuote = i; + ++add; + if (status != quote) { + status = quote; + } else if (newFormat.at(i - 1) != slash) { + status = zero; + } + } else if (status != quote) { + const char sect = newFormat.at(i).toLatin1(); + switch (sect) { + case 'H': + case 'h': + if (parserType != QVariant::Date) { + const Section hour = (sect == 'h') ? Hour12Section : Hour24Section; + const SectionNode sn = { hour, i - add, countRepeat(newFormat, i, 2) }; + newSectionNodes.append(sn); + appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); + i += sn.count - 1; + index = i + 1; + newDisplay |= hour; + } + break; + case 'm': + if (parserType != QVariant::Date) { + const SectionNode sn = { MinuteSection, i - add, countRepeat(newFormat, i, 2) }; + newSectionNodes.append(sn); + appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); + i += sn.count - 1; + index = i + 1; + newDisplay |= MinuteSection; + } + break; + case 's': + if (parserType != QVariant::Date) { + const SectionNode sn = { SecondSection, i - add, countRepeat(newFormat, i, 2) }; + newSectionNodes.append(sn); + appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); + i += sn.count - 1; + index = i + 1; + newDisplay |= SecondSection; + } + break; + + case 'z': + if (parserType != QVariant::Date) { + const SectionNode sn = { MSecSection, i - add, countRepeat(newFormat, i, 3) < 3 ? 1 : 3 }; + newSectionNodes.append(sn); + appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); + i += sn.count - 1; + index = i + 1; + newDisplay |= MSecSection; + } + break; + case 'A': + case 'a': + if (parserType != QVariant::Date) { + const bool cap = (sect == 'A'); + const SectionNode sn = { AmPmSection, i - add, (cap ? 1 : 0) }; + newSectionNodes.append(sn); + appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); + newDisplay |= AmPmSection; + if (i + 1 < newFormat.size() + && newFormat.at(i+1) == (cap ? QLatin1Char('P') : QLatin1Char('p'))) { + ++i; + } + index = i + 1; + } + break; + case 'y': + if (parserType != QVariant::Time) { + const int repeat = countRepeat(newFormat, i, 4); + if (repeat >= 2) { + const SectionNode sn = { repeat == 4 ? YearSection : YearSection2Digits, + i - add, repeat == 4 ? 4 : 2 }; + newSectionNodes.append(sn); + appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); + i += sn.count - 1; + index = i + 1; + newDisplay |= sn.type; + } + } + break; + case 'M': + if (parserType != QVariant::Time) { + const SectionNode sn = { MonthSection, i - add, countRepeat(newFormat, i, 4) }; + newSectionNodes.append(sn); + newSeparators.append(unquote(newFormat.mid(index, i - index))); + i += sn.count - 1; + index = i + 1; + newDisplay |= MonthSection; + } + break; + case 'd': + if (parserType != QVariant::Time) { + const int repeat = countRepeat(newFormat, i, 4); + const SectionNode sn = { repeat >= 3 ? DayOfWeekSection : DaySection, i - add, repeat }; + newSectionNodes.append(sn); + appendSeparator(&newSeparators, newFormat, index, i - index, lastQuote); + i += sn.count - 1; + index = i + 1; + newDisplay |= sn.type; + } + break; + + default: + break; + } + } + } + if (newSectionNodes.isEmpty() && context == DateTimeEdit) { + return false; + } + + if ((newDisplay & (AmPmSection|Hour12Section)) == Hour12Section) { + const int max = newSectionNodes.size(); + for (int i=0; i<max; ++i) { + SectionNode &node = newSectionNodes[i]; + if (node.type == Hour12Section) + node.type = Hour24Section; + } + } + + if (index < newFormat.size()) { + appendSeparator(&newSeparators, newFormat, index, index - max, lastQuote); + } else { + newSeparators.append(QString()); + } + + displayFormat = newFormat; + separators = newSeparators; + sectionNodes = newSectionNodes; + display = newDisplay; + last.pos = -1; + +// for (int i=0; i<sectionNodes.size(); ++i) { +// QDTPDEBUG << sectionName(sectionNodes.at(i).type) << sectionNodes.at(i).count; +// } + + QDTPDEBUG << newFormat << displayFormat; + QDTPDEBUGN("separators:\n'%s'", separators.join(QLatin1String("\n")).toLatin1().constData()); + + return true; +} + +/*! + \internal + + Returns the size of section \a s. +*/ + +int QDateTimeParser::sectionSize(int sectionIndex) const +{ + if (sectionIndex < 0) + return 0; + + if (sectionIndex >= sectionNodes.size()) { + qWarning("QDateTimeParser::sectionSize Internal error (%d)", sectionIndex); + return -1; + } + if (sectionIndex == sectionNodes.size() - 1) { + return displayText().size() - sectionPos(sectionIndex) - separators.last().size(); + } else { + return sectionPos(sectionIndex + 1) - sectionPos(sectionIndex) + - separators.at(sectionIndex + 1).size(); + } +} + + +int QDateTimeParser::sectionMaxSize(Section s, int count) const +{ +#ifndef QT_NO_TEXTDATE + int mcount = 12; +#endif + + switch (s) { + case FirstSection: + case NoSection: + case LastSection: return 0; + + case AmPmSection: { + const int lowerMax = qMin(getAmPmText(AmText, LowerCase).size(), + getAmPmText(PmText, LowerCase).size()); + const int upperMax = qMin(getAmPmText(AmText, UpperCase).size(), + getAmPmText(PmText, UpperCase).size()); + return qMin(4, qMin(lowerMax, upperMax)); + } + + case Hour24Section: + case Hour12Section: + case MinuteSection: + case SecondSection: + case DaySection: return 2; + case DayOfWeekSection: +#ifdef QT_NO_TEXTDATE + return 2; +#else + mcount = 7; + // fall through +#endif + case MonthSection: + if (count <= 2) + return 2; + +#ifdef QT_NO_TEXTDATE + return 2; +#else + { + int ret = 0; + const QLocale l = locale(); + for (int i=1; i<=mcount; ++i) { + const QString str = (s == MonthSection + ? l.monthName(i, count == 4 ? QLocale::LongFormat : QLocale::ShortFormat) + : l.dayName(i, count == 4 ? QLocale::LongFormat : QLocale::ShortFormat)); + ret = qMax(str.size(), ret); + } + return ret; + } +#endif + case MSecSection: return 3; + case YearSection: return 4; + case YearSection2Digits: return 2; + + case CalendarPopupSection: + case Internal: + case TimeSectionMask: + case DateSectionMask: + qWarning("QDateTimeParser::sectionMaxSize: Invalid section %s", + sectionName(s).toLatin1().constData()); + + case NoSectionIndex: + case FirstSectionIndex: + case LastSectionIndex: + case CalendarPopupIndex: + // these cases can't happen + break; + } + return -1; +} + + +int QDateTimeParser::sectionMaxSize(int index) const +{ + const SectionNode &sn = sectionNode(index); + return sectionMaxSize(sn.type, sn.count); +} + +/*! + \internal + + Returns the text of section \a s. This function operates on the + arg text rather than edit->text(). +*/ + + +QString QDateTimeParser::sectionText(const QString &text, int sectionIndex, int index) const +{ + const SectionNode &sn = sectionNode(sectionIndex); + switch (sn.type) { + case NoSectionIndex: + case FirstSectionIndex: + case LastSectionIndex: + return QString(); + default: break; + } + + return text.mid(index, sectionSize(sectionIndex)); +} + +QString QDateTimeParser::sectionText(int sectionIndex) const +{ + const SectionNode &sn = sectionNode(sectionIndex); + switch (sn.type) { + case NoSectionIndex: + case FirstSectionIndex: + case LastSectionIndex: + return QString(); + default: break; + } + + return displayText().mid(sn.pos, sectionSize(sectionIndex)); +} + + +#ifndef QT_NO_TEXTDATE +/*! + \internal:skipToNextSection + + Parses the part of \a text that corresponds to \a s and returns + the value of that field. Sets *stateptr to the right state if + stateptr != 0. +*/ + +int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionIndex, + QString &text, int &cursorPosition, int index, + State &state, int *usedptr) const +{ + state = Invalid; + int num = 0; + const SectionNode &sn = sectionNode(sectionIndex); + if ((sn.type & Internal) == Internal) { + qWarning("QDateTimeParser::parseSection Internal error (%s %d)", + qPrintable(sectionName(sn.type)), sectionIndex); + return -1; + } + + const int sectionmaxsize = sectionMaxSize(sectionIndex); + QString sectiontext = text.mid(index, sectionmaxsize); + int sectiontextSize = sectiontext.size(); + + QDTPDEBUG << "sectionValue for" << sectionName(sn.type) + << "with text" << text << "and st" << sectiontext + << text.mid(index, sectionmaxsize) + << index; + + int used = 0; + switch (sn.type) { + case AmPmSection: { + const int ampm = findAmPm(sectiontext, sectionIndex, &used); + switch (ampm) { + case AM: // sectiontext == AM + case PM: // sectiontext == PM + num = ampm; + state = Acceptable; + break; + case PossibleAM: // sectiontext => AM + case PossiblePM: // sectiontext => PM + num = ampm - 2; + state = Intermediate; + break; + case PossibleBoth: // sectiontext => AM|PM + num = 0; + state = Intermediate; + break; + case Neither: + state = Invalid; + QDTPDEBUG << "invalid because findAmPm(" << sectiontext << ") returned -1"; + break; + default: + QDTPDEBUGN("This should never happen (findAmPm returned %d)", ampm); + break; + } + if (state != Invalid) { + QString str = text; + text.replace(index, used, sectiontext.left(used)); + } + break; } + case MonthSection: + case DayOfWeekSection: + if (sn.count >= 3) { + if (sn.type == MonthSection) { + int min = 1; + const QDate minDate = getMinimum().date(); + if (currentValue.date().year() == minDate.year()) { + min = minDate.month(); + } + num = findMonth(sectiontext.toLower(), min, sectionIndex, §iontext, &used); + } else { + num = findDay(sectiontext.toLower(), 1, sectionIndex, §iontext, &used); + } + + if (num != -1) { + state = (used == sectiontext.size() ? Acceptable : Intermediate); + QString str = text; + text.replace(index, used, sectiontext.left(used)); + } else { + state = Intermediate; + } + break; } + // fall through + case DaySection: + case YearSection: + case YearSection2Digits: + case Hour12Section: + case Hour24Section: + case MinuteSection: + case SecondSection: + case MSecSection: { + if (sectiontextSize == 0) { + num = 0; + used = 0; + state = Intermediate; + } else { + const int absMax = absoluteMax(sectionIndex); + QLocale loc; + bool ok = true; + int last = -1; + used = -1; + + QString digitsStr(sectiontext); + for (int i = 0; i < sectiontextSize; ++i) { + if (digitsStr.at(i).isSpace()) { + sectiontextSize = i; + break; + } + } + + const int max = qMin(sectionmaxsize, sectiontextSize); + for (int digits = max; digits >= 1; --digits) { + digitsStr.truncate(digits); + int tmp = (int)loc.toUInt(digitsStr, &ok, 10); + if (ok && sn.type == Hour12Section) { + if (tmp > 12) { + tmp = -1; + ok = false; + } else if (tmp == 12) { + tmp = 0; + } + } + if (ok && tmp <= absMax) { + QDTPDEBUG << sectiontext.left(digits) << tmp << digits; + last = tmp; + used = digits; + break; + } + } + + if (last == -1) { + QChar first(sectiontext.at(0)); + if (separators.at(sectionIndex + 1).startsWith(first)) { + used = 0; + state = Intermediate; + } else { + state = Invalid; + QDTPDEBUG << "invalid because" << sectiontext << "can't become a uint" << last << ok; + } + } else { + num += last; + const FieldInfo fi = fieldInfo(sectionIndex); + const bool done = (used == sectionmaxsize); + if (!done && fi & Fraction) { // typing 2 in a zzz field should be .200, not .002 + for (int i=used; i<sectionmaxsize; ++i) { + num *= 10; + } + } + const int absMin = absoluteMin(sectionIndex); + if (num < absMin) { + state = done ? Invalid : Intermediate; + if (done) + QDTPDEBUG << "invalid because" << num << "is less than absoluteMin" << absMin; + } else if (num > absMax) { + state = Intermediate; + } else if (!done && (fi & (FixedWidth|Numeric)) == (FixedWidth|Numeric)) { + if (skipToNextSection(sectionIndex, currentValue, digitsStr)) { + state = Acceptable; + const int missingZeroes = sectionmaxsize - digitsStr.size(); + text.insert(index, QString().fill(QLatin1Char('0'), missingZeroes)); + used = sectionmaxsize; + cursorPosition += missingZeroes; + } else { + state = Intermediate;; + } + } else { + state = Acceptable; + } + } + } + break; } + default: + qWarning("QDateTimeParser::parseSection Internal error (%s %d)", + qPrintable(sectionName(sn.type)), sectionIndex); + return -1; + } + + if (usedptr) + *usedptr = used; + + return (state != Invalid ? num : -1); +} +#endif // QT_NO_TEXTDATE + +#ifndef QT_NO_DATESTRING +/*! + \internal +*/ + +QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPosition, + const QDateTime ¤tValue, bool fixup) const +{ + const QDateTime minimum = getMinimum(); + const QDateTime maximum = getMaximum(); + + State state = Acceptable; + + QDateTime newCurrentValue; + int pos = 0; + bool conflicts = false; + const int sectionNodesCount = sectionNodes.size(); + + QDTPDEBUG << "parse" << input; + { + int year, month, day, hour12, hour, minute, second, msec, ampm, dayofweek, year2digits; + getDateFromJulianDay(currentValue.date().toJulianDay(), &year, &month, &day); + year2digits = year % 100; + hour = currentValue.time().hour(); + hour12 = -1; + minute = currentValue.time().minute(); + second = currentValue.time().second(); + msec = currentValue.time().msec(); + dayofweek = currentValue.date().dayOfWeek(); + + ampm = -1; + Sections isSet = NoSection; + int num; + State tmpstate; + + for (int index=0; state != Invalid && index<sectionNodesCount; ++index) { + if (QStringRef(&input, pos, separators.at(index).size()) != separators.at(index)) { + QDTPDEBUG << "invalid because" << input.mid(pos, separators.at(index).size()) + << "!=" << separators.at(index) + << index << pos << currentSectionIndex; + state = Invalid; + goto end; + } + pos += separators.at(index).size(); + sectionNodes[index].pos = pos; + int *current = 0; + const SectionNode sn = sectionNodes.at(index); + int used; + + num = parseSection(currentValue, index, input, cursorPosition, pos, tmpstate, &used); + QDTPDEBUG << "sectionValue" << sectionName(sectionType(index)) << input + << "pos" << pos << "used" << used << stateName(tmpstate); + if (fixup && tmpstate == Intermediate && used < sn.count) { + const FieldInfo fi = fieldInfo(index); + if ((fi & (Numeric|FixedWidth)) == (Numeric|FixedWidth)) { + const QString newText = QString::fromLatin1("%1").arg(num, sn.count, 10, QLatin1Char('0')); + input.replace(pos, used, newText); + used = sn.count; + } + } + pos += qMax(0, used); + + state = qMin<State>(state, tmpstate); + if (state == Intermediate && context == FromString) { + state = Invalid; + break; + } + + QDTPDEBUG << index << sectionName(sectionType(index)) << "is set to" + << pos << "state is" << stateName(state); + + + if (state != Invalid) { + switch (sn.type) { + case Hour24Section: current = &hour; break; + case Hour12Section: current = &hour12; break; + case MinuteSection: current = &minute; break; + case SecondSection: current = &second; break; + case MSecSection: current = &msec; break; + case YearSection: current = &year; break; + case YearSection2Digits: current = &year2digits; break; + case MonthSection: current = &month; break; + case DayOfWeekSection: current = &dayofweek; break; + case DaySection: current = &day; num = qMax<int>(1, num); break; + case AmPmSection: current = &m; break; + default: + qWarning("QDateTimeParser::parse Internal error (%s)", + qPrintable(sectionName(sn.type))); + break; + } + if (!current) { + qWarning("QDateTimeParser::parse Internal error 2"); + return StateNode(); + } + if (isSet & sn.type && *current != num) { + QDTPDEBUG << "CONFLICT " << sectionName(sn.type) << *current << num; + conflicts = true; + if (index != currentSectionIndex || num == -1) { + continue; + } + } + if (num != -1) + *current = num; + isSet |= sn.type; + } + } + + if (state != Invalid && QStringRef(&input, pos, input.size() - pos) != separators.last()) { + QDTPDEBUG << "invalid because" << input.mid(pos) + << "!=" << separators.last() << pos; + state = Invalid; + } + + if (state != Invalid) { + if (parserType != QVariant::Time) { + if (year % 100 != year2digits) { + switch (isSet & (YearSection2Digits|YearSection)) { + case YearSection2Digits: + year = (year / 100) * 100; + year += year2digits; + break; + case ((uint)YearSection2Digits|(uint)YearSection): { + conflicts = true; + const SectionNode &sn = sectionNode(currentSectionIndex); + if (sn.type == YearSection2Digits) { + year = (year / 100) * 100; + year += year2digits; + } + break; } + default: + break; + } + } + + const QDate date(year, month, day); + const int diff = dayofweek - date.dayOfWeek(); + if (diff != 0 && state == Acceptable && isSet & DayOfWeekSection) { + conflicts = isSet & DaySection; + const SectionNode &sn = sectionNode(currentSectionIndex); + if (sn.type == DayOfWeekSection || currentSectionIndex == -1) { + // dayofweek should be preferred + day += diff; + if (day <= 0) { + day += 7; + } else if (day > date.daysInMonth()) { + day -= 7; + } + QDTPDEBUG << year << month << day << dayofweek + << diff << QDate(year, month, day).dayOfWeek(); + } + } + bool needfixday = false; + if (sectionType(currentSectionIndex) & (DaySection|DayOfWeekSection)) { + cachedDay = day; + } else if (cachedDay > day) { + day = cachedDay; + needfixday = true; + } + + if (!QDate::isValid(year, month, day)) { + if (day < 32) { + cachedDay = day; + } + if (day > 28 && QDate::isValid(year, month, 1)) { + needfixday = true; + } + } + if (needfixday) { + if (context == FromString) { + state = Invalid; + goto end; + } + if (state == Acceptable && fixday) { + day = qMin<int>(day, QDate(year, month, 1).daysInMonth()); + + const QLocale loc = locale(); + for (int i=0; i<sectionNodesCount; ++i) { + if (sectionType(i) & (DaySection|DayOfWeekSection)) { + input.replace(sectionPos(i), sectionSize(i), loc.toString(day)); + } + } + } else { + state = qMin(Intermediate, state); + } + } + } + + if (parserType != QVariant::Date) { + if (isSet & Hour12Section) { + const bool hasHour = isSet & Hour24Section; + if (ampm == -1) { + if (hasHour) { + ampm = (hour < 12 ? 0 : 1); + } else { + ampm = 0; // no way to tell if this is am or pm so I assume am + } + } + hour12 = (ampm == 0 ? hour12 % 12 : (hour12 % 12) + 12); + if (!hasHour) { + hour = hour12; + } else if (hour != hour12) { + conflicts = true; + } + } else if (ampm != -1) { + if (!(isSet & (Hour24Section))) { + hour = (12 * ampm); // special case. Only ap section + } else if ((ampm == 0) != (hour < 12)) { + conflicts = true; + } + } + + } + + newCurrentValue = QDateTime(QDate(year, month, day), QTime(hour, minute, second, msec), spec); + QDTPDEBUG << year << month << day << hour << minute << second << msec; + } + QDTPDEBUGN("'%s' => '%s'(%s)", input.toLatin1().constData(), + newCurrentValue.toString(QLatin1String("yyyy/MM/dd hh:mm:ss.zzz")).toLatin1().constData(), + stateName(state).toLatin1().constData()); + } +end: + if (newCurrentValue.isValid()) { + if (context != FromString && state != Invalid && newCurrentValue < minimum) { + const QLatin1Char space(' '); + if (newCurrentValue >= minimum) + qWarning("QDateTimeParser::parse Internal error 3 (%s %s)", + qPrintable(newCurrentValue.toString()), qPrintable(minimum.toString())); + + bool done = false; + state = Invalid; + for (int i=0; i<sectionNodesCount && !done; ++i) { + const SectionNode &sn = sectionNodes.at(i); + QString t = sectionText(input, i, sn.pos).toLower(); + if ((t.size() < sectionMaxSize(i) && (((int)fieldInfo(i) & (FixedWidth|Numeric)) != Numeric)) + || t.contains(space)) { + switch (sn.type) { + case AmPmSection: + switch (findAmPm(t, i)) { + case AM: + case PM: + state = Acceptable; + done = true; + break; + case Neither: + state = Invalid; + done = true; + break; + case PossibleAM: + case PossiblePM: + case PossibleBoth: { + const QDateTime copy(newCurrentValue.addSecs(12 * 60 * 60)); + if (copy >= minimum && copy <= maximum) { + state = Intermediate; + done = true; + } + break; } + } + case MonthSection: + if (sn.count >= 3) { + int tmp = newCurrentValue.date().month(); + // I know the first possible month makes the date too early + while ((tmp = findMonth(t, tmp + 1, i)) != -1) { + const QDateTime copy(newCurrentValue.addMonths(tmp - newCurrentValue.date().month())); + if (copy >= minimum && copy <= maximum) + break; // break out of while + } + if (tmp == -1) { + break; + } + state = Intermediate; + done = true; + break; + } + // fallthrough + default: { + int toMin; + int toMax; + + if (sn.type & TimeSectionMask) { + if (newCurrentValue.daysTo(minimum) != 0) { + break; + } + toMin = newCurrentValue.time().msecsTo(minimum.time()); + if (newCurrentValue.daysTo(maximum) > 0) { + toMax = -1; // can't get to max + } else { + toMax = newCurrentValue.time().msecsTo(maximum.time()); + } + } else { + toMin = newCurrentValue.daysTo(minimum); + toMax = newCurrentValue.daysTo(maximum); + } + const int maxChange = QDateTimeParser::maxChange(i); + if (toMin > maxChange) { + QDTPDEBUG << "invalid because toMin > maxChange" << toMin + << maxChange << t << newCurrentValue << minimum; + state = Invalid; + done = true; + break; + } else if (toMax > maxChange) { + toMax = -1; // can't get to max + } + + const int min = getDigit(minimum, i); + if (min == -1) { + qWarning("QDateTimeParser::parse Internal error 4 (%s)", + qPrintable(sectionName(sn.type))); + state = Invalid; + done = true; + break; + } + + int max = toMax != -1 ? getDigit(maximum, i) : absoluteMax(i, newCurrentValue); + int pos = cursorPosition - sn.pos; + if (pos < 0 || pos >= t.size()) + pos = -1; + if (!potentialValue(t.simplified(), min, max, i, newCurrentValue, pos)) { + QDTPDEBUG << "invalid because potentialValue(" << t.simplified() << min << max + << sectionName(sn.type) << "returned" << toMax << toMin << pos; + state = Invalid; + done = true; + break; + } + state = Intermediate; + done = true; + break; } + } + } + } + } else { + if (context == FromString) { + // optimization + Q_ASSERT(getMaximum().date().toJulianDay() == 4642999); + if (newCurrentValue.date().toJulianDay() > 4642999) + state = Invalid; + } else { + if (newCurrentValue > getMaximum()) + state = Invalid; + } + + QDTPDEBUG << "not checking intermediate because newCurrentValue is" << newCurrentValue << getMinimum() << getMaximum(); + } + } + StateNode node; + node.input = input; + node.state = state; + node.conflicts = conflicts; + node.value = newCurrentValue.toTimeSpec(spec); + text = input; + return node; +} +#endif // QT_NO_DATESTRING + +#ifndef QT_NO_TEXTDATE +/*! + \internal finds the first possible monthname that \a str1 can + match. Starting from \a index; str should already by lowered +*/ + +int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionIndex, + QString *usedMonth, int *used) const +{ + int bestMatch = -1; + int bestCount = 0; + if (!str1.isEmpty()) { + const SectionNode &sn = sectionNode(sectionIndex); + if (sn.type != MonthSection) { + qWarning("QDateTimeParser::findMonth Internal error"); + return -1; + } + + QLocale::FormatType type = sn.count == 3 ? QLocale::ShortFormat : QLocale::LongFormat; + QLocale l = locale(); + + for (int month=startMonth; month<=12; ++month) { + QString str2 = l.monthName(month, type).toLower(); + + if (str1.startsWith(str2)) { + if (used) { + QDTPDEBUG << "used is set to" << str2.size(); + *used = str2.size(); + } + if (usedMonth) + *usedMonth = l.monthName(month, type); + + return month; + } + if (context == FromString) + continue; + + const int limit = qMin(str1.size(), str2.size()); + + QDTPDEBUG << "limit is" << limit << str1 << str2; + bool equal = true; + for (int i=0; i<limit; ++i) { + if (str1.at(i) != str2.at(i)) { + equal = false; + if (i > bestCount) { + bestCount = i; + bestMatch = month; + } + break; + } + } + if (equal) { + if (used) + *used = limit; + if (usedMonth) + *usedMonth = l.monthName(month, type); + return month; + } + } + if (usedMonth && bestMatch != -1) + *usedMonth = l.monthName(bestMatch, type); + } + if (used) { + QDTPDEBUG << "used is set to" << bestCount; + *used = bestCount; + } + return bestMatch; +} + +int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex, QString *usedDay, int *used) const +{ + int bestMatch = -1; + int bestCount = 0; + if (!str1.isEmpty()) { + const SectionNode &sn = sectionNode(sectionIndex); + if (!(sn.type & (DaySection|DayOfWeekSection))) { + qWarning("QDateTimeParser::findDay Internal error"); + return -1; + } + const QLocale l = locale(); + for (int day=startDay; day<=7; ++day) { + const QString str2 = l.dayName(day, sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat); + + if (str1.startsWith(str2.toLower())) { + if (used) + *used = str2.size(); + if (usedDay) { + *usedDay = str2; + } + return day; + } + if (context == FromString) + continue; + + const int limit = qMin(str1.size(), str2.size()); + bool found = true; + for (int i=0; i<limit; ++i) { + if (str1.at(i) != str2.at(i) && !str1.at(i).isSpace()) { + if (i > bestCount) { + bestCount = i; + bestMatch = day; + } + found = false; + break; + } + + } + if (found) { + if (used) + *used = limit; + if (usedDay) + *usedDay = str2; + + return day; + } + } + if (usedDay && bestMatch != -1) { + *usedDay = l.dayName(bestMatch, sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat); + } + } + if (used) + *used = bestCount; + + return bestMatch; +} +#endif // QT_NO_TEXTDATE + +/*! + \internal + + returns + 0 if str == QDateTimeEdit::tr("AM") + 1 if str == QDateTimeEdit::tr("PM") + 2 if str can become QDateTimeEdit::tr("AM") + 3 if str can become QDateTimeEdit::tr("PM") + 4 if str can become QDateTimeEdit::tr("PM") and can become QDateTimeEdit::tr("AM") + -1 can't become anything sensible + +*/ + +int QDateTimeParser::findAmPm(QString &str, int index, int *used) const +{ + const SectionNode &s = sectionNode(index); + if (s.type != AmPmSection) { + qWarning("QDateTimeParser::findAmPm Internal error"); + return -1; + } + if (used) + *used = str.size(); + if (str.trimmed().isEmpty()) { + return PossibleBoth; + } + const QLatin1Char space(' '); + int size = sectionMaxSize(index); + + enum { + amindex = 0, + pmindex = 1 + }; + QString ampm[2]; + ampm[amindex] = getAmPmText(AmText, s.count == 1 ? UpperCase : LowerCase); + ampm[pmindex] = getAmPmText(PmText, s.count == 1 ? UpperCase : LowerCase); + for (int i=0; i<2; ++i) + ampm[i].truncate(size); + + QDTPDEBUG << "findAmPm" << str << ampm[0] << ampm[1]; + + if (str.indexOf(ampm[amindex], 0, Qt::CaseInsensitive) == 0) { + str = ampm[amindex]; + return AM; + } else if (str.indexOf(ampm[pmindex], 0, Qt::CaseInsensitive) == 0) { + str = ampm[pmindex]; + return PM; + } else if (context == FromString || (str.count(space) == 0 && str.size() >= size)) { + return Neither; + } + size = qMin(size, str.size()); + + bool broken[2] = {false, false}; + for (int i=0; i<size; ++i) { + if (str.at(i) != space) { + for (int j=0; j<2; ++j) { + if (!broken[j]) { + int index = ampm[j].indexOf(str.at(i)); + QDTPDEBUG << "looking for" << str.at(i) + << "in" << ampm[j] << "and got" << index; + if (index == -1) { + if (str.at(i).category() == QChar::Letter_Uppercase) { + index = ampm[j].indexOf(str.at(i).toLower()); + QDTPDEBUG << "trying with" << str.at(i).toLower() + << "in" << ampm[j] << "and got" << index; + } else if (str.at(i).category() == QChar::Letter_Lowercase) { + index = ampm[j].indexOf(str.at(i).toUpper()); + QDTPDEBUG << "trying with" << str.at(i).toUpper() + << "in" << ampm[j] << "and got" << index; + } + if (index == -1) { + broken[j] = true; + if (broken[amindex] && broken[pmindex]) { + QDTPDEBUG << str << "didn't make it"; + return Neither; + } + continue; + } else { + str[i] = ampm[j].at(index); // fix case + } + } + ampm[j].remove(index, 1); + } + } + } + } + if (!broken[pmindex] && !broken[amindex]) + return PossibleBoth; + return (!broken[amindex] ? PossibleAM : PossiblePM); +} + +/*! + \internal + Max number of units that can be changed by this section. +*/ + +int QDateTimeParser::maxChange(int index) const +{ + const SectionNode &sn = sectionNode(index); + switch (sn.type) { + // Time. unit is msec + case MSecSection: return 999; + case SecondSection: return 59 * 1000; + case MinuteSection: return 59 * 60 * 1000; + case Hour24Section: case Hour12Section: return 59 * 60 * 60 * 1000; + + // Date. unit is day + case DayOfWeekSection: return 7; + case DaySection: return 30; + case MonthSection: return 365 - 31; + case YearSection: return 9999 * 365; + case YearSection2Digits: return 100 * 365; + default: + qWarning("QDateTimeParser::maxChange() Internal error (%s)", + qPrintable(sectionName(sectionType(index)))); + } + + return -1; +} + +QDateTimeParser::FieldInfo QDateTimeParser::fieldInfo(int index) const +{ + FieldInfo ret = 0; + const SectionNode &sn = sectionNode(index); + const Section s = sn.type; + switch (s) { + case MSecSection: + ret |= Fraction; + // fallthrough + case SecondSection: + case MinuteSection: + case Hour24Section: + case Hour12Section: + case YearSection: + case YearSection2Digits: + ret |= Numeric; + if (s != YearSection) { + ret |= AllowPartial; + } + if (sn.count != 1) { + ret |= FixedWidth; + } + break; + case MonthSection: + case DaySection: + switch (sn.count) { + case 2: + ret |= FixedWidth; + // fallthrough + case 1: + ret |= (Numeric|AllowPartial); + break; + } + break; + case DayOfWeekSection: + if (sn.count == 3) + ret |= FixedWidth; + break; + case AmPmSection: + ret |= FixedWidth; + break; + default: + qWarning("QDateTimeParser::fieldInfo Internal error 2 (%d %s %d)", + index, qPrintable(sectionName(sn.type)), sn.count); + break; + } + return ret; +} + +/*! + \internal Get a number that str can become which is between min + and max or -1 if this is not possible. +*/ + + +QString QDateTimeParser::sectionFormat(int index) const +{ + const SectionNode &sn = sectionNode(index); + return sectionFormat(sn.type, sn.count); +} + +QString QDateTimeParser::sectionFormat(Section s, int count) const +{ + QChar fillChar; + switch (s) { + case AmPmSection: return count == 1 ? QLatin1String("AP") : QLatin1String("ap"); + case MSecSection: fillChar = QLatin1Char('z'); break; + case SecondSection: fillChar = QLatin1Char('s'); break; + case MinuteSection: fillChar = QLatin1Char('m'); break; + case Hour24Section: fillChar = QLatin1Char('H'); break; + case Hour12Section: fillChar = QLatin1Char('h'); break; + case DayOfWeekSection: + case DaySection: fillChar = QLatin1Char('d'); break; + case MonthSection: fillChar = QLatin1Char('M'); break; + case YearSection2Digits: + case YearSection: fillChar = QLatin1Char('y'); break; + default: + qWarning("QDateTimeParser::sectionFormat Internal error (%s)", + qPrintable(sectionName(s))); + return QString(); + } + if (fillChar.isNull()) { + qWarning("QDateTimeParser::sectionFormat Internal error 2"); + return QString(); + } + + QString str; + str.fill(fillChar, count); + return str; +} + + +/*! \internal Returns true if str can be modified to represent a + number that is within min and max. +*/ + +bool QDateTimeParser::potentialValue(const QString &str, int min, int max, int index, + const QDateTime ¤tValue, int insert) const +{ + if (str.isEmpty()) { + return true; + } + const int size = sectionMaxSize(index); + int val = (int)locale().toUInt(str); + const SectionNode &sn = sectionNode(index); + if (sn.type == YearSection2Digits) { + val += currentValue.date().year() - (currentValue.date().year() % 100); + } + if (val >= min && val <= max && str.size() == size) { + return true; + } else if (val > max) { + return false; + } else if (str.size() == size && val < min) { + return false; + } + + const int len = size - str.size(); + for (int i=0; i<len; ++i) { + for (int j=0; j<10; ++j) { + if (potentialValue(str + QLatin1Char('0' + j), min, max, index, currentValue, insert)) { + return true; + } else if (insert >= 0) { + QString tmp = str; + tmp.insert(insert, QLatin1Char('0' + j)); + if (potentialValue(tmp, min, max, index, currentValue, insert)) + return true; + } + } + } + + return false; +} + +bool QDateTimeParser::skipToNextSection(int index, const QDateTime ¤t, const QString &text) const +{ + Q_ASSERT(current >= getMinimum() && current <= getMaximum()); + + const SectionNode &node = sectionNode(index); + Q_ASSERT(text.size() < sectionMaxSize(index)); + + const QDateTime maximum = getMaximum(); + const QDateTime minimum = getMinimum(); + QDateTime tmp = current; + int min = absoluteMin(index); + setDigit(tmp, index, min); + if (tmp < minimum) { + min = getDigit(minimum, index); + } + + int max = absoluteMax(index, current); + setDigit(tmp, index, max); + if (tmp > maximum) { + max = getDigit(maximum, index); + } + int pos = cursorPosition() - node.pos; + if (pos < 0 || pos >= text.size()) + pos = -1; + + const bool potential = potentialValue(text, min, max, index, current, pos); + return !potential; + + /* If the value potentially can become another valid entry we + * don't want to skip to the next. E.g. In a M field (month + * without leading 0 if you type 1 we don't want to autoskip but + * if you type 3 we do + */ +} + +/*! + \internal + For debugging. Returns the name of the section \a s. +*/ + +QString QDateTimeParser::sectionName(int s) const +{ + switch (s) { + case QDateTimeParser::AmPmSection: return QLatin1String("AmPmSection"); + case QDateTimeParser::DaySection: return QLatin1String("DaySection"); + case QDateTimeParser::DayOfWeekSection: return QLatin1String("DayOfWeekSection"); + case QDateTimeParser::Hour24Section: return QLatin1String("Hour24Section"); + case QDateTimeParser::Hour12Section: return QLatin1String("Hour12Section"); + case QDateTimeParser::MSecSection: return QLatin1String("MSecSection"); + case QDateTimeParser::MinuteSection: return QLatin1String("MinuteSection"); + case QDateTimeParser::MonthSection: return QLatin1String("MonthSection"); + case QDateTimeParser::SecondSection: return QLatin1String("SecondSection"); + case QDateTimeParser::YearSection: return QLatin1String("YearSection"); + case QDateTimeParser::YearSection2Digits: return QLatin1String("YearSection2Digits"); + case QDateTimeParser::NoSection: return QLatin1String("NoSection"); + case QDateTimeParser::FirstSection: return QLatin1String("FirstSection"); + case QDateTimeParser::LastSection: return QLatin1String("LastSection"); + default: return QLatin1String("Unknown section ") + QString::number(s); + } +} + +/*! + \internal + For debugging. Returns the name of the state \a s. +*/ + +QString QDateTimeParser::stateName(int s) const +{ + switch (s) { + case Invalid: return QLatin1String("Invalid"); + case Intermediate: return QLatin1String("Intermediate"); + case Acceptable: return QLatin1String("Acceptable"); + default: return QLatin1String("Unknown state ") + QString::number(s); + } +} + +#ifndef QT_NO_DATESTRING +bool QDateTimeParser::fromString(const QString &t, QDate *date, QTime *time) const +{ + QDateTime val(QDate(1900, 1, 1), QDATETIMEEDIT_TIME_MIN); + QString text = t; + int copy = -1; + const StateNode tmp = parse(text, copy, val, false); + if (tmp.state != Acceptable || tmp.conflicts) { + return false; + } + if (time) { + const QTime t = tmp.value.time(); + if (!t.isValid()) { + return false; + } + *time = t; + } + + if (date) { + const QDate d = tmp.value.date(); + if (!d.isValid()) { + return false; + } + *date = d; + } + return true; +} +#endif // QT_NO_DATESTRING + +QDateTime QDateTimeParser::getMinimum() const +{ + return QDateTime(QDATETIMEEDIT_DATE_MIN, QDATETIMEEDIT_TIME_MIN, spec); +} + +QDateTime QDateTimeParser::getMaximum() const +{ + return QDateTime(QDATETIMEEDIT_DATE_MAX, QDATETIMEEDIT_TIME_MAX, spec); +} + +QString QDateTimeParser::getAmPmText(AmPm ap, Case cs) const +{ + if (ap == AmText) { + return (cs == UpperCase ? QLatin1String("AM") : QLatin1String("am")); + } else { + return (cs == UpperCase ? QLatin1String("PM") : QLatin1String("pm")); + } +} + +/* + \internal + + I give arg2 preference because arg1 is always a QDateTime. +*/ + +bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2) +{ + return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count); +} + +#ifdef Q_OS_SYMBIAN +const static TTime UnixEpochOffset(I64LIT(0xdcddb30f2f8000)); +const static TInt64 MinimumMillisecondTime(KMinTInt64 / 1000); +const static TInt64 MaximumMillisecondTime(KMaxTInt64 / 1000); +QDateTime qt_symbian_TTime_To_QDateTime(const TTime& time) +{ + TTimeIntervalMicroSeconds absolute = time.MicroSecondsFrom(UnixEpochOffset); + + return QDateTime::fromMSecsSinceEpoch(absolute.Int64() / 1000); +} + +TTime qt_symbian_QDateTime_To_TTime(const QDateTime& datetime) +{ + qint64 absolute = datetime.toMSecsSinceEpoch(); + if(absolute > MaximumMillisecondTime) + return TTime(KMaxTInt64); + if(absolute < MinimumMillisecondTime) + return TTime(KMinTInt64); + return TTime(absolute * 1000); +} + +time_t qt_symbian_TTime_To_time_t(const TTime& time) +{ + TTimeIntervalSeconds interval; + TInt err = time.SecondsFrom(UnixEpochOffset, interval); + if (err || interval.Int() < 0) + return (time_t) 0; + return (time_t) interval.Int(); +} + +TTime qt_symbian_time_t_To_TTime(time_t time) +{ + return UnixEpochOffset + TTimeIntervalSeconds(time); +} +#endif //Q_OS_SYMBIAN + +#endif // QT_BOOTSTRAPPED + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h new file mode 100644 index 0000000000..432c906372 --- /dev/null +++ b/src/corelib/tools/qdatetime.h @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QDATETIME_H +#define QDATETIME_H + +#include <QtCore/qstring.h> +#include <QtCore/qnamespace.h> +#include <QtCore/qsharedpointer.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +class Q_CORE_EXPORT QDate +{ +public: + enum MonthNameType { + DateFormat = 0, + StandaloneFormat + }; +public: + QDate() { jd = 0; } + QDate(int y, int m, int d); + + bool isNull() const { return jd == 0; } + bool isValid() const; + + int year() const; + int month() const; + int day() const; + int dayOfWeek() const; + int dayOfYear() const; + int daysInMonth() const; + int daysInYear() const; + int weekNumber(int *yearNum = 0) const; + +#ifndef QT_NO_TEXTDATE +#ifdef QT3_SUPPORT + static QT3_SUPPORT QString monthName(int month) { return shortMonthName(month); } + static QT3_SUPPORT QString dayName(int weekday) { return shortDayName(weekday); } +#endif + // ### Qt 5: merge these functions. + static QString shortMonthName(int month); + static QString shortMonthName(int month, MonthNameType type); + static QString shortDayName(int weekday); + static QString shortDayName(int weekday, MonthNameType type); + static QString longMonthName(int month); + static QString longMonthName(int month, MonthNameType type); + static QString longDayName(int weekday); + static QString longDayName(int weekday, MonthNameType type); +#endif // QT_NO_TEXTDATE +#ifndef QT_NO_DATESTRING + QString toString(Qt::DateFormat f = Qt::TextDate) const; + QString toString(const QString &format) const; +#endif + bool setYMD(int y, int m, int d); + bool setDate(int year, int month, int day); + + void getDate(int *year, int *month, int *day); + + QDate addDays(int days) const; + QDate addMonths(int months) const; + QDate addYears(int years) const; + int daysTo(const QDate &) const; + + bool operator==(const QDate &other) const { return jd == other.jd; } + bool operator!=(const QDate &other) const { return jd != other.jd; } + bool operator<(const QDate &other) const { return jd < other.jd; } + bool operator<=(const QDate &other) const { return jd <= other.jd; } + bool operator>(const QDate &other) const { return jd > other.jd; } + bool operator>=(const QDate &other) const { return jd >= other.jd; } + + static QDate currentDate(); +#ifndef QT_NO_DATESTRING + static QDate fromString(const QString &s, Qt::DateFormat f = Qt::TextDate); + static QDate fromString(const QString &s, const QString &format); +#endif + static bool isValid(int y, int m, int d); + static bool isLeapYear(int year); +#ifdef QT3_SUPPORT + inline static QT3_SUPPORT bool leapYear(int year) { return isLeapYear(year); } +#endif + + // ### Qt 5: remove these two functions + static uint gregorianToJulian(int y, int m, int d); + static void julianToGregorian(uint jd, int &y, int &m, int &d); + +#ifdef QT3_SUPPORT + static QT3_SUPPORT QDate currentDate(Qt::TimeSpec spec); +#endif + + static inline QDate fromJulianDay(int jd) { QDate d; d.jd = jd; return d; } + inline int toJulianDay() const { return jd; } + +private: + uint jd; + + friend class QDateTime; + friend class QDateTimePrivate; +#ifndef QT_NO_DATASTREAM + friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDate &); + friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDate &); +#endif +}; +Q_DECLARE_TYPEINFO(QDate, Q_MOVABLE_TYPE); + +class Q_CORE_EXPORT QTime +{ +public: + QTime(): mds(NullTime) +#if defined(Q_OS_WINCE) + , startTick(NullTime) +#endif + {} + QTime(int h, int m, int s = 0, int ms = 0); + + bool isNull() const { return mds == NullTime; } + bool isValid() const; + + int hour() const; + int minute() const; + int second() const; + int msec() const; +#ifndef QT_NO_DATESTRING + QString toString(Qt::DateFormat f = Qt::TextDate) const; + QString toString(const QString &format) const; +#endif + bool setHMS(int h, int m, int s, int ms = 0); + + QTime addSecs(int secs) const; + int secsTo(const QTime &) const; + QTime addMSecs(int ms) const; + int msecsTo(const QTime &) const; + + bool operator==(const QTime &other) const { return mds == other.mds; } + bool operator!=(const QTime &other) const { return mds != other.mds; } + bool operator<(const QTime &other) const { return mds < other.mds; } + bool operator<=(const QTime &other) const { return mds <= other.mds; } + bool operator>(const QTime &other) const { return mds > other.mds; } + bool operator>=(const QTime &other) const { return mds >= other.mds; } + + static QTime currentTime(); +#ifndef QT_NO_DATESTRING + static QTime fromString(const QString &s, Qt::DateFormat f = Qt::TextDate); + static QTime fromString(const QString &s, const QString &format); +#endif + static bool isValid(int h, int m, int s, int ms = 0); + +#ifdef QT3_SUPPORT + static QT3_SUPPORT QTime currentTime(Qt::TimeSpec spec); +#endif + + void start(); + int restart(); + int elapsed() const; +private: + enum TimeFlag { NullTime = -1 }; + inline int ds() const { return mds == -1 ? 0 : mds; } + int mds; +#if defined(Q_OS_WINCE) + int startTick; +#endif + + friend class QDateTime; + friend class QDateTimePrivate; +#ifndef QT_NO_DATASTREAM + friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QTime &); + friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QTime &); +#endif +}; +Q_DECLARE_TYPEINFO(QTime, Q_MOVABLE_TYPE); + +class QDateTimePrivate; + +class Q_CORE_EXPORT QDateTime +{ +public: + QDateTime(); + explicit QDateTime(const QDate &); + QDateTime(const QDate &, const QTime &, Qt::TimeSpec spec = Qt::LocalTime); + QDateTime(const QDateTime &other); + ~QDateTime(); + + QDateTime &operator=(const QDateTime &other); + + bool isNull() const; + bool isValid() const; + + QDate date() const; + QTime time() const; + Qt::TimeSpec timeSpec() const; + qint64 toMSecsSinceEpoch() const; + uint toTime_t() const; + void setDate(const QDate &date); + void setTime(const QTime &time); + void setTimeSpec(Qt::TimeSpec spec); + void setMSecsSinceEpoch(qint64 msecs); + void setTime_t(uint secsSince1Jan1970UTC); +#ifndef QT_NO_DATESTRING + QString toString(Qt::DateFormat f = Qt::TextDate) const; + QString toString(const QString &format) const; +#endif + QDateTime addDays(int days) const; + QDateTime addMonths(int months) const; + QDateTime addYears(int years) const; + QDateTime addSecs(int secs) const; + QDateTime addMSecs(qint64 msecs) const; + QDateTime toTimeSpec(Qt::TimeSpec spec) const; + inline QDateTime toLocalTime() const { return toTimeSpec(Qt::LocalTime); } + inline QDateTime toUTC() const { return toTimeSpec(Qt::UTC); } + int daysTo(const QDateTime &) const; + int secsTo(const QDateTime &) const; + qint64 msecsTo(const QDateTime &) const; + + bool operator==(const QDateTime &other) const; + inline bool operator!=(const QDateTime &other) const { return !(*this == other); } + bool operator<(const QDateTime &other) const; + inline bool operator<=(const QDateTime &other) const { return !(other < *this); } + inline bool operator>(const QDateTime &other) const { return other < *this; } + inline bool operator>=(const QDateTime &other) const { return !(*this < other); } + + void setUtcOffset(int seconds); + int utcOffset() const; + + static QDateTime currentDateTime(); + static QDateTime currentDateTimeUtc(); +#ifndef QT_NO_DATESTRING + static QDateTime fromString(const QString &s, Qt::DateFormat f = Qt::TextDate); + static QDateTime fromString(const QString &s, const QString &format); +#endif + static QDateTime fromTime_t(uint secsSince1Jan1970UTC); + static QDateTime fromMSecsSinceEpoch(qint64 msecs); + static qint64 currentMSecsSinceEpoch(); + +#ifdef QT3_SUPPORT + inline QT3_SUPPORT void setTime_t(uint secsSince1Jan1970UTC, Qt::TimeSpec spec) { + setTime_t(secsSince1Jan1970UTC); + if (spec == Qt::UTC) + *this = toUTC(); + } + static inline QT3_SUPPORT QDateTime currentDateTime(Qt::TimeSpec spec) { + if (spec == Qt::LocalTime) + return currentDateTime(); + else + return currentDateTime().toUTC(); + } + +#endif + +private: + friend class QDateTimePrivate; + void detach(); + QExplicitlySharedDataPointer<QDateTimePrivate> d; + +#ifndef QT_NO_DATASTREAM + friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDateTime &); + friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDateTime &); +#endif +}; +Q_DECLARE_TYPEINFO(QDateTime, Q_MOVABLE_TYPE); + +#ifdef QT3_SUPPORT +inline QDate QDate::currentDate(Qt::TimeSpec spec) +{ + if (spec == Qt::LocalTime) + return currentDate(); + else + return QDateTime::currentDateTime().toUTC().date(); +} + +inline QTime QTime::currentTime(Qt::TimeSpec spec) +{ + if (spec == Qt::LocalTime) + return currentTime(); + else + return QDateTime::currentDateTime().toUTC().time(); +} +#endif + +#ifndef QT_NO_DATASTREAM +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDate &); +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDate &); +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QTime &); +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QTime &); +Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDateTime &); +Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDateTime &); +#endif // QT_NO_DATASTREAM + +#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING) +Q_CORE_EXPORT QDebug operator<<(QDebug, const QDate &); +Q_CORE_EXPORT QDebug operator<<(QDebug, const QTime &); +Q_CORE_EXPORT QDebug operator<<(QDebug, const QDateTime &); +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDATETIME_H diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h new file mode 100644 index 0000000000..ad4055db51 --- /dev/null +++ b/src/corelib/tools/qdatetime_p.h @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +#ifndef QDATETIME_P_H +#define QDATETIME_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qplatformdefs.h" +#include "QtCore/qatomic.h" +#include "QtCore/qdatetime.h" +#include "QtCore/qstringlist.h" +#include "QtCore/qlocale.h" +#ifndef QT_BOOTSTRAPPED +# include "QtCore/qvariant.h" +#endif +#include "QtCore/qvector.h" + + +#define QDATETIMEEDIT_TIME_MIN QTime(0, 0, 0, 0) +#define QDATETIMEEDIT_TIME_MAX QTime(23, 59, 59, 999) +#define QDATETIMEEDIT_DATE_MIN QDate(100, 1, 1) +#define QDATETIMEEDIT_COMPAT_DATE_MIN QDate(1752, 9, 14) +#define QDATETIMEEDIT_DATE_MAX QDate(7999, 12, 31) +#define QDATETIMEEDIT_DATETIME_MIN QDateTime(QDATETIMEEDIT_DATE_MIN, QDATETIMEEDIT_TIME_MIN) +#define QDATETIMEEDIT_COMPAT_DATETIME_MIN QDateTime(QDATETIMEEDIT_COMPAT_DATE_MIN, QDATETIMEEDIT_TIME_MIN) +#define QDATETIMEEDIT_DATETIME_MAX QDateTime(QDATETIMEEDIT_DATE_MAX, QDATETIMEEDIT_TIME_MAX) +#define QDATETIMEEDIT_DATE_INITIAL QDate(2000, 1, 1) + +QT_BEGIN_NAMESPACE + +class QDateTimePrivate +{ +public: + enum Spec { LocalUnknown = -1, LocalStandard = 0, LocalDST = 1, UTC = 2, OffsetFromUTC = 3}; + + QDateTimePrivate() : spec(LocalUnknown), utcOffset(0) {} + QDateTimePrivate(const QDateTimePrivate &other) + : date(other.date), time(other.time), spec(other.spec), utcOffset(other.utcOffset) + {} + + QAtomicInt ref; + QDate date; + QTime time; + Spec spec; + /*! + \internal + \since 4.4 + + The offset in seconds. Applies only when timeSpec() is OffsetFromUTC. + */ + int utcOffset; + + Spec getLocal(QDate &outDate, QTime &outTime) const; + void getUTC(QDate &outDate, QTime &outTime) const; + static QDateTime addMSecs(const QDateTime &dt, qint64 msecs); + static void addMSecs(QDate &utcDate, QTime &utcTime, qint64 msecs); +}; + +#ifndef QT_BOOTSTRAPPED + +class Q_CORE_EXPORT QDateTimeParser +{ +public: + enum Context { + FromString, + DateTimeEdit + }; + QDateTimeParser(QVariant::Type t, Context ctx) + : currentSectionIndex(-1), display(0), cachedDay(-1), parserType(t), + fixday(false), spec(Qt::LocalTime), context(ctx) + { + defaultLocale = QLocale::system(); + first.type = FirstSection; + first.pos = -1; + first.count = -1; + last.type = FirstSection; + last.pos = -1; + last.count = -1; + none.type = NoSection; + none.pos = -1; + none.count = -1; + } + virtual ~QDateTimeParser() {} + enum { + Neither = -1, + AM = 0, + PM = 1, + PossibleAM = 2, + PossiblePM = 3, + PossibleBoth = 4 + }; + + enum Section { + NoSection = 0x00000, + AmPmSection = 0x00001, + MSecSection = 0x00002, + SecondSection = 0x00004, + MinuteSection = 0x00008, + Hour12Section = 0x00010, + Hour24Section = 0x00020, + TimeSectionMask = (AmPmSection|MSecSection|SecondSection|MinuteSection|Hour12Section|Hour24Section), + Internal = 0x10000, + DaySection = 0x00100, + MonthSection = 0x00200, + YearSection = 0x00400, + YearSection2Digits = 0x00800, + DayOfWeekSection = 0x01000, + DateSectionMask = (DaySection|MonthSection|YearSection|YearSection2Digits|DayOfWeekSection), + FirstSection = 0x02000|Internal, + LastSection = 0x04000|Internal, + CalendarPopupSection = 0x08000|Internal, + + NoSectionIndex = -1, + FirstSectionIndex = -2, + LastSectionIndex = -3, + CalendarPopupIndex = -4 + }; // duplicated from qdatetimeedit.h + Q_DECLARE_FLAGS(Sections, Section) + + struct SectionNode { + Section type; + mutable int pos; + int count; + }; + + enum State { // duplicated from QValidator + Invalid, + Intermediate, + Acceptable + }; + + struct StateNode { + StateNode() : state(Invalid), conflicts(false) {} + QString input; + State state; + bool conflicts; + QDateTime value; + }; + + enum AmPm { + AmText, + PmText + }; + + enum Case { + UpperCase, + LowerCase + }; + +#ifndef QT_NO_DATESTRING + StateNode parse(QString &input, int &cursorPosition, const QDateTime ¤tValue, bool fixup) const; +#endif + int sectionMaxSize(int index) const; + int sectionSize(int index) const; + int sectionMaxSize(Section s, int count) const; + int sectionPos(int index) const; + int sectionPos(const SectionNode &sn) const; + + const SectionNode §ionNode(int index) const; + Section sectionType(int index) const; + QString sectionText(int sectionIndex) const; + QString sectionText(const QString &text, int sectionIndex, int index) const; + int getDigit(const QDateTime &dt, int index) const; + bool setDigit(QDateTime &t, int index, int newval) const; + int parseSection(const QDateTime ¤tValue, int sectionIndex, QString &txt, int &cursorPosition, + int index, QDateTimeParser::State &state, int *used = 0) const; + int absoluteMax(int index, const QDateTime &value = QDateTime()) const; + int absoluteMin(int index) const; + bool parseFormat(const QString &format); +#ifndef QT_NO_DATESTRING + bool fromString(const QString &text, QDate *date, QTime *time) const; +#endif + +#ifndef QT_NO_TEXTDATE + int findMonth(const QString &str1, int monthstart, int sectionIndex, + QString *monthName = 0, int *used = 0) const; + int findDay(const QString &str1, int intDaystart, int sectionIndex, + QString *dayName = 0, int *used = 0) const; +#endif + int findAmPm(QString &str1, int index, int *used = 0) const; + int maxChange(int s) const; + bool potentialValue(const QString &str, int min, int max, int index, + const QDateTime ¤tValue, int insert) const; + bool skipToNextSection(int section, const QDateTime ¤t, const QString §ionText) const; + QString sectionName(int s) const; + QString stateName(int s) const; + + QString sectionFormat(int index) const; + QString sectionFormat(Section s, int count) const; + + enum FieldInfoFlag { + Numeric = 0x01, + FixedWidth = 0x02, + AllowPartial = 0x04, + Fraction = 0x08 + }; + Q_DECLARE_FLAGS(FieldInfo, FieldInfoFlag) + + FieldInfo fieldInfo(int index) const; + + virtual QDateTime getMinimum() const; + virtual QDateTime getMaximum() const; + virtual int cursorPosition() const { return -1; } + virtual QString displayText() const { return text; } + virtual QString getAmPmText(AmPm ap, Case cs) const; + virtual QLocale locale() const { return defaultLocale; } + + mutable int currentSectionIndex; + Sections display; + mutable int cachedDay; + mutable QString text; + QVector<SectionNode> sectionNodes; + SectionNode first, last, none, popup; + QStringList separators; + QString displayFormat; + QLocale defaultLocale; + QVariant::Type parserType; + + bool fixday; + + Qt::TimeSpec spec; // spec if used by QDateTimeEdit + Context context; +}; + +Q_CORE_EXPORT bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2); + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::Sections) +Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimeParser::FieldInfo) + +#ifdef Q_OS_SYMBIAN +QDateTime qt_symbian_TTime_To_QDateTime(const TTime& time); +TTime qt_symbian_QDateTime_To_TTime(const QDateTime& datetime); +time_t qt_symbian_TTime_To_time_t(const TTime& time); +TTime qt_symbian_time_t_To_TTime(time_t time); +#endif //Q_OS_SYMBIAN + +#endif // QT_BOOTSTRAPPED + +QT_END_NAMESPACE + +#endif // QDATETIME_P_H diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp new file mode 100644 index 0000000000..7daf95abe1 --- /dev/null +++ b/src/corelib/tools/qeasingcurve.cpp @@ -0,0 +1,937 @@ +/**************************************************************************** +** +** 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 QtCore 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$ +** +****************************************************************************/ + +/* + +| *property* | *Used for type* | +| period | QEasingCurve::{In,Out,InOut,OutIn}Elastic | +| amplitude | QEasingCurve::{In,Out,InOut,OutIn}Bounce, QEasingCurve::{In,Out,InOut,OutIn}Elastic | +| overshoot | QEasingCurve::{In,Out,InOut,OutIn}Back | + +*/ + + + + +/*! + \class QEasingCurve + \since 4.6 + \ingroup animation + \brief The QEasingCurve class provides easing curves for controlling animation. + + Easing curves describe a function that controls how the speed of the interpolation + between 0 and 1 should be. Easing curves allow transitions from + one value to another to appear more natural than a simple constant speed would allow. + The QEasingCurve class is usually used in conjunction with the QVariantAnimation and + QPropertyAnimation classes but can be used on its own. It is usually used to accelerate + the interpolation from zero velocity (ease in) or decelerate to zero velocity (ease out). + Ease in and ease out can also be combined in the same easing curve. + + To calculate the speed of the interpolation, the easing curve provides the function + valueForProgress(), where the \a progress argument specifies the progress of the + interpolation: 0 is the start value of the interpolation, 1 is the end value of the + interpolation. The returned value is the effective progress of the interpolation. + If the returned value is the same as the input value for all input values the easing + curve is a linear curve. This is the default behaviour. + + For example, + \code + QEasingCurve easing(QEasingCurve::InOutQuad); + + for(qreal t = 0.0; t < 1.0; t+=0.1) + qWarning() << "Effective progress" << t << " is + << easing.valueForProgress(t); + \endcode + will print the effective progress of the interpolation between 0 and 1. + + When using a QPropertyAnimation, the associated easing curve will be used to control the + progress of the interpolation between startValue and endValue: + \code + QPropertyAnimation animation; + animation.setStartValue(0); + animation.setEndValue(1000); + animation.setDuration(1000); + animation.setEasingCurve(QEasingCurve::InOutQuad); + \endcode + + The ability to set an amplitude, overshoot, or period depends on + the QEasingCurve type. Amplitude access is available to curves + that behave as springs such as elastic and bounce curves. Changing + the amplitude changes the height of the curve. Period access is + only available to elastic curves and setting a higher period slows + the rate of bounce. Only curves that have "boomerang" behaviors + such as the InBack, OutBack, InOutBack, and OutInBack have + overshoot settings. These curves will interpolate beyond the end + points and return to the end point, acting similar to a boomerang. + + The \l{Easing Curves Example} contains samples of QEasingCurve + types and lets you change the curve settings. + + */ + +/*! + \enum QEasingCurve::Type + + The type of easing curve. + + \value Linear \inlineimage qeasingcurve-linear.png + \br + Easing curve for a linear (t) function: + velocity is constant. + \value InQuad \inlineimage qeasingcurve-inquad.png + \br + Easing curve for a quadratic (t^2) function: + accelerating from zero velocity. + \value OutQuad \inlineimage qeasingcurve-outquad.png + \br + Easing curve for a quadratic (t^2) function: + decelerating to zero velocity. + \value InOutQuad \inlineimage qeasingcurve-inoutquad.png + \br + Easing curve for a quadratic (t^2) function: + acceleration until halfway, then deceleration. + \value OutInQuad \inlineimage qeasingcurve-outinquad.png + \br + Easing curve for a quadratic (t^2) function: + deceleration until halfway, then acceleration. + \value InCubic \inlineimage qeasingcurve-incubic.png + \br + Easing curve for a cubic (t^3) function: + accelerating from zero velocity. + \value OutCubic \inlineimage qeasingcurve-outcubic.png + \br + Easing curve for a cubic (t^3) function: + decelerating to zero velocity. + \value InOutCubic \inlineimage qeasingcurve-inoutcubic.png + \br + Easing curve for a cubic (t^3) function: + acceleration until halfway, then deceleration. + \value OutInCubic \inlineimage qeasingcurve-outincubic.png + \br + Easing curve for a cubic (t^3) function: + deceleration until halfway, then acceleration. + \value InQuart \inlineimage qeasingcurve-inquart.png + \br + Easing curve for a quartic (t^4) function: + accelerating from zero velocity. + \value OutQuart \inlineimage qeasingcurve-outquart.png + \br + Easing curve for a quartic (t^4) function: + decelerating to zero velocity. + \value InOutQuart \inlineimage qeasingcurve-inoutquart.png + \br + Easing curve for a quartic (t^4) function: + acceleration until halfway, then deceleration. + \value OutInQuart \inlineimage qeasingcurve-outinquart.png + \br + Easing curve for a quartic (t^4) function: + deceleration until halfway, then acceleration. + \value InQuint \inlineimage qeasingcurve-inquint.png + \br + Easing curve for a quintic (t^5) easing + in: accelerating from zero velocity. + \value OutQuint \inlineimage qeasingcurve-outquint.png + \br + Easing curve for a quintic (t^5) function: + decelerating to zero velocity. + \value InOutQuint \inlineimage qeasingcurve-inoutquint.png + \br + Easing curve for a quintic (t^5) function: + acceleration until halfway, then deceleration. + \value OutInQuint \inlineimage qeasingcurve-outinquint.png + \br + Easing curve for a quintic (t^5) function: + deceleration until halfway, then acceleration. + \value InSine \inlineimage qeasingcurve-insine.png + \br + Easing curve for a sinusoidal (sin(t)) function: + accelerating from zero velocity. + \value OutSine \inlineimage qeasingcurve-outsine.png + \br + Easing curve for a sinusoidal (sin(t)) function: + decelerating from zero velocity. + \value InOutSine \inlineimage qeasingcurve-inoutsine.png + \br + Easing curve for a sinusoidal (sin(t)) function: + acceleration until halfway, then deceleration. + \value OutInSine \inlineimage qeasingcurve-outinsine.png + \br + Easing curve for a sinusoidal (sin(t)) function: + deceleration until halfway, then acceleration. + \value InExpo \inlineimage qeasingcurve-inexpo.png + \br + Easing curve for an exponential (2^t) function: + accelerating from zero velocity. + \value OutExpo \inlineimage qeasingcurve-outexpo.png + \br + Easing curve for an exponential (2^t) function: + decelerating from zero velocity. + \value InOutExpo \inlineimage qeasingcurve-inoutexpo.png + \br + Easing curve for an exponential (2^t) function: + acceleration until halfway, then deceleration. + \value OutInExpo \inlineimage qeasingcurve-outinexpo.png + \br + Easing curve for an exponential (2^t) function: + deceleration until halfway, then acceleration. + \value InCirc \inlineimage qeasingcurve-incirc.png + \br + Easing curve for a circular (sqrt(1-t^2)) function: + accelerating from zero velocity. + \value OutCirc \inlineimage qeasingcurve-outcirc.png + \br + Easing curve for a circular (sqrt(1-t^2)) function: + decelerating from zero velocity. + \value InOutCirc \inlineimage qeasingcurve-inoutcirc.png + \br + Easing curve for a circular (sqrt(1-t^2)) function: + acceleration until halfway, then deceleration. + \value OutInCirc \inlineimage qeasingcurve-outincirc.png + \br + Easing curve for a circular (sqrt(1-t^2)) function: + deceleration until halfway, then acceleration. + \value InElastic \inlineimage qeasingcurve-inelastic.png + \br + Easing curve for an elastic + (exponentially decaying sine wave) function: + accelerating from zero velocity. The peak amplitude + can be set with the \e amplitude parameter, and the + period of decay by the \e period parameter. + \value OutElastic \inlineimage qeasingcurve-outelastic.png + \br + Easing curve for an elastic + (exponentially decaying sine wave) function: + decelerating from zero velocity. The peak amplitude + can be set with the \e amplitude parameter, and the + period of decay by the \e period parameter. + \value InOutElastic \inlineimage qeasingcurve-inoutelastic.png + \br + Easing curve for an elastic + (exponentially decaying sine wave) function: + acceleration until halfway, then deceleration. + \value OutInElastic \inlineimage qeasingcurve-outinelastic.png + \br + Easing curve for an elastic + (exponentially decaying sine wave) function: + deceleration until halfway, then acceleration. + \value InBack \inlineimage qeasingcurve-inback.png + \br + Easing curve for a back (overshooting + cubic function: (s+1)*t^3 - s*t^2) easing in: + accelerating from zero velocity. + \value OutBack \inlineimage qeasingcurve-outback.png + \br + Easing curve for a back (overshooting + cubic function: (s+1)*t^3 - s*t^2) easing out: + decelerating to zero velocity. + \value InOutBack \inlineimage qeasingcurve-inoutback.png + \br + Easing curve for a back (overshooting + cubic function: (s+1)*t^3 - s*t^2) easing in/out: + acceleration until halfway, then deceleration. + \value OutInBack \inlineimage qeasingcurve-outinback.png + \br + Easing curve for a back (overshooting + cubic easing: (s+1)*t^3 - s*t^2) easing out/in: + deceleration until halfway, then acceleration. + \value InBounce \inlineimage qeasingcurve-inbounce.png + \br + Easing curve for a bounce (exponentially + decaying parabolic bounce) function: accelerating + from zero velocity. + \value OutBounce \inlineimage qeasingcurve-outbounce.png + \br + Easing curve for a bounce (exponentially + decaying parabolic |