fort/src/ui/util/ip4range.cpp

166 lines
3.7 KiB
C++
Raw Normal View History

2017-08-28 09:03:45 +00:00
#include "ip4range.h"
#include <QHash>
#include <QRegularExpression>
#include "netutil.h"
Ip4Range::Ip4Range(QObject *parent) :
QObject(parent),
m_errorLineNo(0)
{
}
void Ip4Range::setErrorLineNo(int lineNo)
{
if (m_errorLineNo != lineNo) {
m_errorLineNo = lineNo;
emit errorLineNoChanged();
}
}
void Ip4Range::setErrorMessage(const QString &errorMessage)
{
if (m_errorMessage != errorMessage) {
m_errorMessage = errorMessage;
emit errorMessageChanged();
}
}
2017-08-29 08:40:23 +00:00
QString Ip4Range::errorLineAndMessage() const
{
return tr("Error at line %1: %2")
.arg(QString::number(m_errorLineNo),
m_errorMessage);
}
2017-08-28 09:03:45 +00:00
QString Ip4Range::toText()
{
QString text;
2017-08-29 08:40:23 +00:00
const int n = size();
2017-08-28 09:03:45 +00:00
for (int i = 0; i < n; ++i) {
2017-08-29 08:40:23 +00:00
const Ip4Pair ip = at(i);
2017-08-28 09:03:45 +00:00
text += QString("%1-%2\n")
.arg(NetUtil::ip4ToText(ip.from),
NetUtil::ip4ToText(ip.to));
}
return text;
}
bool Ip4Range::fromText(const QString &text)
{
2017-08-29 08:40:23 +00:00
m_fromArray.clear();
m_toArray.clear();
2017-08-28 09:03:45 +00:00
ip4range_map_t ipRangeMap;
int lineNo = 0;
2017-08-29 08:40:23 +00:00
foreach (const QStringRef &line,
text.splitRef(QLatin1Char('\n'))) {
2017-08-28 09:03:45 +00:00
++lineNo;
2017-08-29 08:40:23 +00:00
if (line.isEmpty())
continue;
2017-08-28 09:03:45 +00:00
quint32 from, to;
if (!parseAddressMask(line, from, to)) {
setErrorLineNo(lineNo);
return false;
}
ipRangeMap.insert(from, to);
}
fillRange(ipRangeMap);
setErrorLineNo(0);
return true;
}
// Parse "127.0.0.0-127.255.255.255" or "127.0.0.0/24"
bool Ip4Range::parseAddressMask(const QStringRef &line,
quint32 &from, quint32 &to)
{
const QRegularExpression re("([\\d.]+)\\s*([/-])\\s*(\\S+)");
const QRegularExpressionMatch match = re.match(line);
if (!match.hasMatch()) {
setErrorMessage(tr("Bad format"));
return false;
}
const QString ip = match.captured(1);
const QChar sep = match.capturedRef(2).at(0);
const QString mask = match.captured(3);
bool ok;
from = NetUtil::textToIp4(ip, &ok);
if (!ok) {
2017-08-29 08:40:23 +00:00
setErrorMessage(tr("Bad IP address"));
2017-08-28 09:03:45 +00:00
return false;
}
if (sep == QLatin1Char('-')) { // e.g. "127.0.0.0-127.255.255.255"
to = NetUtil::textToIp4(mask, &ok);
if (!ok) {
2017-08-29 08:40:23 +00:00
setErrorMessage(tr("Bad second IP address"));
2017-08-28 09:03:45 +00:00
return false;
}
if (from > to) {
setErrorMessage(tr("Bad range"));
return false;
}
} else if (sep == QLatin1Char('/')) { // e.g. "127.0.0.0/24"
bool ok;
const int nbits = mask.toInt(&ok);
if (!ok || nbits < 0 || nbits > 32) {
setErrorMessage(tr("Bad mask"));
return false;
}
to = (nbits == 32) ? 0xFFFFFFFF
: (from | ((1 << nbits) - 1));
}
return true;
}
void Ip4Range::fillRange(const ip4range_map_t &ipRangeMap)
{
ip4range_map_t::const_iterator it = ipRangeMap.constBegin();
ip4range_map_t::const_iterator end = ipRangeMap.constEnd();
2017-08-29 08:40:23 +00:00
const int mapSize = ipRangeMap.size();
m_fromArray.reserve(mapSize);
m_toArray.reserve(mapSize);
2017-08-28 09:03:45 +00:00
2017-08-29 08:40:23 +00:00
Ip4Pair prevIp;
int prevIndex = -1;
2017-08-28 09:03:45 +00:00
for (; it != end; ++it) {
Ip4Pair ip{it.key(), it.value()};
// try to merge colliding adresses
2017-08-29 08:40:23 +00:00
if (prevIndex >= 0 && ip.from <= prevIp.to) {
if (ip.to > prevIp.to) {
m_toArray.replace(prevIndex, ip.to);
prevIp.to = ip.to;
2017-08-28 09:03:45 +00:00
}
// else skip it
} else {
2017-08-29 08:40:23 +00:00
m_fromArray.append(ip.from);
m_toArray.append(ip.to);
prevIp = ip;
++prevIndex;
2017-08-28 09:03:45 +00:00
}
}
}