#include "licensedata.h"
|
#include <QDataStream>
|
#include <QtDebug>
|
|
LicenseData::LicenseData()
|
: productId(0), verMajor(0), verMinor(0), activeState(0)
|
{
|
}
|
|
QByteArray LicenseData::toBinary() const
|
{
|
QByteArray data;
|
data.reserve(64);
|
QDataStream stream(&data, QIODevice::WriteOnly);
|
stream.setByteOrder(QDataStream::BigEndian);
|
|
// 1. 主板UUID:固定16字节
|
QByteArray uuid = boardUuid.left(16);
|
uuid.append(QByteArray(16 - uuid.size(), '\0'));
|
stream.writeRawData(uuid.constData(), 16);
|
|
// 2. CPU序列号:固定8字节
|
QByteArray cpu = cpuSerial.left(8);
|
cpu.append(QByteArray(8 - cpu.size(), '\0'));
|
stream.writeRawData(cpu.constData(), 8);
|
|
// 3. 用户名:长度前缀(1B) + UTF-8数据
|
QByteArray userBytes = userName.toUtf8();
|
if (userBytes.size() > 255) {
|
userBytes = userBytes.left(255);
|
}
|
stream << static_cast<quint8>(userBytes.size());
|
stream.writeRawData(userBytes.constData(), userBytes.size());
|
|
// 4. 失效日期:2字节(距2000-01-01的天数)
|
stream << dateToDays(expireDate);
|
|
// 5. 产品号:1字节
|
stream << productId;
|
|
// 6. 版本号:主版本 + 次版本,各1字节
|
stream << verMajor << verMinor;
|
|
// 7. 激活状态:1字节
|
stream << activeState;
|
|
return data;
|
}
|
|
bool LicenseData::fromBinary(const QByteArray &data)
|
{
|
if (data.size() < 30) {
|
qWarning() << "LicenseData::fromBinary: data too short, need at least 30 bytes";
|
return false;
|
}
|
|
QDataStream stream(data);
|
stream.setByteOrder(QDataStream::BigEndian);
|
|
// 1. UUID
|
boardUuid.resize(16);
|
stream.readRawData(boardUuid.data(), 16);
|
|
// 2. CPU序列号
|
cpuSerial.resize(8);
|
stream.readRawData(cpuSerial.data(), 8);
|
|
// 3. 用户名
|
quint8 nameLen = 0;
|
stream >> nameLen;
|
if (data.size() < 25 + nameLen + 5) {
|
qWarning() << "LicenseData::fromBinary: insufficient data for remaining fields";
|
return false;
|
}
|
QByteArray userBytes(nameLen, '\0');
|
stream.readRawData(userBytes.data(), nameLen);
|
userName = QString::fromUtf8(userBytes);
|
|
// 4. 日期
|
quint16 days = 0;
|
stream >> days;
|
expireDate = daysToDate(days);
|
|
// 5. 产品号
|
stream >> productId;
|
|
// 6. 版本
|
stream >> verMajor >> verMinor;
|
|
// 7. 激活状态
|
stream >> activeState;
|
|
return true;
|
}
|
|
QString LicenseData::toDebugString() const
|
{
|
return QString("{UUID:%1, CPU:%2, User:%3, Expire:%4, Prod:%5, Ver:%6.%7, State:%8}")
|
.arg(uuidBinaryToString(boardUuid))
|
.arg(binaryToHexString(cpuSerial))
|
.arg(userName)
|
.arg(expireDate.toString("yyyy-MM-dd"))
|
.arg(productId)
|
.arg(verMajor).arg(verMinor)
|
.arg(activeState);
|
}
|
|
quint16 LicenseData::dateToDays(const QDate &date) const
|
{
|
QDate base(BASE_YEAR, BASE_MONTH, BASE_DAY);
|
if (!date.isValid() || date < base) {
|
return 0;
|
}
|
return static_cast<quint16>(base.daysTo(date));
|
}
|
|
QDate LicenseData::daysToDate(quint16 days) const
|
{
|
QDate base(BASE_YEAR, BASE_MONTH, BASE_DAY);
|
return base.addDays(days);
|
}
|
|
QByteArray LicenseData::uuidStringToBinary(const QString &uuidStr)
|
{
|
QString clean = uuidStr;
|
clean.remove('-');
|
clean.remove('{');
|
clean.remove('}');
|
clean = clean.toUpper();
|
if (clean.size() != 32) {
|
return QByteArray();
|
}
|
return hexStringToBinary(clean);
|
}
|
|
QString LicenseData::uuidBinaryToString(const QByteArray &bin)
|
{
|
if (bin.size() != 16) {
|
return QString();
|
}
|
QString hex = binaryToHexString(bin);
|
return QString("%1-%2-%3-%4-%5")
|
.arg(hex.mid(0, 8))
|
.arg(hex.mid(8, 4))
|
.arg(hex.mid(12, 4))
|
.arg(hex.mid(16, 4))
|
.arg(hex.mid(20, 12));
|
}
|
|
QByteArray LicenseData::hexStringToBinary(const QString &hexStr)
|
{
|
QString clean = hexStr;
|
clean.remove(' ');
|
QByteArray result;
|
result.reserve(clean.size() / 2);
|
for (int i = 0; i + 1 < clean.size(); i += 2) {
|
bool ok;
|
result.append(static_cast<char>(clean.mid(i, 2).toUInt(&ok, 16)));
|
}
|
return result;
|
}
|
|
QString LicenseData::binaryToHexString(const QByteArray &bin)
|
{
|
return QString::fromLatin1(bin.toHex()).toUpper();
|
}
|