517 lines
14 KiB
C++
517 lines
14 KiB
C++
|
|
|
|
|
|
#include "LogViewTetraTelegramsParser.hpp"
|
|
|
|
#include <QFile>
|
|
#include <QVector>
|
|
|
|
namespace N_LogView
|
|
{
|
|
|
|
LogViewTetraTelegramsParser::LogViewTetraTelegramsParser()
|
|
: m_logger(getLogger("LogViewTetraTelegramsParser"))
|
|
{
|
|
insertPod(QStringLiteral("bool"), 1, true, true, true);
|
|
insertPod(QStringLiteral("int"), 4, true, true);
|
|
insertPod(QStringLiteral("int32_t"), 4, true, true);
|
|
insertPod(QStringLiteral("qint64"), 8, true, true);
|
|
insertPod(QStringLiteral("float"), 4, true, false);
|
|
insertPod(QStringLiteral("double"), 8, true, false);
|
|
}
|
|
|
|
EnumInformation LogViewTetraTelegramsParser::enumFromType(const QString &type) const
|
|
{
|
|
for (const auto &ei : m_enums)
|
|
{
|
|
const QString fqType = ei.ns.isEmpty() ? ei.type : (ei.ns + QStringLiteral("::") + ei.type);
|
|
if (fqType == type)
|
|
return ei;
|
|
}
|
|
return EnumInformation();
|
|
}
|
|
|
|
StructInformation LogViewTetraTelegramsParser::structFromType(const QString &type) const
|
|
{
|
|
return m_structs.value(type);
|
|
}
|
|
|
|
PodInformation LogViewTetraTelegramsParser::podFromType(const QString &type) const
|
|
{
|
|
return m_pods.value(type);
|
|
}
|
|
|
|
bool LogViewTetraTelegramsParser::isEnum(const QString &type) const
|
|
{
|
|
for (const auto &ei : m_enums)
|
|
if (ei.type == type)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool LogViewTetraTelegramsParser::isStruct(const QString &type) const
|
|
{
|
|
return m_structs.contains(type);
|
|
}
|
|
|
|
bool LogViewTetraTelegramsParser::isPod(const QString &type) const
|
|
{
|
|
return m_pods.contains(type);
|
|
}
|
|
|
|
static void fillBasemembers(StructInformation &si, const QHash<QString, StructInformation> &structs)
|
|
{
|
|
if (si.baseStruct.isEmpty())
|
|
return;
|
|
StructInformation base = structs.value(si.baseStruct);
|
|
fillBasemembers(base, structs);
|
|
si.member = (base.member + si.member);
|
|
}
|
|
|
|
bool LogViewTetraTelegramsParser::parse(const QString &filename)
|
|
{
|
|
m_telegramIdEnum = EnumInformation();
|
|
m_enums.clear();
|
|
m_structs.clear();
|
|
|
|
m_visibleTelegrams.clear();
|
|
|
|
QFile f(filename);
|
|
if (!f.open(QIODevice::ReadOnly))
|
|
{
|
|
WARNING_LOG(m_logger) << "Can not open file " << filename << " for reading: " << f.errorString();
|
|
return false;
|
|
}
|
|
|
|
const QString content = QString::fromUtf8(f.readAll());
|
|
f.close();
|
|
|
|
const QVector<QStringRef> lines = content.splitRef(QLatin1Char('\n'));
|
|
QVector<QStringRef> linesTrimmed;
|
|
linesTrimmed.reserve(lines.size());
|
|
for (const QStringRef &line : lines)
|
|
linesTrimmed += line.trimmed();
|
|
|
|
int i = 0;
|
|
while (i < linesTrimmed.size())
|
|
{
|
|
const QStringRef &line = linesTrimmed.at(i);
|
|
if (line.startsWith(QLatin1String("struct")))
|
|
{
|
|
i = parseStruct(linesTrimmed, i);
|
|
if (i < 0)
|
|
return false;
|
|
}
|
|
else if (line.startsWith(QLatin1String("enum")))
|
|
{
|
|
i = parseEnum(linesTrimmed, i, QString());
|
|
if (i < 0)
|
|
return false;
|
|
}
|
|
else if (line.startsWith(QLatin1String("template <> struct Constraints")))
|
|
{
|
|
i = parseConstraint(linesTrimmed, i);
|
|
if (i < 0)
|
|
return false;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
const auto completeStructs = m_structs;
|
|
for (StructInformation &si : m_structs)
|
|
fillBasemembers(si, completeStructs);
|
|
return true;
|
|
}
|
|
|
|
void LogViewTetraTelegramsParser::insertPod(const QString &type, int byteLen, bool isSigned, bool isIntegral, bool isBoolean)
|
|
{
|
|
PodInformation pod;
|
|
pod.type = type;
|
|
pod.byteLen = byteLen;
|
|
pod.isBoolean = isBoolean;
|
|
pod.isIntegral = isIntegral;
|
|
pod.isSigned = isSigned;
|
|
m_pods[type] = pod;
|
|
}
|
|
|
|
|
|
int LogViewTetraTelegramsParser::parseStruct(const QVector<QStringRef> &lines, int iStartPos)
|
|
{
|
|
const QVector<QStringRef> tokens = tokenize(lines.at(iStartPos));
|
|
if (tokens.size() < 2)
|
|
return -1;
|
|
const QStringRef &structType = tokens.at(1);
|
|
if (structType.endsWith(QLatin1Char(';')))
|
|
return iStartPos;
|
|
|
|
StructInformation si;
|
|
si.type = structType.toString();
|
|
if (tokens.size() > 2)
|
|
{
|
|
if (tokens.at(2) != QLatin1String(":"))
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not parse struct: '" << lines.at(iStartPos).toString() << "', line: " << iStartPos + 1;
|
|
return -1;
|
|
}
|
|
|
|
for (int i = 3; i < tokens.size(); ++i)
|
|
{
|
|
if (!si.baseStruct.isEmpty())
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not parse struct: '" << lines.at(iStartPos).toString() << "', line: " << iStartPos + 1;
|
|
return -1;
|
|
}
|
|
QStringRef base = tokens.at(i);
|
|
if (base == QLatin1String("public") ||
|
|
base == QLatin1String("protected") ||
|
|
base == QLatin1String("private"))
|
|
continue;
|
|
if (base.endsWith(QLatin1Char(',')))
|
|
base.chop(1);
|
|
if (base.endsWith(QLatin1Char('>')))
|
|
{
|
|
si.isVisible = true;
|
|
continue;
|
|
}
|
|
si.baseStruct = tokens.at(i).toString();
|
|
}
|
|
}
|
|
|
|
int i = iStartPos + 1;
|
|
while (i < lines.size())
|
|
{
|
|
const QVector<QStringRef> tokens = tokenize(lines.at(i));
|
|
if (!validStructTokens(tokens))
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
if (tokens.at(0) == QLatin1String("};"))
|
|
break;
|
|
if (tokens.at(0) == QLatin1String("enum"))
|
|
{
|
|
i = parseEnum(lines, i, si.type, &si);
|
|
if (i < 0)
|
|
return -1;
|
|
++i;
|
|
continue;
|
|
}
|
|
|
|
MemberInformation mi;
|
|
if (tokens.size() > 2)
|
|
{
|
|
const int parserCommentPos = tokens.at(2) == QLatin1String("=") ? 4 : 2;
|
|
if (tokens.size() > parserCommentPos)
|
|
{
|
|
const QStringRef &comment = tokens.at(parserCommentPos);
|
|
DEBUG_LOG(m_logger) << "comment: " << comment.toString();
|
|
if (comment.startsWith(QLatin1String("//@array: ")))
|
|
{
|
|
const QStringRef hint = comment.mid(QLatin1String("//@array: ").size());
|
|
QString structStr = QLatin1String("struct ") + si.type + QLatin1String("::") + tokens.at(0).toString() + QLatin1Char('\n') + hint.toString();
|
|
structStr.replace(QLatin1Char(';'), QLatin1String(";\n"));
|
|
DEBUG_LOG(m_logger) << "structStr: " << structStr;
|
|
parseStruct(structStr.splitRef(QLatin1Char('\n')), 0);
|
|
|
|
mi.type = si.type + QLatin1String("::") + tokens.at(0).toString();
|
|
mi.isArray = true;
|
|
}
|
|
if (comment == QLatin1String("//@invisible"))
|
|
mi.isVisible = false;
|
|
}
|
|
}
|
|
|
|
QStringRef name = tokens.at(1);
|
|
if (name.endsWith(QLatin1Char(';')))
|
|
name.chop(1);
|
|
if (mi.type.isEmpty())
|
|
mi.type += tokens.at(0).toString();
|
|
categorizeMember(mi);
|
|
mi.name = name.toString();
|
|
if (mi.isEnum && !mi.type.contains(QLatin1String("::")))
|
|
{
|
|
|
|
for (const auto &ei : std::as_const(m_enums))
|
|
{
|
|
if (ei.type == mi.type)
|
|
{
|
|
if (!ei.ns.isEmpty())
|
|
mi.type = ei.ns + QLatin1String("::") + mi.type;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
si.member.push_back(std::move(mi));
|
|
|
|
++i;
|
|
}
|
|
|
|
if (m_logger.isDebugEnabled())
|
|
{
|
|
if (si.baseStruct.isEmpty())
|
|
DEBUG_LOG(m_logger) << "Found Struct: " << si.type;
|
|
else
|
|
DEBUG_LOG(m_logger) << "Found Struct: " << si.type << ", base: " << si.baseStruct;
|
|
for (int j = 0; j < si.member.size(); ++j)
|
|
{
|
|
const MemberInformation &mi = si.member.at(j);
|
|
DEBUG_LOG(m_logger) << "Member[" << j << "]: " << mi.type << " - " << mi.name;
|
|
}
|
|
}
|
|
|
|
m_structs[si.type] = si;
|
|
|
|
return i;
|
|
}
|
|
|
|
int LogViewTetraTelegramsParser::parseEnum(const QVector<QStringRef> &lines, int iStartPos, const QString &ns, StructInformation *si)
|
|
{
|
|
const QVector<QStringRef> tokens = tokenize(lines.at(iStartPos));
|
|
if (tokens.size() < 2)
|
|
return -1;
|
|
QStringRef enumName = tokens.at(1);
|
|
if (enumName == QLatin1String("class"))
|
|
{
|
|
if (tokens.size() < 3)
|
|
return -1;
|
|
enumName = tokens.at(2);
|
|
}
|
|
if (enumName.endsWith(QLatin1Char(';')))
|
|
return iStartPos;
|
|
|
|
EnumInformation ei;
|
|
ei.type = enumName.toString();
|
|
ei.ns = ns;
|
|
|
|
int i = iStartPos + 1;
|
|
while (i < lines.size())
|
|
{
|
|
const QVector<QStringRef> tokens = tokenize(lines.at(i).split(QStringLiteral("//")).first());
|
|
if (tokens.isEmpty() ||
|
|
(tokens.at(0) == QLatin1String("{")))
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
if (tokens.at(0) == QLatin1String("};"))
|
|
break;
|
|
if ((tokens.size() != 1 && tokens.size() != 3) ||
|
|
(tokens.size() == 3 && tokens.at(1) != QLatin1String("=")))
|
|
{
|
|
if (tokens.size() == 4 && tokens.at(0) == QLatin1String("}") && tokens.at(3).endsWith(QLatin1Char(';')) && si)
|
|
{
|
|
|
|
MemberInformation mi;
|
|
if (ns.isEmpty())
|
|
mi.type = ei.type;
|
|
else
|
|
mi.type = ns + QStringLiteral("::") + ei.type;
|
|
mi.isEnum = true;
|
|
mi.name = tokens.at(1).toString();
|
|
si->member.push_back(std::move(mi));
|
|
break;
|
|
}
|
|
WARNING_LOG(m_logger) << "Could not parse enum: '" << lines.at(i).toString() << "', line: " << i + 1;
|
|
return -1;
|
|
}
|
|
|
|
EnumValue ev;
|
|
ev.key = tokens.at(0).toString();
|
|
if (tokens.size() == 3)
|
|
{
|
|
QStringRef value = tokens.at(2);
|
|
if (value.endsWith(QLatin1Char(',')))
|
|
value.chop(1);
|
|
ev.value = value.toInt();
|
|
}
|
|
else
|
|
{
|
|
int val = ei.values.isEmpty() ? 0 : (ei.values.last().value + 1);
|
|
ev.value = val;
|
|
}
|
|
ei.values.push_back(std::move(ev));
|
|
++i;
|
|
}
|
|
|
|
DEBUG_LOG(m_logger) << "Found Enum: " << ei.type;
|
|
for (const EnumValue &ev : std::as_const(ei.values))
|
|
DEBUG_LOG(m_logger) << "Member[" << i << "]: " << ev.key << " = " << ev.value;
|
|
|
|
if (ei.type == QLatin1String("TelegramId"))
|
|
m_telegramIdEnum = ei;
|
|
|
|
m_enums.push_back(std::move(ei));
|
|
|
|
return i;
|
|
}
|
|
|
|
int LogViewTetraTelegramsParser::parseConstraint(const QVector<QStringRef> &lines, int iStartPos)
|
|
{
|
|
const QVector<QStringRef> tokens = tokenize(lines.at(iStartPos));
|
|
if (tokens.size() != 4)
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(iStartPos).toString() << "'";
|
|
return -1;
|
|
}
|
|
const QStringRef &cs = tokens.at(3);
|
|
if (!cs.startsWith(QLatin1String("Constraints<")) || !cs.endsWith(QLatin1Char('>')))
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(iStartPos).toString() << "'";
|
|
return -1;
|
|
}
|
|
QStringRef structName = cs.mid(QLatin1String("Constraints<").size());
|
|
structName.chop(1);
|
|
DEBUG_LOG(m_logger) << "Constraint: " << structName.toString();
|
|
|
|
int i = iStartPos + 1;
|
|
while (i < lines.size())
|
|
{
|
|
const QVector<QStringRef> tokens = tokenize(lines.at(i));
|
|
if (tokens.isEmpty() ||
|
|
(tokens.at(0) == QLatin1String("{")))
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
if (tokens.at(0) == QLatin1String("};"))
|
|
break;
|
|
if (tokens.size() != 8 || tokens.at(2) != QLatin1String("TelegramId"))
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
const QVector<QStringRef> parts = tokens.at(6).split(QLatin1String("::"));
|
|
if (parts.size() != 2)
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not parse constraint: '" << lines.at(i).toString() << "'";
|
|
return -1;
|
|
}
|
|
|
|
QStringRef enumKey = parts.at(1);
|
|
if (enumKey.endsWith(QLatin1Char(';')))
|
|
enumKey.chop(1);
|
|
bool bFound = false;
|
|
for (const auto &v : std::as_const(m_telegramIdEnum.values))
|
|
{
|
|
if (v.key == enumKey)
|
|
{
|
|
m_visibleTelegrams.insert(v.value, structName.toString());
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bFound)
|
|
{
|
|
WARNING_LOG(m_logger) << "Could not find enum value '" << enumKey.toString() << "' in enum TelegramId";
|
|
return -1;
|
|
}
|
|
++i;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
QString LogViewTetraTelegramsParser::getInnerType(const QString &type)
|
|
{
|
|
int idxLt = type.lastIndexOf(QLatin1Char('>'));
|
|
if (idxLt < 0)
|
|
return QString();
|
|
int idxGt = type.indexOf(QLatin1Char('<'));
|
|
if (idxGt < 0)
|
|
return QString();
|
|
return type.mid(idxGt + 1, idxLt - idxGt - 1);
|
|
}
|
|
|
|
void LogViewTetraTelegramsParser::categorizeMember(MemberInformation &mi) const
|
|
{
|
|
mi.isPod = isPod(mi.type);
|
|
mi.isEnum = mi.isPod ? false : isEnum(mi.type);
|
|
if (mi.type.startsWith(QLatin1String("std::vector<")))
|
|
mi.isArray = true;
|
|
mi.isStruct = mi.isArray ? false : isStruct(mi.type);
|
|
mi.isString = (mi.type == QLatin1String("std::string") || mi.type == QLatin1String("QString"));
|
|
mi.isBinary = (mi.type == QLatin1String("std::vector<unsigned char>") || mi.type == QLatin1String("QByteArray"));
|
|
}
|
|
|
|
static inline void bracketCount(const QStringRef &str, int &cntLt, int &cntGt)
|
|
{
|
|
cntLt = 0;
|
|
cntGt = 0;
|
|
for (int i = 0; i < str.size(); ++i)
|
|
{
|
|
if (str.at(i) == QLatin1Char('<'))
|
|
cntLt++;
|
|
else if (str.at(i) == QLatin1Char('>'))
|
|
cntGt++;
|
|
}
|
|
}
|
|
|
|
QVector<QStringRef> LogViewTetraTelegramsParser::tokenize(const QStringRef &line) const
|
|
{
|
|
QVector<QStringRef> ret = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
|
int i = 0;
|
|
while (i < ret.size())
|
|
{
|
|
const QStringRef &token = ret.at(i);
|
|
if (token.startsWith(QLatin1String("//")))
|
|
{
|
|
|
|
if (i == ret.size() - 1)
|
|
break;
|
|
const QStringRef &lastToken = ret.last();
|
|
const QStringRef newToken = QStringRef(token.string(), token.position(), lastToken.position() - token.position() + lastToken.size());
|
|
DEBUG_LOG(m_logger) << "New Token: " << newToken.toString();
|
|
ret.resize(i + 1);
|
|
ret[i] = newToken;
|
|
break;
|
|
}
|
|
if (i == ret.size() - 1)
|
|
break;
|
|
int cntLt;
|
|
int cntGt;
|
|
bracketCount(token, cntLt, cntGt);
|
|
if (cntLt == cntGt)
|
|
{
|
|
++i;
|
|
continue;
|
|
}
|
|
const QStringRef &nextToken = ret.at(i + 1);
|
|
const QStringRef newToken = QStringRef(token.string(), token.position(), nextToken.position() - token.position() + nextToken.size());
|
|
DEBUG_LOG(m_logger) << "New Token: " << newToken.toString();
|
|
ret.removeAt(i + 1);
|
|
ret[i] = newToken;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool LogViewTetraTelegramsParser::validStructTokens(const QVector<QStringRef> &tokens)
|
|
{
|
|
if (tokens.isEmpty() ||
|
|
(tokens.at(0) == QLatin1String("{")) ||
|
|
(tokens.at(0) == QLatin1String("{}")) ||
|
|
(tokens.at(0) == QLatin1String("}")) ||
|
|
(tokens.at(0) == QLatin1String(":")) ||
|
|
(tokens.at(0) == QLatin1String(",")) ||
|
|
(tokens.at(0) == QLatin1String("virtual")))
|
|
return false;
|
|
|
|
if (tokens.at(0) == QLatin1String("};") || tokens.at(0) == QLatin1String("enum"))
|
|
return true;
|
|
|
|
const int len = tokens.last().startsWith(QLatin1String("//")) ? tokens.size() - 1 : tokens.size();
|
|
|
|
if (len == 2)
|
|
return true;
|
|
|
|
if (len < 4)
|
|
return false;
|
|
|
|
if (len >= 4 && tokens.at(2) == QLatin1String("="))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|