Make QIPAddress::parseIp6 return the first bad character

In case of undetermined error, returns end.

Change-Id: Ic5d16bab5fc56ad24f19da25f73f9b844ce11d3f
Reviewed-by: David Faure (KDE) <faure@kde.org>
This commit is contained in:
Thiago Macieira 2013-07-01 18:24:40 -07:00 committed by The Qt Project
parent 4b3acf5aff
commit 9063119268
5 changed files with 42 additions and 29 deletions

View File

@ -53,7 +53,7 @@ static QString number(quint8 val, int base = 10)
}
typedef QVarLengthArray<char, 64> Buffer;
static bool checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end)
static const QChar *checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end)
{
const ushort *const ubegin = reinterpret_cast<const ushort *>(begin);
const ushort *const uend = reinterpret_cast<const ushort *>(end);
@ -64,11 +64,11 @@ static bool checkedToAscii(Buffer &buffer, const QChar *begin, const QChar *end)
while (src != uend) {
if (*src >= 0x7f)
return false;
return reinterpret_cast<const QChar *>(src);
*dst++ = *src++;
}
*dst = '\0';
return true;
return 0;
}
static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptLeadingZero);
@ -76,7 +76,7 @@ bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end)
{
Q_ASSERT(begin != end);
Buffer buffer;
if (!checkedToAscii(buffer, begin, end))
if (checkedToAscii(buffer, begin, end))
return false;
const char *ptr = buffer.data();
@ -137,12 +137,23 @@ void toString(QString &appendTo, IPv4Address address)
% number(address);
}
bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
/*!
\internal
\since 5.0
Parses one IPv6 address from \a begin to \a end and stores the
representation in \a address. Returns null if everything was parsed
correctly, or the pointer to the first bad character where parsing failed.
If the parsing failed for a reason not related to a particular character,
returns \a end.
*/
const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
{
Q_ASSERT(begin != end);
Buffer buffer;
if (!checkedToAscii(buffer, begin, end))
return false;
const QChar *ret = checkedToAscii(buffer, begin, end);
if (ret)
return ret;
const char *ptr = buffer.data();
@ -158,11 +169,11 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
}
// IPv4-in-IPv6 addresses are stricter in what they accept
if (dotCount != 0 && dotCount != 3)
return false;
return end;
memset(address, 0, sizeof address);
if (colonCount == 2 && end - begin == 2) // "::"
return true;
return 0;
// if there's a double colon ("::"), this is how many zeroes it means
int zeroWordsToFill;
@ -174,7 +185,7 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
(ptr[end - begin - 2] == ':' && ptr[end - begin - 1] == ':')) {
zeroWordsToFill = 9 - colonCount;
} else if (colonCount < 2 || colonCount > 7) {
return false;
return end;
} else {
zeroWordsToFill = 8 - colonCount;
}
@ -183,18 +194,13 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
int pos = 0;
while (pos < 15) {
const char *endptr;
bool ok;
quint64 ll = qstrtoull(ptr, &endptr, 16, &ok);
quint16 x = ll;
if (ptr == endptr) {
if (*ptr == ':') {
// empty field, we hope it's "::"
if (zeroWordsToFill < 1)
return false;
return begin + (ptr - buffer.data());
if (pos == 0 || pos == colonCount * 2) {
if (ptr[0] == '\0' || ptr[1] != ':')
return false;
return begin + (ptr - buffer.data());
++ptr;
}
pos += zeroWordsToFill * 2;
@ -202,24 +208,30 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
++ptr;
continue;
}
const char *endptr;
bool ok;
quint64 ll = qstrtoull(ptr, &endptr, 16, &ok);
quint16 x = ll;
if (!ok || ll != x)
return false;
return begin + (ptr - buffer.data());
if (*endptr == '.') {
// this could be an IPv4 address
// it's only valid in the last element
if (pos != 12)
return false;
return begin + (ptr - buffer.data());
IPv4Address ip4;
if (!parseIp4Internal(ip4, ptr, false))
return false;
return begin + (ptr - buffer.data());
address[12] = ip4 >> 24;
address[13] = ip4 >> 16;
address[14] = ip4 >> 8;
address[15] = ip4;
return true;
return 0;
}
address[pos++] = x >> 8;
@ -228,10 +240,10 @@ bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
if (*endptr == '\0')
break;
if (*endptr != ':')
return false;
return begin + (endptr - buffer.data());
ptr = endptr + 1;
}
return pos == 16;
return pos == 16 ? 0 : end;
}
static inline QChar toHex(uchar c)

View File

@ -63,7 +63,7 @@ typedef quint32 IPv4Address;
typedef quint8 IPv6Address[16];
Q_CORE_EXPORT bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end);
Q_CORE_EXPORT bool parseIp6(IPv6Address &address, const QChar *begin, const QChar *end);
Q_CORE_EXPORT const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end);
Q_CORE_EXPORT void toString(QString &appendTo, IPv4Address address);
Q_CORE_EXPORT void toString(QString &appendTo, IPv6Address address);

View File

@ -1141,7 +1141,8 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar
static bool parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
{
QIPAddressUtils::IPv6Address address;
if (!QIPAddressUtils::parseIp6(address, begin, end)) {
const QChar *ret = QIPAddressUtils::parseIp6(address, begin, end);
if (ret) {
// this struct is kept in automatic storage because it's only 4 bytes
const ushort decodeColon[] = { decode(':'), 0 };

View File

@ -189,7 +189,7 @@ static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr,
} else {
scopeId->clear();
}
return QIPAddressUtils::parseIp6(addr, tmp.constBegin(), tmp.constEnd());
return QIPAddressUtils::parseIp6(addr, tmp.constBegin(), tmp.constEnd()) == 0;
}
bool QHostAddressPrivate::parse()

View File

@ -361,7 +361,7 @@ void tst_QIpAddress::parseIp6()
#endif
Ip6 result;
bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd());
bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0;
QVERIFY(ok);
QCOMPARE(result, expected);
}
@ -441,7 +441,7 @@ void tst_QIpAddress::invalidParseIp6()
#endif
Ip6 result;
bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd());
bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0;
QVERIFY(!ok);
}