32 #include <QHostAddress>
83 , m_data(new uchar[size])
93 error = tr(
"Unsupported database file size.");
97 if (!
file.open(QFile::ReadOnly))
99 error =
file.errorString();
107 error =
file.errorString();
127 error = tr(
"Unsupported database file size.");
133 memcpy(
reinterpret_cast<char *
>(db->
m_data), data.constData(), db->
m_size);
166 Q_IPV6ADDR addr = hostAddr.toIPv6Address();
168 const uchar *ptr =
m_data;
170 for (
int i = 0; i < 16; ++i)
172 for (
int j = 0; j < 8; ++j)
174 const bool right =
static_cast<bool>((addr[i] >> (7 - j)) & 1);
180 auto *idPtr =
reinterpret_cast<uchar *
>(&id);
191 if (country.isEmpty())
196 if (val.userType() == QMetaType::QVariantHash)
198 country = val.toHash()[
"country"].toHash()[
"iso_code"].toString();
212 #define CHECK_METADATA_REQ(key, type) \
213 if (!metadata.contains(#key)) \
215 error = errMsgNotFound.arg(#key); \
218 if (metadata.value(#key).userType() != QMetaType::type) \
220 error = errMsgInvalid.arg(#key); \
224 #define CHECK_METADATA_OPT(key, type) \
225 if (metadata.contains(#key)) \
227 if (metadata.value(#key).userType() != QMetaType::type) \
229 error = errMsgInvalid.arg(#key); \
236 const QString errMsgNotFound = tr(
"Metadata error: '%1' entry not found.");
237 const QString errMsgInvalid = tr(
"Metadata error: '%1' entry has invalid type.");
239 qDebug() <<
"Parsing MaxMindDB metadata...";
243 const uint versionMajor = metadata.value(
"binary_format_major_version").toUInt();
244 const uint versionMinor = metadata.value(
"binary_format_minor_version").toUInt();
245 if (versionMajor != 2)
247 error = tr(
"Unsupported database version: %1.%2").arg(versionMajor).arg(versionMinor);
252 m_ipVersion = metadata.value(
"ip_version").value<quint16>();
255 error = tr(
"Unsupported IP version: %1").arg(
m_ipVersion);
260 m_recordSize = metadata.value(
"record_size").value<quint16>();
263 error = tr(
"Unsupported record size: %1").arg(
m_recordSize);
270 m_nodeCount = metadata.value(
"node_count").value<quint32>();
274 m_dbType = metadata.value(
"database_type").toString();
277 m_buildEpoch = QDateTime::fromSecsSinceEpoch(metadata.value(
"build_epoch").toULongLong());
287 qDebug() <<
"Parsing IP geolocation database index tree...";
294 error = tr(
"Database corrupted: no data section found.");
303 const char *ptr =
reinterpret_cast<const char *
>(
m_data);
311 const QByteArray data = QByteArray::fromRawData(ptr, size);
319 if (metadata.userType() == QMetaType::QVariantHash)
320 return metadata.toHash();
332 quint32 locOffset = offset;
333 bool usePointer =
false;
334 if (descr.
fieldType == DataType::Pointer)
346 case DataType::Pointer:
347 qDebug() <<
"* Illegal Pointer using";
349 case DataType::String:
350 fieldValue = QString::fromUtf8(
reinterpret_cast<const char *
>(
m_data + locOffset), descr.
fieldSize);
353 case DataType::Double:
355 fieldValue = readPlainValue<double>(locOffset, descr.
fieldSize);
357 qDebug() <<
"* Invalid field size for type: Double";
359 case DataType::Bytes:
360 fieldValue = QByteArray(
reinterpret_cast<const char *
>(
m_data + locOffset), descr.
fieldSize);
363 case DataType::Integer16:
364 fieldValue = readPlainValue<quint16>(locOffset, descr.
fieldSize);
366 case DataType::Integer32:
367 fieldValue = readPlainValue<quint32>(locOffset, descr.
fieldSize);
372 case DataType::SignedInteger32:
373 fieldValue = readPlainValue<qint32>(locOffset, descr.
fieldSize);
375 case DataType::Integer64:
376 fieldValue = readPlainValue<quint64>(locOffset, descr.
fieldSize);
378 case DataType::Integer128:
379 qDebug() <<
"* Unsupported data type: Integer128";
381 case DataType::Array:
384 case DataType::DataCacheContainer:
385 qDebug() <<
"* Unsupported data type: DataCacheContainer";
387 case DataType::EndMarker:
388 qDebug() <<
"* Unsupported data type: EndMarker";
390 case DataType::Boolean:
391 fieldValue = QVariant::fromValue(
static_cast<bool>(descr.
fieldSize));
393 case DataType::Float:
395 fieldValue = readPlainValue<float>(locOffset, descr.
fieldSize);
397 qDebug() <<
"* Invalid field size for type: Float";
400 qDebug() <<
"* Unsupported data type: Unknown";
410 const uchar *dataPtr =
m_data + offset;
411 const int availSize =
m_size - offset;
412 if (availSize < 1)
return false;
417 const int size = ((dataPtr[0] & 0x18) >> 3);
418 if (availSize < (size + 2))
return false;
421 out.
offset = ((dataPtr[0] & 0x07) << 8) + dataPtr[1];
423 out.
offset = ((dataPtr[0] & 0x07) << 16) + (dataPtr[1] << 8) + dataPtr[2] + 2048;
425 out.
offset = ((dataPtr[0] & 0x07) << 24) + (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3] + 526336;
427 out.
offset = (dataPtr[1] << 24) + (dataPtr[2] << 16) + (dataPtr[3] << 8) + dataPtr[4];
439 if ((out.
fieldType <= DataType::Map) || (out.
fieldType > DataType::Float) || (availSize < 3))
450 if (availSize < 2)
return false;
456 if (availSize < 3)
return false;
457 out.
fieldSize = (dataPtr[1] << 8) + dataPtr[2] + 285;
462 if (availSize < 4)
return false;
463 out.
fieldSize = (dataPtr[1] << 16) + (dataPtr[2] << 8) + dataPtr[3] + 65821;
472 #if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
473 std::reverse(buf, buf + len);
484 for (quint32 i = 0; i < count; ++i)
487 if (field.userType() != QMetaType::QString)
490 const QString key = field.toString();
492 if (field.userType() == QVariant::Invalid)
505 for (quint32 i = 0; i < count; ++i)
508 if (field.userType() == QVariant::Invalid)
bool loadDB(QString &error) const
quint16 ipVersion() const
void fromBigEndian(uchar *buf, quint32 len) const
QVariant readArrayValue(quint32 &offset, quint32 count) const
QDateTime buildEpoch() const
QVariant readDataField(quint32 &offset) const
bool readDataFieldDescriptor(quint32 &offset, DataFieldDescriptor &out) const
QString lookup(const QHostAddress &hostAddr) const
QHash< quint32, QString > m_countries
GeoIPDatabase(quint32 size)
QVariantHash readMetadata() const
static GeoIPDatabase * load(const QString &filename, QString &error)
bool parseMetadata(const QVariantHash &metadata, QString &error)
QVariant readMapValue(quint32 &offset, quint32 count) const
#define CHECK_METADATA_OPT(key, type)
#define CHECK_METADATA_REQ(key, type)
const qint32 MAX_FILE_SIZE
const char DATA_SECTION_SEPARATOR[16]
const quint32 MAX_METADATA_SIZE
const char METADATA_BEGIN_MARK[]
file(GLOB QBT_TS_FILES "${qBittorrent_SOURCE_DIR}/src/lang/*.ts") set_source_files_properties($