summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qstring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qstring.cpp')
-rw-r--r--src/corelib/tools/qstring.cpp111
1 files changed, 72 insertions, 39 deletions
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 32f12bd092..a8e924b62d 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -1786,17 +1786,12 @@ void QString::reallocData(uint alloc, bool grow)
}
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void QString::expand(int i)
{
- int sz = d->size;
- resize(qMax(i + 1, sz));
- if (d->size - 1 > sz) {
- ushort *n = d->data() + d->size - 1;
- ushort *e = d->data() + sz;
- while (n != e)
- * --n = ' ';
- }
+ resize(qMax(i + 1, d->size), QLatin1Char(' '));
}
+#endif
/*! \fn void QString::clear()
@@ -1982,7 +1977,10 @@ QString &QString::insert(int i, QLatin1String str)
return *this;
int len = str.size();
- expand(qMax(d->size, i) + len - 1);
+ if (Q_UNLIKELY(i > d->size))
+ resize(i + len, QLatin1Char(' '));
+ else
+ resize(d->size + len);
::memmove(d->data() + i + len, d->data() + i, (d->size - i - len) * sizeof(QChar));
qt_from_latin1(d->data() + i, s, uint(len));
@@ -2012,7 +2010,10 @@ QString& QString::insert(int i, const QChar *unicode, int size)
return *this;
}
- expand(qMax(d->size, i) + size - 1);
+ if (Q_UNLIKELY(i > d->size))
+ resize(i + size, QLatin1Char(' '));
+ else
+ resize(d->size + size);
::memmove(d->data() + i + size, d->data() + i, (d->size - i - size) * sizeof(QChar));
memcpy(d->data() + i, s, size * sizeof(QChar));
@@ -2032,7 +2033,10 @@ QString& QString::insert(int i, QChar ch)
i += d->size;
if (i < 0)
return *this;
- expand(qMax(i, d->size));
+ if (Q_UNLIKELY(i > d->size))
+ resize(i + 1, QLatin1Char(' '));
+ else
+ resize(d->size + 1);
::memmove(d->data() + i + 1, d->data() + i, (d->size - i - 1) * sizeof(QChar));
d->data()[i] = ch.unicode();
return *this;
@@ -2404,26 +2408,40 @@ QString &QString::replace(const QString &before, const QString &after, Qt::CaseS
return replace(before.constData(), before.size(), after.constData(), after.size(), cs);
}
+namespace { // helpers for replace and its helper:
+QChar *textCopy(const QChar *start, int len)
+{
+ const size_t size = len * sizeof(QChar);
+ QChar *const copy = static_cast<QChar *>(::malloc(size));
+ Q_CHECK_PTR(copy);
+ ::memcpy(copy, start, size);
+ return copy;
+}
+
+bool pointsIntoRange(const QChar *ptr, const ushort *base, int len)
+{
+ const QChar *const start = reinterpret_cast<const QChar *>(base);
+ return start <= ptr && ptr < start + len;
+}
+} // end namespace
+
/*!
\internal
*/
void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar *after, int alen)
{
- // copy *after in case it lies inside our own d->data() area
- // (which we could possibly invalidate via a realloc or corrupt via memcpy operations.)
- QChar *afterBuffer = const_cast<QChar *>(after);
- if (after >= reinterpret_cast<QChar *>(d->data()) && after < reinterpret_cast<QChar *>(d->data()) + d->size) {
- afterBuffer = static_cast<QChar *>(::malloc(alen*sizeof(QChar)));
- Q_CHECK_PTR(afterBuffer);
- ::memcpy(afterBuffer, after, alen*sizeof(QChar));
- }
+ // Copy after if it lies inside our own d->data() area (which we could
+ // possibly invalidate via a realloc or modify by replacement).
+ QChar *afterBuffer = 0;
+ if (pointsIntoRange(after, d->data(), d->size)) // Use copy in place of vulnerable original:
+ after = afterBuffer = textCopy(after, alen);
QT_TRY {
if (blen == alen) {
// replace in place
detach();
for (int i = 0; i < nIndices; ++i)
- memcpy(d->data() + indices[i], afterBuffer, alen * sizeof(QChar));
+ memcpy(d->data() + indices[i], after, alen * sizeof(QChar));
} else if (alen < blen) {
// replace from front
detach();
@@ -2439,7 +2457,7 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
to += msize;
}
if (alen) {
- memcpy(d->data() + to, afterBuffer, alen*sizeof(QChar));
+ memcpy(d->data() + to, after, alen * sizeof(QChar));
to += alen;
}
movestart = indices[i] + blen;
@@ -2462,17 +2480,15 @@ void QString::replace_helper(uint *indices, int nIndices, int blen, const QChar
int moveto = insertstart + alen;
memmove(d->data() + moveto, d->data() + movestart,
(moveend - movestart)*sizeof(QChar));
- memcpy(d->data() + insertstart, afterBuffer, alen*sizeof(QChar));
+ memcpy(d->data() + insertstart, after, alen * sizeof(QChar));
moveend = movestart-blen;
}
}
} QT_CATCH(const std::bad_alloc &) {
- if (afterBuffer != after)
- ::free(afterBuffer);
+ ::free(afterBuffer);
QT_RETHROW;
}
- if (afterBuffer != after)
- ::free(afterBuffer);
+ ::free(afterBuffer);
}
/*!
@@ -2501,31 +2517,48 @@ QString &QString::replace(const QChar *before, int blen,
return *this;
QStringMatcher matcher(before, blen, cs);
+ QChar *beforeBuffer = 0, *afterBuffer = 0;
int index = 0;
while (1) {
uint indices[1024];
uint pos = 0;
- while (pos < 1023) {
+ while (pos < 1024) {
index = matcher.indexIn(*this, index);
if (index == -1)
break;
indices[pos++] = index;
- index += blen;
- // avoid infinite loop
- if (!blen)
+ if (blen) // Step over before:
+ index += blen;
+ else // Only count one instance of empty between any two characters:
index++;
}
- if (!pos)
+ if (!pos) // Nothing to replace
break;
+ if (Q_UNLIKELY(index != -1)) {
+ /*
+ We're about to change data, that before and after might point
+ into, and we'll need that data for our next batch of indices.
+ */
+ if (!afterBuffer && pointsIntoRange(after, d->data(), d->size))
+ after = afterBuffer = textCopy(after, alen);
+
+ if (!beforeBuffer && pointsIntoRange(before, d->data(), d->size)) {
+ beforeBuffer = textCopy(before, blen);
+ matcher = QStringMatcher(beforeBuffer, blen, cs);
+ }
+ }
+
replace_helper(indices, pos, blen, after, alen);
- if (index == -1)
+ if (Q_LIKELY(index == -1)) // Nothing left to replace
break;
- // index has to be adjusted in case we get back into the loop above.
+ // The call to replace_helper just moved what index points at:
index += pos*(alen-blen);
}
+ ::free(afterBuffer);
+ ::free(beforeBuffer);
return *this;
}
@@ -2556,26 +2589,26 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
uint indices[1024];
uint pos = 0;
if (cs == Qt::CaseSensitive) {
- while (pos < 1023 && index < d->size) {
+ while (pos < 1024 && index < d->size) {
if (d->data()[index] == cc)
indices[pos++] = index;
index++;
}
} else {
- while (pos < 1023 && index < d->size) {
+ while (pos < 1024 && index < d->size) {
if (QChar::toCaseFolded(d->data()[index]) == cc)
indices[pos++] = index;
index++;
}
}
- if (!pos)
+ if (!pos) // Nothing to replace
break;
replace_helper(indices, pos, 1, after.constData(), after.d->size);
- if (index == -1)
+ if (Q_LIKELY(index == -1)) // Nothing left to replace
break;
- // index has to be adjusted in case we get back into the loop above.
+ // The call to replace_helper just moved what index points at:
index += pos*(after.d->size - 1);
}
return *this;
@@ -5001,7 +5034,7 @@ void QString::truncate(int pos)
Removes \a n characters from the end of the string.
If \a n is greater than or equal to size(), the result is an
- empty string.
+ empty string; if \a n is negative, it is equivalent to passing zero.
Example:
\snippet qstring/main.cpp 15