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:
parent
4b3acf5aff
commit
9063119268
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 };
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user