diff options
author | Kent Hansen <khansen@trolltech.com> | 2009-07-28 15:32:59 (GMT) |
---|---|---|
committer | Kent Hansen <khansen@trolltech.com> | 2009-07-28 15:32:59 (GMT) |
commit | 14aa95bf83e8fa91151b5edd3c346c20d942eb81 (patch) | |
tree | 46ec6389eb1590e0a018c4acbfba670d315987ba /src/corelib | |
parent | 1c72e77e43593dfea6c6392d1058e63762efb534 (diff) | |
parent | f340825f35ad3de28685f4890cd73bbf9bb6c0e6 (diff) | |
download | Qt-14aa95bf83e8fa91151b5edd3c346c20d942eb81.zip Qt-14aa95bf83e8fa91151b5edd3c346c20d942eb81.tar.gz Qt-14aa95bf83e8fa91151b5edd3c346c20d942eb81.tar.bz2 |
Merge branch 'qtwebkit-4.6-staging' into qtscript-jsc-backend
Conflicts:
src/corelib/tools/qregexp.cpp
src/script/qscriptengine.cpp
src/script/qscriptvalue.cpp
Diffstat (limited to 'src/corelib')
78 files changed, 2968 insertions, 1401 deletions
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 75decf8..ced86d2 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -620,8 +620,8 @@ void QAbstractAnimation::start(DeletionPolicy policy) Q_D(QAbstractAnimation); if (d->state == Running) return; - d->setState(Running); d->deleteWhenStopped = policy; + d->setState(Running); } /*! @@ -643,9 +643,8 @@ void QAbstractAnimation::stop() /*! Pauses the animation. When the animation is paused, state() returns Paused. - The currenttime will remain unchanged until resume() or start() is called. - If you want to continue from the current time, call resume(). - + The value of currentTime will remain unchanged until resume() or start() + is called. If you want to continue from the current time, call resume(). \sa start(), state(), resume() */ diff --git a/src/corelib/animation/qsequentialanimationgroup.cpp b/src/corelib/animation/qsequentialanimationgroup.cpp index 5932e7c..05dc307 100644 --- a/src/corelib/animation/qsequentialanimationgroup.cpp +++ b/src/corelib/animation/qsequentialanimationgroup.cpp @@ -269,8 +269,10 @@ QSequentialAnimationGroup::~QSequentialAnimationGroup() /*! Adds a pause of \a msecs to this animation group. - The pause is considered as a special type of animation, thus count() will be + The pause is considered as a special type of animation, thus + \l{QAnimationGroup::animationCount()}{animationCount} will be increased by one. + \sa insertPauseAt(), QAnimationGroup::addAnimation() */ QPauseAnimation *QSequentialAnimationGroup::addPause(int msecs) diff --git a/src/corelib/arch/qatomic_powerpc.h b/src/corelib/arch/qatomic_powerpc.h index ea3f458..c3b31f9 100644 --- a/src/corelib/arch/qatomic_powerpc.h +++ b/src/corelib/arch/qatomic_powerpc.h @@ -101,8 +101,6 @@ template <typename T> Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() { return false; } -QT_BEGIN_NAMESPACE - #if defined(Q_CC_GNU) #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) \ diff --git a/src/corelib/codecs/qtextcodec.cpp b/src/corelib/codecs/qtextcodec.cpp index c4266a0..f49e34a 100644 --- a/src/corelib/codecs/qtextcodec.cpp +++ b/src/corelib/codecs/qtextcodec.cpp @@ -99,6 +99,10 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QTextCodecFactoryInterface_iid, QLatin1String("/codecs"))) #endif +static char qtolower(register char c) +{ if (c >= 'A' && c <= 'Z') return c + 0x20; return c; } +static bool qisalnum(register char c) +{ return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'z'); } static bool nameMatch(const QByteArray &name, const QByteArray &test) { @@ -111,21 +115,21 @@ static bool nameMatch(const QByteArray &name, const QByteArray &test) // if the letters and numbers are the same, we have a match while (*n != '\0') { - if (isalnum((uchar)*n)) { + if (qisalnum(*n)) { for (;;) { if (*h == '\0') return false; - if (isalnum((uchar)*h)) + if (qisalnum(*h)) break; ++h; } - if (tolower((uchar)*n) != tolower((uchar)*h)) + if (qtolower(*n) != qtolower(*h)) return false; ++h; } ++n; } - while (*h && !isalnum((uchar)*h)) + while (*h && !qisalnum(*h)) ++h; return (*h == '\0'); } @@ -1532,9 +1536,13 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba, QTextCodec *defaultCo } /*! - \overload + \overload - If the codec cannot be detected, this overload returns a Latin-1 QTextCodec. + Tries to detect the encoding of the provided snippet of HTML in + the given byte array, \a ba, by checking the BOM (Byte Order Mark) + and the content-type meta header and returns a QTextCodec instance + that is capable of decoding the html to unicode. If the codec cannot + be detected, this overload returns a Latin-1 QTextCodec. */ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba) { @@ -1546,10 +1554,13 @@ QTextCodec *QTextCodec::codecForHtml(const QByteArray &ba) Tries to detect the encoding of the provided snippet \a ba by using the BOM (Byte Order Mark) and returns a QTextCodec instance - that is capable of decoding the text to unicode. If the codec + that is capable of decoding the text to unicode. If the codec cannot be detected from the content provided, \a defaultCodec is returned. + The behavior of this function is undefined if \a ba is not + encoded in unicode. + \sa codecForHtml() */ QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba, QTextCodec *defaultCodec) @@ -1587,9 +1598,17 @@ QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba, QTextCodec *defaul } /*! - \overload + \overload + + Tries to detect the encoding of the provided snippet \a ba by + using the BOM (Byte Order Mark) and returns a QTextCodec instance + that is capable of decoding the text to unicode. If the codec + cannot be detected, this overload returns a Latin-1 QTextCodec. + + The behavior of this function is undefined if \a ba is not + encoded in unicode. - If the codec cannot be detected, this overload returns a Latin-1 QTextCodec. + \sa codecForHtml() */ QTextCodec *QTextCodec::codecForUtfText(const QByteArray &ba) { diff --git a/src/corelib/codecs/qtextcodec_p.h b/src/corelib/codecs/qtextcodec_p.h index 499c0f9..5c82735 100644 --- a/src/corelib/codecs/qtextcodec_p.h +++ b/src/corelib/codecs/qtextcodec_p.h @@ -77,6 +77,33 @@ struct QTextCodecUnalignedPointer } }; +#else + +class QTextCodec +{ +public: + enum ConversionFlag { + DefaultConversion, + ConvertInvalidToNull = 0x80000000, + IgnoreHeader = 0x1, + FreeFunction = 0x2 + }; + Q_DECLARE_FLAGS(ConversionFlags, ConversionFlag) + + struct ConverterState { + ConverterState(ConversionFlags f = DefaultConversion) + : flags(f), remainingChars(0), invalidChars(0), d(0) { state_data[0] = state_data[1] = state_data[2] = 0; } + ~ConverterState() { } + ConversionFlags flags; + int remainingChars; + int invalidChars; + uint state_data[3]; + void *d; + private: + Q_DISABLE_COPY(ConverterState) + }; +}; + #endif //QT_NO_TEXTCODEC QT_END_NAMESPACE diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp index abae6f7..abcc07c 100644 --- a/src/corelib/codecs/qutfcodec.cpp +++ b/src/corelib/codecs/qutfcodec.cpp @@ -44,23 +44,19 @@ #include "qendian.h" #include "qchar.h" -#ifndef QT_NO_TEXTCODEC - QT_BEGIN_NAMESPACE -QUtf8Codec::~QUtf8Codec() -{ -} +enum { Endian = 0, Data = 1 }; -QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +QByteArray QUtf8::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state) { uchar replacement = '?'; int rlen = 3*len; int surrogate_high = -1; if (state) { - if (state->flags & ConvertInvalidToNull) + if (state->flags & QTextCodec::ConvertInvalidToNull) replacement = 0; - if (!(state->flags & IgnoreHeader)) + if (!(state->flags & QTextCodec::IgnoreHeader)) rlen += 3; if (state->remainingChars) surrogate_high = state->state_data[0]; @@ -71,7 +67,7 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta uchar* cursor = (uchar*)rstr.data(); const QChar *ch = uc; int invalid = 0; - if (state && !(state->flags & IgnoreHeader)) { + if (state && !(state->flags & QTextCodec::IgnoreHeader)) { *cursor++ = 0xef; *cursor++ = 0xbb; *cursor++ = 0xbf; @@ -133,7 +129,7 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta rstr.resize(cursor - (const uchar*)rstr.constData()); if (state) { state->invalidChars += invalid; - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->remainingChars = 0; if (surrogate_high >= 0) { state->remainingChars = 1; @@ -143,18 +139,18 @@ QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterSta return rstr; } -void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const +QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state) { bool headerdone = false; - QChar replacement = QChar::ReplacementCharacter; + ushort replacement = QChar::ReplacementCharacter; int need = 0; int error = -1; uint uc = 0; uint min_uc = 0; if (state) { - if (state->flags & IgnoreHeader) + if (state->flags & QTextCodec::IgnoreHeader) headerdone = true; - if (state->flags & ConvertInvalidToNull) + if (state->flags & QTextCodec::ConvertInvalidToNull) replacement = QChar::Null; need = state->remainingChars; if (need) { @@ -170,40 +166,28 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C headerdone = true; } - int originalLength = target->length(); - QString &result = *target; - result.resize(originalLength + len + 1); // worst case - QChar *qch = result.data() + originalLength; + QString result(need + len + 1, Qt::Uninitialized); // worst case + ushort *qch = (ushort *)result.unicode(); uchar ch; int invalid = 0; - for (int i=0; i<len; i++) { + for (int i = 0; i < len; ++i) { ch = chars[i]; if (need) { if ((ch&0xc0) == 0x80) { uc = (uc << 6) | (ch & 0x3f); - need--; + --need; if (!need) { // utf-8 bom composes into 0xfeff code point if (!headerdone && uc == 0xfeff) { // dont do anything, just skip the BOM } else if (uc > 0xffff && uc < 0x110000) { // surrogate pair - uc -= 0x10000; - unsigned short high = uc/0x400 + 0xd800; - unsigned short low = uc%0x400 + 0xdc00; - - // resize if necessary - long where = qch - result.unicode(); - if (where + 2 >= result.length()) { - result.resize(where + 2); - qch = result.data() + where; - } - - *qch++ = QChar(high); - *qch++ = QChar(low); + Q_ASSERT((qch - (ushort*)result.unicode()) + 2 < result.length()); + *qch++ = QChar::highSurrogate(uc); + *qch++ = QChar::lowSurrogate(uc); } else if ((uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff) || (uc >= 0xfffe)) { - // error + // error: overlong sequence, UTF16 surrogate or BOM *qch++ = replacement; ++invalid; } else { @@ -221,7 +205,7 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C } } else { if (ch < 128) { - *qch++ = QLatin1Char(ch); + *qch++ = ushort(ch); headerdone = true; } else if ((ch & 0xe0) == 0xc0) { uc = ch & 0x1f; @@ -255,57 +239,35 @@ void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, C ++invalid; } } - result.truncate(qch - result.unicode()); + result.truncate(qch - (ushort *)result.unicode()); if (state) { state->invalidChars += invalid; state->remainingChars = need; if (headerdone) - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->state_data[0] = need ? uc : 0; state->state_data[1] = need ? min_uc : 0; } -} - -QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const -{ - QString result; - convertToUnicode(&result, chars, len, state); return result; } -QByteArray QUtf8Codec::name() const -{ - return "UTF-8"; -} - -int QUtf8Codec::mibEnum() const -{ - return 106; -} - -enum { Endian = 0, Data = 1 }; - -QUtf16Codec::~QUtf16Codec() -{ -} - -QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +QByteArray QUtf16::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; int length = 2*len; - if (!state || (!(state->flags & IgnoreHeader))) { + if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) { length += 2; } - if (e == Detect) { - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (e == DetectEndianness) { + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; } QByteArray d; d.resize(length); char *data = d.data(); - if (!state || !(state->flags & IgnoreHeader)) { + if (!state || !(state->flags & QTextCodec::IgnoreHeader)) { QChar bom(QChar::ByteOrderMark); - if (endian == BE) { + if (endian == BigEndianness) { data[0] = bom.row(); data[1] = bom.cell(); } else { @@ -314,7 +276,7 @@ QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt } data += 2; } - if (endian == BE) { + if (endian == BigEndianness) { for (int i = 0; i < len; ++i) { *(data++) = uc[i].row(); *(data++) = uc[i].cell(); @@ -328,35 +290,35 @@ QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt if (state) { state->remainingChars = 0; - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; } return d; } -QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +QString QUtf16::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; bool half = false; uchar buf = 0; bool headerdone = false; if (state) { - headerdone = state->flags & IgnoreHeader; - if (endian == Detect) - endian = (Endianness)state->state_data[Endian]; + headerdone = state->flags & QTextCodec::IgnoreHeader; + if (endian == DetectEndianness) + endian = (DataEndianness)state->state_data[Endian]; if (state->remainingChars) { half = true; buf = state->state_data[Data]; } } - if (headerdone && endian == Detect) - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (headerdone && endian == DetectEndianness) + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; QString result(len, Qt::Uninitialized); // worst case QChar *qch = (QChar *)result.unicode(); while (len--) { if (half) { QChar ch; - if (endian == LE) { + if (endian == LittleEndianness) { ch.setRow(*chars++); ch.setCell(buf); } else { @@ -364,17 +326,17 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState ch.setCell(*chars++); } if (!headerdone) { - if (endian == Detect) { - if (ch == QChar::ByteOrderSwapped && endian != BE) { - endian = LE; - } else if (ch == QChar::ByteOrderMark && endian != LE) { + if (endian == DetectEndianness) { + if (ch == QChar::ByteOrderSwapped && endian != BigEndianness) { + endian = LittleEndianness; + } else if (ch == QChar::ByteOrderMark && endian != LittleEndianness) { // ignore BOM - endian = BE; + endian = BigEndianness; } else { if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - endian = BE; + endian = BigEndianness; } else { - endian = LE; + endian = LittleEndianness; ch = QChar((ch.unicode() >> 8) | ((ch.unicode() & 0xff) << 8)); } *qch++ = ch; @@ -396,7 +358,7 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState if (state) { if (headerdone) - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->state_data[Endian] = endian; if (half) { state->remainingChars = 1; @@ -409,72 +371,21 @@ QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState return result; } -int QUtf16Codec::mibEnum() const -{ - return 1015; -} - -QByteArray QUtf16Codec::name() const -{ - return "UTF-16"; -} - -QList<QByteArray> QUtf16Codec::aliases() const -{ - return QList<QByteArray>(); -} - -int QUtf16BECodec::mibEnum() const -{ - return 1013; -} - -QByteArray QUtf16BECodec::name() const -{ - return "UTF-16BE"; -} - -QList<QByteArray> QUtf16BECodec::aliases() const -{ - QList<QByteArray> list; - return list; -} - -int QUtf16LECodec::mibEnum() const -{ - return 1014; -} - -QByteArray QUtf16LECodec::name() const -{ - return "UTF-16LE"; -} - -QList<QByteArray> QUtf16LECodec::aliases() const -{ - QList<QByteArray> list; - return list; -} - -QUtf32Codec::~QUtf32Codec() -{ -} - -QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +QByteArray QUtf32::convertFromUnicode(const QChar *uc, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; int length = 4*len; - if (!state || (!(state->flags & IgnoreHeader))) { + if (!state || (!(state->flags & QTextCodec::IgnoreHeader))) { length += 4; } - if (e == Detect) { - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (e == DetectEndianness) { + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; } QByteArray d(length, Qt::Uninitialized); char *data = d.data(); - if (!state || !(state->flags & IgnoreHeader)) { - if (endian == BE) { + if (!state || !(state->flags & QTextCodec::IgnoreHeader)) { + if (endian == BigEndianness) { data[0] = 0; data[1] = 0; data[2] = (char)0xfe; @@ -487,7 +398,7 @@ QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt } data += 4; } - if (endian == BE) { + if (endian == BigEndianness) { for (int i = 0; i < len; ++i) { uint cp = uc[i].unicode(); if (uc[i].isHighSurrogate() && i < len - 1) @@ -511,59 +422,59 @@ QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterSt if (state) { state->remainingChars = 0; - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; } return d; } -QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +QString QUtf32::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state, DataEndianness e) { - Endianness endian = e; + DataEndianness endian = e; uchar tuple[4]; int num = 0; bool headerdone = false; if (state) { - headerdone = state->flags & IgnoreHeader; - if (endian == Detect) { - endian = (Endianness)state->state_data[Endian]; + headerdone = state->flags & QTextCodec::IgnoreHeader; + if (endian == DetectEndianness) { + endian = (DataEndianness)state->state_data[Endian]; } num = state->remainingChars; memcpy(tuple, &state->state_data[Data], 4); } - if (headerdone && endian == Detect) - endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BE : LE; + if (headerdone && endian == DetectEndianness) + endian = (QSysInfo::ByteOrder == QSysInfo::BigEndian) ? BigEndianness : LittleEndianness; QString result; result.resize((num + len) >> 2 << 1); // worst case QChar *qch = (QChar *)result.unicode(); - + const char *end = chars + len; while (chars < end) { tuple[num++] = *chars++; if (num == 4) { if (!headerdone) { - if (endian == Detect) { - if (endian == Detect) { - if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BE) { - endian = LE; + if (endian == DetectEndianness) { + if (endian == DetectEndianness) { + if (tuple[0] == 0xff && tuple[1] == 0xfe && tuple[2] == 0 && tuple[3] == 0 && endian != BigEndianness) { + endian = LittleEndianness; num = 0; continue; - } else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LE) { - endian = BE; + } else if (tuple[0] == 0 && tuple[1] == 0 && tuple[2] == 0xfe && tuple[3] == 0xff && endian != LittleEndianness) { + endian = BigEndianness; num = 0; continue; } else if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - endian = BE; + endian = BigEndianness; } else { - endian = LE; + endian = LittleEndianness; } } - } else if (((endian == BE) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple)) == QChar::ByteOrderMark) { + } else if (((endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple)) == QChar::ByteOrderMark) { num = 0; continue; } } - uint code = (endian == BE) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple); + uint code = (endian == BigEndianness) ? qFromBigEndian<quint32>(tuple) : qFromLittleEndian<quint32>(tuple); if (code >= 0x10000) { *qch++ = QChar::highSurrogate(code); *qch++ = QChar::lowSurrogate(code); @@ -574,10 +485,10 @@ QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState } } result.truncate(qch - result.unicode()); - + if (state) { if (headerdone) - state->flags |= IgnoreHeader; + state->flags |= QTextCodec::IgnoreHeader; state->state_data[Endian] = endian; state->remainingChars = num; memcpy(&state->state_data[Data], tuple, 4); @@ -585,6 +496,113 @@ QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState return result; } + +#ifndef QT_NO_TEXTCODEC + +QUtf8Codec::~QUtf8Codec() +{ +} + +QByteArray QUtf8Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf8::convertFromUnicode(uc, len, state); +} + +void QUtf8Codec::convertToUnicode(QString *target, const char *chars, int len, ConverterState *state) const +{ + *target += QUtf8::convertToUnicode(chars, len, state); +} + +QString QUtf8Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf8::convertToUnicode(chars, len, state); +} + +QByteArray QUtf8Codec::name() const +{ + return "UTF-8"; +} + +int QUtf8Codec::mibEnum() const +{ + return 106; +} + +QUtf16Codec::~QUtf16Codec() +{ +} + +QByteArray QUtf16Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf16::convertFromUnicode(uc, len, state, e); +} + +QString QUtf16Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf16::convertToUnicode(chars, len, state, e); +} + +int QUtf16Codec::mibEnum() const +{ + return 1015; +} + +QByteArray QUtf16Codec::name() const +{ + return "UTF-16"; +} + +QList<QByteArray> QUtf16Codec::aliases() const +{ + return QList<QByteArray>(); +} + +int QUtf16BECodec::mibEnum() const +{ + return 1013; +} + +QByteArray QUtf16BECodec::name() const +{ + return "UTF-16BE"; +} + +QList<QByteArray> QUtf16BECodec::aliases() const +{ + QList<QByteArray> list; + return list; +} + +int QUtf16LECodec::mibEnum() const +{ + return 1014; +} + +QByteArray QUtf16LECodec::name() const +{ + return "UTF-16LE"; +} + +QList<QByteArray> QUtf16LECodec::aliases() const +{ + QList<QByteArray> list; + return list; +} + +QUtf32Codec::~QUtf32Codec() +{ +} + +QByteArray QUtf32Codec::convertFromUnicode(const QChar *uc, int len, ConverterState *state) const +{ + return QUtf32::convertFromUnicode(uc, len, state, e); +} + +QString QUtf32Codec::convertToUnicode(const char *chars, int len, ConverterState *state) const +{ + return QUtf32::convertToUnicode(chars, len, state, e); +} + int QUtf32Codec::mibEnum() const { return 1017; @@ -633,7 +651,6 @@ QList<QByteArray> QUtf32LECodec::aliases() const return list; } +#endif //QT_NO_TEXTCODEC QT_END_NAMESPACE - -#endif //QT_NO_TEXTCODEC diff --git a/src/corelib/codecs/qutfcodec_p.h b/src/corelib/codecs/qutfcodec_p.h index 749f5be..4f8f92e 100644 --- a/src/corelib/codecs/qutfcodec_p.h +++ b/src/corelib/codecs/qutfcodec_p.h @@ -54,9 +54,35 @@ // #include "QtCore/qtextcodec.h" +#include "private/qtextcodec_p.h" QT_BEGIN_NAMESPACE +enum DataEndianness +{ + DetectEndianness, + BigEndianness, + LittleEndianness +}; + +struct QUtf8 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *); +}; + +struct QUtf16 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); +}; + +struct QUtf32 +{ + static QString convertToUnicode(const char *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); + static QByteArray convertFromUnicode(const QChar *, int, QTextCodec::ConverterState *, DataEndianness = DetectEndianness); +}; + #ifndef QT_NO_TEXTCODEC class QUtf8Codec : public QTextCodec { @@ -73,13 +99,8 @@ public: class QUtf16Codec : public QTextCodec { protected: - enum Endianness { - Detect, - BE, - LE - }; public: - QUtf16Codec() { e = Detect; } + QUtf16Codec() { e = DetectEndianness; } ~QUtf16Codec(); QByteArray name() const; @@ -90,12 +111,12 @@ public: QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; protected: - Endianness e; + DataEndianness e; }; class QUtf16BECodec : public QUtf16Codec { public: - QUtf16BECodec() : QUtf16Codec() { e = BE; } + QUtf16BECodec() : QUtf16Codec() { e = BigEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; @@ -103,21 +124,15 @@ public: class QUtf16LECodec : public QUtf16Codec { public: - QUtf16LECodec() : QUtf16Codec() { e = LE; } + QUtf16LECodec() : QUtf16Codec() { e = LittleEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; }; class QUtf32Codec : public QTextCodec { -protected: - enum Endianness { - Detect, - BE, - LE - }; public: - QUtf32Codec() { e = Detect; } + QUtf32Codec() { e = DetectEndianness; } ~QUtf32Codec(); QByteArray name() const; @@ -128,12 +143,12 @@ public: QByteArray convertFromUnicode(const QChar *, int, ConverterState *) const; protected: - Endianness e; + DataEndianness e; }; class QUtf32BECodec : public QUtf32Codec { public: - QUtf32BECodec() : QUtf32Codec() { e = BE; } + QUtf32BECodec() : QUtf32Codec() { e = BigEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; @@ -141,7 +156,7 @@ public: class QUtf32LECodec : public QUtf32Codec { public: - QUtf32LECodec() : QUtf32Codec() { e = LE; } + QUtf32LECodec() : QUtf32Codec() { e = LittleEndianness; } QByteArray name() const; QList<QByteArray> aliases() const; int mibEnum() const; diff --git a/src/corelib/concurrent/qfuture.h b/src/corelib/concurrent/qfuture.h index 47015ee..f2db5ac 100644 --- a/src/corelib/concurrent/qfuture.h +++ b/src/corelib/concurrent/qfuture.h @@ -210,7 +210,7 @@ public: bool operator==(const QFuture &other) const { return (d == other.d); } bool operator!=(const QFuture &other) const { return (d != other.d); } -#ifndef QT_NO_MEMBER_TEMPLATES +#if !defined(QT_NO_MEMBER_TEMPLATES) && !defined(Q_CC_XLC) template <typename T> QFuture(const QFuture<T> &other) : d(other.d) diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp index a26cc07..ee1ed3a 100644 --- a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp @@ -42,20 +42,14 @@ #include "qtconcurrentiteratekernel.h" #if defined(Q_OS_MAC) - #include <mach/mach.h> #include <mach/mach_time.h> #include <unistd.h> - #elif defined(Q_OS_UNIX) - #include <time.h> #include <unistd.h> - #elif defined(Q_OS_WIN) - -#include <windows.h> - +#include <qt_windows.h> #endif diff --git a/src/corelib/concurrent/qtconcurrentthreadengine.h b/src/corelib/concurrent/qtconcurrentthreadengine.h index 1f359fc..2f610de 100644 --- a/src/corelib/concurrent/qtconcurrentthreadengine.h +++ b/src/corelib/concurrent/qtconcurrentthreadengine.h @@ -238,9 +238,11 @@ protected: template <typename T> class ThreadEngineStarter : public ThreadEngineStarterBase<T> { + typedef ThreadEngineStarterBase<T> Base; + typedef ThreadEngine<T> TypedThreadEngine; public: - ThreadEngineStarter(ThreadEngine<T> *threadEngine) - :ThreadEngineStarterBase<T>(threadEngine) {} + ThreadEngineStarter(TypedThreadEngine *eng) + : Base(eng) { } T startBlocking() { diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index ad4868d..f7d6514 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1668,7 +1668,7 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() winver = QSysInfo::WV_WINDOWS7; } else { qWarning("Qt: Untested Windows version %d.%d detected!", - osver.dwMajorVersion, osver.dwMinorVersion); + int(osver.dwMajorVersion), int(osver.dwMinorVersion)); winver = QSysInfo::WV_NT_based; } } diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index d6c708c..4ceabee 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -319,10 +319,6 @@ namespace QT_NAMESPACE {} # endif #endif -#ifdef QT_MAC_USE_COCOA -#define QT_MAC_NO_QUICKDRAW 1 -#endif - #ifdef __LSB_VERSION__ # if __LSB_VERSION__ < 40 # error "This version of the Linux Standard Base is unsupported" @@ -657,15 +653,17 @@ namespace QT_NAMESPACE {} in which case _BOOL is not defined this is the default in 4.2 compatibility mode triggered by -compat=4 */ # if __SUNPRO_CC >= 0x500 -# if __SUNPRO_CC < 0x570 -# define QT_NO_TEMPLATE_TEMPLATE_PARAMETERS -# endif +# define QT_NO_TEMPLATE_TEMPLATE_PARAMETERS /* see http://developers.sun.com/sunstudio/support/Ccompare.html */ # if __SUNPRO_CC >= 0x590 # define Q_ALIGNOF(type) __alignof__(type) # define Q_TYPEOF(expr) __typeof__(expr) # define Q_DECL_ALIGN(n) __attribute__((__aligned__(n))) -# define Q_DECL_EXPORT __attribute__((__visibility__("default"))) +// using CC 5.9: Warning: attribute visibility is unsupported and will be skipped.. +//# define Q_DECL_EXPORT __attribute__((__visibility__("default"))) +# endif +# if __SUNPRO_CC < 0x5a0 +# define Q_NO_TEMPLATE_FRIENDS # endif # if !defined(_BOOL) # define Q_NO_BOOL_TYPE @@ -705,7 +703,7 @@ namespace QT_NAMESPACE {} # define Q_DECL_ALIGNED(n) __attribute__((aligned(n))) # endif # if __HP_aCC-0 >= 062000 -# define Q_DECL_EXPORT __attribute__((visibility("default")) +# define Q_DECL_EXPORT __attribute__((visibility("default"))) # define Q_DECL_IMPORT Q_DECL_EXPORT # endif # else @@ -2407,28 +2405,15 @@ QT_LICENSED_MODULE(DBus) # define QT_NO_QFUTURE #endif -/* - Turn off certain features for compilers that have problems parsing - the code. -*/ -#if (defined(Q_CC_HPACC) && defined(QT_ARCH_PARISC)) \ - || defined(Q_CC_MIPS) \ - || defined(Q_CC_XLC) -// HP aCC A.03.*, MIPSpro, and xlC cannot handle -// the template function declarations for the QtConcurrent functions -# define QT_NO_QFUTURE -# define QT_NO_CONCURRENT -#endif - -// MSVC 6.0, MSVC .NET 2002, and old versions of Sun CC can`t handle the map(), etc templates, +// MSVC 6.0 and MSVC .NET 2002, can`t handle the map(), etc templates, // but the QFuture class compiles. -#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300) || (defined (__SUNPRO_CC) && __SUNPRO_CC <= 0x590) +#if (defined(Q_CC_MSVC) && _MSC_VER <= 1300) # define QT_NO_CONCURRENT #endif -// Mingw uses a gcc 3 version which has problems with some of the -// map/filter overloads. So does IRIX and Solaris. -#if (defined(Q_OS_IRIX) || defined(Q_CC_MINGW) || defined (Q_OS_SOLARIS)) && (__GNUC__ < 4) +// gcc 3 version has problems with some of the +// map/filter overloads. +#if defined(Q_CC_GNU) && (__GNUC__ < 4) # define QT_NO_CONCURRENT_MAP # define QT_NO_CONCURRENT_FILTER #endif diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index e0584e5..7770fd6 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1410,7 +1410,8 @@ public: ToolButtonIconOnly, ToolButtonTextOnly, ToolButtonTextBesideIcon, - ToolButtonTextUnderIcon + ToolButtonTextUnderIcon, + ToolButtonFollowStyle }; enum LayoutDirection { diff --git a/src/corelib/global/qt_windows.h b/src/corelib/global/qt_windows.h index 4f2bcf6..fc7d75e 100644 --- a/src/corelib/global/qt_windows.h +++ b/src/corelib/global/qt_windows.h @@ -53,6 +53,13 @@ #endif #endif +#if defined(Q_CC_MINGW) +// mingw's windows.h does not set _WIN32_WINNT, resulting breaking compilation +#ifndef WINVER +#define WINVER 0x500 +#endif +#endif + #include <windows.h> #ifdef _WIN32_WCE diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 5033b21..bd41f5e 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -65,7 +65,10 @@ win32 { SOURCES += io/qfsfileengine_unix.cpp SOURCES += io/qfsfileengine_iterator_unix.cpp SOURCES += io/qprocess_unix.cpp - mac:SOURCES += io/qsettings_mac.cpp + macx-*: { + HEADERS += io/qfilesystemwatcher_fsevents_p.h + SOURCES += io/qsettings_mac.cpp io/qfilesystemwatcher_fsevents.cpp + } linux-*:{ SOURCES += \ diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp index 93097bc..9eb3305 100644 --- a/src/corelib/io/qabstractfileengine.cpp +++ b/src/corelib/io/qabstractfileengine.cpp @@ -42,7 +42,7 @@ #include "qabstractfileengine.h" #include "private/qabstractfileengine_p.h" #include "qdatetime.h" -#include "qmutex.h" +#include "qreadwritelock.h" #include "qvariant.h" // built-in handlers #include "qfsfileengine.h" @@ -98,14 +98,14 @@ QT_BEGIN_NAMESPACE All application-wide handlers are stored in this list. The mutex must be acquired to ensure thread safety. */ -Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fileEngineHandlerMutex, (QMutex::Recursive)) +Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, fileEngineHandlerMutex, (QReadWriteLock::Recursive)) static bool qt_abstractfileenginehandlerlist_shutDown = false; class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *> { public: ~QAbstractFileEngineHandlerList() { - QMutexLocker locker(fileEngineHandlerMutex()); + QWriteLocker locker(fileEngineHandlerMutex()); qt_abstractfileenginehandlerlist_shutDown = true; } }; @@ -122,7 +122,7 @@ Q_GLOBAL_STATIC(QAbstractFileEngineHandlerList, fileEngineHandlers) */ QAbstractFileEngineHandler::QAbstractFileEngineHandler() { - QMutexLocker locker(fileEngineHandlerMutex()); + QWriteLocker locker(fileEngineHandlerMutex()); fileEngineHandlers()->prepend(this); } @@ -132,7 +132,7 @@ QAbstractFileEngineHandler::QAbstractFileEngineHandler() */ QAbstractFileEngineHandler::~QAbstractFileEngineHandler() { - QMutexLocker locker(fileEngineHandlerMutex()); + QWriteLocker locker(fileEngineHandlerMutex()); // Remove this handler from the handler list only if the list is valid. if (!qt_abstractfileenginehandlerlist_shutDown) fileEngineHandlers()->removeAll(this); @@ -166,12 +166,14 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler() */ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName) { - QMutexLocker locker(fileEngineHandlerMutex()); + { + QReadLocker locker(fileEngineHandlerMutex()); - // check for registered handlers that can load the file - for (int i = 0; i < fileEngineHandlers()->size(); i++) { - if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName)) - return ret; + // check for registered handlers that can load the file + for (int i = 0; i < fileEngineHandlers()->size(); i++) { + if (QAbstractFileEngine *ret = fileEngineHandlers()->at(i)->create(fileName)) + return ret; + } } #ifdef QT_BUILD_CORE_LIB diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 244299c..1023868 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -362,17 +362,19 @@ QDataStream::~QDataStream() /*! \fn QIODevice *QDataStream::device() const - Returns the I/O device currently set. + Returns the I/O device currently set, or 0 if no + device is currently set. - \sa setDevice(), unsetDevice() + \sa setDevice() */ /*! void QDataStream::setDevice(QIODevice *d) - Sets the I/O device to \a d. + Sets the I/O device to \a d, which can be 0 + to unset to current I/O device. - \sa device(), unsetDevice() + \sa device() */ void QDataStream::setDevice(QIODevice *d) diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index 582d657..30d2558 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -106,26 +106,29 @@ public: QDir::Filters filters, QDirIterator::IteratorFlags flags); ~QDirIteratorPrivate(); - void pushSubDirectory(const QString &path, const QStringList &nameFilters, - QDir::Filters filters); void advance(); - bool shouldFollowDirectory(const QFileInfo &); + + void pushDirectory(const QFileInfo &fileInfo); + void checkAndPushDirectory(const QFileInfo &); bool matchesFilters(const QString &fileName, const QFileInfo &fi) const; - QSet<QString> visitedLinks; - QAbstractFileEngine *engine; + QAbstractFileEngine * const engine; + + const QString path; + const QStringList nameFilters; + const QDir::Filters filters; + const QDirIterator::IteratorFlags iteratorFlags; + +#ifndef QT_NO_REGEXP + QVector<QRegExp> nameRegExps; +#endif + QStack<QAbstractFileEngineIterator *> fileEngineIterators; - QString path; - QFileInfo nextFileInfo; - //This fileinfo is the current that we will return from the public API QFileInfo currentFileInfo; - QString currentFilePath; - QDirIterator::IteratorFlags iteratorFlags; - QDir::Filters filters; - QStringList nameFilters; - bool followNextDir; - bool first; - bool done; + QFileInfo nextFileInfo; + + // Loop protection + QSet<QString> visitedLinks; QDirIterator *q; }; @@ -135,15 +138,24 @@ public: */ QDirIteratorPrivate::QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, QDir::Filters filters, QDirIterator::IteratorFlags flags) - : engine(0), path(path), nextFileInfo(path), iteratorFlags(flags), followNextDir(false), first(true), done(false) + : engine(QAbstractFileEngine::create(path)) + , path(path) + , nameFilters(nameFilters.contains(QLatin1String("*")) ? QStringList() : nameFilters) + , filters(QDir::NoFilter == filters ? QDir::AllEntries : filters) + , iteratorFlags(flags) { - if (filters == QDir::NoFilter) - filters = QDir::AllEntries; - this->filters = filters; - this->nameFilters = nameFilters; +#ifndef QT_NO_REGEXP + nameRegExps.reserve(nameFilters.size()); + for (int i = 0; i < nameFilters.size(); ++i) + nameRegExps.append( + QRegExp(nameFilters.at(i), + (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive, + QRegExp::Wildcard)); +#endif - pushSubDirectory(nextFileInfo.isSymLink() ? nextFileInfo.canonicalFilePath() : path, - nameFilters, filters); + // Populate fields for hasNext() and next() + pushDirectory(QFileInfo(path)); + advance(); } /*! @@ -157,20 +169,19 @@ QDirIteratorPrivate::~QDirIteratorPrivate() /*! \internal */ -void QDirIteratorPrivate::pushSubDirectory(const QString &path, const QStringList &nameFilters, - QDir::Filters filters) +void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo) { - if (iteratorFlags & QDirIterator::FollowSymlinks) { - if (nextFileInfo.filePath() != path) - nextFileInfo.setFile(path); - if (nextFileInfo.isSymLink()) { - visitedLinks << nextFileInfo.canonicalFilePath(); - } else { - visitedLinks << nextFileInfo.absoluteFilePath(); - } - } - - if (engine || (engine = QAbstractFileEngine::create(this->path))) { + QString path = fileInfo.filePath(); + +#ifdef Q_OS_WIN + if (fileInfo.isSymLink()) + path = fileInfo.canonicalFilePath(); +#endif + + if (iteratorFlags & QDirIterator::FollowSymlinks) + visitedLinks << fileInfo.canonicalFilePath(); + + if (engine) { engine->setFileName(path); QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters); if (it) { @@ -187,95 +198,64 @@ void QDirIteratorPrivate::pushSubDirectory(const QString &path, const QStringLis */ void QDirIteratorPrivate::advance() { - // Store the current entry - if (!fileEngineIterators.isEmpty()) - currentFilePath = fileEngineIterators.top()->currentFilePath(); - - // Advance to the next entry - if (followNextDir) { - // Start by navigating into the current directory. - followNextDir = false; - - QAbstractFileEngineIterator *it = fileEngineIterators.top(); - - QString subDir = it->currentFilePath(); -#ifdef Q_OS_WIN - if (nextFileInfo.isSymLink()) - subDir = nextFileInfo.canonicalFilePath(); -#endif - pushSubDirectory(subDir, it->nameFilters(), it->filters()); - } - while (!fileEngineIterators.isEmpty()) { - QAbstractFileEngineIterator *it = fileEngineIterators.top(); // Find the next valid iterator that matches the filters. - bool foundDirectory = false; - while (it->hasNext()) { + while (fileEngineIterators.top()->hasNext()) { + QAbstractFileEngineIterator *it = fileEngineIterators.top(); it->next(); + const QFileInfo info = it->currentFileInfo(); + checkAndPushDirectory(it->currentFileInfo()); + if (matchesFilters(it->currentFileName(), info)) { currentFileInfo = nextFileInfo; nextFileInfo = info; - // Signal that we want to follow this entry. - followNextDir = shouldFollowDirectory(nextFileInfo); + //We found a matching entry. return; - - } else if (iteratorFlags & QDirIterator::Subdirectories) { - - if (!shouldFollowDirectory(info)) - continue; - QString subDir = it->currentFilePath(); -#ifdef Q_OS_WIN - if (info.isSymLink()) - subDir = info.canonicalFilePath(); -#endif - pushSubDirectory(subDir, it->nameFilters(), it->filters()); - - foundDirectory = true; - break; } } - if (!foundDirectory) - delete fileEngineIterators.pop(); + + delete fileEngineIterators.pop(); } + currentFileInfo = nextFileInfo; - done = true; + nextFileInfo = QFileInfo(); } /*! \internal */ -bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo) +void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo) { // If we're doing flat iteration, we're done. if (!(iteratorFlags & QDirIterator::Subdirectories)) - return false; - + return; + // Never follow non-directory entries if (!fileInfo.isDir()) - return false; + return; + // Follow symlinks only when asked + if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink()) + return; // Never follow . and .. - if (fileInfo.fileName() == QLatin1String(".") || fileInfo.fileName() == QLatin1String("..")) - return false; + QString fileName = fileInfo.fileName(); + if (QLatin1String(".") == fileName || QLatin1String("..") == fileName) + return; - - // Check symlinks - if (fileInfo.isSymLink() && !(iteratorFlags & QDirIterator::FollowSymlinks)) { - // Follow symlinks only if FollowSymlinks was passed - return false; - } + // No hidden directories unless requested + if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden()) + return; // Stop link loops if (visitedLinks.contains(fileInfo.canonicalFilePath())) - return false; - - return true; + return; + + pushDirectory(fileInfo); } - /*! \internal @@ -289,10 +269,7 @@ bool QDirIteratorPrivate::shouldFollowDirectory(const QFileInfo &fileInfo) */ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const { - if (fileName.isEmpty()) { - // invalid entry - return false; - } + Q_ASSERT(!fileName.isEmpty()); // filter . and ..? const int fileNameSize = fileName.size(); @@ -303,16 +280,15 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf return false; // name filter -#ifndef QT_NO_REGEXP - const bool hasNameFilters = !nameFilters.isEmpty() && !(nameFilters.contains(QLatin1String("*"))); +#ifndef QT_NO_REGEXP // Pass all entries through name filters, except dirs if the AllDirs - if (hasNameFilters && !((filters & QDir::AllDirs) && fi.isDir())) { + if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) { bool matched = false; - for (int i = 0; i < nameFilters.size(); ++i) { - QRegExp regexp(nameFilters.at(i), - (filters & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive, - QRegExp::Wildcard); - if (regexp.exactMatch(fileName)) { + for (QVector<QRegExp>::const_iterator iter = nameRegExps.constBegin(), + end = nameRegExps.constEnd(); + iter != end; ++iter) { + + if (iter->exactMatch(fileName)) { matched = true; break; } @@ -333,17 +309,11 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf || (!fi.exists() && fi.isSymLink()))) return false; - - if (!includeSystem && !dotOrDotDot && ((fi.exists() && !fi.isFile() && !fi.isDir() && !fi.isSymLink()) - || (!fi.exists() && fi.isSymLink()))) { - return false; - } - // skip directories const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs)); if (skipDirs && fi.isDir()) { - if (!(includeHidden && !dotOrDotDot && fi.isHidden()) - || (includeSystem && !fi.exists() && fi.isSymLink())) + if (!((includeHidden && !dotOrDotDot && fi.isHidden()) + || (includeSystem && !fi.exists() && fi.isSymLink()))) return false; } @@ -368,7 +338,7 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf || (doExecutable && !fi.isExecutable()))) { return false; } - + return true; } @@ -410,7 +380,7 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags) \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), filters, flags)) + : d(new QDirIteratorPrivate(path, QStringList(), filters, flags)) { d->q = this; } @@ -428,7 +398,7 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF \sa hasNext(), next(), IteratorFlags */ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) - : d(new QDirIteratorPrivate(path, QStringList(QLatin1String("*")), QDir::NoFilter, flags)) + : d(new QDirIteratorPrivate(path, QStringList(), QDir::NoFilter, flags)) { d->q = this; } @@ -445,7 +415,7 @@ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags) passed to the flags. \warning This constructor expects \c flags to be left at its default value. Use the - constructors that do not take the \a filters argument instead. + constructors that do not take the \a filters argument instead. \sa hasNext(), next(), IteratorFlags */ @@ -477,8 +447,6 @@ QDirIterator::~QDirIterator() */ QString QDirIterator::next() { - if (!hasNext()) - return QString(); d->advance(); return filePath(); } @@ -491,22 +459,17 @@ QString QDirIterator::next() */ bool QDirIterator::hasNext() const { - if (d->first) { - d->first = false; - d->advance(); - } - return !d->done; + return !d->fileEngineIterators.isEmpty(); } /*! Returns the file name for the current directory entry, without the path - prepended. If the current entry is invalid (i.e., isValid() returns - false), a null QString is returned. + prepended. + + This function is convenient when iterating a single directory. When using + the QDirIterator::Subdirectories flag, you can use filePath() to get the + full path. - This function is provided for the convenience when iterating single - directories. For recursive iteration, you should call filePath() or - fileInfo() instead. - \sa filePath(), fileInfo() */ QString QDirIterator::fileName() const @@ -515,20 +478,17 @@ QString QDirIterator::fileName() const } /*! - Returns the full file path for the current directory entry. If the current - entry is invalid (i.e., isValid() returns false), a null QString is - returned. + Returns the full file path for the current directory entry. \sa fileInfo(), fileName() */ QString QDirIterator::filePath() const { - return d->currentFilePath; + return d->currentFileInfo.filePath(); } /*! - Returns a QFileInfo for the current directory entry. If the current entry - is invalid (i.e., isValid() returns false), a null QFileInfo is returned. + Returns a QFileInfo for the current directory entry. \sa filePath(), fileName() */ diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index b321644..27fe1c2 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -58,6 +58,9 @@ # include "qfilesystemwatcher_inotify_p.h" # include "qfilesystemwatcher_dnotify_p.h" #elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) +# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) +# include "qfilesystemwatcher_fsevents_p.h" +# endif //MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) # include "qfilesystemwatcher_kqueue_p.h" #endif @@ -243,7 +246,12 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine() eng = QDnotifyFileSystemWatcherEngine::create(); return eng; #elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) - return QKqueueFileSystemWatcherEngine::create(); +# if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) + return QFSEventsFileSystemWatcherEngine::create(); + else +# endif + return QKqueueFileSystemWatcherEngine::create(); #else return 0; #endif @@ -376,15 +384,17 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re \note The act of monitoring files and directories for modifications consumes system resources. This implies there is a limit to the number of files and directories your process can - monitor simultaneously. On Mac OS and all BSD variants, for + monitor simultaneously. On Mac OS X 10.4 and all BSD variants, for example, an open file descriptor is required for each monitored - file. The system limits the number of open file descriptors to 256 + file. Some system limits the number of open file descriptors to 256 by default. This means that addPath() and addPaths() will fail if your process tries to add more than 256 files or directories to the file system monitor. Also note that your process may have other file descriptors open in addition to the ones for files being monitored, and these other open descriptors also count in - the total. + the total. Mac OS X 10.5 and up use a different backend and do not + suffer from this issue. + \sa QFile, QDir */ diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.cpp b/src/corelib/io/qfilesystemwatcher_fsevents.cpp new file mode 100644 index 0000000..3e0aee8 --- /dev/null +++ b/src/corelib/io/qfilesystemwatcher_fsevents.cpp @@ -0,0 +1,467 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qplatformdefs.h> + +#include "qfilesystemwatcher.h" +#include "qfilesystemwatcher_fsevents_p.h" + +#include <qdebug.h> +#include <qfile.h> +#include <qdatetime.h> +#include <qfileinfo.h> +#include <qvarlengtharray.h> + +#include <mach/mach.h> +#include <sys/types.h> +#include <CoreFoundation/CFRunLoop.h> +#include <CoreFoundation/CFUUID.h> +#include <CoreServices/CoreServices.h> +#include <AvailabilityMacros.h> +#include <private/qcore_mac_p.h> + +QT_BEGIN_NAMESPACE + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +// Static operator overloading so for the sake of some convieniece. +// They only live in this compilation unit to avoid polluting Qt in general. +static bool operator==(const struct ::timespec &left, const struct ::timespec &right) +{ + return left.tv_sec == right.tv_sec + && left.tv_nsec == right.tv_nsec; +} + +static bool operator==(const struct ::stat64 &left, const struct ::stat64 &right) +{ + return left.st_dev == right.st_dev + && left.st_mode == right.st_mode + && left.st_size == right.st_size + && left.st_ino == right.st_ino + && left.st_uid == right.st_uid + && left.st_gid == right.st_gid + && left.st_mtimespec == right.st_mtimespec + && left.st_ctimespec == right.st_ctimespec + && left.st_flags == right.st_flags; +} + +static bool operator!=(const struct ::stat64 &left, const struct ::stat64 &right) +{ + return !(operator==(left, right)); +} + + +static void addPathToHash(PathHash &pathHash, const QString &key, const QFileInfo &fileInfo, + const QString &path) +{ + PathInfoList &list = pathHash[key]; + list.push_back(PathInfo(path, + fileInfo.absoluteFilePath().normalized(QString::NormalizationForm_D).toUtf8())); + pathHash.insert(key, list); +} + +static void removePathFromHash(PathHash &pathHash, const QString &key, const QString &path) +{ + PathInfoList &list = pathHash[key]; + // We make the assumption that the list contains unique paths + PathInfoList::iterator End = list.end(); + PathInfoList::iterator it = list.begin(); + while (it != End) { + if (it->originalPath == path) { + list.erase(it); + break; + } + ++it; + } + if (list.isEmpty()) + pathHash.remove(key); +} + +static void stopFSStream(FSEventStreamRef stream) +{ + if (stream) { + FSEventStreamStop(stream); + FSEventStreamInvalidate(stream); + } +} + +static QString createFSStreamPath(const QString &absolutePath) +{ + // The path returned has a trailing slash, so ensure that here. + QString string = absolutePath; + string.reserve(string.size() + 1); + string.append(QLatin1Char('/')); + return string; +} + +static void cleanupFSStream(FSEventStreamRef stream) +{ + if (stream) + FSEventStreamRelease(stream); +} + +const FSEventStreamCreateFlags QtFSEventFlags = (kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer /* | kFSEventStreamCreateFlagWatchRoot*/); + +const CFTimeInterval Latency = 0.033; // This will do updates 30 times a second which is probably more than you need. +#endif + +QFSEventsFileSystemWatcherEngine::QFSEventsFileSystemWatcherEngine() + : fsStream(0), pathsToWatch(0), threadsRunLoop(0) +{ +} + +QFSEventsFileSystemWatcherEngine::~QFSEventsFileSystemWatcherEngine() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + // I assume that at this point, QFileSystemWatcher has already called stop + // on me, so I don't need to invalidate or stop my stream, simply + // release it. + cleanupFSStream(fsStream); + if (pathsToWatch) + CFRelease(pathsToWatch); +#endif +} + +QFSEventsFileSystemWatcherEngine *QFSEventsFileSystemWatcherEngine::create() +{ + return new QFSEventsFileSystemWatcherEngine(); +} + +QStringList QFSEventsFileSystemWatcherEngine::addPaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + stop(); + QMutexLocker locker(&mutex); + QStringList failedToAdd; + // if we have a running FSStreamEvent, we have to kill it, we'll re-add the stream soon. + FSEventStreamEventId idToCheck; + if (fsStream) { + idToCheck = FSEventStreamGetLatestEventId(fsStream); + cleanupFSStream(fsStream); + } else { + idToCheck = kFSEventStreamEventIdSinceNow; + } + + // Brain-dead approach, but works. FSEvents actually can already read sub-trees, but since it's + // work to figure out if we are doing a double register, we just register it twice as FSEvents + // seems smart enough to only deliver one event. We also duplicate directory entries in here + // (e.g., if you watch five files in the same directory, you get that directory included in the + // array 5 times). This stupidity also makes remove work correctly though. I'll freely admit + // that we could make this a bit smarter. If you do, check the auto-tests, they should catch at + // least a couple of the issues. + QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + for (int i = 0; i < paths.size(); ++i) { + const QString &path = paths.at(i); + + QFileInfo fileInfo(path); + if (!fileInfo.exists()) { + failedToAdd.append(path); + continue; + } + + if (fileInfo.isDir()) { + if (directories->contains(path)) { + failedToAdd.append(path); + continue; + } else { + directories->append(path); + // Full file path for dirs. + QCFString cfpath(createFSStreamPath(fileInfo.absoluteFilePath())); + addPathToHash(dirPathInfoHash, cfpath, fileInfo, path); + CFArrayAppendValue(tmpArray, cfpath); + } + } else { + if (files->contains(path)) { + failedToAdd.append(path); + continue; + } else { + // Just the absolute path (minus it's filename) for files. + QCFString cfpath(createFSStreamPath(fileInfo.absolutePath())); + files->append(path); + addPathToHash(filePathInfoHash, cfpath, fileInfo, path); + CFArrayAppendValue(tmpArray, cfpath); + } + } + } + if (CFArrayGetCount(tmpArray) > 0) { + if (pathsToWatch) { + CFArrayAppendArray(tmpArray, pathsToWatch, CFRangeMake(0, CFArrayGetCount(pathsToWatch))); + CFRelease(pathsToWatch); + } + pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray); + } + FSEventStreamContext context = { 0, this, 0, 0, 0 }; + fsStream = FSEventStreamCreate(kCFAllocatorDefault, + QFSEventsFileSystemWatcherEngine::fseventsCallback, + &context, pathsToWatch, + idToCheck, Latency, QtFSEventFlags); + warmUpFSEvents(); + + return failedToAdd; +#else + Q_UNUSED(paths); + Q_UNUSED(files); + Q_UNUSED(directories); + return QStringList(); +#endif +} + +void QFSEventsFileSystemWatcherEngine::warmUpFSEvents() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + // This function assumes that the mutex has already been grabbed before calling it. + // It exits with the mutex still locked (Q_ASSERT(mutex.isLocked()) ;-). + start(); + waitCondition.wait(&mutex); +#endif +} + +QStringList QFSEventsFileSystemWatcherEngine::removePaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + stop(); + QMutexLocker locker(&mutex); + // short circuit for smarties that call remove before add and we have nothing. + if (pathsToWatch == 0) + return paths; + QStringList failedToRemove; + // if we have a running FSStreamEvent, we have to stop it, we'll re-add the stream soon. + FSEventStreamEventId idToCheck; + if (fsStream) { + idToCheck = FSEventStreamGetLatestEventId(fsStream); + cleanupFSStream(fsStream); + fsStream = 0; + } else { + idToCheck = kFSEventStreamEventIdSinceNow; + } + + CFIndex itemCount = CFArrayGetCount(pathsToWatch); + QCFType<CFMutableArrayRef> tmpArray = CFArrayCreateMutableCopy(kCFAllocatorDefault, itemCount, + pathsToWatch); + CFRelease(pathsToWatch); + pathsToWatch = 0; + for (int i = 0; i < paths.size(); ++i) { + // Get the itemCount at the beginning to avoid any overruns during the iteration. + itemCount = CFArrayGetCount(tmpArray); + const QString &path = paths.at(i); + QFileInfo fi(path); + QCFString cfpath(createFSStreamPath(fi.absolutePath())); + + CFIndex index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfpath); + if (index != -1) { + CFArrayRemoveValueAtIndex(tmpArray, index); + files->removeAll(path); + removePathFromHash(filePathInfoHash, cfpath, path); + } else { + // Could be a directory we are watching instead. + QCFString cfdirpath(createFSStreamPath(fi.absoluteFilePath())); + index = CFArrayGetFirstIndexOfValue(tmpArray, CFRangeMake(0, itemCount), cfdirpath); + if (index != -1) { + CFArrayRemoveValueAtIndex(tmpArray, index); + directories->removeAll(path); + removePathFromHash(dirPathInfoHash, cfpath, path); + } else { + failedToRemove.append(path); + } + } + } + itemCount = CFArrayGetCount(tmpArray); + if (itemCount != 0) { + pathsToWatch = CFArrayCreateCopy(kCFAllocatorDefault, tmpArray); + + FSEventStreamContext context = { 0, this, 0, 0, 0 }; + fsStream = FSEventStreamCreate(kCFAllocatorDefault, + QFSEventsFileSystemWatcherEngine::fseventsCallback, + &context, pathsToWatch, idToCheck, Latency, QtFSEventFlags); + warmUpFSEvents(); + } + return failedToRemove; +#else + Q_UNUSED(paths); + Q_UNUSED(files); + Q_UNUSED(directories); + return QStringList(); +#endif +} + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +void QFSEventsFileSystemWatcherEngine::updateList(PathInfoList &list, bool directory, bool emitSignals) +{ + PathInfoList::iterator End = list.end(); + PathInfoList::iterator it = list.begin(); + while (it != End) { + struct ::stat64 newInfo; + if (::stat64(it->absolutePath, &newInfo) == 0) { + if (emitSignals) { + if (newInfo != it->savedInfo) { + it->savedInfo = newInfo; + if (directory) + emit directoryChanged(it->originalPath, false); + else + emit fileChanged(it->originalPath, false); + } + } else { + it->savedInfo = newInfo; + } + } else { + if (errno == ENOENT) { + if (emitSignals) { + if (directory) + emit directoryChanged(it->originalPath, true); + else + emit fileChanged(it->originalPath, true); + } + it = list.erase(it); + continue; + } else { + qWarning("%s:%d:QFSEventsFileSystemWatcherEngine: stat error on %s:%s", + __FILE__, __LINE__, qPrintable(it->originalPath), strerror(errno)); + + } + } + ++it; + } +} + +void QFSEventsFileSystemWatcherEngine::updateHash(PathHash &pathHash) +{ + PathHash::iterator HashEnd = pathHash.end(); + PathHash::iterator it = pathHash.begin(); + const bool IsDirectory = (&pathHash == &dirPathInfoHash); + while (it != HashEnd) { + updateList(it.value(), IsDirectory, false); + if (it.value().isEmpty()) + it = pathHash.erase(it); + else + ++it; + } +} +#endif + +void QFSEventsFileSystemWatcherEngine::fseventsCallback(ConstFSEventStreamRef , + void *clientCallBackInfo, size_t numEvents, + void *eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId []) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + QFSEventsFileSystemWatcherEngine *watcher = static_cast<QFSEventsFileSystemWatcherEngine *>(clientCallBackInfo); + QMutexLocker locker(&watcher->mutex); + CFArrayRef paths = static_cast<CFArrayRef>(eventPaths); + for (size_t i = 0; i < numEvents; ++i) { + const QString path = QCFString::toQString( + static_cast<CFStringRef>(CFArrayGetValueAtIndex(paths, i))); + const FSEventStreamEventFlags pathFlags = eventFlags[i]; + // There are several flags that may be passed, but we really don't care about them ATM. + // Here they are and why we don't care. + // kFSEventStreamEventFlagHistoryDone--(very unlikely to be gotten, but even then, not much changes). + // kFSEventStreamEventFlagMustScanSubDirs--Likely means the data is very much out of date, we + // aren't coalescing our directories, so again not so much of an issue + // kFSEventStreamEventFlagRootChanged | kFSEventStreamEventFlagMount | kFSEventStreamEventFlagUnmount-- + // These three flags indicate something has changed, but the stat will likely show this, so + // there's not really much to worry about. + // (btw, FSEvents is not the correct way of checking for mounts/unmounts, + // there are real CarbonCore events for that.) + Q_UNUSED(pathFlags); + if (watcher->filePathInfoHash.contains(path)) + watcher->updateList(watcher->filePathInfoHash[path], false, true); + + if (watcher->dirPathInfoHash.contains(path)) + watcher->updateList(watcher->dirPathInfoHash[path], true, true); + } +#else + Q_UNUSED(clientCallBackInfo); + Q_UNUSED(numEvents); + Q_UNUSED(eventPaths); + Q_UNUSED(eventFlags); +#endif +} + +void QFSEventsFileSystemWatcherEngine::stop() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + stopFSStream(fsStream); + if (threadsRunLoop) + CFRunLoopStop(threadsRunLoop); +#endif +} + +void QFSEventsFileSystemWatcherEngine::updateFiles() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + QMutexLocker locker(&mutex); + updateHash(filePathInfoHash); + updateHash(dirPathInfoHash); + if (filePathInfoHash.isEmpty() && dirPathInfoHash.isEmpty()) { + // Everything disappeared before we got to start, don't bother. + stop(); + cleanupFSStream(fsStream); + } + waitCondition.wakeAll(); +#endif +} + +void QFSEventsFileSystemWatcherEngine::run() +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + threadsRunLoop = CFRunLoopGetCurrent(); + FSEventStreamScheduleWithRunLoop(fsStream, threadsRunLoop, kCFRunLoopDefaultMode); + bool startedOK = FSEventStreamStart(fsStream); + // It's recommended by Apple that you only update the files after you've started + // the stream, because otherwise you might miss an update in between starting it. + updateFiles(); +#ifdef QT_NO_DEBUG + Q_UNUSED(startedOK); +#else + Q_ASSERT(startedOK); +#endif + // If for some reason we called stop up above (and invalidated our stream), this call will return + // immediately. + CFRunLoopRun(); + threadsRunLoop = 0; +#endif +} + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/src/corelib/io/qfilesystemwatcher_fsevents_p.h new file mode 100644 index 0000000..4770867 --- /dev/null +++ b/src/corelib/io/qfilesystemwatcher_fsevents_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef FILEWATCHER_FSEVENTS_P_H +#define FILEWATCHER_FSEVENTS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qfilesystemwatcher_p.h" + +#include <QtCore/qmutex.h> +#include <QtCore/qwaitcondition.h> +#include <QtCore/qthread.h> +#include <QtCore/QHash> +#include <QtCore/QLinkedList> +#include <private/qcore_mac_p.h> +#include <sys/stat.h> + +typedef struct __FSEventStream *FSEventStreamRef; +typedef const struct __FSEventStream *ConstFSEventStreamRef; +typedef const struct __CFArray *CFArrayRef; +typedef UInt32 FSEventStreamEventFlags; +typedef uint64_t FSEventStreamEventId; + +QT_BEGIN_NAMESPACE + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +// Yes, I use a stat64 element here. QFileInfo requires too much knowledge about implementation +// details to be used as a long-standing record. Since I'm going to have to store this information, I can +// do the stat myself too. +struct PathInfo { + PathInfo(const QString &path, const QByteArray &absPath) + : originalPath(path), absolutePath(absPath) {} + QString originalPath; // The path we need to emit + QByteArray absolutePath; // The path we need to stat. + struct ::stat64 savedInfo; // All the info for the path so we can compare it. +}; +typedef QLinkedList<PathInfo> PathInfoList; +typedef QHash<QString, PathInfoList> PathHash; +#endif + +class QFSEventsFileSystemWatcherEngine : public QFileSystemWatcherEngine +{ + Q_OBJECT +public: + ~QFSEventsFileSystemWatcherEngine(); + + static QFSEventsFileSystemWatcherEngine *create(); + + QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); + QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); + + void stop(); + +private: + QFSEventsFileSystemWatcherEngine(); + void warmUpFSEvents(); + void updateFiles(); + + static void fseventsCallback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, size_t numEvents, + void *eventPaths, const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]); + void run(); + FSEventStreamRef fsStream; + CFArrayRef pathsToWatch; + CFRunLoopRef threadsRunLoop; + QMutex mutex; + QWaitCondition waitCondition; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + PathHash filePathInfoHash; + PathHash dirPathInfoHash; + void updateHash(PathHash &pathHash); + void updateList(PathInfoList &list, bool directory, bool emitSignals); +#endif +}; + +#endif + +QT_END_NAMESPACE diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h index 850e150..83be197 100644 --- a/src/corelib/io/qfilesystemwatcher_p.h +++ b/src/corelib/io/qfilesystemwatcher_p.h @@ -69,13 +69,14 @@ class QFileSystemWatcherEngine : public QThread Q_OBJECT protected: - inline QFileSystemWatcherEngine() + inline QFileSystemWatcherEngine(bool move = true) { - moveToThread(this); + if (move) + moveToThread(this); } public: - // fills \a files and \a directires with the \a paths it could + // fills \a files and \a directories with the \a paths it could // watch, and returns a list of paths this engine could not watch virtual QStringList addPaths(const QStringList &paths, QStringList *files, diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp index c15b1d2..9eeef02 100644 --- a/src/corelib/io/qfilesystemwatcher_win.cpp +++ b/src/corelib/io/qfilesystemwatcher_win.cpp @@ -53,23 +53,268 @@ QT_BEGIN_NAMESPACE +void QWindowsFileSystemWatcherEngine::stop() +{ + foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) + thread->stop(); +} + QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine() - : msg(0) + : QFileSystemWatcherEngine(false) { - if (HANDLE h = CreateEvent(0, false, false, 0)) { - handles.reserve(MAXIMUM_WAIT_OBJECTS); - handles.append(h); - } } QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine() { - if (handles.isEmpty()) + if (threads.isEmpty()) return; - stop(); - wait(); + foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) { + thread->stop(); + thread->wait(); + delete thread; + } +} + +QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ + // qDebug()<<"Adding"<<paths.count()<<"to existing"<<(files->count() + directories->count())<<"watchers"; + QStringList p = paths; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + QString normalPath = path; + if ((normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) +#ifdef Q_OS_WINCE + && normalPath.size() > 1) +#else + ) +#endif + normalPath.chop(1); + QFileInfo fileInfo(normalPath.toLower()); + if (!fileInfo.exists()) + continue; + + bool isDir = fileInfo.isDir(); + if (isDir) { + if (directories->contains(path)) + continue; + } else { + if (files->contains(path)) + continue; + } + + // qDebug()<<"Looking for a thread/handle for"<<normalPath; + + const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath(); + const uint flags = isDir + ? (FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_FILE_NAME) + : (FILE_NOTIFY_CHANGE_DIR_NAME + | FILE_NOTIFY_CHANGE_FILE_NAME + | FILE_NOTIFY_CHANGE_ATTRIBUTES + | FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_LAST_WRITE + | FILE_NOTIFY_CHANGE_SECURITY); + + QWindowsFileSystemWatcherEngine::PathInfo pathInfo; + pathInfo.absolutePath = absolutePath; + pathInfo.isDir = isDir; + pathInfo.path = path; + pathInfo = fileInfo; + + // Look for a thread + QWindowsFileSystemWatcherEngineThread *thread = 0; + QWindowsFileSystemWatcherEngine::Handle handle; + QList<QWindowsFileSystemWatcherEngineThread *>::const_iterator jt, end; + end = threads.constEnd(); + for(jt = threads.constBegin(); jt != end; ++jt) { + thread = *jt; + QMutexLocker locker(&(thread->mutex)); + + handle = thread->handleForDir.value(absolutePath); + if (handle.handle != INVALID_HANDLE_VALUE && handle.flags == flags) { + // found a thread now insert... + // qDebug()<<" Found a thread"<<thread; + + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h + = thread->pathInfoForHandle[handle.handle]; + if (!h.contains(fileInfo.absoluteFilePath())) { + thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + if (isDir) + directories->append(path); + else + files->append(path); + } + it.remove(); + thread->wakeup(); + break; + } + } + + // no thread found, first create a handle + if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) { + // qDebug()<<" No thread found"; + // Volume and folder paths need a trailing slash for proper notification + // (e.g. "c:" -> "c:/"). + const QString effectiveAbsolutePath = + isDir ? (absolutePath + QLatin1Char('/')) : absolutePath; + + handle.handle = FindFirstChangeNotification((wchar_t*) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(), false, flags); + handle.flags = flags; + if (handle.handle == INVALID_HANDLE_VALUE) + continue; + + // now look for a thread to insert + bool found = false; + foreach(QWindowsFileSystemWatcherEngineThread *thread, threads) { + QMutexLocker(&(thread->mutex)); + if (thread->handles.count() < MAXIMUM_WAIT_OBJECTS) { + // qDebug() << " Added handle" << handle.handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath(); + // qDebug()<< " to existing thread"<<thread; + thread->handles.append(handle.handle); + thread->handleForDir.insert(absolutePath, handle); + + thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + if (isDir) + directories->append(path); + else + files->append(path); + + it.remove(); + found = true; + thread->wakeup(); + break; + } + } + if (!found) { + QWindowsFileSystemWatcherEngineThread *thread = new QWindowsFileSystemWatcherEngineThread(); + //qDebug()<<" ###Creating new thread"<<thread<<"("<<(threads.count()+1)<<"threads)"; + thread->handles.append(handle.handle); + thread->handleForDir.insert(absolutePath, handle); + + thread->pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); + if (isDir) + directories->append(path); + else + files->append(path); + + connect(thread, SIGNAL(fileChanged(const QString &, bool)), + this, SIGNAL(fileChanged(const QString &, bool))); + connect(thread, SIGNAL(directoryChanged(const QString &, bool)), + this, SIGNAL(directoryChanged(const QString &, bool))); + + thread->msg = '@'; + thread->start(); + threads.append(thread); + it.remove(); + } + } + } + return p; +} + +QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &paths, + QStringList *files, + QStringList *directories) +{ + // qDebug()<<"removePaths"<<paths; + QStringList p = paths; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + QString normalPath = path; + if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) + normalPath.chop(1); + QFileInfo fileInfo(normalPath.toLower()); + // qDebug()<<"removing"<<normalPath; + QString absolutePath = fileInfo.absoluteFilePath(); + QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end; + end = threads.end(); + for(jt = threads.begin(); jt!= end; ++jt) { + QWindowsFileSystemWatcherEngineThread *thread = *jt; + if (*jt == 0) + continue; + + QMutexLocker locker(&(thread->mutex)); + + QWindowsFileSystemWatcherEngine::Handle handle = thread->handleForDir.value(absolutePath); + if (handle.handle == INVALID_HANDLE_VALUE) { + // perhaps path is a file? + absolutePath = fileInfo.absolutePath(); + handle = thread->handleForDir.value(absolutePath); + } + if (handle.handle != INVALID_HANDLE_VALUE) { + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = + thread->pathInfoForHandle[handle.handle]; + if (h.remove(fileInfo.absoluteFilePath())) { + // ### + files->removeAll(path); + directories->removeAll(path); + + if (h.isEmpty()) { + // qDebug() << "Closing handle" << handle.handle; + FindCloseChangeNotification(handle.handle); // This one might generate a notification + + int indexOfHandle = thread->handles.indexOf(handle.handle); + Q_ASSERT(indexOfHandle != -1); + thread->handles.remove(indexOfHandle); + + thread->handleForDir.remove(absolutePath); + // h is now invalid + + it.remove(); + + if (thread->handleForDir.isEmpty()) { + // qDebug()<<"Stopping thread "<<thread; + locker.unlock(); + thread->stop(); + thread->wait(); + locker.relock(); + // We can't delete the thread until the mutex locker is + // out of scope + } + } + } + // Found the file, go to next one + break; + } + } + } + + // Remove all threads that we stopped + QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end; + end = threads.end(); + for(jt = threads.begin(); jt != end; ++jt) { + if (!(*jt)->isRunning()) { + delete *jt; + *jt = 0; + } + } + + threads.removeAll(0); + return p; +} + +/////////// +// QWindowsFileSystemWatcherEngineThread +/////////// +QWindowsFileSystemWatcherEngineThread::QWindowsFileSystemWatcherEngineThread() + : msg(0) +{ + if (HANDLE h = CreateEvent(0, false, false, 0)) { + handles.reserve(MAXIMUM_WAIT_OBJECTS); + handles.append(h); + } + moveToThread(this); +} + + +QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread() +{ CloseHandle(handles.at(0)); handles[0] = INVALID_HANDLE_VALUE; @@ -80,13 +325,13 @@ QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine() } } -void QWindowsFileSystemWatcherEngine::run() +void QWindowsFileSystemWatcherEngineThread::run() { QMutexLocker locker(&mutex); forever { QVector<HANDLE> handlesCopy = handles; locker.unlock(); - // qDebug() << "QWindowsFileSystemWatcherEngine: waiting on" << handlesCopy.count() << "handles"; + // qDebug() << "QWindowsFileSystemWatcherThread"<<this<<"waiting on" << handlesCopy.count() << "handles"; DWORD r = WaitForMultipleObjects(handlesCopy.count(), handlesCopy.constData(), false, INFINITE); locker.relock(); do { @@ -94,7 +339,7 @@ void QWindowsFileSystemWatcherEngine::run() int m = msg; msg = 0; if (m == 'q') { - // qDebug() << "thread told to quit"; + // qDebug() << "thread"<<this<<"told to quit"; return; } if (m != '@') { @@ -109,15 +354,15 @@ void QWindowsFileSystemWatcherEngine::run() // When removing a path, FindCloseChangeNotification might actually fire a notification // for some reason, so we must check if the handle exist in the handles vector if (handles.contains(handle)) { - // qDebug("Acknowledged handle: %d, %p", at, handle); + // qDebug()<<"thread"<<this<<"Acknowledged handle:"<<at<<handle; if (!FindNextChangeNotification(handle)) { - qErrnoWarning("QFileSystemWatcher: FindNextChangeNotification failed"); + qErrnoWarning("QFileSystemWatcher: FindNextChangeNotification failed!!"); } - QHash<QString, PathInfo> &h = pathInfoForHandle[handle]; - QMutableHashIterator<QString, PathInfo> it(h); + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> &h = pathInfoForHandle[handle]; + QMutableHashIterator<QString, QWindowsFileSystemWatcherEngine::PathInfo> it(h); while (it.hasNext()) { - QHash<QString, PathInfo>::iterator x = it.next(); + QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo>::iterator x = it.next(); QString absolutePath = x.value().absolutePath; QFileInfo fileInfo(x.value().path); // qDebug() << "checking" << x.key(); @@ -162,160 +407,14 @@ void QWindowsFileSystemWatcherEngine::run() } } -QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ - if (handles.isEmpty() || handles.count() == MAXIMUM_WAIT_OBJECTS) - return paths; - - QMutexLocker locker(&mutex); - - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - QString normalPath = path; - if ((normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) -#ifdef Q_OS_WINCE - && normalPath.size() > 1) -#else - ) -#endif - normalPath.chop(1); - QFileInfo fileInfo(normalPath.toLower()); - if (!fileInfo.exists()) - continue; - - bool isDir = fileInfo.isDir(); - if (isDir) { - if (directories->contains(path)) - continue; - } else { - if (files->contains(path)) - continue; - } - const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath(); - const uint flags = isDir - ? (FILE_NOTIFY_CHANGE_DIR_NAME - | FILE_NOTIFY_CHANGE_FILE_NAME) - : (FILE_NOTIFY_CHANGE_DIR_NAME - | FILE_NOTIFY_CHANGE_FILE_NAME - | FILE_NOTIFY_CHANGE_ATTRIBUTES - | FILE_NOTIFY_CHANGE_SIZE - | FILE_NOTIFY_CHANGE_LAST_WRITE - | FILE_NOTIFY_CHANGE_SECURITY); - - Handle handle = handleForDir.value(absolutePath); - if (handle.handle == INVALID_HANDLE_VALUE || handle.flags != flags) { - // Volume and folder paths need a trailing slash for proper notification - // (e.g. "c:" -> "c:/"). - const QString effectiveAbsolutePath = - isDir ? (absolutePath + QLatin1Char('/')) : absolutePath; - - handle.handle = FindFirstChangeNotification((wchar_t*) QDir::toNativeSeparators(effectiveAbsolutePath).utf16(), false, flags); - handle.flags = flags; - if (handle.handle == INVALID_HANDLE_VALUE) - continue; - // qDebug() << "Added handle" << handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath(); - handles.append(handle.handle); - handleForDir.insert(absolutePath, handle); - } - - PathInfo pathInfo; - pathInfo.absolutePath = absolutePath; - pathInfo.isDir = isDir; - pathInfo.path = path; - pathInfo = fileInfo; - QHash<QString, PathInfo> &h = pathInfoForHandle[handle.handle]; - if (!h.contains(fileInfo.absoluteFilePath())) { - pathInfoForHandle[handle.handle].insert(fileInfo.absoluteFilePath(), pathInfo); - if (isDir) - directories->append(path); - else - files->append(path); - } - - it.remove(); - } - - if (!isRunning()) { - msg = '@'; - start(); - } else { - wakeup(); - } - - return p; -} - -QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &paths, - QStringList *files, - QStringList *directories) -{ - QMutexLocker locker(&mutex); - - QStringList p = paths; - QMutableListIterator<QString> it(p); - while (it.hasNext()) { - QString path = it.next(); - QString normalPath = path; - if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) - normalPath.chop(1); - QFileInfo fileInfo(normalPath.toLower()); - - QString absolutePath = fileInfo.absoluteFilePath(); - Handle handle = handleForDir.value(absolutePath); - if (handle.handle == INVALID_HANDLE_VALUE) { - // perhaps path is a file? - absolutePath = fileInfo.absolutePath(); - handle = handleForDir.value(absolutePath); - if (handle.handle == INVALID_HANDLE_VALUE) - continue; - } - - QHash<QString, PathInfo> &h = pathInfoForHandle[handle.handle]; - if (h.remove(fileInfo.absoluteFilePath())) { - // ### - files->removeAll(path); - directories->removeAll(path); - - if (h.isEmpty()) { - // qDebug() << "Closing handle" << handle; - FindCloseChangeNotification(handle.handle); // This one might generate a notification - - int indexOfHandle = handles.indexOf(handle.handle); - Q_ASSERT(indexOfHandle != -1); - handles.remove(indexOfHandle); - - handleForDir.remove(absolutePath); - // h is now invalid - - it.remove(); - } - } - } - - if (handleForDir.isEmpty()) { - stop(); - locker.unlock(); - wait(); - locker.relock(); - } else { - wakeup(); - } - - return p; -} - -void QWindowsFileSystemWatcherEngine::stop() +void QWindowsFileSystemWatcherEngineThread::stop() { msg = 'q'; SetEvent(handles.at(0)); } -void QWindowsFileSystemWatcherEngine::wakeup() +void QWindowsFileSystemWatcherEngineThread::wakeup() { msg = '@'; SetEvent(handles.at(0)); diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h index d0eecfc..405d255 100644 --- a/src/corelib/io/qfilesystemwatcher_win_p.h +++ b/src/corelib/io/qfilesystemwatcher_win_p.h @@ -57,7 +57,7 @@ #ifndef QT_NO_FILESYSTEMWATCHER -#include <windows.h> +#include <qt_windows.h> #include <QtCore/qdatetime.h> #include <QtCore/qfile.h> @@ -68,27 +68,24 @@ QT_BEGIN_NAMESPACE +class QWindowsFileSystemWatcherEngineThread; + +// Even though QWindowsFileSystemWatcherEngine is derived of QThread +// via QFileSystemWatcher, it does not start a thread. +// Instead QWindowsFileSystemWatcher creates QWindowsFileSystemWatcherEngineThreads +// to do the actually watching. class QWindowsFileSystemWatcherEngine : public QFileSystemWatcherEngine { Q_OBJECT - public: QWindowsFileSystemWatcherEngine(); ~QWindowsFileSystemWatcherEngine(); - void run(); - QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories); QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories); void stop(); -private: - void wakeup(); - - QMutex mutex; - QVector<HANDLE> handles; - int msg; class Handle { @@ -97,13 +94,12 @@ private: uint flags; Handle() - : handle(INVALID_HANDLE_VALUE), flags(0u) + : handle(INVALID_HANDLE_VALUE), flags(0u) { } Handle(const Handle &other) - : handle(other.handle), flags(other.flags) + : handle(other.handle), flags(other.flags) { } }; - QHash<QString, Handle> handleForDir; class PathInfo { public: @@ -118,7 +114,7 @@ private: QDateTime lastModified; PathInfo &operator=(const QFileInfo &fileInfo) - { + { ownerId = fileInfo.ownerId(); groupId = fileInfo.groupId(); permissions = fileInfo.permissions(); @@ -134,8 +130,35 @@ private: || lastModified != fileInfo.lastModified()); } }; - QHash<HANDLE, QHash<QString, PathInfo> > pathInfoForHandle; +private: + QList<QWindowsFileSystemWatcherEngineThread *> threads; + +}; + +class QWindowsFileSystemWatcherEngineThread : public QThread +{ + Q_OBJECT + +public: + QWindowsFileSystemWatcherEngineThread(); + ~QWindowsFileSystemWatcherEngineThread(); + void run(); + void stop(); + void wakeup(); + + QMutex mutex; + QVector<HANDLE> handles; + int msg; + + QHash<QString, QWindowsFileSystemWatcherEngine::Handle> handleForDir; + + QHash<HANDLE, QHash<QString, QWindowsFileSystemWatcherEngine::PathInfo> > pathInfoForHandle; + +Q_SIGNALS: + void fileChanged(const QString &path, bool removed); + void directoryChanged(const QString &path, bool removed); }; + #endif // QT_NO_FILESYSTEMWATCHER QT_END_NAMESPACE diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index beafe72..3a43ec7 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -44,6 +44,7 @@ #include "qdatetime.h" #include "qdiriterator.h" #include "qset.h" +#include <QtCore/qdebug.h> #ifndef QT_NO_FSFILEENGINE @@ -571,7 +572,7 @@ bool QFSFileEnginePrivate::seekFdFh(qint64 pos) } else { // Unbuffered stdio mode. if (QT_LSEEK(fd, pos, SEEK_SET) == -1) { - qWarning("QFile::at: Cannot set file position %lld", pos); + qWarning() << "QFile::at: Cannot set file position" << pos; q->setError(QFile::PositionError, qt_error_string(errno)); return false; } diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index ee49853..819034a 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -109,9 +109,9 @@ static QString qfsPrivateCurrentDir = QLatin1String(""); QT_BEGIN_INCLUDE_NAMESPACE typedef DWORD (WINAPI *PtrGetNamedSecurityInfoW)(LPWSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION, PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); static PtrGetNamedSecurityInfoW ptrGetNamedSecurityInfoW = 0; -typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); +typedef BOOL (WINAPI *PtrLookupAccountSidW)(LPCWSTR, PSID, LPWSTR, LPDWORD, LPWSTR, LPDWORD, PSID_NAME_USE); static PtrLookupAccountSidW ptrLookupAccountSidW = 0; -typedef DECLSPEC_IMPORT BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); +typedef BOOL (WINAPI *PtrAllocateAndInitializeSid)(PSID_IDENTIFIER_AUTHORITY, BYTE, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, PSID*); static PtrAllocateAndInitializeSid ptrAllocateAndInitializeSid = 0; typedef VOID (WINAPI *PtrBuildTrusteeWithSidW)(PTRUSTEE_W, PSID); static PtrBuildTrusteeWithSidW ptrBuildTrusteeWithSidW = 0; @@ -119,7 +119,7 @@ typedef VOID (WINAPI *PtrBuildTrusteeWithNameW)(PTRUSTEE_W, unsigned short*); static PtrBuildTrusteeWithNameW ptrBuildTrusteeWithNameW = 0; typedef DWORD (WINAPI *PtrGetEffectiveRightsFromAclW)(PACL, PTRUSTEE_W, OUT PACCESS_MASK); static PtrGetEffectiveRightsFromAclW ptrGetEffectiveRightsFromAclW = 0; -typedef DECLSPEC_IMPORT PVOID (WINAPI *PtrFreeSid)(PSID); +typedef PVOID (WINAPI *PtrFreeSid)(PSID); static PtrFreeSid ptrFreeSid = 0; static TRUSTEE_W currentUserTrusteeW; @@ -165,11 +165,11 @@ void QFSFileEnginePrivate::resolveLibs() if (ptrBuildTrusteeWithNameW) { HINSTANCE versionHnd = LoadLibraryW(L"version"); if (versionHnd) { - typedef DWORD (WINAPI *PtrGetFileVersionInfoSizeW)(LPWSTR lptstrFilename,LPDWORD lpdwHandle); + typedef DWORD (WINAPI *PtrGetFileVersionInfoSizeW)(LPCWSTR lptstrFilename,LPDWORD lpdwHandle); PtrGetFileVersionInfoSizeW ptrGetFileVersionInfoSizeW = (PtrGetFileVersionInfoSizeW)GetProcAddress(versionHnd, "GetFileVersionInfoSizeW"); - typedef BOOL (WINAPI *PtrGetFileVersionInfoW)(LPWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); + typedef BOOL (WINAPI *PtrGetFileVersionInfoW)(LPCWSTR lptstrFilename,DWORD dwHandle,DWORD dwLen,LPVOID lpData); PtrGetFileVersionInfoW ptrGetFileVersionInfoW = (PtrGetFileVersionInfoW)GetProcAddress(versionHnd, "GetFileVersionInfoW"); - typedef BOOL (WINAPI *PtrVerQueryValueW)(const LPVOID pBlock,LPWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); + typedef BOOL (WINAPI *PtrVerQueryValueW)(const LPVOID pBlock,LPCWSTR lpSubBlock,LPVOID *lplpBuffer,PUINT puLen); PtrVerQueryValueW ptrVerQueryValueW = (PtrVerQueryValueW)GetProcAddress(versionHnd, "VerQueryValueW"); if(ptrGetFileVersionInfoSizeW && ptrGetFileVersionInfoW && ptrVerQueryValueW) { DWORD fakeHandle; @@ -527,6 +527,28 @@ qint64 QFSFileEnginePrivate::nativeSize() const WIN32_FILE_ATTRIBUTE_DATA attribData; bool ok = ::GetFileAttributesEx((const wchar_t*)nativeFilePath.constData(), GetFileExInfoStandard, &attribData); + if (!ok) { + int errorCode = GetLastError(); + if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { + QByteArray path = nativeFilePath; + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith('\\')) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(':')) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((const wchar_t*)path.constData(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + ok = true; + attribData.nFileSizeHigh = findData.nFileSizeHigh; + attribData.nFileSizeLow = findData.nFileSizeLow; + } + } + } + } if (ok) { qint64 size = attribData.nFileSizeHigh; size <<= 32; @@ -588,28 +610,28 @@ qint64 QFSFileEnginePrivate::nativePos() const if (fileHandle == INVALID_HANDLE_VALUE) return 0; -#if !defined(QT_NO_LIBRARY) +#if !defined(QT_NO_LIBRARY) && !defined(Q_OS_WINCE) QFSFileEnginePrivate::resolveLibs(); if (!ptrSetFilePointerEx) { #endif - DWORD newFilePointer = SetFilePointer(fileHandle, 0, NULL, FILE_CURRENT); - if (newFilePointer == 0xFFFFFFFF) { + LARGE_INTEGER filepos; + filepos.HighPart = 0; + DWORD newFilePointer = SetFilePointer(fileHandle, 0, &filepos.HighPart, FILE_CURRENT); + if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { thatQ->setError(QFile::UnspecifiedError, qt_error_string()); return 0; } - // Note: returns <4GB; does not work with large files. This is the - // case for MOC, UIC, qmake and other bootstrapped tools, and for - // Win9x/ME. - return qint64(newFilePointer); -#if !defined(QT_NO_LIBRARY) + // Note: This is the case for MOC, UIC, qmake and other + // bootstrapped tools, and for Windows CE. + filepos.LowPart = newFilePointer; + return filepos.QuadPart; +#if !defined(QT_NO_LIBRARY) && !defined(Q_OS_WINCE) } - // This approach supports large files. LARGE_INTEGER currentFilePos; LARGE_INTEGER offset; - offset.LowPart = 0; - offset.HighPart = 0; + offset.QuadPart = 0; if (!ptrSetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_CURRENT)) { thatQ->setError(QFile::UnspecifiedError, qt_error_string()); return 0; @@ -632,28 +654,27 @@ bool QFSFileEnginePrivate::nativeSeek(qint64 pos) return seekFdFh(pos); } -#if !defined(QT_NO_LIBRARY) +#if !defined(QT_NO_LIBRARY) && !defined(Q_OS_WINCE) QFSFileEnginePrivate::resolveLibs(); if (!ptrSetFilePointerEx) { #endif - LONG seekToPos = LONG(pos); // <- lossy - DWORD newFilePointer = SetFilePointer(fileHandle, seekToPos, NULL, FILE_BEGIN); - if (newFilePointer == 0xFFFFFFFF) { - thatQ->setError(QFile::UnspecifiedError, qt_error_string()); + DWORD newFilePointer; + LARGE_INTEGER *li = reinterpret_cast<LARGE_INTEGER*>(&pos); + newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN); + if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) { + thatQ->setError(QFile::PositionError, qt_error_string()); return false; } - // Note: does not work with large files. This is the case for MOC, - // UIC, qmake and other bootstrapped tools, and for Win9x/ME. + // Note: This is the case for MOC, UIC, qmake and other + // bootstrapped tools, and for Windows CE. return true; -#if !defined(QT_NO_LIBRARY) +#if !defined(QT_NO_LIBRARY) && !defined(Q_OS_WINCE) } - // This approach supports large files. LARGE_INTEGER currentFilePos; LARGE_INTEGER offset; - offset.LowPart = (unsigned int)(quint64(pos) & Q_UINT64_C(0xffffffff)); - offset.HighPart = (unsigned int)((quint64(pos) >> 32) & Q_UINT64_C(0xffffffff)); + offset.QuadPart = pos; if (ptrSetFilePointerEx(fileHandle, offset, ¤tFilePos, FILE_BEGIN) == 0) { thatQ->setError(QFile::UnspecifiedError, qt_error_string()); return false; @@ -879,6 +900,25 @@ static inline bool isDirPath(const QString &dirPath, bool *existed) path += QLatin1Char('\\'); DWORD fileAttrib = ::GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16()); + if (fileAttrib == INVALID_FILE_ATTRIBUTES) { + int errorCode = GetLastError(); + if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(QLatin1Char(':'))) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + fileAttrib = findData.dwFileAttributes; + } + } + } + } if (existed) *existed = fileAttrib != INVALID_FILE_ATTRIBUTES; @@ -1150,6 +1190,26 @@ bool QFSFileEnginePrivate::doStat() const #endif } else { fileAttrib = GetFileAttributes((wchar_t*)QFSFileEnginePrivate::longFileName(fname).utf16()); + if (fileAttrib == INVALID_FILE_ATTRIBUTES) { + int errorCode = GetLastError(); + if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { + QString path = QDir::toNativeSeparators(fname); + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(QLatin1Char(':'))) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + fileAttrib = findData.dwFileAttributes; + } + } + } + } could_stat = fileAttrib != INVALID_FILE_ATTRIBUTES; if (!could_stat) { #if !defined(Q_OS_WINCE) @@ -1520,8 +1580,8 @@ QString QFSFileEngine::fileName(FileName file) const if (!isRelativePath()) { #if !defined(Q_OS_WINCE) - if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') - && d->filePath.at(2) != QLatin1Char('/') || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt + if ((d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') + && d->filePath.at(2) != QLatin1Char('/')) || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt d->filePath.startsWith(QLatin1Char('/')) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt ) { ret = QDir::fromNativeSeparators(nativeAbsoluteFilePath(d->filePath)); @@ -1745,6 +1805,29 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const } else { WIN32_FILE_ATTRIBUTE_DATA attribData; bool ok = ::GetFileAttributesEx((wchar_t*)QFSFileEnginePrivate::longFileName(d->filePath).utf16(), GetFileExInfoStandard, &attribData); + if (!ok) { + int errorCode = GetLastError(); + if (errorCode == ERROR_ACCESS_DENIED || errorCode == ERROR_SHARING_VIOLATION) { + QString path = QDir::toNativeSeparators(d->filePath); + // path for the FindFirstFile should not end with a trailing slash + while (path.endsWith(QLatin1Char('\\'))) + path.chop(1); + + // FindFirstFile can not handle drives + if (!path.endsWith(QLatin1Char(':'))) { + WIN32_FIND_DATA findData; + HANDLE hFind = ::FindFirstFile((wchar_t*)QFSFileEnginePrivate::longFileName(path).utf16(), + &findData); + if (hFind != INVALID_HANDLE_VALUE) { + ::FindClose(hFind); + ok = true; + attribData.ftCreationTime = findData.ftCreationTime; + attribData.ftLastWriteTime = findData.ftLastWriteTime; + attribData.ftLastAccessTime = findData.ftLastAccessTime; + } + } + } + } if (ok) { if(time == CreationTime) ret = fileTimeToQDateTime(&attribData.ftCreationTime); diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 8d23d35..e75c314 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -305,7 +305,7 @@ void QProcessPrivate::Channel::clear() writes to its standard output and standard error will be written to the standard output and standard error of the main process. - \sa setReadChannelMode() + \sa setProcessChannelMode() */ /*! @@ -862,7 +862,7 @@ void QProcess::setReadChannelMode(ProcessChannelMode mode) Returns the channel mode of the QProcess standard output and standard error channels. - \sa setReadChannelMode(), ProcessChannelMode, setReadChannel() + \sa setProcessChannelMode(), ProcessChannelMode, setReadChannel() */ QProcess::ProcessChannelMode QProcess::processChannelMode() const { @@ -879,7 +879,7 @@ QProcess::ProcessChannelMode QProcess::processChannelMode() const \snippet doc/src/snippets/code/src_corelib_io_qprocess.cpp 0 - \sa readChannelMode(), ProcessChannelMode, setReadChannel() + \sa processChannelMode(), ProcessChannelMode, setReadChannel() */ void QProcess::setProcessChannelMode(ProcessChannelMode mode) { diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index fafce07..607b734 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -1161,10 +1161,10 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a // To catch the startup of the child int startedPipe[2]; - ::pipe(startedPipe); + qt_safe_pipe(startedPipe); // To communicate the pid of the child int pidPipe[2]; - ::pipe(pidPipe); + qt_safe_pipe(pidPipe); pid_t childPid = qt_fork(); if (childPid == 0) { diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index a70b92f..16927ea 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -575,7 +575,7 @@ QResource::addSearchPath(const QString &path) Returns the current search path list. This list is consulted when creating a relative resource. - \sa addSearchPath() + \sa QDir::addSearchPath() QDir::setSearchPaths() */ QStringList diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp index e97ac59..11f4acf 100644 --- a/src/corelib/io/qresource_iterator.cpp +++ b/src/corelib/io/qresource_iterator.cpp @@ -73,13 +73,11 @@ bool QResourceFileEngineIterator::hasNext() const return false; // Initialize and move to the next entry. - QResourceFileEngineIterator *that = const_cast<QResourceFileEngineIterator *>(this); - that->entries = resource.children(); - if (!that->entries.isEmpty()) - that->index = 0; + entries = resource.children(); + index = 0; } - return index <= entries.size(); + return index < entries.size(); } QString QResourceFileEngineIterator::currentFileName() const diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h index b5e8382..5165157 100644 --- a/src/corelib/io/qresource_iterator_p.h +++ b/src/corelib/io/qresource_iterator_p.h @@ -71,8 +71,8 @@ public: QString currentFileName() const; private: - QStringList entries; - int index; + mutable QStringList entries; + mutable int index; }; QT_END_NAMESPACE diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 180e9ec..79cd2f0 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -2336,12 +2336,12 @@ static const NameprepCaseFoldingEntry NameprepCaseFolding[] = { { 0x1D7BB, { 0x03C3, 0x0000, 0x0000, 0x0000 } } }; -static void mapToLowerCase(QString *str) +static void mapToLowerCase(QString *str, int from) { int N = sizeof(NameprepCaseFolding) / sizeof(NameprepCaseFolding[0]); QChar *d = 0; - for (int i = 0; i < str->size(); ++i) { + for (int i = from; i < str->size(); ++i) { int uc = str->at(i).unicode(); if (uc < 0x80) { if (uc <= 'Z' && uc >= 'A') { @@ -2388,11 +2388,11 @@ static bool isMappedToNothing(const QChar &ch) } -static void stripProhibitedOutput(QString *str) +static void stripProhibitedOutput(QString *str, int from) { - ushort *out = (ushort *)str->data(); + ushort *out = (ushort *)str->data() + from; const ushort *in = out; - const ushort *end = out + str->size(); + const ushort *end = (ushort *)str->data() + str->size(); while (in < end) { ushort uc = *in; if (uc < 0x80 || @@ -2901,66 +2901,99 @@ static bool isBidirectionalL(const QChar &ch) return false; } +#ifdef QT_BUILD_INTERNAL +// export for tst_qurl.cpp +Q_AUTOTEST_EXPORT void qt_nameprep(QString *source, int from); +Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len); +#else +// non-test build, keep the symbols for ourselves +static void qt_nameprep(QString *source, int from); +static bool qt_check_std3rules(const QChar *uc, int len); +#endif -Q_AUTOTEST_EXPORT QString qt_nameprep(const QString &source) +void qt_nameprep(QString *source, int from) { - QString mapped = source; - - bool simple = true; - for (int i = 0; i < mapped.size(); ++i) { - ushort uc = mapped.at(i).unicode(); + QChar *src = source->data(); // causes a detach, so we're sure the only one using it + QChar *out = src + from; + const QChar *e = src + source->size(); + + for ( ; out < e; ++out) { + register ushort uc = out->unicode(); if (uc > 0x80) { - simple = false; break; } else if (uc >= 'A' && uc <= 'Z') { - mapped[i] = QChar(uc | 0x20); + *out = QChar(uc | 0x20); } } - if (simple) - return mapped; - + if (out == e) + return; // everything was mapped easily (lowercased, actually) + int firstNonAscii = out - src; + // Characters commonly mapped to nothing are simply removed // (Table B.1) - QChar *out = mapped.data(); const QChar *in = out; - const QChar *e = in + mapped.size(); while (in < e) { if (!isMappedToNothing(*in)) *out++ = *in; ++in; } if (out != in) - mapped.truncate(out - mapped.constData()); + source->truncate(out - src); // Map to lowercase (Table B.2) - mapToLowerCase(&mapped); + mapToLowerCase(source, firstNonAscii); // Normalize to Unicode 3.2 form KC - mapped = mapped.normalized(QString::NormalizationForm_KC, QChar::Unicode_3_2); + extern void qt_string_normalize(QString *data, QString::NormalizationForm mode, + QChar::UnicodeVersion version, int from); + qt_string_normalize(source, QString::NormalizationForm_KC, QChar::Unicode_3_2, firstNonAscii); // Strip prohibited output - stripProhibitedOutput(&mapped); + stripProhibitedOutput(source, firstNonAscii); // Check for valid bidirectional characters bool containsLCat = false; bool containsRandALCat = false; - for (int j = 0; j < mapped.size() && (!containsLCat || !containsRandALCat); ++j) { - if (isBidirectionalL(mapped.at(j))) + src = source->data(); + e = src + source->size(); + for (in = src + from; in < e && (!containsLCat || !containsRandALCat); ++in) { + if (isBidirectionalL(*in)) containsLCat = true; - else if (isBidirectionalRorAL(mapped.at(j))) + else if (isBidirectionalRorAL(*in)) containsRandALCat = true; } if (containsRandALCat) { - if (containsLCat || (!isBidirectionalRorAL(mapped.at(0)) - || !isBidirectionalRorAL(mapped.at(mapped.size() - 1)))) - mapped.clear(); + if (containsLCat || (!isBidirectionalRorAL(src[from]) + || !isBidirectionalRorAL(e[-1]))) + source->resize(from); // not allowed, clear the label } +} + +bool qt_check_std3rules(const QChar *uc, int len) +{ + if (len > 63) + return false; - return mapped; + for (int i = 0; i < len; ++i) { + register ushort c = uc[i].unicode(); + if (c == '-' && (i == 0 || i == len - 1)) + return false; + + // verifying the absence of LDH is the same as verifying that + // only LDH is present + if (c == '-' || (c >= '0' && c <= '9') + || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z')) + continue; + + return false; + } + + return true; } -static inline char encodeDigit(uint digit) +static inline uint encodeDigit(uint digit) { return digit + 22 + 75 * (digit < 26); } @@ -2977,7 +3010,7 @@ static inline uint adapt(uint delta, uint numpoints, bool firsttime) return k + (((base - tmin + 1) * delta) / (delta + skew)); } -static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uint& b, uint& h) +static inline void appendEncode(QString* output, uint& delta, uint& bias, uint& b, uint& h) { uint qq; uint k; @@ -2991,17 +3024,17 @@ static inline void appendEncode(QByteArray* output, uint& delta, uint& bias, uin t = (k <= bias) ? tmin : (k >= bias + tmax) ? tmax : k - bias; if (qq < t) break; - *output += encodeDigit(t + (qq - t) % (base - t)); + *output += QChar(encodeDigit(t + (qq - t) % (base - t))); qq = (qq - t) / (base - t); } - *output += encodeDigit(qq); + *output += QChar(encodeDigit(qq)); bias = adapt(delta, h + 1, h == b); delta = 0; ++h; } -static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) +static void toPunycodeHelper(const QChar *s, int ucLength, QString *output) { uint n = initial_n; uint delta = 0; @@ -3010,7 +3043,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) int outLen = output->length(); output->resize(outLen + ucLength); - char *d = output->data() + outLen; + QChar *d = output->data() + outLen; bool skipped = false; // copy all basic code points verbatim to output. for (uint j = 0; j < (uint) ucLength; ++j) { @@ -3035,7 +3068,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) // if basic code points were copied, add the delimiter character. if (h > 0) - *output += 0x2d; + *output += QChar(0x2d); // while there are still unprocessed non-basic code points left in // the input string... @@ -3083,7 +3116,7 @@ static void toPunycodeHelper(const QChar *s, int ucLength, QByteArray *output) } // prepend ACE prefix - output->insert(outLen, "xn--"); + output->insert(outLen, QLatin1String("xn--")); return; } @@ -3144,11 +3177,15 @@ static bool qt_is_idn_enabled(const QString &domain) int idx = domain.lastIndexOf(QLatin1Char('.')); if (idx == -1) return false; - const QChar *tld = domain.constData() + idx + 1; + int len = domain.size() - idx - 1; + QString tldString(domain.constData() + idx + 1, len); + qt_nameprep(&tldString, 0); + + const QChar *tld = tldString.constData(); if (user_idn_whitelist) - return user_idn_whitelist->contains(QString(tld, len)); + return user_idn_whitelist->contains(tldString); int l = 0; int r = sizeof(idn_whitelist)/sizeof(const char *) - 1; @@ -3164,46 +3201,127 @@ static bool qt_is_idn_enabled(const QString &domain) return equal(tld, len, idn_whitelist[i]); } -static QString qt_from_ACE(const QString &domainMC) +static inline bool isDotDelimiter(ushort uc) { - QString domain = domainMC.toLower(); - int idx = domain.indexOf(QLatin1Char('.')); - if (idx != -1) { - if (!domain.contains(QLatin1String("xn--"))) { - bool simple = true; - for (int i = 0; i < domain.size(); ++i) { - ushort ch = domain.at(i).unicode(); - if (ch > 'z' || ch < '-' || ch == '/' || (ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a')) { + // IDNA / rfc3490 describes these four delimiters used for + // separating labels in unicode international domain + // names. + return uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61; +} + +static int nextDotDelimiter(const QString &domain, int from = 0) +{ + const QChar *b = domain.unicode(); + const QChar *ch = b + from; + const QChar *e = b + domain.length(); + while (ch < e) { + if (isDotDelimiter(ch->unicode())) + break; + else + ++ch; + } + return ch - b; +} + +enum AceOperation { ToAceOnly, NormalizeAce }; +static QString qt_ACE_do(const QString &domain, AceOperation op) +{ + if (domain.isEmpty()) + return domain; + + QString result; + result.reserve(domain.length()); + + const bool isIdnEnabled = op == NormalizeAce ? qt_is_idn_enabled(domain) : false; + int lastIdx = 0; + QString aceForm; // this variable is here for caching + + while (1) { + int idx = nextDotDelimiter(domain, lastIdx); + int labelLength = idx - lastIdx; + if (labelLength == 0) + return QString(); // two delimiters in a row -- empty label not allowed + + // RFC 3490 says, about the ToASCII operation: + // 3. If the UseSTD3ASCIIRules flag is set, then perform these checks: + // + // (a) Verify the absence of non-LDH ASCII code points; that is, the + // absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F. + // + // (b) Verify the absence of leading and trailing hyphen-minus; that + // is, the absence of U+002D at the beginning and end of the + // sequence. + // and: + // 8. Verify that the number of code points is in the range 1 to 63 + // inclusive. + + // copy the label to the destination, which also serves as our scratch area, lowercasing it + int prevLen = result.size(); + bool simple = true; + result.resize(prevLen + labelLength); + { + QChar *out = result.data() + prevLen; + const QChar *in = domain.constData() + lastIdx; + const QChar *e = in + labelLength; + for (; in < e; ++in, ++out) { + register ushort uc = in->unicode(); + if (uc > 0x7f) simple = false; - break; - } + if (uc >= 'A' && uc <= 'Z') + *out = QChar(uc | 0x20); + else + *out = *in; } - if (simple) - return domain; } - - const bool isIdnEnabled = qt_is_idn_enabled(domain); - int lastIdx = 0; - QString result; - while (1) { - // Nameprep the host. If the labels in the hostname are Punycode - // encoded, we decode them immediately, then nameprep them. - QByteArray label; - toPunycodeHelper(domain.constData() + lastIdx, idx - lastIdx, &label); - result += qt_nameprep(isIdnEnabled ? QUrl::fromPunycode(label) : QString::fromLatin1(label)); - lastIdx = idx + 1; - if (lastIdx < domain.size() + 1) - result += QLatin1Char('.'); - else - break; - idx = domain.indexOf(QLatin1Char('.'), lastIdx); - if (idx == -1) - idx = domain.size(); + + if (simple && labelLength > 6) { + // ACE form domains contain only ASCII characters, but we can't consider them simple + // is this an ACE form? + // the shortest valid ACE domain is 6 characters long (U+0080 would be 1, but it's not allowed) + static const ushort acePrefixUtf16[] = { 'x', 'n', '-', '-' }; + if (memcmp(result.constData() + prevLen, acePrefixUtf16, sizeof acePrefixUtf16) == 0) + simple = false; } - return result; - } else { - return qt_nameprep(domain); + + if (simple) { + // fastest case: this is the common case (non IDN-domains) + // so we're done + if (!qt_check_std3rules(result.constData() + prevLen, labelLength)) + return QString(); + } else { + // Punycode encoding and decoding cannot be done in-place + // That means we need one or two temporaries + qt_nameprep(&result, prevLen); + labelLength = result.length() - prevLen; + register int toReserve = labelLength + 4 + 6; // "xn--" plus some extra bytes + if (toReserve > aceForm.capacity()) + aceForm.reserve(toReserve); + toPunycodeHelper(result.constData() + prevLen, result.size() - prevLen, &aceForm); + + // We use resize()+memcpy() here because we're overwriting the data we've copied + if (isIdnEnabled) { + QString tmp = QUrl::fromPunycode(aceForm.toLatin1()); + if (tmp.isEmpty()) + return QString(); // shouldn't happen, since we've just punycode-encoded it + result.resize(prevLen + tmp.size()); + memcpy(result.data() + prevLen, tmp.constData(), tmp.size() * sizeof(QChar)); + } else { + result.resize(prevLen + aceForm.size()); + memcpy(result.data() + prevLen, aceForm.constData(), aceForm.size() * sizeof(QChar)); + } + + if (!qt_check_std3rules(aceForm.constData(), aceForm.size())) + return QString(); + } + + + lastIdx = idx + 1; + if (lastIdx < domain.size() + 1) + result += QLatin1Char('.'); + else + break; } + return result; } @@ -3246,12 +3364,27 @@ QUrlPrivate::QUrlPrivate(const QUrlPrivate ©) QString QUrlPrivate::canonicalHost() const { - if (QURL_HASFLAG(stateFlags, HostCanonicalized)) + if (QURL_HASFLAG(stateFlags, HostCanonicalized) || host.isEmpty()) return host; QUrlPrivate *that = const_cast<QUrlPrivate *>(this); QURL_SETFLAG(that->stateFlags, HostCanonicalized); - that->host = qt_from_ACE(host); + if (host.contains(QLatin1Char(':'))) { + // This is an IP Literal, use _IPLiteral to validate + QByteArray ba = host.toLatin1(); + if (!ba.startsWith('[')) { + // surround the IP Literal with [ ] if it's not already done so + ba.reserve(ba.length() + 2); + ba.prepend('['); + ba.append(']'); + } + + const char *ptr = ba.constData(); + if (!_IPLiteral(&ptr)) + that->host.clear(); + } else { + that->host = qt_ACE_do(host, NormalizeAce); + } return that->host; } @@ -3737,7 +3870,10 @@ QByteArray QUrlPrivate::toEncoded(QUrl::FormattingOptions options) const } } - url += QUrl::toAce(host); + if (host.startsWith(QLatin1Char('['))) + url += host.toLatin1(); + else + url += QUrl::toAce(host); if (!(options & QUrl::RemovePort) && port != -1) { url += ':'; url += QString::number(port).toAscii(); @@ -4412,8 +4548,6 @@ void QUrl::setHost(const QString &host) QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized | QUrlPrivate::HostCanonicalized); d->host = host; - if (d->host.contains(QLatin1Char(':'))) - d->host = QLatin1Char('[') + d->host + QLatin1Char(']'); } /*! @@ -5425,9 +5559,9 @@ QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclu */ QByteArray QUrl::toPunycode(const QString &uc) { - QByteArray output; + QString output; toPunycodeHelper(uc.constData(), uc.size(), &output); - return output; + return output.toLatin1(); } /*! @@ -5528,7 +5662,7 @@ QString QUrl::fromPunycode(const QByteArray &pc) */ QString QUrl::fromAce(const QByteArray &domain) { - return qt_from_ACE(QString::fromLatin1(domain)); + return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce); } /*! @@ -5545,26 +5679,8 @@ QString QUrl::fromAce(const QByteArray &domain) */ QByteArray QUrl::toAce(const QString &domain) { - // IDNA / rfc3490 describes these four delimiters used for - // separating labels in unicode international domain - // names. - QString nameprepped = qt_nameprep(domain); - int lastIdx = 0; - QByteArray result; - for (int i = 0; i < nameprepped.size(); ++i) { - ushort uc = nameprepped.at(i).unicode(); - if (uc == 0x2e || uc == 0x3002 || uc == 0xff0e || uc == 0xff61) { - if (lastIdx) - result += '.'; - toPunycodeHelper(nameprepped.constData() + lastIdx, i - lastIdx, &result); - lastIdx = i + 1; - } - } - if (lastIdx) - result += '.'; - toPunycodeHelper(nameprepped.constData() + lastIdx, nameprepped.size() - lastIdx, &result); - - return result; + QString result = qt_ACE_do(domain, ToAceOnly); + return result.toLatin1(); } /*! diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp index 1c3371f..3d9263e 100644 --- a/src/corelib/kernel/qabstractitemmodel.cpp +++ b/src/corelib/kernel/qabstractitemmodel.cpp @@ -2278,7 +2278,8 @@ void QAbstractItemModel::endRemoveColumns() \note The view to which the model is attached to will be reset as well. When a model is reset it means that any previous data reported from the - model is now invalid and has to be queried for again. + model is now invalid and has to be queried for again. This also means + that the current item and any selected items will become invalid. When a model radically changes its data it can sometimes be easier to just call this function rather than emit dataChanged() to inform other diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp index b04abae..28c1d9c 100644 --- a/src/corelib/kernel/qcore_unix.cpp +++ b/src/corelib/kernel/qcore_unix.cpp @@ -34,7 +34,7 @@ ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. +** contact the sales department at http://www.qtsoftware.com/contact. ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -47,6 +47,10 @@ #include "qeventdispatcher_unix_p.h" // for the timeval operators +#ifdef Q_OS_MAC +#include <mach/mach_time.h> +#endif + #if !defined(QT_NO_CLOCK_MONOTONIC) # if defined(QT_BOOTSTRAPPED) # define QT_NO_CLOCK_MONOTONIC @@ -55,37 +59,72 @@ QT_BEGIN_NAMESPACE -static inline timeval gettime() +bool qt_gettime_is_monotonic() { - timeval tv; -#ifndef QT_NO_CLOCK_MONOTONIC - // use the monotonic clock - static volatile bool monotonicClockDisabled = false; - struct timespec ts; - if (!monotonicClockDisabled) { - if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { - monotonicClockDisabled = true; - } else { - tv.tv_sec = ts.tv_sec; - tv.tv_usec = ts.tv_nsec / 1000; - return tv; - } +#if (_POSIX_MONOTONIC_CLOCK-0 > 0) || defined(Q_OS_MAC) + return true; +#else + static int returnValue = 0; + + if (returnValue == 0) { +# if (_POSIX_MONOTONIC_CLOCK-0 < 0) + returnValue = -1; +# elif (_POSIX_MONOTONIC_CLOCK == 0) + // detect if the system support monotonic timers + long x = sysconf(_SC_MONOTONIC_CLOCK); + returnValue = (x >= 200112L) ? 1 : -1; +# endif } + + return returnValue != -1; #endif +} + +timeval qt_gettime() +{ + timeval tv; +#if defined(Q_OS_MAC) + static mach_timebase_info_data_t info = {0,0}; + if (info.denom == 0) + mach_timebase_info(&info); + + uint64_t cpu_time = mach_absolute_time(); + uint64_t nsecs = cpu_time * (info.numer / info.denom); + tv.tv_sec = nsecs / 1000000000ull; + tv.tv_usec = (nsecs / 1000) - (tv.tv_sec * 1000000); + return tv; +#elif (_POSIX_MONOTONIC_CLOCK-0 > 0) + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + return tv; +#else +# if !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED) + if (qt_gettime_is_monotonic()) { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + return tv; + } +# endif // use gettimeofday ::gettimeofday(&tv, 0); return tv; +#endif } static inline bool time_update(struct timeval *tv, const struct timeval &start, const struct timeval &timeout) { - struct timeval now = gettime(); - if (now < start) { - // clock reset, give up + if (!qt_gettime_is_monotonic()) { + // we cannot recalculate the timeout without a monotonic clock as the time may have changed return false; } + // clock source is monotonic, so we can recalculate how much timeout is left + struct timeval now = qt_gettime(); *tv = timeout + start - now; return true; } @@ -100,7 +139,7 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, return ret; } - timeval start = gettime(); + timeval start = qt_gettime(); timeval timeout = *orig_timeout; // loop and recalculate the timeout as needed diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h index 8d43897..bffd670 100644 --- a/src/corelib/kernel/qcore_unix_p.h +++ b/src/corelib/kernel/qcore_unix_p.h @@ -69,10 +69,27 @@ struct sockaddr; -#if defined(Q_OS_LINUX) && defined(O_CLOEXEC) && defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0204 +#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0204 // Linux supports thread-safe FD_CLOEXEC # define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1 +// add defines for the consts for Linux +# ifndef O_CLOEXEC +# define O_CLOEXEC 02000000 +# endif +# ifndef FD_DUPFD_CLOEXEC +# define F_DUPFD_CLOEXEC 1030 +# endif +# ifndef SOCK_CLOEXEC +# define SOCK_CLOEXEC O_CLOEXEC +# endif +# ifndef SOCK_NONBLOCK +# define SOCK_NONBLOCK O_NONBLOCK +# endif +# ifndef MSG_CMSG_CLOEXEC +# define MSG_CMSG_CLOEXEC 0x40000000 +# endif + QT_BEGIN_NAMESPACE namespace QtLibcSupplement { Q_CORE_EXPORT int accept4(int, sockaddr *, QT_SOCKLEN_T *, int flags); @@ -250,6 +267,8 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options) return ret; } +bool qt_gettime_is_monotonic(); +timeval qt_gettime(); Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept, const struct timeval *tv); diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index a71f284..bf5716a 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -280,7 +280,7 @@ QT_END_INCLUDE_NAMESPACE // The values below should never change. Note that none of the usual // WM_...FIRST & WM_...LAST values are in the list, as they normally have other // WM_... representations -struct { +struct KnownWM { uint WM; const char* str; } knownWM[] = @@ -582,7 +582,7 @@ struct { { 0,0 }}; // End of known messages // Looks up the WM_ message in the table above -const char* findWMstr(uint msg) +static const char* findWMstr(uint msg) { uint i = 0; const char* result = 0; diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index c636716..a682fad9 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -219,6 +219,7 @@ QT_BEGIN_NAMESPACE \value WindowStateChange The \l{QWidget::windowState()}{window's state} (minimized, maximized or full-screen) has changed (QWindowStateChangeEvent). \value WindowTitleChange The window title has changed. \value WindowUnblocked The window is unblocked after a modal dialog exited. + \value Wrapped The event is a wrapper for, i.e., contains, another event (QWrappedEvent). \value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows. \value KeyboardLayoutChange The keyboard layout has changed. \value DynamicPropertyChange A dynamic property was added, changed or removed from the object. @@ -267,7 +268,6 @@ QT_BEGIN_NAMESPACE \omitvalue NetworkReplyUpdated \omitvalue FutureCallOut \omitvalue CocoaRequestModal - \omitvalue Wrapped \omitvalue Signal \omitvalue WinGesture */ diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 0eeea04..2943c6d 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -259,18 +259,10 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, QTimerInfoList::QTimerInfoList() { -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) - useMonotonicTimers = false; + currentTime = qt_gettime(); -# if (_POSIX_MONOTONIC_CLOCK == 0) - // detect if the system support monotonic timers - long x = sysconf(_SC_MONOTONIC_CLOCK); - useMonotonicTimers = x != -1; -# endif - - getTime(currentTime); - - if (!useMonotonicTimers) { +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC) + if (!qt_gettime_is_monotonic()) { // not using monotonic timers, initialize the timeChanged() machinery previousTime = currentTime; @@ -286,9 +278,6 @@ QTimerInfoList::QTimerInfoList() ticksPerSecond = 0; msPerTick = 0; } -#else - // using monotonic timers unconditionally - getTime(currentTime); #endif firstTimerInfo = currentTimerInfo = 0; @@ -296,11 +285,24 @@ QTimerInfoList::QTimerInfoList() timeval QTimerInfoList::updateCurrentTime() { - getTime(currentTime); - return currentTime; + return (currentTime = qt_gettime()); } -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) +#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED) + +template <> +timeval qAbs(const timeval &t) +{ + timeval tmp = t; + if (tmp.tv_sec < 0) { + tmp.tv_sec = -tmp.tv_sec - 1; + tmp.tv_usec -= 1000000; + } + if (tmp.tv_sec == 0 && tmp.tv_usec < 0) { + tmp.tv_usec = -tmp.tv_usec; + } + return normalizedTimeval(tmp); +} /* Returns true if the real time clock has changed by more than 10% @@ -314,57 +316,32 @@ bool QTimerInfoList::timeChanged(timeval *delta) tms unused; clock_t currentTicks = times(&unused); - int elapsedTicks = currentTicks - previousTicks; + clock_t elapsedTicks = currentTicks - previousTicks; timeval elapsedTime = currentTime - previousTime; - int elapsedMsecTicks = (elapsedTicks * 1000) / ticksPerSecond; - int deltaMsecs = (elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000) - - elapsedMsecTicks; - if (delta) { - delta->tv_sec = deltaMsecs / 1000; - delta->tv_usec = (deltaMsecs % 1000) * 1000; - } + timeval elapsedTimeTicks; + elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond; + elapsedTimeTicks.tv_usec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000; + + timeval dummy; + if (!delta) + delta = &dummy; + *delta = elapsedTime - elapsedTimeTicks; + previousTicks = currentTicks; previousTime = currentTime; // If tick drift is more than 10% off compared to realtime, we assume that the clock has // been set. Of course, we have to allow for the tick granularity as well. - - return (qAbs(deltaMsecs) - msPerTick) * 10 > elapsedMsecTicks; -} - -void QTimerInfoList::getTime(timeval &t) -{ -#if !defined(QT_NO_CLOCK_MONOTONIC) && !defined(QT_BOOTSTRAPPED) - if (useMonotonicTimers) { - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - t.tv_sec = ts.tv_sec; - t.tv_usec = ts.tv_nsec / 1000; - return; - } -#endif - - gettimeofday(&t, 0); - // NTP-related fix - while (t.tv_usec >= 1000000l) { - t.tv_usec -= 1000000l; - ++t.tv_sec; - } - while (t.tv_usec < 0l) { - if (t.tv_sec > 0l) { - t.tv_usec += 1000000l; - --t.tv_sec; - } else { - t.tv_usec = 0l; - break; - } - } + timeval tickGranularity; + tickGranularity.tv_sec = 0; + tickGranularity.tv_usec = msPerTick * 1000; + return elapsedTimeTicks < ((qAbs(*delta) - tickGranularity) * 10); } void QTimerInfoList::repairTimersIfNeeded() { - if (useMonotonicTimers) + if (qt_gettime_is_monotonic()) return; timeval delta; if (timeChanged(&delta)) @@ -373,14 +350,6 @@ void QTimerInfoList::repairTimersIfNeeded() #else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED) -void QTimerInfoList::getTime(timeval &t) -{ - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - t.tv_sec = ts.tv_sec; - t.tv_usec = ts.tv_nsec / 1000; -} - void QTimerInfoList::repairTimersIfNeeded() { } @@ -409,7 +378,7 @@ void QTimerInfoList::timerRepair(const timeval &diff) // repair all timers for (int i = 0; i < size(); ++i) { register QTimerInfo *t = at(i); - t->timeout = t->timeout - diff; + t->timeout = t->timeout + diff; } } @@ -606,25 +575,7 @@ QEventDispatcherUNIX::~QEventDispatcherUNIX() int QEventDispatcherUNIX::select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, timeval *timeout) { - Q_D(QEventDispatcherUNIX); - if (timeout) { - // handle the case where select returns with a timeout, too - // soon. - timeval tvStart = d->timerList.currentTime; - timeval tvCurrent = tvStart; - timeval originalTimeout = *timeout; - - int nsel; - do { - timeval tvRest = originalTimeout + tvStart - tvCurrent; - nsel = ::select(nfds, readfds, writefds, exceptfds, &tvRest); - d->timerList.getTime(tvCurrent); - } while (nsel == 0 && (tvCurrent - tvStart) < originalTimeout); - - return nsel; - } - - return ::select(nfds, readfds, writefds, exceptfds, timeout); + return ::qt_safe_select(nfds, readfds, writefds, exceptfds, timeout); } /*! diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h index d1f7431..61d94c9 100644 --- a/src/corelib/kernel/qeventdispatcher_unix_p.h +++ b/src/corelib/kernel/qeventdispatcher_unix_p.h @@ -71,6 +71,18 @@ QT_BEGIN_NAMESPACE #endif // Internal operator functions for timevals +inline timeval &normalizedTimeval(timeval &t) +{ + while (t.tv_usec > 1000000l) { + ++t.tv_sec; + t.tv_usec -= 1000000l; + } + while (t.tv_usec < 0l) { + --t.tv_sec; + t.tv_usec += 1000000l; + } + return t; +} inline bool operator<(const timeval &t1, const timeval &t2) { return t1.tv_sec < t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_usec < t2.tv_usec); } inline bool operator==(const timeval &t1, const timeval &t2) @@ -78,31 +90,29 @@ inline bool operator==(const timeval &t1, const timeval &t2) inline timeval &operator+=(timeval &t1, const timeval &t2) { t1.tv_sec += t2.tv_sec; - if ((t1.tv_usec += t2.tv_usec) >= 1000000l) { - ++t1.tv_sec; - t1.tv_usec -= 1000000l; - } - return t1; + t1.tv_usec += t2.tv_usec; + return normalizedTimeval(t1); } inline timeval operator+(const timeval &t1, const timeval &t2) { timeval tmp; tmp.tv_sec = t1.tv_sec + t2.tv_sec; - if ((tmp.tv_usec = t1.tv_usec + t2.tv_usec) >= 1000000l) { - ++tmp.tv_sec; - tmp.tv_usec -= 1000000l; - } - return tmp; + tmp.tv_usec = t1.tv_usec + t2.tv_usec; + return normalizedTimeval(tmp); } inline timeval operator-(const timeval &t1, const timeval &t2) { timeval tmp; - tmp.tv_sec = t1.tv_sec - t2.tv_sec; - if ((tmp.tv_usec = t1.tv_usec - t2.tv_usec) < 0l) { - --tmp.tv_sec; - tmp.tv_usec += 1000000l; - } - return tmp; + tmp.tv_sec = t1.tv_sec - (t2.tv_sec - 1); + tmp.tv_usec = t1.tv_usec - (t2.tv_usec + 1000000); + return normalizedTimeval(tmp); +} +inline timeval operator*(const timeval &t1, int mul) +{ + timeval tmp; + tmp.tv_sec = t1.tv_sec * mul; + tmp.tv_usec = t1.tv_usec * mul; + return normalizedTimeval(tmp); } // internal timer info @@ -116,9 +126,7 @@ struct QTimerInfo { class QTimerInfoList : public QList<QTimerInfo*> { -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) - bool useMonotonicTimers; - +#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_MAC)) || defined(QT_BOOTSTRAPPED) timeval previousTime; clock_t previousTicks; int ticksPerSecond; @@ -133,8 +141,6 @@ class QTimerInfoList : public QList<QTimerInfo*> public: QTimerInfoList(); - void getTime(timeval &t); - timeval currentTime; timeval updateCurrentTime(); diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index 3184244..08cecaf 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -2304,6 +2304,8 @@ QMetaMethod QMetaProperty::notifySignal() const } /*! + \since 4.6 + Returns the index of the property change notifying signal if one was specified, otherwise returns -1. diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 91266db..bd27ec2 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -171,6 +171,11 @@ QT_BEGIN_NAMESPACE \value QBitmap QBitmap \value QMatrix QMatrix \value QTransform QTransform + \value QMatrix4x4 QMatrix4x4 + \value QVector2D QVector2D + \value QVector3D QVector3D + \value QVector4D QVector4D + \value QQuaternion QQuaternion \value User Base value for user types @@ -272,6 +277,11 @@ static const struct { const char * typeName; int type; } types[] = { {"QTextFormat", QMetaType::QTextFormat}, {"QMatrix", QMetaType::QMatrix}, {"QTransform", QMetaType::QTransform}, + {"QMatrix4x4", QMetaType::QMatrix4x4}, + {"QVector2D", QMetaType::QVector2D}, + {"QVector3D", QMetaType::QVector3D}, + {"QVector4D", QMetaType::QVector4D}, + {"QQuaternion", QMetaType::QQuaternion}, /* All Metatype builtins */ {"void*", QMetaType::VoidStar}, @@ -430,16 +440,15 @@ int QMetaType::registerType(const char *typeName, Destructor destructor, #endif QWriteLocker locker(customTypesLock()); - static int currentIdx = User; int idx = qMetaTypeType_unlocked(normalizedTypeName); if (!idx) { - idx = currentIdx++; - ct->resize(ct->count() + 1); - QCustomTypeInfo &inf = (*ct)[idx - User]; + QCustomTypeInfo inf; inf.typeName = normalizedTypeName; inf.constr = constructor; inf.destr = destructor; + idx = ct->size() + User; + ct->append(inf); } return idx; } @@ -671,6 +680,11 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data) case QMetaType::QTextFormat: case QMetaType::QMatrix: case QMetaType::QTransform: + case QMetaType::QMatrix4x4: + case QMetaType::QVector2D: + case QMetaType::QVector3D: + case QMetaType::QVector4D: + case QMetaType::QQuaternion: if (!qMetaTypeGuiHelper) return false; qMetaTypeGuiHelper[type - FirstGuiType].saveOp(stream, data); @@ -863,6 +877,11 @@ bool QMetaType::load(QDataStream &stream, int type, void *data) case QMetaType::QTextFormat: case QMetaType::QMatrix: case QMetaType::QTransform: + case QMetaType::QMatrix4x4: + case QMetaType::QVector2D: + case QMetaType::QVector3D: + case QMetaType::QVector4D: + case QMetaType::QQuaternion: if (!qMetaTypeGuiHelper) return false; qMetaTypeGuiHelper[type - FirstGuiType].loadOp(stream, data); diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 497c014..052312c 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -79,7 +79,9 @@ public: QIcon = 69, QImage = 70, QPolygon = 71, QRegion = 72, QBitmap = 73, QCursor = 74, QSizePolicy = 75, QKeySequence = 76, QPen = 77, QTextLength = 78, QTextFormat = 79, QMatrix = 80, QTransform = 81, - LastGuiType = 81 /* QTransform */, + QMatrix4x4 = 82, QVector2D = 83, QVector3D = 84, QVector4D = 85, + QQuaternion = 86, + LastGuiType = 86 /* QQuaternion */, FirstCoreExtType = 128 /* VoidStar */, VoidStar = 128, Long = 129, Short = 130, Char = 131, ULong = 132, @@ -292,6 +294,11 @@ class QTextLength; class QTextFormat; class QMatrix; class QTransform; +class QMatrix4x4; +class QVector2D; +class QVector3D; +class QVector4D; +class QQuaternion; QT_END_NAMESPACE @@ -354,6 +361,11 @@ Q_DECLARE_BUILTIN_METATYPE(QTextLength, QTextLength) Q_DECLARE_BUILTIN_METATYPE(QTextFormat, QTextFormat) Q_DECLARE_BUILTIN_METATYPE(QMatrix, QMatrix) Q_DECLARE_BUILTIN_METATYPE(QTransform, QTransform) +Q_DECLARE_BUILTIN_METATYPE(QMatrix4x4, QMatrix4x4) +Q_DECLARE_BUILTIN_METATYPE(QVector2D, QVector2D) +Q_DECLARE_BUILTIN_METATYPE(QVector3D, QVector3D) +Q_DECLARE_BUILTIN_METATYPE(QVector4D, QVector4D) +Q_DECLARE_BUILTIN_METATYPE(QQuaternion, QQuaternion) QT_END_HEADER diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index eb1bd0b..6503ab0 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -854,7 +854,7 @@ QObject::~QObject() QObjectPrivate::Connection::~Connection() { if (argumentTypes != &DIRECT_CONNECTION_ONLY) - delete [] argumentTypes; + delete [] static_cast<int *>(argumentTypes); } diff --git a/src/corelib/kernel/qsharedmemory_unix.cpp b/src/corelib/kernel/qsharedmemory_unix.cpp index 04739ff..05369c4 100644 --- a/src/corelib/kernel/qsharedmemory_unix.cpp +++ b/src/corelib/kernel/qsharedmemory_unix.cpp @@ -85,7 +85,7 @@ void QSharedMemoryPrivate::setErrorString(const QString &function) error = QSharedMemory::AlreadyExists; break; case ENOENT: - errorString = QSharedMemory::tr("%1: doesn't exists").arg(function); + errorString = QSharedMemory::tr("%1: doesn't exist").arg(function); error = QSharedMemory::NotFound; break; case EMFILE: @@ -124,7 +124,7 @@ key_t QSharedMemoryPrivate::handle() // ftok requires that an actual file exists somewhere QString fileName = makePlatformSafeKey(key); if (!QFile::exists(fileName)) { - errorString = QSharedMemory::tr("%1: unix key file doesn't exists").arg(QLatin1String("QSharedMemory::handle:")); + errorString = QSharedMemory::tr("%1: UNIX key file doesn't exist").arg(QLatin1String("QSharedMemory::handle:")); error = QSharedMemory::NotFound; return 0; } diff --git a/src/corelib/kernel/qsharedmemory_win.cpp b/src/corelib/kernel/qsharedmemory_win.cpp index c88149a..ae64806 100644 --- a/src/corelib/kernel/qsharedmemory_win.cpp +++ b/src/corelib/kernel/qsharedmemory_win.cpp @@ -71,7 +71,7 @@ void QSharedMemoryPrivate::setErrorString(const QString &function) case ERROR_INVALID_PARAMETER: #endif error = QSharedMemory::NotFound; - errorString = QSharedMemory::tr("%1: doesn't exists").arg(function); + errorString = QSharedMemory::tr("%1: doesn't exist").arg(function); break; case ERROR_COMMITMENT_LIMIT: error = QSharedMemory::InvalidSize; diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 2ef9de4..2b5ea0a 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -1264,6 +1264,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; \value Map a QVariantMap \value Matrix a QMatrix \value Transform a QTransform + \value Matrix4x4 a QMatrix4x4 \value Palette a QPalette \value Pen a QPen \value Pixmap a QPixmap @@ -1271,6 +1272,7 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; \value PointArray a QPointArray \value PointF a QPointF \value Polygon a QPolygon + \value Quaternion a QQuaternion \value Rect a QRect \value RectF a QRectF \value RegExp a QRegExp @@ -1286,6 +1288,9 @@ const QVariant::Handler *QVariant::handler = &qt_kernel_variant_handler; \value UInt a \l uint \value ULongLong a \l qulonglong \value Url a QUrl + \value Vector2D a QVector2D + \value Vector3D a QVector3D + \value Vector4D a QVector4D \value UserType Base value for user-defined types. @@ -1677,7 +1682,7 @@ QVariant::QVariant(Qt::GlobalColor color) { create(62, &color); } Note that return values in the ranges QVariant::Char through QVariant::RegExp and QVariant::Font through QVariant::Transform correspond to the values in the ranges QMetaType::QChar through - QMetaType::QRegExp and QMetaType::QFont through QMetaType::QTransform. + QMetaType::QRegExp and QMetaType::QFont through QMetaType::QQuaternion. Pay particular attention when working with char and QChar variants. Note that there is no QVariant constructor specifically diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index e923844..a68939d 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -154,7 +154,12 @@ class Q_CORE_EXPORT QVariant TextFormat = 79, Matrix = 80, Transform = 81, - LastGuiType = Transform, + Matrix4x4 = 82, + Vector2D = 83, + Vector3D = 84, + Vector4D = 85, + Quaternion = 86, + LastGuiType = Quaternion, UserType = 127, #ifdef QT3_SUPPORT diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp index 670aa7d..0004d3e 100644 --- a/src/corelib/statemachine/qabstracttransition.cpp +++ b/src/corelib/statemachine/qabstracttransition.cpp @@ -115,13 +115,10 @@ QAbstractTransitionPrivate *QAbstractTransitionPrivate::get(QAbstractTransition QStateMachine *QAbstractTransitionPrivate::machine() const { - QObject *par = parent; - while (par != 0) { - if (QStateMachine *mach = qobject_cast<QStateMachine*>(par)) - return mach; - par = par->parent(); - } - return 0; + QState *source = sourceState(); + if (!source) + return 0; + return source->machine(); } bool QAbstractTransitionPrivate::callEventTest(QEvent *e) @@ -256,10 +253,6 @@ void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets) qWarning("QAbstractTransition::setTargetStates: target state(s) cannot be null"); return; } - if (target->machine() != 0 && target->machine()->rootState() == target) { - qWarning("QAbstractTransition::setTargetStates: root state cannot be target of transition"); - return; - } } d->targetStates.clear(); diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp index 83dd869..2042288 100644 --- a/src/corelib/statemachine/qstate.cpp +++ b/src/corelib/statemachine/qstate.cpp @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE The assignProperty() function is used for defining property assignments that should be performed when a state is entered. - Top-level states must be passed QStateMachine::rootState() as their parent + Top-level states must be passed a QStateMachine object as their parent state, or added to a state machine using QStateMachine::addState(). \section1 States with Child States @@ -215,6 +215,8 @@ QList<QAbstractTransition*> QStatePrivate::transitions() const return result; } +#ifndef QT_NO_PROPERTIES + /*! Instructs this state to set the property with the given \a name of the given \a object to the given \a value when the state is entered. @@ -239,10 +241,12 @@ void QState::assignProperty(QObject *object, const char *name, d->propertyAssignments.append(QPropertyAssignment(object, name, value)); } +#endif // QT_NO_PROPERTIES + /*! Returns this state's error state. - \sa QStateMachine::errorState(), QStateMachine::setErrorState() + \sa QStateMachine::error() */ QAbstractState *QState::errorState() const { @@ -256,19 +260,17 @@ QAbstractState *QState::errorState() const state recursively. If no error state is set for the state itself or any of its ancestors, an error will cause the machine to stop executing and an error will be printed to the console. - - \sa QStateMachine::setErrorState(), QStateMachine::errorState() */ void QState::setErrorState(QAbstractState *state) { Q_D(QState); - if (state != 0 && state->machine() != machine()) { - qWarning("QState::setErrorState: error state cannot belong " - "to a different state machine"); + if (state != 0 && qobject_cast<QStateMachine*>(state)) { + qWarning("QStateMachine::setErrorState: root state cannot be error state"); return; } - if (state != 0 && state->machine() != 0 && state->machine()->rootState() == state) { - qWarning("QStateMachine::setErrorState: root state cannot be error state"); + if (state != 0 && (!state->machine() || ((state->machine() != machine()) && !qobject_cast<QStateMachine*>(this)))) { + qWarning("QState::setErrorState: error state cannot belong " + "to a different state machine"); return; } @@ -288,12 +290,7 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition) return 0; } - // machine() will always be non-null for root state - if (machine() != 0 && machine()->rootState() == this) { - qWarning("QState::addTransition: cannot add transition from root state"); - return 0; - } - + transition->setParent(this); const QList<QPointer<QAbstractState> > &targets = QAbstractTransitionPrivate::get(transition)->targetStates; for (int i = 0; i < targets.size(); ++i) { QAbstractState *t = targets.at(i); @@ -308,7 +305,6 @@ QAbstractTransition *QState::addTransition(QAbstractTransition *transition) return 0; } } - transition->setParent(this); if (machine() != 0 && machine()->configuration().contains(this)) QStateMachinePrivate::get(machine())->registerTransitions(this); return transition; diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h index 41d32be..ce88b25 100644 --- a/src/corelib/statemachine/qstate.h +++ b/src/corelib/statemachine/qstate.h @@ -87,8 +87,10 @@ public: ChildMode childMode() const; void setChildMode(ChildMode mode); +#ifndef QT_NO_PROPERTIES void assignProperty(QObject *object, const char *name, const QVariant &value); +#endif Q_SIGNALS: void finished(); diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index bf3ee31..a02480b 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -102,14 +102,9 @@ QT_BEGIN_NAMESPACE Framework}{overview} gives several state graphs and the code to build them. - The rootState() is the parent of all top-level states in the - machine; it is used, for instance, when the state graph is - deleted. It is created by the machine. - - Use the addState() function to add a state to the state machine. - All top-level states are added to the root state. States are - removed with the removeState() function. Removing states while the - machine is running is discouraged. + Use the addState() function to add a top-level state to the state machine. + States are removed with the removeState() function. Removing states while + the machine is running is discouraged. Before the machine can be started, the \l{initialState}{initial state} must be set. The initial state is the state that the @@ -179,26 +174,6 @@ This is */ /*! - \property QStateMachine::rootState - - \brief the root state of this state machine -*/ - -/*! - \property QStateMachine::initialState - - \brief the initial state of this state machine - - The initial state must be one of the rootState()'s child states. -*/ - -/*! - \property QStateMachine::errorState - - \brief the error state of this state machine -*/ - -/*! \property QStateMachine::errorString \brief the error string of this state machine @@ -235,7 +210,6 @@ QStateMachinePrivate::QStateMachinePrivate() stop = false; error = QStateMachine::NoError; globalRestorePolicy = QStateMachine::DoNotRestoreProperties; - rootState = 0; signalEventGenerator = 0; #ifndef QT_NO_ANIMATION animationsEnabled = true; @@ -255,6 +229,11 @@ QStateMachinePrivate *QStateMachinePrivate::get(QStateMachine *q) return 0; } +QState *QStateMachinePrivate::rootState() const +{ + return const_cast<QStateMachine*>(q_func()); +} + static QEvent *cloneEvent(QEvent *e) { switch (e->type()) { @@ -302,7 +281,9 @@ bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState } else if (isDescendantOf(s2, s1)) { return true; } else { - QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2); + Q_ASSERT(s1->machine() != 0); + QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine()); + QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2); Q_ASSERT(lca != 0); return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2)); } @@ -318,17 +299,19 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState } else if (isDescendantOf(s2, s1)) { return false; } else { - QState *lca = findLCA(QList<QAbstractState*>() << s1 << s2); + Q_ASSERT(s1->machine() != 0); + QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine()); + QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2); Q_ASSERT(lca != 0); return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2)); } } -QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) +QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) const { if (states.isEmpty()) return 0; - QList<QState*> ancestors = properAncestors(states.at(0), 0); + QList<QState*> ancestors = properAncestors(states.at(0), rootState()->parentState()); for (int i = 0; i < ancestors.size(); ++i) { QState *anc = ancestors.at(i); bool ok = true; @@ -376,7 +359,7 @@ QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event continue; if (isPreempted(state, enabledTransitions)) continue; - QList<QState*> lst = properAncestors(state, 0); + QList<QState*> lst = properAncestors(state, rootState()->parentState()); if (QState *grp = qobject_cast<QState*>(state)) lst.prepend(grp); bool found = false; @@ -412,7 +395,9 @@ void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransit #endif executeTransitionContent(event, enabledTransitions); QList<QAbstractState*> enteredStates = enterStates(event, enabledTransitions); +#ifndef QT_NO_PROPERTIES applyProperties(enabledTransitions, exitedStates, enteredStates); +#endif #ifdef QSTATEMACHINE_DEBUG qDebug() << q_func() << ": configuration after entering states:" << configuration; qDebug() << q_func() << ": end microstep"; @@ -557,11 +542,13 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL if (isFinal(s)) { QState *parent = s->parentState(); if (parent) { - QState *grandparent = parent->parentState(); + if (parent != rootState()) { #ifdef QSTATEMACHINE_DEBUG - qDebug() << q << ": emitting finished signal for" << parent; + qDebug() << q << ": emitting finished signal for" << parent; #endif - QStatePrivate::get(parent)->emitFinished(); + QStatePrivate::get(parent)->emitFinished(); + } + QState *grandparent = parent->parentState(); if (grandparent && isParallel(grandparent)) { bool allChildStatesFinal = true; QList<QAbstractState*> childStates = QStatePrivate::get(grandparent)->childStates(); @@ -572,7 +559,7 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL break; } } - if (allChildStatesFinal) { + if (allChildStatesFinal && (grandparent != rootState())) { #ifdef QSTATEMACHINE_DEBUG qDebug() << q << ": emitting finished signal for" << grandparent; #endif @@ -585,7 +572,7 @@ QList<QAbstractState*> QStateMachinePrivate::enterStates(QEvent *event, const QL { QSet<QAbstractState*>::const_iterator it; for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) { - if (isFinal(*it) && (*it)->parentState() == rootState) { + if (isFinal(*it) && (*it)->parentState() == rootState()) { processing = false; stopProcessingReason = Finished; break; @@ -630,6 +617,11 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, } } } else { + if (s == rootState()) { + // Error has already been set by exitStates(). + Q_ASSERT(error != QStateMachine::NoError); + return; + } statesToEnter.insert(s); if (isParallel(s)) { QState *grp = qobject_cast<QState*>(s); @@ -643,6 +635,7 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, QState *grp = qobject_cast<QState*>(s); QAbstractState *initial = grp->initialState(); if (initial != 0) { + Q_ASSERT(initial->machine() == q_func()); addStatesToEnter(initial, grp, statesToEnter, statesForDefaultEntry); } else { setError(QStateMachine::NoInitialStateError, grp); @@ -675,6 +668,8 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root, } } +#ifndef QT_NO_PROPERTIES + void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &transitionList, const QList<QAbstractState*> &exitedStates, const QList<QAbstractState*> &enteredStates) @@ -862,6 +857,8 @@ void QStateMachinePrivate::applyProperties(const QList<QAbstractTransition*> &tr } } +#endif // QT_NO_PROPERTIES + bool QStateMachinePrivate::isFinal(const QAbstractState *s) { return qobject_cast<const QFinalState*>(s) != 0; @@ -873,20 +870,26 @@ bool QStateMachinePrivate::isParallel(const QAbstractState *s) return ss && (QStatePrivate::get(ss)->childMode == QState::ParallelStates); } -bool QStateMachinePrivate::isCompound(const QAbstractState *s) +bool QStateMachinePrivate::isCompound(const QAbstractState *s) const { const QState *group = qobject_cast<const QState*>(s); if (!group) return false; + bool isMachine = (qobject_cast<const QStateMachine*>(group) != 0); + // Don't treat the machine as compound if it's a sub-state of this machine + if (isMachine && (group != rootState())) + return false; return (!isParallel(group) && !QStatePrivate::get(group)->childStates().isEmpty()) - || (qobject_cast<QStateMachine*>(group->parent()) != 0); + || isMachine; } -bool QStateMachinePrivate::isAtomic(const QAbstractState *s) +bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const { const QState *ss = qobject_cast<const QState*>(s); return (ss && QStatePrivate::get(ss)->childStates().isEmpty()) - || isFinal(s); + || isFinal(s) + // Treat the machine as atomic if it's a sub-state of this machine + || (ss && (qobject_cast<const QStateMachine*>(ss) != 0) && (ss != rootState())); } @@ -935,6 +938,8 @@ bool QStateMachinePrivate::isInFinalState(QAbstractState* s) const return false; } +#ifndef QT_NO_PROPERTIES + void QStateMachinePrivate::registerRestorable(QObject *object, const QByteArray &propertyName) { RestorableId id(object, propertyName); @@ -979,6 +984,8 @@ void QStateMachinePrivate::unregisterRestorable(QObject *object, const QByteArra registeredRestorables.remove(id); } +#endif // QT_NO_PROPERTIES + QAbstractState *QStateMachinePrivate::findErrorState(QAbstractState *context) { // Find error state recursively in parent hierarchy if not set explicitly for context state @@ -1034,7 +1041,7 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta if (currentContext == currentErrorState) currentErrorState = 0; - Q_ASSERT(currentErrorState != rootState); + Q_ASSERT(currentErrorState != rootState()); if (currentErrorState != 0) { QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext); @@ -1091,12 +1098,14 @@ void QStateMachinePrivate::_q_animationFinished() resetAnimationEndValues.remove(anim); } +#ifndef QT_NO_PROPERTIES // Set the final property value. QPropertyAssignment assn = propertyForAnimation.take(anim); Q_ASSERT(assn.object != 0); assn.object->setProperty(assn.propertyName, assn.value); if (!assn.explicitlySet) unregisterRestorable(assn.object, assn.propertyName); +#endif QAbstractState *state = stateForAnimation.take(anim); Q_ASSERT(state != 0); @@ -1141,11 +1150,8 @@ void QStateMachinePrivate::_q_start() { Q_Q(QStateMachine); Q_ASSERT(state == Starting); - if (!rootState) { - state = NotRunning; - return; - } - QAbstractState *initial = rootState->initialState(); + Q_ASSERT(rootState() != 0); + QAbstractState *initial = rootState()->initialState(); configuration.clear(); qDeleteAll(internalEventQueue); internalEventQueue.clear(); @@ -1159,7 +1165,7 @@ void QStateMachinePrivate::_q_start() processingScheduled = true; // we call _q_process() below emit q->started(); - StartState *start = new StartState(rootState); + StartState *start = new StartState(rootState()); QAbstractTransition *initialTransition = new InitialTransition(initial); start->addTransition(initialTransition); QList<QAbstractTransition*> transitions; @@ -1167,8 +1173,10 @@ void QStateMachinePrivate::_q_start() QEvent nullEvent(QEvent::None); executeTransitionContent(&nullEvent, transitions); QList<QAbstractState*> enteredStates = enterStates(&nullEvent, transitions); +#ifndef QT_NO_PROPERTIES applyProperties(transitions, QList<QAbstractState*>() << start, enteredStates); +#endif delete start; #ifdef QSTATEMACHINE_DEBUG @@ -1371,15 +1379,22 @@ void QStateMachinePrivate::unregisterSignalTransition(QSignalTransition *transit void QStateMachinePrivate::unregisterAllTransitions() { + Q_Q(QStateMachine); { - QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState); - for (int i = 0; i < transitions.size(); ++i) - unregisterSignalTransition(transitions.at(i)); + QList<QSignalTransition*> transitions = qFindChildren<QSignalTransition*>(rootState()); + for (int i = 0; i < transitions.size(); ++i) { + QSignalTransition *t = transitions.at(i); + if (t->machine() == q) + unregisterSignalTransition(t); + } } { - QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState); - for (int i = 0; i < transitions.size(); ++i) - unregisterEventTransition(transitions.at(i)); + QList<QEventTransition*> transitions = qFindChildren<QEventTransition*>(rootState()); + for (int i = 0; i < transitions.size(); ++i) { + QEventTransition *t = transitions.at(i); + if (t->machine() == q) + unregisterEventTransition(t); + } } } @@ -1457,16 +1472,20 @@ void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int sig Constructs a new state machine with the given \a parent. */ QStateMachine::QStateMachine(QObject *parent) - : QObject(*new QStateMachinePrivate, parent) + : QState(*new QStateMachinePrivate, /*parentState=*/0) { + // Can't pass the parent to the QState constructor, as it expects a QState + // But this works as expected regardless of whether parent is a QState or not + setParent(parent); } /*! \internal */ QStateMachine::QStateMachine(QStateMachinePrivate &dd, QObject *parent) - : QObject(dd, parent) + : QState(dd, /*parentState=*/0) { + setParent(parent); } /*! @@ -1476,69 +1495,6 @@ QStateMachine::~QStateMachine() { } -namespace { - -class RootState : public QState -{ -public: - RootState(QState *parent) - : QState(parent) - { - } - - void onEntry(QEvent *) {} - void onExit(QEvent *) {} -}; - -} // namespace - -/*! - Returns this state machine's root state. -*/ -QState *QStateMachine::rootState() const -{ - Q_D(const QStateMachine); - if (!d->rootState) { - const_cast<QStateMachinePrivate*>(d)->rootState = new RootState(0); - d->rootState->setParent(const_cast<QStateMachine*>(this)); - } - return d->rootState; -} - -/*! - Returns the error state of the state machine's root state. - - \sa QState::errorState() -*/ -QAbstractState *QStateMachine::errorState() const -{ - return rootState()->errorState(); -} - -/*! - Sets the error state of this state machine's root state to be \a state. When a running state - machine encounters an error which puts it in an undefined state, it will enter an error state - based on the context of the error that occurred. It will enter this state regardless of what - is currently in the event queue. - - If the erroneous state has an error state set, this will be entered by the machine. If no error - state has been set, the state machine will search the parent hierarchy recursively for an - error state. The error state of the root state can thus be seen as a global error state that - applies for all states for which a more specific error state has not been set. - - Before entering the error state, the state machine will set the error code returned by error() and - error message returned by errorString(). - - If there is no error state available for the erroneous state, the state machine will print a - warning message on the console and stop executing. - - \sa QState::setErrorState(), rootState() -*/ -void QStateMachine::setErrorState(QAbstractState *state) -{ - rootState()->setErrorState(state); -} - /*! \enum QStateMachine::Error This enum type defines errors that can occur in the state machine at run time. When the state @@ -1640,39 +1596,13 @@ void QStateMachine::setGlobalRestorePolicy(QStateMachine::RestorePolicy restoreP } /*! - Returns this state machine's initial state, or 0 if no initial state has - been set. -*/ -QAbstractState *QStateMachine::initialState() const -{ - Q_D(const QStateMachine); - if (!d->rootState) - return 0; - return d->rootState->initialState(); -} - -/*! - Sets this state machine's initial \a state. -*/ -void QStateMachine::setInitialState(QAbstractState *state) -{ - Q_D(QStateMachine); - if (!d->rootState) { - if (!state) - return; - rootState()->setInitialState(state); - } - d->rootState->setInitialState(state); -} - -/*! Adds the given \a state to this state machine. The state becomes a top-level - state (i.e. a child of the rootState()). + state. If the state is already in a different machine, it will first be removed from its old machine, and then added to this machine. - \sa removeState(), rootState(), setInitialState() + \sa removeState(), setInitialState() */ void QStateMachine::addState(QAbstractState *state) { @@ -1684,7 +1614,7 @@ void QStateMachine::addState(QAbstractState *state) qWarning("QStateMachine::addState: state has already been added to this machine"); return; } - state->setParent(rootState()); + state->setParent(this); } /*! @@ -1730,7 +1660,7 @@ void QStateMachine::start() { Q_D(QStateMachine); - if (rootState()->initialState() == 0) { + if (initialState() == 0) { qWarning("QStateMachine::start: No initial state set for machine. Refusing to start."); return; } @@ -1821,7 +1751,7 @@ void QStateMachine::postInternalEvent(QEvent *event) Returns the maximal consistent set of states (including parallel and final states) that this state machine is currently in. If a state \c s is in the configuration, it is always the case that the parent of \c s is also in - c. Note, however, that the rootState() is not an explicit member of the + c. Note, however, that the machine itself is not an explicit member of the configuration. */ QSet<QAbstractState*> QStateMachine::configuration() const @@ -1840,15 +1770,6 @@ QSet<QAbstractState*> QStateMachine::configuration() const */ /*! - \fn QStateMachine::finished() - - This signal is emitted when the state machine has reached a top-level final - state (QFinalState). - - \sa QStateMachine::started() -*/ - -/*! \fn QStateMachine::stopped() This signal is emitted when the state machine has stopped. @@ -1872,14 +1793,6 @@ bool QStateMachine::event(QEvent *e) d->scheduleProcess(); return true; } - } else if (e->type() == QEvent::ChildAdded) { - QChildEvent *ce = static_cast<QChildEvent*>(e); - if (QAbstractState *state = qobject_cast<QAbstractState*>(ce->child())) { - if (state != rootState()) { - state->setParent(rootState()); - return true; - } - } } return QObject::event(e); } @@ -1949,6 +1862,24 @@ void QStateMachine::endMicrostep(QEvent *event) Q_UNUSED(event); } +/*! + \reimp +*/ +void QStateMachine::onEntry(QEvent *event) +{ + start(); + QState::onEntry(event); +} + +/*! + \reimp +*/ +void QStateMachine::onExit(QEvent *event) +{ + stop(); + QState::onExit(event); +} + #ifndef QT_NO_ANIMATION /*! @@ -2155,6 +2086,8 @@ QSignalEvent::~QSignalEvent() Constructs a new QWrappedEvent object with the given \a object and \a event. + + The QWrappedEvent object takes ownership of \a event. */ QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event) : QEvent(QEvent::Wrapped), m_object(object), m_event(event) @@ -2166,6 +2099,7 @@ QWrappedEvent::QWrappedEvent(QObject *object, QEvent *event) */ QWrappedEvent::~QWrappedEvent() { + delete m_event; } /*! diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h index 30d0e3a..230d852 100644 --- a/src/corelib/statemachine/qstatemachine.h +++ b/src/corelib/statemachine/qstatemachine.h @@ -42,7 +42,7 @@ #ifndef QSTATEMACHINE_H #define QSTATEMACHINE_H -#include <QtCore/qabstractstate.h> +#include <QtCore/qstate.h> #include <QtCore/qlist.h> #include <QtCore/qobject.h> @@ -57,18 +57,12 @@ QT_MODULE(Core) #ifndef QT_NO_STATEMACHINE class QEvent; -class QAbstractState; -class QState; class QStateMachinePrivate; class QAbstractAnimation; -class QAbstractState; -class Q_CORE_EXPORT QStateMachine : public QObject +class Q_CORE_EXPORT QStateMachine : public QState { Q_OBJECT - Q_PROPERTY(QState* rootState READ rootState) - Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState) - Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState) Q_PROPERTY(QString errorString READ errorString) Q_PROPERTY(RestorePolicy globalRestorePolicy READ globalRestorePolicy WRITE setGlobalRestorePolicy) Q_ENUMS(RestorePolicy) @@ -94,14 +88,6 @@ public: void addState(QAbstractState *state); void removeState(QAbstractState *state); - QState *rootState() const; - - QAbstractState *initialState() const; - void setInitialState(QAbstractState *state); - - QAbstractState *errorState() const; - void setErrorState(QAbstractState *state); - Error error() const; QString errorString() const; void clearError(); @@ -135,9 +121,11 @@ public Q_SLOTS: Q_SIGNALS: void started(); void stopped(); - void finished(); protected: + void onEntry(QEvent *event); + void onExit(QEvent *event); + void postInternalEvent(QEvent *event); virtual void beginSelectTransitions(QEvent *event); diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h index 1335b93..cae21aa 100644 --- a/src/corelib/statemachine/qstatemachine_p.h +++ b/src/corelib/statemachine/qstatemachine_p.h @@ -53,7 +53,8 @@ // We mean it. // -#include <private/qobject_p.h> +#include "private/qstate_p.h" + #include <QtCore/qcoreevent.h> #include <QtCore/qhash.h> #include <QtCore/qlist.h> @@ -61,9 +62,6 @@ #include <QtCore/qset.h> #include <QtCore/qvector.h> -#include "qstate.h" -#include "private/qstate_p.h" - QT_BEGIN_NAMESPACE class QEvent; @@ -81,7 +79,7 @@ class QAbstractAnimation; #endif class QStateMachine; -class QStateMachinePrivate : public QObjectPrivate +class QStateMachinePrivate : public QStatePrivate { Q_DECLARE_PUBLIC(QStateMachine) public: @@ -101,7 +99,7 @@ public: static QStateMachinePrivate *get(QStateMachine *q); - static QState *findLCA(const QList<QAbstractState*> &states); + QState *findLCA(const QList<QAbstractState*> &states) const; static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2); static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2); @@ -116,6 +114,8 @@ public: void _q_animationFinished(); #endif + QState *rootState() const; + void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList); bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const; QSet<QAbstractTransition*> selectTransitions(QEvent *event) const; @@ -133,8 +133,8 @@ public: bool isInFinalState(QAbstractState *s) const; static bool isFinal(const QAbstractState *s); static bool isParallel(const QAbstractState *s); - static bool isCompound(const QAbstractState *s); - static bool isAtomic(const QAbstractState *s); + bool isCompound(const QAbstractState *s) const; + bool isAtomic(const QAbstractState *s) const; static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other); static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound); @@ -151,6 +151,7 @@ public: void **args); void scheduleProcess(); +#ifndef QT_NO_PROPERTIES typedef QPair<QObject *, QByteArray> RestorableId; QHash<RestorableId, QVariant> registeredRestorables; void registerRestorable(QObject *object, const QByteArray &propertyName); @@ -158,13 +159,13 @@ public: bool hasRestorable(QObject *object, const QByteArray &propertyName) const; QVariant restorableValue(QObject *object, const QByteArray &propertyName) const; QList<QPropertyAssignment> restorablesToPropertyList(const QHash<RestorableId, QVariant> &restorables) const; +#endif State state; bool processing; bool processingScheduled; bool stop; StopProcessingReason stopProcessingReason; - QState *rootState; QSet<QAbstractState*> configuration; QList<QEvent*> internalEventQueue; QList<QEvent*> externalEventQueue; diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index 1d247fc..ae79735 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include <windows.h> +#include <qt_windows.h> #include "qmutex.h" #include <qatomic.h> diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h index 51d42b5..4742bea 100644 --- a/src/corelib/thread/qreadwritelock.h +++ b/src/corelib/thread/qreadwritelock.h @@ -190,7 +190,8 @@ inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock) class Q_CORE_EXPORT QReadWriteLock { public: - inline explicit QReadWriteLock() { } + enum RecursionMode { NonRecursive, Recursive }; + inline explicit QReadWriteLock(RecursionMode = NonRecursive) { } inline ~QReadWriteLock() { } static inline void lockForRead() { } diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index 6c24784..32b680e 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -54,7 +54,7 @@ #include <private/qcoreapplication_p.h> #include <private/qeventdispatcher_win_p.h> -#include <windows.h> +#include <qt_windows.h> #ifndef Q_OS_WINCE diff --git a/src/corelib/tools/qbytearraymatcher.h b/src/corelib/tools/qbytearraymatcher.h index 697b6ff..4bad24c 100644 --- a/src/corelib/tools/qbytearraymatcher.h +++ b/src/corelib/tools/qbytearraymatcher.h @@ -81,13 +81,14 @@ private: // explicitely allow anonymous unions for RVCT to prevent compiler warnings #pragma anon_unions #endif + struct Data { + uchar q_skiptable[256]; + const uchar *p; + int l; + }; union { uint dummy[256]; - struct { - uchar q_skiptable[256]; - const uchar *p; - int l; - } p; + Data p; }; }; diff --git a/src/corelib/tools/qbytedata_p.h b/src/corelib/tools/qbytedata_p.h new file mode 100644 index 0000000..cc10ea2 --- /dev/null +++ b/src/corelib/tools/qbytedata_p.h @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** 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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QBYTEDATA_H +#define QBYTEDATA_H + +#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(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]; + } +}; + +QT_END_NAMESPACE + +#endif // QBYTEDATA_H diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 88053d6..458a383 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -1421,16 +1421,15 @@ QDataStream &operator>>(QDataStream &in, QChar &chr) // --------------------------------------------------------------------------- -static QString decomposeHelper - (const QString &str, bool canonical, QChar::UnicodeVersion version) +static void decomposeHelper(QString *str, bool canonical, QChar::UnicodeVersion version, int from) { unsigned short buffer[3]; - QString s = str; + QString &s = *str; - const unsigned short *utf16 = s.utf16(); + const unsigned short *utf16 = reinterpret_cast<unsigned short *>(s.data()); const unsigned short *uc = utf16 + s.length(); - while (uc != utf16) { + while (uc != utf16 + from) { uint ucs4 = *(--uc); if (QChar(ucs4).isLowSurrogate() && uc != utf16) { ushort high = *(uc - 1); @@ -1450,11 +1449,9 @@ static QString decomposeHelper s.replace(uc - utf16, ucs4 > 0x10000 ? 2 : 1, (const QChar *)d, length); // since the insert invalidates the pointers and we do decomposition recursive int pos = uc - utf16; - utf16 = s.utf16(); + utf16 = reinterpret_cast<unsigned short *>(s.data()); uc = utf16 + pos + length; } - - return s; } @@ -1489,21 +1486,21 @@ static ushort ligatureHelper(ushort u1, ushort u2) return 0; } -static QString composeHelper(const QString &str) +static void composeHelper(QString *str, int from) { - QString s = str; + QString &s = *str; - if (s.length() < 2) - return s; + 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 = 0; + int pos = from; while (pos < s.length()) { - uint uc = s.utf16()[pos]; + uint uc = s.at(pos).unicode(); if (QChar(uc).isHighSurrogate() && pos < s.length()-1) { - ushort low = s.utf16()[pos+1]; + ushort low = s.at(pos+1).unicode(); if (QChar(low).isLowSurrogate()) { uc = QChar::surrogateToUcs4(uc, low); ++pos; @@ -1512,7 +1509,7 @@ static QString composeHelper(const QString &str) int combining = QChar::combiningClass(uc); if (starter == pos - 1 || combining > lastCombining) { // allowed to form ligature with S - QChar ligature = ligatureHelper(s.utf16()[starter], uc); + QChar ligature = ligatureHelper(s.at(starter).unicode(), uc); if (ligature.unicode()) { s[starter] = ligature; s.remove(pos, 1); @@ -1524,16 +1521,14 @@ static QString composeHelper(const QString &str) lastCombining = combining; ++pos; } - return s; } -static QString canonicalOrderHelper - (const QString &str, QChar::UnicodeVersion version) +static void canonicalOrderHelper(QString *str, QChar::UnicodeVersion version, int from) { - QString s = str; + QString &s = *str; const int l = s.length()-1; - int pos = 0; + int pos = from; while (pos < l) { int p2 = pos+1; uint u1 = s.at(pos).unicode(); @@ -1593,7 +1588,6 @@ static QString canonicalOrderHelper ++pos; } } - return s; } int QT_FASTCALL QUnicodeTables::script(unsigned int uc) diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp index e738ec8..f42b7a0 100644 --- a/src/corelib/tools/qcontiguouscache.cpp +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -61,6 +61,7 @@ void QContiguousCacheData::dump() const \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 @@ -95,7 +96,7 @@ MyRecord record(int row) const 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 + 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 @@ -104,9 +105,9 @@ MyRecord record(int row) const 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 the [] operator. Calling these - functions when the cache has invalid indexes will result in undefined - behavior. The indexes can be checked by using areIndexesValid() + 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. @@ -190,8 +191,6 @@ MyRecord record(int row) const /*! \fn int QContiguousCache::count() const - \overload - Same as size(). */ @@ -258,14 +257,15 @@ MyRecord record(int row) const /*! \fn T &QContiguousCache::operator[](int i) - Returns the item at index position \a i as a modifiable reference. If + 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 that using non-const operators can cause QContiguousCache to do a deep - copy. + \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() */ diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index 7d52f1e..0020d22 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -166,8 +166,8 @@ void QContiguousCache<T>::detach_helper() T *dest = x.d->array + x.d->start; T *src = d->array + d->start; - int count = x.d->count; - while (count--) { + int oldcount = x.d->count; + while (oldcount--) { if (QTypeInfo<T>::isComplex) { new (dest) T(*src); } else { @@ -200,8 +200,8 @@ void QContiguousCache<T>::setCapacity(int asize) x.d->start = x.d->offset % x.d->alloc; T *dest = x.d->array + (x.d->start + x.d->count-1) % x.d->alloc; T *src = d->array + (d->start + d->count-1) % d->alloc; - int count = x.d->count; - while (count--) { + int oldcount = x.d->count; + while (oldcount--) { if (QTypeInfo<T>::isComplex) { new (dest) T(*src); } else { @@ -224,10 +224,10 @@ void QContiguousCache<T>::clear() { if (d->ref == 1) { if (QTypeInfo<T>::isComplex) { - int count = d->count; + int oldcount = d->count; T * i = d->array + d->start; T * e = d->array + d->alloc; - while (count--) { + while (oldcount--) { i->~T(); i++; if (i == e) @@ -254,11 +254,11 @@ inline QContiguousCacheData *QContiguousCache<T>::malloc(int aalloc) } template <typename T> -QContiguousCache<T>::QContiguousCache(int capacity) +QContiguousCache<T>::QContiguousCache(int cap) { - p = malloc(capacity); + p = malloc(cap); d->ref = 1; - d->alloc = capacity; + d->alloc = cap; d->count = d->start = d->offset = 0; d->sharable = true; } @@ -295,10 +295,10 @@ template <typename T> void QContiguousCache<T>::free(Data *x) { if (QTypeInfo<T>::isComplex) { - int count = d->count; + int oldcount = d->count; T * i = d->array + d->start; T * e = d->array + d->alloc; - while (count--) { + while (oldcount--) { i->~T(); i++; if (i == e) diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 42f4304..2c2418c 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -49,7 +49,7 @@ #include "qregexp.h" #include "qdebug.h" #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) -#include <windows.h> +#include <qt_windows.h> #endif #ifndef Q_WS_WIN #include <locale.h> diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index 18a252a..0828c61 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -60,8 +60,10 @@ 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 QAnimation class, - but can be used on its own. + 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 @@ -80,10 +82,10 @@ \endcode will print the effective progress of the interpolation between 0 and 1. - When using a QAnimation, the easing curve will be used to control the + When using a QPropertyAnimation, the associated easing curve will be used to control the progress of the interpolation between startValue and endValue: \code - QAnimation animation; + QPropertyAnimation animation; animation.setStartValue(0); animation.setEndValue(1000); animation.setDuration(1000); @@ -98,189 +100,191 @@ \value Linear \inlineimage qeasingcurve-linear.png \br - Easing equation function for a simple linear tweening, - with no easing. + Easing curve for a linear (t) function: + velocity is constant. \value InQuad \inlineimage qeasingcurve-inquad.png \br - Easing equation function for a quadratic (t^2) easing - in: accelerating from zero velocity. + Easing curve for a quadratic (t^2) function: + accelerating from zero velocity. \value OutQuad \inlineimage qeasingcurve-outquad.png \br - Easing equation function for a quadratic (t^2) easing - out: decelerating to zero velocity. + Easing curve for a quadratic (t^2) function: + decelerating to zero velocity. \value InOutQuad \inlineimage qeasingcurve-inoutquad.png \br - Easing equation function for a quadratic (t^2) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a quadratic (t^2) function: + acceleration until halfway, then deceleration. \value OutInQuad \inlineimage qeasingcurve-outinquad.png \br - Easing equation function for a quadratic (t^2) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a quadratic (t^2) function: + deceleration until halfway, then acceleration. \value InCubic \inlineimage qeasingcurve-incubic.png \br - Easing equation function for a cubic (t^3) easing - in: accelerating from zero velocity. + Easing curve for a cubic (t^3) function: + accelerating from zero velocity. \value OutCubic \inlineimage qeasingcurve-outcubic.png \br - Easing equation function for a cubic (t^3) easing - out: decelerating from zero velocity. + Easing curve for a cubic (t^3) function: + decelerating from zero velocity. \value InOutCubic \inlineimage qeasingcurve-inoutcubic.png \br - Easing equation function for a cubic (t^3) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a cubic (t^3) function: + acceleration until halfway, then deceleration. \value OutInCubic \inlineimage qeasingcurve-outincubic.png \br - Easing equation function for a cubic (t^3) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a cubic (t^3) function: + deceleration until halfway, then acceleration. \value InQuart \inlineimage qeasingcurve-inquart.png \br - Easing equation function for a quartic (t^4) easing - in: accelerating from zero velocity. + Easing curve for a quartic (t^4) function: + accelerating from zero velocity. \value OutQuart \inlineimage qeasingcurve-outquart.png \br - Easing equation function for a quartic (t^4) easing - out: decelerating from zero velocity. + Easing curve for a cubic (t^4) function: + decelerating from zero velocity. \value InOutQuart \inlineimage qeasingcurve-inoutquart.png \br - Easing equation function for a quartic (t^4) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a cubic (t^4) function: + acceleration until halfway, then deceleration. \value OutInQuart \inlineimage qeasingcurve-outinquart.png \br - Easing equation function for a quartic (t^4) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a cubic (t^4) function: + deceleration until halfway, then acceleration. \value InQuint \inlineimage qeasingcurve-inquint.png \br - Easing equation function for a quintic (t^5) easing + Easing curve for a quintic (t^5) easing in: accelerating from zero velocity. \value OutQuint \inlineimage qeasingcurve-outquint.png \br - Easing equation function for a quintic (t^5) easing - out: decelerating from zero velocity. + Easing curve for a cubic (t^5) function: + decelerating from zero velocity. \value InOutQuint \inlineimage qeasingcurve-inoutquint.png \br - Easing equation function for a quintic (t^5) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a cubic (t^5) function: + acceleration until halfway, then deceleration. \value OutInQuint \inlineimage qeasingcurve-outinquint.png \br - Easing equation function for a quintic (t^5) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a cubic (t^5) function: + deceleration until halfway, then acceleration. \value InSine \inlineimage qeasingcurve-insine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - in: accelerating from zero velocity. + Easing curve for a sinusoidal (sin(t)) function: + accelerating from zero velocity. \value OutSine \inlineimage qeasingcurve-outsine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - out: decelerating from zero velocity. + Easing curve for a sinusoidal (sin(t)) function: + decelerating from zero velocity. \value InOutSine \inlineimage qeasingcurve-inoutsine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a sinusoidal (sin(t)) function: + acceleration until halfway, then deceleration. \value OutInSine \inlineimage qeasingcurve-outinsine.png \br - Easing equation function for a sinusoidal (sin(t)) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a sinusoidal (sin(t)) function: + deceleration until halfway, then acceleration. \value InExpo \inlineimage qeasingcurve-inexpo.png \br - Easing equation function for an exponential (2^t) easing - in: accelerating from zero velocity. + Easing curve for an exponential (2^t) function: + accelerating from zero velocity. \value OutExpo \inlineimage qeasingcurve-outexpo.png \br - Easing equation function for an exponential (2^t) easing - out: decelerating from zero velocity. + Easing curve for an exponential (2^t) function: + decelerating from zero velocity. \value InOutExpo \inlineimage qeasingcurve-inoutexpo.png \br - Easing equation function for an exponential (2^t) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for an exponential (2^t) function: + acceleration until halfway, then deceleration. \value OutInExpo \inlineimage qeasingcurve-outinexpo.png \br - Easing equation function for an exponential (2^t) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for an exponential (2^t) function: + deceleration until halfway, then acceleration. \value InCirc \inlineimage qeasingcurve-incirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - in: accelerating from zero velocity. + Easing curve for a circular (sqrt(1-t^2)) function: + accelerating from zero velocity. \value OutCirc \inlineimage qeasingcurve-outcirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - out: decelerating from zero velocity. + Easing curve for a circular (sqrt(1-t^2)) function: + decelerating from zero velocity. \value InOutCirc \inlineimage qeasingcurve-inoutcirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - in/out: acceleration until halfway, then deceleration. + Easing curve for a circular (sqrt(1-t^2)) function: + acceleration until halfway, then deceleration. \value OutInCirc \inlineimage qeasingcurve-outincirc.png \br - Easing equation function for a circular (sqrt(1-t^2)) easing - out/in: deceleration until halfway, then acceleration. + Easing curve for a circular (sqrt(1-t^2)) function: + deceleration until halfway, then acceleration. \value InElastic \inlineimage qeasingcurve-inelastic.png \br - Easing equation function for an elastic - (exponentially decaying sine wave) easing in: + 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 equation function for an elastic - (exponentially decaying sine wave) easing out: + 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 equation function for an elastic - (exponentially decaying sine wave) easing in/out: + Easing curve for an elastic + (exponentially decaying sine wave) function: acceleration until halfway, then deceleration. \value OutInElastic \inlineimage qeasingcurve-outinelastic.png \br - Easing equation function for an elastic - (exponentially decaying sine wave) easing out/in: + Easing curve for an elastic + (exponentially decaying sine wave) function: deceleration until halfway, then acceleration. \value InBack \inlineimage qeasingcurve-inback.png \br - Easing equation function for a back (overshooting - cubic easing: (s+1)*t^3 - s*t^2) easing in: + 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 equation function for a back (overshooting - cubic easing: (s+1)*t^3 - s*t^2) easing out: - decelerating from zero velocity. + 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 equation function for a back (overshooting - cubic easing: (s+1)*t^3 - s*t^2) easing in/out: + 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 equation function for a back (overshooting + 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 equation function for a bounce (exponentially - decaying parabolic bounce) easing in: accelerating + Easing curve for a bounce (exponentially + decaying parabolic bounce) function: accelerating from zero velocity. \value OutBounce \inlineimage qeasingcurve-outbounce.png \br - Easing equation function for a bounce (exponentially - decaying parabolic bounce) easing out: decelerating + Easing curve for a bounce (exponentially + decaying parabolic bounce) function: decelerating from zero velocity. \value InOutBounce \inlineimage qeasingcurve-inoutbounce.png \br - Easing equation function for a bounce (exponentially - decaying parabolic bounce) easing in/out: + Easing curve for a bounce (exponentially + decaying parabolic bounce) function easing in/out: acceleration until halfway, then deceleration. \value OutInBounce \inlineimage qeasingcurve-outinbounce.png \br - Easing equation function for a bounce (exponentially - decaying parabolic bounce) easing out/in: + Easing curve for a bounce (exponentially + decaying parabolic bounce) function easing out/in: deceleration until halfway, then acceleration. \omitvalue InCurve \omitvalue OutCurve \omitvalue SineCurve \omitvalue CosineCurve - \value Custom This is returned if the user have specified a custom curve type with setCustomType(). Note that you cannot call setType() with this value, but type() can return it. + \value Custom This is returned if the user specified a custom curve type with + setCustomType(). Note that you cannot call setType() with this value, + but type() can return it. \omitvalue NCurveTypes */ diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index fef1931..85e49c7 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -413,8 +413,8 @@ QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT) result = envVarLocale(); QChar lang[3]; QChar cntry[2]; - if ( result == "C" || !result.isEmpty() - && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry) ) { + if ( result == "C" || (!result.isEmpty() + && splitLocaleName(QString::fromLocal8Bit(result), lang, cntry)) ) { long id = 0; bool ok = false; id = qstrtoll(result.data(), 0, 0, &ok); @@ -5299,7 +5299,11 @@ struct p5s_deleter { ~p5s_deleter() { - Bfree(p5s); + while (p5s) { + Bigint *next = p5s->next; + Bfree(p5s); + p5s = next; + } } }; diff --git a/src/corelib/tools/qpoint.cpp b/src/corelib/tools/qpoint.cpp index 49afdca..af60f52 100644 --- a/src/corelib/tools/qpoint.cpp +++ b/src/corelib/tools/qpoint.cpp @@ -444,6 +444,8 @@ QDebug operator<<(QDebug d, const QPointF &p) /*! + \since 4.6 + Returns the sum of the absolute values of x() and y(), traditionally known as the "Manhattan length" of the vector from the origin to the point. diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp index b0f2054..804ce20 100644 --- a/src/corelib/tools/qregexp.cpp +++ b/src/corelib/tools/qregexp.cpp @@ -70,6 +70,8 @@ int qFindString(const QChar *haystack, int haystackLen, int from, #define RXERR_LEFTDELIM QT_TRANSLATE_NOOP("QRegExp", "missing left delim") #define RXERR_END QT_TRANSLATE_NOOP("QRegExp", "unexpected end") #define RXERR_LIMIT QT_TRANSLATE_NOOP("QRegExp", "met internal limit") +#define RXERR_INTERVAL QT_TRANSLATE_NOOP("QRegExp", "invalid interval") +#define RXERR_CATEGORY QT_TRANSLATE_NOOP("QRegExp", "invalid category") /* WARNING! Be sure to read qregexp.tex before modifying this file. @@ -1116,6 +1118,7 @@ private: bool valid; // is the regular expression valid? Qt::CaseSensitivity cs; // case sensitive? bool greedyQuantifiers; // RegExp2? + bool xmlSchemaExtensions; #ifndef QT_NO_REGEXP_BACKREF int nbrefs; // number of back-references #endif @@ -1193,6 +1196,8 @@ private: friend class Box; + void setupCategoriesRangeMap(); + /* This is the lexical analyzer for regular expressions. */ @@ -1232,6 +1237,7 @@ private: int yyTok; // the last token read bool yyMayCapture; // set this to false to disable capturing + QHash<QByteArray, QPair<int, int> > categoriesRangeMap; // fast lookup hash for xml schema extensions friend struct QRegExpMatchState; }; @@ -1268,13 +1274,15 @@ Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &pattern, QRegExp::Pat case QRegExp::FixedString: return QRegExp::escape(pattern); break; + case QRegExp::W3CXmlSchema11: default: return pattern; } } QRegExpEngine::QRegExpEngine(const QRegExpEngineKey &key) - : cs(key.cs), greedyQuantifiers(key.patternSyntax == QRegExp::RegExp2) + : cs(key.cs), greedyQuantifiers(key.patternSyntax == QRegExp::RegExp2), + xmlSchemaExtensions(key.patternSyntax == QRegExp::W3CXmlSchema11) { setup(); @@ -1487,9 +1495,8 @@ int QRegExpEngine::anchorAlternation(int a, int b) return Anchor_Alternation | (n - 1); #endif - aa.resize(n + 1); - aa[n].a = a; - aa[n].b = b; + QRegExpAnchorAlternation element = {a, b}; + aa.append(element); return Anchor_Alternation | n; } @@ -2629,6 +2636,152 @@ void QRegExpEngine::Box::addAnchorsToEngine(const Box &to) const } } +void QRegExpEngine::setupCategoriesRangeMap() +{ + categoriesRangeMap.insert("IsBasicLatin", qMakePair(0x0000, 0x007F)); + categoriesRangeMap.insert("IsLatin-1Supplement", qMakePair(0x0080, 0x00FF)); + categoriesRangeMap.insert("IsLatinExtended-A", qMakePair(0x0100, 0x017F)); + categoriesRangeMap.insert("IsLatinExtended-B", qMakePair(0x0180, 0x024F)); + categoriesRangeMap.insert("IsIPAExtensions", qMakePair(0x0250, 0x02AF)); + categoriesRangeMap.insert("IsSpacingModifierLetters", qMakePair(0x02B0, 0x02FF)); + categoriesRangeMap.insert("IsCombiningDiacriticalMarks", qMakePair(0x0300, 0x036F)); + categoriesRangeMap.insert("IsGreek", qMakePair(0x0370, 0x03FF)); + categoriesRangeMap.insert("IsCyrillic", qMakePair(0x0400, 0x04FF)); + categoriesRangeMap.insert("IsCyrillicSupplement", qMakePair(0x0500, 0x052F)); + categoriesRangeMap.insert("IsArmenian", qMakePair(0x0530, 0x058F)); + categoriesRangeMap.insert("IsHebrew", qMakePair(0x0590, 0x05FF)); + categoriesRangeMap.insert("IsArabic", qMakePair(0x0600, 0x06FF)); + categoriesRangeMap.insert("IsSyriac", qMakePair(0x0700, 0x074F)); + categoriesRangeMap.insert("IsArabicSupplement", qMakePair(0x0750, 0x077F)); + categoriesRangeMap.insert("IsThaana", qMakePair(0x0780, 0x07BF)); + categoriesRangeMap.insert("IsDevanagari", qMakePair(0x0900, 0x097F)); + categoriesRangeMap.insert("IsBengali", qMakePair(0x0980, 0x09FF)); + categoriesRangeMap.insert("IsGurmukhi", qMakePair(0x0A00, 0x0A7F)); + categoriesRangeMap.insert("IsGujarati", qMakePair(0x0A80, 0x0AFF)); + categoriesRangeMap.insert("IsOriya", qMakePair(0x0B00, 0x0B7F)); + categoriesRangeMap.insert("IsTamil", qMakePair(0x0B80, 0x0BFF)); + categoriesRangeMap.insert("IsTelugu", qMakePair(0x0C00, 0x0C7F)); + categoriesRangeMap.insert("IsKannada", qMakePair(0x0C80, 0x0CFF)); + categoriesRangeMap.insert("IsMalayalam", qMakePair(0x0D00, 0x0D7F)); + categoriesRangeMap.insert("IsSinhala", qMakePair(0x0D80, 0x0DFF)); + categoriesRangeMap.insert("IsThai", qMakePair(0x0E00, 0x0E7F)); + categoriesRangeMap.insert("IsLao", qMakePair(0x0E80, 0x0EFF)); + categoriesRangeMap.insert("IsTibetan", qMakePair(0x0F00, 0x0FFF)); + categoriesRangeMap.insert("IsMyanmar", qMakePair(0x1000, 0x109F)); + categoriesRangeMap.insert("IsGeorgian", qMakePair(0x10A0, 0x10FF)); + categoriesRangeMap.insert("IsHangulJamo", qMakePair(0x1100, 0x11FF)); + categoriesRangeMap.insert("IsEthiopic", qMakePair(0x1200, 0x137F)); + categoriesRangeMap.insert("IsEthiopicSupplement", qMakePair(0x1380, 0x139F)); + categoriesRangeMap.insert("IsCherokee", qMakePair(0x13A0, 0x13FF)); + categoriesRangeMap.insert("IsUnifiedCanadianAboriginalSyllabics", qMakePair(0x1400, 0x167F)); + categoriesRangeMap.insert("IsOgham", qMakePair(0x1680, 0x169F)); + categoriesRangeMap.insert("IsRunic", qMakePair(0x16A0, 0x16FF)); + categoriesRangeMap.insert("IsTagalog", qMakePair(0x1700, 0x171F)); + categoriesRangeMap.insert("IsHanunoo", qMakePair(0x1720, 0x173F)); + categoriesRangeMap.insert("IsBuhid", qMakePair(0x1740, 0x175F)); + categoriesRangeMap.insert("IsTagbanwa", qMakePair(0x1760, 0x177F)); + categoriesRangeMap.insert("IsKhmer", qMakePair(0x1780, 0x17FF)); + categoriesRangeMap.insert("IsMongolian", qMakePair(0x1800, 0x18AF)); + categoriesRangeMap.insert("IsLimbu", qMakePair(0x1900, 0x194F)); + categoriesRangeMap.insert("IsTaiLe", qMakePair(0x1950, 0x197F)); + categoriesRangeMap.insert("IsNewTaiLue", qMakePair(0x1980, 0x19DF)); + categoriesRangeMap.insert("IsKhmerSymbols", qMakePair(0x19E0, 0x19FF)); + categoriesRangeMap.insert("IsBuginese", qMakePair(0x1A00, 0x1A1F)); + categoriesRangeMap.insert("IsPhoneticExtensions", qMakePair(0x1D00, 0x1D7F)); + categoriesRangeMap.insert("IsPhoneticExtensionsSupplement", qMakePair(0x1D80, 0x1DBF)); + categoriesRangeMap.insert("IsCombiningDiacriticalMarksSupplement", qMakePair(0x1DC0, 0x1DFF)); + categoriesRangeMap.insert("IsLatinExtendedAdditional", qMakePair(0x1E00, 0x1EFF)); + categoriesRangeMap.insert("IsGreekExtended", qMakePair(0x1F00, 0x1FFF)); + categoriesRangeMap.insert("IsGeneralPunctuation", qMakePair(0x2000, 0x206F)); + categoriesRangeMap.insert("IsSuperscriptsandSubscripts", qMakePair(0x2070, 0x209F)); + categoriesRangeMap.insert("IsCurrencySymbols", qMakePair(0x20A0, 0x20CF)); + categoriesRangeMap.insert("IsCombiningMarksforSymbols", qMakePair(0x20D0, 0x20FF)); + categoriesRangeMap.insert("IsLetterlikeSymbols", qMakePair(0x2100, 0x214F)); + categoriesRangeMap.insert("IsNumberForms", qMakePair(0x2150, 0x218F)); + categoriesRangeMap.insert("IsArrows", qMakePair(0x2190, 0x21FF)); + categoriesRangeMap.insert("IsMathematicalOperators", qMakePair(0x2200, 0x22FF)); + categoriesRangeMap.insert("IsMiscellaneousTechnical", qMakePair(0x2300, 0x23FF)); + categoriesRangeMap.insert("IsControlPictures", qMakePair(0x2400, 0x243F)); + categoriesRangeMap.insert("IsOpticalCharacterRecognition", qMakePair(0x2440, 0x245F)); + categoriesRangeMap.insert("IsEnclosedAlphanumerics", qMakePair(0x2460, 0x24FF)); + categoriesRangeMap.insert("IsBoxDrawing", qMakePair(0x2500, 0x257F)); + categoriesRangeMap.insert("IsBlockElements", qMakePair(0x2580, 0x259F)); + categoriesRangeMap.insert("IsGeometricShapes", qMakePair(0x25A0, 0x25FF)); + categoriesRangeMap.insert("IsMiscellaneousSymbols", qMakePair(0x2600, 0x26FF)); + categoriesRangeMap.insert("IsDingbats", qMakePair(0x2700, 0x27BF)); + categoriesRangeMap.insert("IsMiscellaneousMathematicalSymbols-A", qMakePair(0x27C0, 0x27EF)); + categoriesRangeMap.insert("IsSupplementalArrows-A", qMakePair(0x27F0, 0x27FF)); + categoriesRangeMap.insert("IsBraillePatterns", qMakePair(0x2800, 0x28FF)); + categoriesRangeMap.insert("IsSupplementalArrows-B", qMakePair(0x2900, 0x297F)); + categoriesRangeMap.insert("IsMiscellaneousMathematicalSymbols-B", qMakePair(0x2980, 0x29FF)); + categoriesRangeMap.insert("IsSupplementalMathematicalOperators", qMakePair(0x2A00, 0x2AFF)); + categoriesRangeMap.insert("IsMiscellaneousSymbolsandArrows", qMakePair(0x2B00, 0x2BFF)); + categoriesRangeMap.insert("IsGlagolitic", qMakePair(0x2C00, 0x2C5F)); + categoriesRangeMap.insert("IsCoptic", qMakePair(0x2C80, 0x2CFF)); + categoriesRangeMap.insert("IsGeorgianSupplement", qMakePair(0x2D00, 0x2D2F)); + categoriesRangeMap.insert("IsTifinagh", qMakePair(0x2D30, 0x2D7F)); + categoriesRangeMap.insert("IsEthiopicExtended", qMakePair(0x2D80, 0x2DDF)); + categoriesRangeMap.insert("IsSupplementalPunctuation", qMakePair(0x2E00, 0x2E7F)); + categoriesRangeMap.insert("IsCJKRadicalsSupplement", qMakePair(0x2E80, 0x2EFF)); + categoriesRangeMap.insert("IsKangxiRadicals", qMakePair(0x2F00, 0x2FDF)); + categoriesRangeMap.insert("IsIdeographicDescriptionCharacters", qMakePair(0x2FF0, 0x2FFF)); + categoriesRangeMap.insert("IsCJKSymbolsandPunctuation", qMakePair(0x3000, 0x303F)); + categoriesRangeMap.insert("IsHiragana", qMakePair(0x3040, 0x309F)); + categoriesRangeMap.insert("IsKatakana", qMakePair(0x30A0, 0x30FF)); + categoriesRangeMap.insert("IsBopomofo", qMakePair(0x3100, 0x312F)); + categoriesRangeMap.insert("IsHangulCompatibilityJamo", qMakePair(0x3130, 0x318F)); + categoriesRangeMap.insert("IsKanbun", qMakePair(0x3190, 0x319F)); + categoriesRangeMap.insert("IsBopomofoExtended", qMakePair(0x31A0, 0x31BF)); + categoriesRangeMap.insert("IsCJKStrokes", qMakePair(0x31C0, 0x31EF)); + categoriesRangeMap.insert("IsKatakanaPhoneticExtensions", qMakePair(0x31F0, 0x31FF)); + categoriesRangeMap.insert("IsEnclosedCJKLettersandMonths", qMakePair(0x3200, 0x32FF)); + categoriesRangeMap.insert("IsCJKCompatibility", qMakePair(0x3300, 0x33FF)); + categoriesRangeMap.insert("IsCJKUnifiedIdeographsExtensionA", qMakePair(0x3400, 0x4DB5)); + categoriesRangeMap.insert("IsYijingHexagramSymbols", qMakePair(0x4DC0, 0x4DFF)); + categoriesRangeMap.insert("IsCJKUnifiedIdeographs", qMakePair(0x4E00, 0x9FFF)); + categoriesRangeMap.insert("IsYiSyllables", qMakePair(0xA000, 0xA48F)); + categoriesRangeMap.insert("IsYiRadicals", qMakePair(0xA490, 0xA4CF)); + categoriesRangeMap.insert("IsModifierToneLetters", qMakePair(0xA700, 0xA71F)); + categoriesRangeMap.insert("IsSylotiNagri", qMakePair(0xA800, 0xA82F)); + categoriesRangeMap.insert("IsHangulSyllables", qMakePair(0xAC00, 0xD7A3)); + categoriesRangeMap.insert("IsPrivateUse", qMakePair(0xE000, 0xF8FF)); + categoriesRangeMap.insert("IsCJKCompatibilityIdeographs", qMakePair(0xF900, 0xFAFF)); + categoriesRangeMap.insert("IsAlphabeticPresentationForms", qMakePair(0xFB00, 0xFB4F)); + categoriesRangeMap.insert("IsArabicPresentationForms-A", qMakePair(0xFB50, 0xFDFF)); + categoriesRangeMap.insert("IsVariationSelectors", qMakePair(0xFE00, 0xFE0F)); + categoriesRangeMap.insert("IsVerticalForms", qMakePair(0xFE10, 0xFE1F)); + categoriesRangeMap.insert("IsCombiningHalfMarks", qMakePair(0xFE20, 0xFE2F)); + categoriesRangeMap.insert("IsCJKCompatibilityForms", qMakePair(0xFE30, 0xFE4F)); + categoriesRangeMap.insert("IsSmallFormVariants", qMakePair(0xFE50, 0xFE6F)); + categoriesRangeMap.insert("IsArabicPresentationForms-B", qMakePair(0xFE70, 0xFEFF)); + categoriesRangeMap.insert("IsHalfwidthandFullwidthForms", qMakePair(0xFF00, 0xFFEF)); + categoriesRangeMap.insert("IsSpecials", qMakePair(0xFFF0, 0xFFFF)); + categoriesRangeMap.insert("IsLinearBSyllabary", qMakePair(0x10000, 0x1007F)); + categoriesRangeMap.insert("IsLinearBIdeograms", qMakePair(0x10080, 0x100FF)); + categoriesRangeMap.insert("IsAegeanNumbers", qMakePair(0x10100, 0x1013F)); + categoriesRangeMap.insert("IsAncientGreekNumbers", qMakePair(0x10140, 0x1018F)); + categoriesRangeMap.insert("IsOldItalic", qMakePair(0x10300, 0x1032F)); + categoriesRangeMap.insert("IsGothic", qMakePair(0x10330, 0x1034F)); + categoriesRangeMap.insert("IsUgaritic", qMakePair(0x10380, 0x1039F)); + categoriesRangeMap.insert("IsOldPersian", qMakePair(0x103A0, 0x103DF)); + categoriesRangeMap.insert("IsDeseret", qMakePair(0x10400, 0x1044F)); + categoriesRangeMap.insert("IsShavian", qMakePair(0x10450, 0x1047F)); + categoriesRangeMap.insert("IsOsmanya", qMakePair(0x10480, 0x104AF)); + categoriesRangeMap.insert("IsCypriotSyllabary", qMakePair(0x10800, 0x1083F)); + categoriesRangeMap.insert("IsKharoshthi", qMakePair(0x10A00, 0x10A5F)); + categoriesRangeMap.insert("IsByzantineMusicalSymbols", qMakePair(0x1D000, 0x1D0FF)); + categoriesRangeMap.insert("IsMusicalSymbols", qMakePair(0x1D100, 0x1D1FF)); + categoriesRangeMap.insert("IsAncientGreekMusicalNotation", qMakePair(0x1D200, 0x1D24F)); + categoriesRangeMap.insert("IsTaiXuanJingSymbols", qMakePair(0x1D300, 0x1D35F)); + categoriesRangeMap.insert("IsMathematicalAlphanumericSymbols", qMakePair(0x1D400, 0x1D7FF)); + categoriesRangeMap.insert("IsCJKUnifiedIdeographsExtensionB", qMakePair(0x20000, 0x2A6DF)); + categoriesRangeMap.insert("IsCJKCompatibilityIdeographsSupplement", qMakePair(0x2F800, 0x2FA1F)); + categoriesRangeMap.insert("IsTags", qMakePair(0xE0000, 0xE007F)); + categoriesRangeMap.insert("IsVariationSelectorsSupplement", qMakePair(0xE0100, 0xE01EF)); + categoriesRangeMap.insert("IsSupplementaryPrivateUseArea-A", qMakePair(0xF0000, 0xFFFFF)); + categoriesRangeMap.insert("IsSupplementaryPrivateUseArea-B", qMakePair(0x100000, 0x10FFFF)); +} + int QRegExpEngine::getChar() { return (yyPos == yyLen) ? EOS : yyIn[yyPos++].unicode(); @@ -2721,6 +2874,177 @@ int QRegExpEngine::getEscape() yyCharClass->addCategories(0x000f807e); yyCharClass->addSingleton(0x005f); // '_' return Tok_CharClass; + case 'I': + if (xmlSchemaExtensions) { + yyCharClass->setNegative(!yyCharClass->negative()); + // fall through + } + case 'i': + if (xmlSchemaExtensions) { + yyCharClass->addCategories(0x000f807e); + yyCharClass->addSingleton(0x003a); // ':' + yyCharClass->addSingleton(0x005f); // '_' + yyCharClass->addRange(0x0041, 0x005a); // [A-Z] + yyCharClass->addRange(0x0061, 0x007a); // [a-z] + yyCharClass->addRange(0xc0, 0xd6); + yyCharClass->addRange(0xd8, 0xf6); + yyCharClass->addRange(0xf8, 0x2ff); + yyCharClass->addRange(0x370, 0x37d); + yyCharClass->addRange(0x37f, 0x1fff); + yyCharClass->addRange(0x200c, 0x200d); + yyCharClass->addRange(0x2070, 0x218f); + yyCharClass->addRange(0x2c00, 0x2fef); + yyCharClass->addRange(0x3001, 0xd7ff); + yyCharClass->addRange(0xf900, 0xfdcf); + yyCharClass->addRange(0xfdf0, 0xfffd); + yyCharClass->addRange((ushort)0x10000, (ushort)0xeffff); + } + return Tok_CharClass; + case 'C': + if (xmlSchemaExtensions) { + yyCharClass->setNegative(!yyCharClass->negative()); + // fall through + } + case 'c': + if (xmlSchemaExtensions) { + yyCharClass->addCategories(0x000f807e); + yyCharClass->addSingleton(0x002d); // '-' + yyCharClass->addSingleton(0x002e); // '.' + yyCharClass->addSingleton(0x003a); // ':' + yyCharClass->addSingleton(0x005f); // '_' + yyCharClass->addSingleton(0xb7); + yyCharClass->addRange(0x0030, 0x0039); // [0-9] + yyCharClass->addRange(0x0041, 0x005a); // [A-Z] + yyCharClass->addRange(0x0061, 0x007a); // [a-z] + yyCharClass->addRange(0xc0, 0xd6); + yyCharClass->addRange(0xd8, 0xf6); + yyCharClass->addRange(0xf8, 0x2ff); + yyCharClass->addRange(0x370, 0x37d); + yyCharClass->addRange(0x37f, 0x1fff); + yyCharClass->addRange(0x200c, 0x200d); + yyCharClass->addRange(0x2070, 0x218f); + yyCharClass->addRange(0x2c00, 0x2fef); + yyCharClass->addRange(0x3001, 0xd7ff); + yyCharClass->addRange(0xf900, 0xfdcf); + yyCharClass->addRange(0xfdf0, 0xfffd); + yyCharClass->addRange((ushort)0x10000, (ushort)0xeffff); + yyCharClass->addRange(0x0300, 0x036f); + yyCharClass->addRange(0x203f, 0x2040); + } + return Tok_CharClass; + case 'P': + if (xmlSchemaExtensions) { + yyCharClass->setNegative(!yyCharClass->negative()); + // fall through + } + case 'p': + if (xmlSchemaExtensions) { + if (yyCh != '{') { + error(RXERR_CHARCLASS); + return Tok_CharClass; + } + + QByteArray category; + yyCh = getChar(); + while (yyCh != '}') { + if (yyCh == EOS) { + error(RXERR_END); + return Tok_CharClass; + } + category.append(yyCh); + yyCh = getChar(); + } + yyCh = getChar(); // skip closing '}' + + if (category == "M") { + yyCharClass->addCategories(0x0000000e); + } else if (category == "Mn") { + yyCharClass->addCategories(0x00000002); + } else if (category == "Mc") { + yyCharClass->addCategories(0x00000004); + } else if (category == "Me") { + yyCharClass->addCategories(0x00000008); + } else if (category == "N") { + yyCharClass->addCategories(0x00000070); + } else if (category == "Nd") { + yyCharClass->addCategories(0x00000010); + } else if (category == "Nl") { + yyCharClass->addCategories(0x00000020); + } else if (category == "No") { + yyCharClass->addCategories(0x00000040); + } else if (category == "Z") { + yyCharClass->addCategories(0x00000380); + } else if (category == "Zs") { + yyCharClass->addCategories(0x00000080); + } else if (category == "Zl") { + yyCharClass->addCategories(0x00000100); + } else if (category == "Zp") { + yyCharClass->addCategories(0x00000200); + } else if (category == "C") { + yyCharClass->addCategories(0x00006c00); + } else if (category == "Cc") { + yyCharClass->addCategories(0x00000400); + } else if (category == "Cf") { + yyCharClass->addCategories(0x00000800); + } else if (category == "Cs") { + yyCharClass->addCategories(0x00001000); + } else if (category == "Co") { + yyCharClass->addCategories(0x00002000); + } else if (category == "Cn") { + yyCharClass->addCategories(0x00004000); + } else if (category == "L") { + yyCharClass->addCategories(0x000f8000); + } else if (category == "Lu") { + yyCharClass->addCategories(0x00008000); + } else if (category == "Ll") { + yyCharClass->addCategories(0x00010000); + } else if (category == "Lt") { + yyCharClass->addCategories(0x00020000); + } else if (category == "Lm") { + yyCharClass->addCategories(0x00040000); + } else if (category == "Lo") { + yyCharClass->addCategories(0x00080000); + } else if (category == "P") { + yyCharClass->addCategories(0x4f580780); + } else if (category == "Pc") { + yyCharClass->addCategories(0x00100000); + } else if (category == "Pd") { + yyCharClass->addCategories(0x00200000); + } else if (category == "Ps") { + yyCharClass->addCategories(0x00400000); + } else if (category == "Pe") { + yyCharClass->addCategories(0x00800000); + } else if (category == "Pi") { + yyCharClass->addCategories(0x01000000); + } else if (category == "Pf") { + yyCharClass->addCategories(0x02000000); + } else if (category == "Po") { + yyCharClass->addCategories(0x04000000); + } else if (category == "S") { + yyCharClass->addCategories(0x78000000); + } else if (category == "Sm") { + yyCharClass->addCategories(0x08000000); + } else if (category == "Sc") { + yyCharClass->addCategories(0x10000000); + } else if (category == "Sk") { + yyCharClass->addCategories(0x20000000); + } else if (category == "So") { + yyCharClass->addCategories(0x40000000); + } else if (category.startsWith("Is")) { + if (categoriesRangeMap.isEmpty()) + setupCategoriesRangeMap(); + + if (categoriesRangeMap.contains(category)) { + const QPair<int, int> range = categoriesRangeMap.value(category); + yyCharClass->addRange(range.first, range.second); + } else { + error(RXERR_CATEGORY); + } + } else { + error(RXERR_CATEGORY); + } + } + return Tok_CharClass; #endif #ifndef QT_NO_REGEXP_ESCAPE case 'x': @@ -2942,7 +3266,7 @@ int QRegExpEngine::getToken() yyMaxRep = getRep(InftyRep); } if (yyMaxRep < yyMinRep) - qSwap(yyMinRep, yyMaxRep); + error(RXERR_INTERVAL); if (yyCh != '}') error(RXERR_REPETITION); yyCh = getChar(); @@ -3304,7 +3628,7 @@ static void prepareEngine_helper(QRegExpPrivate *priv) { bool initMatchState = !priv->eng; #if !defined(QT_NO_REGEXP_OPTIM) - if (!priv->eng) { + if (!priv->eng && globalEngineCache()) { QMutexLocker locker(mutex()); priv->eng = globalEngineCache()->take(priv->engineKey); if (priv->eng != 0) @@ -3382,6 +3706,9 @@ static void invalidateEngine(QRegExpPrivate *priv) equivalent to using the RegExp pattern on a string in which all metacharacters are escaped using escape(). + \value W3CXmlSchema11 The pattern is a regular expression as + defined by the W3C XML Schema 1.1 specification. + \sa setPatternSyntax() */ diff --git a/src/corelib/tools/qregexp.h b/src/corelib/tools/qregexp.h index 057eec2..16682a3 100644 --- a/src/corelib/tools/qregexp.h +++ b/src/corelib/tools/qregexp.h @@ -61,7 +61,7 @@ class QStringList; class Q_CORE_EXPORT QRegExp { public: - enum PatternSyntax { RegExp, Wildcard, FixedString, RegExp2 }; + enum PatternSyntax { RegExp, Wildcard, FixedString, RegExp2, W3CXmlSchema11 }; enum CaretMode { CaretAtZero, CaretAtOffset, CaretWontMatch }; QRegExp(); diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index fe3d9e0..59dfffe 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -341,6 +341,7 @@ /*! \fn QSharedPointer<X> QSharedPointer::objectCast() const + \since 4.6 Performs a \l qobject_cast() from this pointer's type to \tt X and returns a QSharedPointer that shares the reference. If this @@ -737,6 +738,7 @@ /*! \fn QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &other) \relates QSharedPointer + \since 4.6 Returns a shared pointer to the pointer held by \a other, using a \l qobject_cast() to type \tt X to obtain an internal pointer of the @@ -754,6 +756,7 @@ \fn QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &other) \relates QSharedPointer \relates QWeakPointer + \since 4.6 Returns a shared pointer to the pointer held by \a other, using a \l qobject_cast() to type \tt X to obtain an internal pointer of the @@ -800,29 +803,19 @@ # endif # endif -# if !defined(BACKTRACE_SUPPORTED) -// Dummy implementation of the functions. -// Using QHashDummyValue also means that the QHash below is actually a QSet -typedef QT_PREPEND_NAMESPACE(QHashDummyValue) Backtrace; - -static inline Backtrace saveBacktrace() { return Backtrace(); } -static inline void printBacktrace(Backtrace) { } - -# else +# if defined(BACKTRACE_SUPPORTED) # include <sys/types.h> # include <execinfo.h> # include <stdio.h> # include <unistd.h> # include <sys/wait.h> -typedef QT_PREPEND_NAMESPACE(QByteArray) Backtrace; - -static inline Backtrace saveBacktrace() __attribute__((always_inline)); -static inline Backtrace saveBacktrace() +static inline QByteArray saveBacktrace() __attribute__((always_inline)); +static inline QByteArray saveBacktrace() { static const int maxFrames = 32; - Backtrace stacktrace; + QByteArray stacktrace; stacktrace.resize(sizeof(void*) * maxFrames); int stack_size = backtrace((void**)stacktrace.data(), maxFrames); stacktrace.resize(sizeof(void*) * stack_size); @@ -830,7 +823,7 @@ static inline Backtrace saveBacktrace() return stacktrace; } -static void printBacktrace(Backtrace stacktrace) +static void printBacktrace(QByteArray stacktrace) { void *const *stack = (void *const *)stacktrace.constData(); int stack_size = stacktrace.size() / sizeof(void*); @@ -881,11 +874,19 @@ static void printBacktrace(Backtrace stacktrace) namespace { QT_USE_NAMESPACE + struct Data { + const volatile void *pointer; +# ifdef BACKTRACE_SUPPORTED + QByteArray backtrace; +# endif + }; + class KnownPointers { public: QMutex mutex; - QHash<void *, Backtrace> values; + QHash<const void *, Data> dPointers; + QHash<const volatile void *, const void *> dataPointers; }; } @@ -893,38 +894,101 @@ Q_GLOBAL_STATIC(KnownPointers, knownPointers) QT_BEGIN_NAMESPACE +namespace QtSharedPointer { + Q_CORE_EXPORT void internalSafetyCheckAdd(const volatile void *); + Q_CORE_EXPORT void internalSafetyCheckRemove(const volatile void *); +} + +/*! + \internal +*/ +void QtSharedPointer::internalSafetyCheckAdd(const volatile void *) +{ + // Qt 4.5 compatibility + // this function is broken by design, so it was replaced with internalSafetyCheckAdd2 + // + // it's broken because we tracked the pointers added and + // removed from QSharedPointer, converted to void*. + // That is, this is supposed to track the "top-of-object" pointer in + // case of multiple inheritance. + // + // However, it doesn't work well in some compilers: + // if you create an object with a class of type A and the last reference + // is dropped of type B, then the value passed to internalSafetyCheckRemove could + // be different than was added. That would leave dangling addresses. + // + // So instead, we track the pointer by the d-pointer instead. +} + /*! \internal */ -void QtSharedPointer::internalSafetyCheckAdd(const volatile void *ptr) +void QtSharedPointer::internalSafetyCheckRemove(const volatile void *) { + // Qt 4.5 compatibility + // see comments above +} + +/*! + \internal +*/ +void QtSharedPointer::internalSafetyCheckAdd2(const void *d_ptr, const volatile void *ptr) +{ + // see comments above for the rationale for this function KnownPointers *const kp = knownPointers(); if (!kp) return; // end-game: the application is being destroyed already QMutexLocker lock(&kp->mutex); - void *actual = const_cast<void*>(ptr); - if (kp->values.contains(actual)) { - printBacktrace(knownPointers()->values.value(actual)); - qFatal("QSharedPointerData: internal self-check failed: pointer %p was already tracked " - "by another QSharedPointerData object", actual); + Q_ASSERT(!kp->dPointers.contains(d_ptr)); + + //qDebug("Adding d=%p value=%p", d_ptr, ptr); + + const void *other_d_ptr = kp->dataPointers.value(ptr, 0); + if (other_d_ptr) { +# ifdef BACKTRACE_SUPPORTED + printBacktrace(knownPointers()->dPointers.value(other_d_ptr).backtrace); +# endif + qFatal("QSharedPointer: internal self-check failed: pointer %p was already tracked " + "by another QSharedPointer object %p", ptr, other_d_ptr); } - kp->values.insert(actual, saveBacktrace()); + Data data; + data.pointer = ptr; +# ifdef BACKTRACE_SUPPORTED + data.backtrace = saveBacktrace(); +# endif + + kp->dPointers.insert(d_ptr, data); + kp->dataPointers.insert(ptr, d_ptr); } /*! \internal */ -void QtSharedPointer::internalSafetyCheckRemove(const volatile void *ptr) +void QtSharedPointer::internalSafetyCheckRemove2(const void *d_ptr) { KnownPointers *const kp = knownPointers(); if (!kp) return; // end-game: the application is being destroyed already QMutexLocker lock(&kp->mutex); - void *actual = const_cast<void*>(ptr); - kp->values.remove(actual); + + QHash<const void *, Data>::iterator it = kp->dPointers.find(d_ptr); + if (it == kp->dPointers.end()) { + qFatal("QSharedPointer: internal self-check inconsistency: pointer %p was not tracked. " + "To use QT_SHAREDPOINTER_TRACK_POINTERS, you have to enable it throughout " + "in your code.", d_ptr); + } + + QHash<const volatile void *, const void *>::iterator it2 = kp->dataPointers.find(it->pointer); + Q_ASSERT(it2 != kp->dataPointers.end()); + + //qDebug("Removing d=%p value=%p", d_ptr, it->pointer); + + // remove entries + kp->dataPointers.erase(it2); + kp->dPointers.erase(it); } QT_END_NAMESPACE diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 739a949..b8f4139 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -48,6 +48,7 @@ #pragma qt_sync_stop_processing #endif +#include <new> #include <QtCore/qatomic.h> #include <QtCore/qobject.h> // for qobject_cast @@ -97,9 +98,9 @@ namespace QtSharedPointer { template <class X, class Y> QSharedPointer<X> copyAndSetPointer(X * ptr, const QSharedPointer<Y> &src); // used in debug mode to verify the reuse of pointers - Q_CORE_EXPORT void internalSafetyCheckAdd(const volatile void *); - Q_CORE_EXPORT void internalSafetyCheckRemove(const volatile void *); - + Q_CORE_EXPORT void internalSafetyCheckAdd2(const void *, const volatile void *); + Q_CORE_EXPORT void internalSafetyCheckRemove2(const void *); + template <class T, typename Klass, typename RetVal> inline void executeDeleter(T *t, RetVal (Klass:: *memberDeleter)()) { (t->*memberDeleter)(); } @@ -145,17 +146,8 @@ namespace QtSharedPointer { inline void internalConstruct(T *ptr) { -#ifdef QT_SHAREDPOINTER_TRACK_POINTERS - if (ptr) internalSafetyCheckAdd(ptr); -#endif value = ptr; } - inline void internalDestroy() - { -#ifdef QT_SHAREDPOINTER_TRACK_POINTERS - if (value) internalSafetyCheckRemove(value); -#endif - } #if defined(Q_NO_TEMPLATE_FRIENDS) public: @@ -178,15 +170,89 @@ namespace QtSharedPointer { }; template <class T, typename Deleter> - struct ExternalRefCountWithSpecializedDeleter: public ExternalRefCountData + struct CustomDeleter { - T *ptr; Deleter deleter; + T *ptr; + + inline CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {} + }; - inline ExternalRefCountWithSpecializedDeleter(T *p, Deleter d) - : ptr(p), deleter(d) + struct ExternalRefCountWithDestroyFn: public ExternalRefCountData + { + typedef void (*DestroyerFn)(ExternalRefCountData *); + DestroyerFn destroyer; + + inline ExternalRefCountWithDestroyFn(DestroyerFn d) + : destroyer(d) { } - inline bool destroy() { executeDeleter(ptr, deleter); return true; } + + inline bool destroy() { destroyer(this); return true; } + inline void operator delete(void *ptr) { ::operator delete(ptr); } + }; + + template <class T, typename Deleter> + struct ExternalRefCountWithCustomDeleter: public ExternalRefCountWithDestroyFn + { + typedef ExternalRefCountWithCustomDeleter Self; + typedef ExternalRefCountWithDestroyFn Parent; + typedef CustomDeleter<T, Deleter> Next; + Next extra; + + static inline void deleter(ExternalRefCountData *self) + { + Self *realself = static_cast<Self *>(self); + executeDeleter(realself->extra.ptr, realself->extra.deleter); + } + + static inline Self *create(T *ptr, Deleter userDeleter) + { + DestroyerFn destroy = &deleter; + Self *d = static_cast<Self *>(::operator new(sizeof(Self))); + + // initialize the two sub-objects + new (&d->extra) Next(ptr, userDeleter); + new (d) Parent(destroy); // can't throw + + return d; + } + private: + // prevent construction and the emission of virtual symbols + ExternalRefCountWithCustomDeleter(); + ~ExternalRefCountWithCustomDeleter(); + }; + + template <class T> + struct ExternalRefCountWithContiguousData: public ExternalRefCountWithDestroyFn + { + typedef ExternalRefCountWithDestroyFn Parent; + T data; + + static void deleter(ExternalRefCountData *self) + { + ExternalRefCountWithContiguousData *that = + static_cast<ExternalRefCountWithContiguousData *>(self); + that->data.~T(); + } + + static inline ExternalRefCountData *create(T **ptr) + { + DestroyerFn destroy = &deleter; + ExternalRefCountWithContiguousData *d = + static_cast<ExternalRefCountWithContiguousData *>(::operator new(sizeof(ExternalRefCountWithContiguousData))); + + // initialize the d-pointer sub-object + // leave d->data uninitialized + new (d) Parent(destroy); // can't throw + + *ptr = &d->data; + return d; + } + + private: + // prevent construction and the emission of virtual symbols + ExternalRefCountWithContiguousData(); + ~ExternalRefCountWithContiguousData(); }; template <class T> @@ -198,8 +264,9 @@ namespace QtSharedPointer { inline void ref() const { d->weakref.ref(); d->strongref.ref(); } inline bool deref() { - if (!d->strongref.deref()) - this->internalDestroy(); + if (!d->strongref.deref()) { + internalDestroy(); + } return d->weakref.deref(); } @@ -209,6 +276,9 @@ namespace QtSharedPointer { Q_ASSERT(!d); if (ptr) d = new Data; +#ifdef QT_SHAREDPOINTER_TRACK_POINTERS + if (ptr) internalSafetyCheckAdd2(d, ptr); +#endif } template <typename Deleter> @@ -217,7 +287,21 @@ namespace QtSharedPointer { Basic<T>::internalConstruct(ptr); Q_ASSERT(!d); if (ptr) - d = new ExternalRefCountWithSpecializedDeleter<T, Deleter>(ptr, deleter); + d = ExternalRefCountWithCustomDeleter<T, Deleter>::create(ptr, deleter); +#ifdef QT_SHAREDPOINTER_TRACK_POINTERS + if (ptr) internalSafetyCheckAdd2(d, ptr); +#endif + } + + inline void internalCreate() + { + T *ptr; + d = ExternalRefCountWithContiguousData<T>::create(&ptr); + + Basic<T>::internalConstruct(ptr); +#ifdef QT_SHAREDPOINTER_TRACK_POINTERS + if (ptr) internalSafetyCheckAdd2(d, ptr); +#endif } inline ExternalRefCount() : d(0) { } @@ -233,7 +317,9 @@ namespace QtSharedPointer { inline void internalDestroy() { - Basic<T>::internalDestroy(); +#ifdef QT_SHAREDPOINTER_TRACK_POINTERS + internalSafetyCheckRemove2(d); +#endif if (!d->destroy()) delete this->value; } @@ -347,6 +433,17 @@ public: inline void clear() { *this = QSharedPointer<T>(); } QWeakPointer<T> toWeakRef() const; + +public: + static inline QSharedPointer<T> create() + { + QSharedPointer<T> result; + result.internalCreate(); + + // now initialize the data + new (result.data()) T(); + return result; + } }; template <class T> diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index b160b90..99fbaa9 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -45,6 +45,7 @@ #ifndef QT_NO_TEXTCODEC #include <qtextcodec.h> #endif +#include <private/qutfcodec_p.h> #include <qdatastream.h> #include <qlist.h> #include "qlocale.h" @@ -964,7 +965,8 @@ int QString::toWCharArray(wchar_t *array) const Constructs a string initialized with the first \a size characters of the QChar array \a unicode. - QString makes a deep copy of the string data. + QString makes a deep copy of the string data. The unicode data is copied as + is and the Byte Order Mark is preserved if present. */ QString::QString(const QChar *unicode, int size) { @@ -3480,7 +3482,7 @@ QByteArray QString::toAscii() const return toLatin1(); } -#ifndef Q_WS_MAC +#if !defined(Q_WS_MAC) && defined(Q_OS_UNIX) static QByteArray toLocal8Bit_helper(const QChar *data, int length) { #ifndef QT_NO_TEXTCODEC @@ -3843,74 +3845,7 @@ QString QString::fromUtf8(const char *str, int size) if (size < 0) size = qstrlen(str); - QString result(size, Qt::Uninitialized); // worst case - ushort *qch = result.d->data; - uint uc = 0; - uint min_uc = 0; - int need = 0; - int error = -1; - uchar ch; - int i = 0; - - // skip utf8-encoded byte order mark - if (size >= 3 - && (uchar)str[0] == 0xef && (uchar)str[1] == 0xbb && (uchar)str[2] == 0xbf) - i += 3; - - for (; i < size; ++i) { - ch = str[i]; - if (need) { - if ((ch&0xc0) == 0x80) { - uc = (uc << 6) | (ch & 0x3f); - need--; - if (!need) { - if (uc > 0xffffU && uc < 0x110000U) { - // surrogate pair - *qch++ = QChar::highSurrogate(uc); - uc = QChar::lowSurrogate(uc); - } else if ((uc < min_uc) || (uc >= 0xd800 && uc <= 0xdfff) || (uc >= 0xfffe)) { - // overlong seqence, UTF16 surrogate or BOM - uc = QChar::ReplacementCharacter; - } - *qch++ = uc; - } - } else { - i = error; - need = 0; - *qch++ = QChar::ReplacementCharacter; - } - } else { - if (ch < 128) { - *qch++ = ch; - } else if ((ch & 0xe0) == 0xc0) { - uc = ch & 0x1f; - need = 1; - error = i; - min_uc = 0x80; - } else if ((ch & 0xf0) == 0xe0) { - uc = ch & 0x0f; - need = 2; - error = i; - min_uc = 0x800; - } else if ((ch&0xf8) == 0xf0) { - uc = ch & 0x07; - need = 3; - error = i; - min_uc = 0x10000; - } else { - // Error - *qch++ = QChar::ReplacementCharacter; - } - } - } - if (need) { - // we have some invalid characters remaining we need to add to the string - for (int i = error; i < size; ++i) - *qch++ = QChar::ReplacementCharacter; - } - - result.truncate(qch - result.d->data); - return result; + return QUtf8::convertToUnicode(str, size, 0); } /*! @@ -3933,7 +3868,7 @@ QString QString::fromUtf16(const ushort *unicode, int size) while (unicode[size] != 0) ++size; } - return QString((const QChar *)unicode, size); + return QUtf16::convertToUnicode((const char *)unicode, size*2, 0); } @@ -3957,20 +3892,7 @@ QString QString::fromUcs4(const uint *unicode, int size) while (unicode[size] != 0) ++size; } - - QString s(size * 2, Qt::Uninitialized); // worst case - ushort *uc = s.d->data; - for (int i = 0; i < size; ++i) { - uint u = unicode[i]; - if (u > 0xffff) { - // decompose into a surrogate pair - *uc++ = QChar::highSurrogate(u); - u = QChar::lowSurrogate(u); - } - *uc++ = u; - } - s.resize(uc - s.d->data); - return s; + return QUtf32::convertToUnicode((const char *)unicode, size*4, 0); } /*! @@ -6106,6 +6028,7 @@ QString QString::repeated(int times) const return result; } +void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from); /*! \overload \fn QString QString::normalized(NormalizationForm mode, QChar::UnicodeVersion version) const @@ -6115,42 +6038,48 @@ QString QString::repeated(int times) const */ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersion version) const { + QString copy = *this; + qt_string_normalize(©, mode, version, 0); + return copy; +} + +void qt_string_normalize(QString *data, QString::NormalizationForm mode, QChar::UnicodeVersion version, int from) +{ bool simple = true; - for (int i = 0; i < d->size; ++i) { - if (d->data[i] >= 0x80) { + const QChar *p = data->constData(); + int len = data->length(); + for (int i = from; i < len; ++i) { + if (p[i].unicode() >= 0x80) { simple = false; break; } } if (simple) - return *this; + return; - QString s = *this; + QString &s = *data; if (version != CURRENT_VERSION) { for (int i = 0; i < NumNormalizationCorrections; ++i) { const NormalizationCorrection &n = uc_normalization_corrections[i]; if (n.version > version) { + int pos = from; if (n.ucs4 > 0xffff) { ushort ucs4High = QChar::highSurrogate(n.ucs4); ushort ucs4Low = QChar::lowSurrogate(n.ucs4); ushort oldHigh = QChar::highSurrogate(n.old_mapping); ushort oldLow = QChar::lowSurrogate(n.old_mapping); - int pos = 0; - while (pos < s.d->size - 1) { - if (s.d->data[pos] == ucs4High && s.d->data[pos + 1] == ucs4Low) { - s.detach(); - s.d->data[pos] = oldHigh; - s.d->data[pos + 1] = oldLow; + while (pos < s.length() - 1) { + if (s.at(pos).unicode() == ucs4High && s.at(pos + 1).unicode() == ucs4Low) { + s[pos] = oldHigh; + s[pos + 1] = oldLow; ++pos; } ++pos; } } else { - int pos = 0; - while (pos < s.d->size) { - if (s.d->data[pos] == n.ucs4) { - s.detach(); - s.d->data[pos] = n.old_mapping; + while (pos < s.length()) { + if (s.at(pos).unicode() == n.ucs4) { + s[pos] = n.old_mapping; } ++pos; } @@ -6158,15 +6087,14 @@ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersi } } } - s = decomposeHelper(s, mode < QString::NormalizationForm_KD, version); + decomposeHelper(data, mode < QString::NormalizationForm_KD, version, from); - s = canonicalOrderHelper(s, version); + canonicalOrderHelper(data, version, from); if (mode == QString::NormalizationForm_D || mode == QString::NormalizationForm_KD) - return s; - - return composeHelper(s); + return; + composeHelper(data, from); } @@ -6551,7 +6479,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, const QChar &fillCha ArgEscapeData d = findArgEscapes(*this); if (d.occurrences == 0) { - qWarning("QString::arg: Argument missing: %s, %lld", toLocal8Bit().data(), a); + qWarning() << "QString::arg: Argument missing:" << *this << ',' << a; return *this; } @@ -6594,7 +6522,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, const QChar &fillCh ArgEscapeData d = findArgEscapes(*this); if (d.occurrences == 0) { - qWarning("QString::arg: Argument missing: %s, %llu", toLocal8Bit().data(), a); + qWarning() << "QString::arg: Argument missing:" << *this << ',' << a; return *this; } diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 3b43253..463c32d 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -163,7 +163,7 @@ template <> struct QConcatenable<QString> static inline void appendTo(const QString &a, QChar *&out) { const int n = a.size(); - memcpy(out, (char*)a.constData(), sizeof(QChar) * n); + memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); out += n; } }; @@ -175,7 +175,7 @@ template <> struct QConcatenable<QStringRef> static inline void appendTo(QStringRef a, QChar *&out) { const int n = a.size(); - memcpy(out, (char*)a.constData(), sizeof(QChar) * n); + memcpy(out, reinterpret_cast<const char*>(a.constData()), sizeof(QChar) * n); out += n; } }; diff --git a/src/corelib/tools/qstringlist.cpp b/src/corelib/tools/qstringlist.cpp index 5a2b37a..5c550af 100644 --- a/src/corelib/tools/qstringlist.cpp +++ b/src/corelib/tools/qstringlist.cpp @@ -41,6 +41,7 @@ #include <qstringlist.h> #include <qset.h> +#include <qstringmatcher.h> QT_BEGIN_NAMESPACE diff --git a/src/corelib/tools/qstringlist.h b/src/corelib/tools/qstringlist.h index 665c0d0..f36567a 100644 --- a/src/corelib/tools/qstringlist.h +++ b/src/corelib/tools/qstringlist.h @@ -47,7 +47,6 @@ #include <QtCore/qlist.h> #include <QtCore/qregexp.h> #include <QtCore/qstring.h> -#include <QtCore/qstringmatcher.h> #ifdef QT_INCLUDE_COMPAT #include <Qt3Support/q3valuelist.h> #endif diff --git a/src/corelib/tools/qstringmatcher.h b/src/corelib/tools/qstringmatcher.h index 2b8edc9..61b7a95 100644 --- a/src/corelib/tools/qstringmatcher.h +++ b/src/corelib/tools/qstringmatcher.h @@ -81,13 +81,14 @@ private: // explicitely allow anonymous unions for RVCT to prevent compiler warnings #pragma anon_unions #endif + struct Data { + uchar q_skiptable[256]; + const QChar *uc; + int len; + }; union { uint q_data[256]; - struct { - uchar q_skiptable[256]; - const QChar *uc; - int len; - } p; + Data p; }; }; diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp index 04aed39..e32fc03 100644 --- a/src/corelib/tools/qtimeline.cpp +++ b/src/corelib/tools/qtimeline.cpp @@ -555,6 +555,8 @@ void QTimeLine::setCurveShape(CurveShape shape) /*! \property QTimeLine::easingCurve + \since 4.6 + Specifies the easing curve that the timeline will use. If both easing curve and curveShape are set, the last set property will override the previous one. (If valueForTime() is reimplemented it will diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 19b8da4..51a6709 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -415,7 +415,9 @@ void QVector<T>::free(Data *x) { if (QTypeInfo<T>::isComplex) { T* b = x->array; - T* i = b + reinterpret_cast<QVectorData *>(x)->size; + union { QVectorData *d; Data *p; } u; + u.p = x; + T* i = b + u.d->size; while (i-- != b) i->~T(); } diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index c93a065..08c94ac 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -5,6 +5,7 @@ HEADERS += \ tools/qbitarray.h \ tools/qbytearray.h \ tools/qbytearraymatcher.h \ + tools/qbytedata_p.h \ tools/qcache.h \ tools/qchar.h \ tools/qcontainerfwd.h \ diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 1fc2a9f..3e8f73e 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -334,12 +334,17 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const from the PrematureEndOfDocumentError error and continues parsing the new data with the next call to readNext(). - For example, if you read data from the network using QHttp, you - would connect its \l{QHttp::readyRead()}{readyRead()} signal to a - custom slot. In this slot, you read all available data with - \l{QHttp::readAll()}{readAll()} and pass it to the XML stream reader - using addData(). Then you call your custom parsing function that - reads the XML events from the reader. + For example, if your application reads data from the network using a + \l{QNetworkAccessManager} {network access manager}, you would issue + a \l{QNetworkRequest} {network request} to the manager and receive a + \l{QNetworkReply} {network reply} in return. Since a QNetworkReply + is a QIODevice, you connect its \l{QNetworkReply::readyRead()} + {readyRead()} signal to a custom slot, e.g. \c{slotReadyRead()} in + the code snippet shown in the discussion for QNetworkAccessManager. + In this slot, you read all available data with + \l{QNetworkReply::readAll()} {readAll()} and pass it to the XML + stream reader using addData(). Then you call your custom parsing + function that reads the XML events from the reader. \section1 Performance and memory consumption @@ -568,7 +573,7 @@ bool QXmlStreamReader::atEnd() const returns true, hasError() returns true, and this function returns QXmlStreamReader::Invalid. - The exception is when error() return PrematureEndOfDocumentError. + The exception is when error() returns PrematureEndOfDocumentError. This error is reported when the end of an otherwise well-formed chunk of XML is reached, but the chunk doesn't represent a complete XML document. In that case, parsing \e can be resumed by calling |