RuleTextParser: Prepare lines parsing

This commit is contained in:
Nodir Temirkhodjaev 2024-06-11 17:30:43 +03:00
parent da79ae6714
commit e47ba8f627
2 changed files with 199 additions and 32 deletions

View File

@ -6,31 +6,36 @@
namespace { namespace {
RuleCharType processChar(const QChar c) const char *const extraNameChars = "_";
const char *const extraValueChars = ".:-/]";
RuleCharType processChar(const QChar c, const char *extraChars = nullptr)
{ {
if (c.isLetter()) { if (c.isLetter()) {
return CharNameBegin; return CharLetter;
} }
if (c.isDigit()) { if (c.isDigit()) {
return CharValueBegin; return CharDigit;
} }
static const QHash<char, RuleCharType> charTypeMap = { const char c1 = c.toLatin1();
{ '{', CharListBegin },
{ '}', CharListEnd },
{ '(', CharBracketBegin },
{ ')', CharBracketEnd },
{ '[', CharValueBegin },
{ ',', CharValueSeparator },
{ ':', CharColon },
{ '#', CharComment },
};
return charTypeMap.value(c.unicode(), CharNone); if (extraChars && strchr(extraChars, c1)) {
return CharExtra;
}
static const char chars[] = "{}()[,:#!\n";
static const RuleCharType charTypes[] = { CharListBegin, CharListEnd, CharBracketBegin,
CharBracketEnd, CharValueBegin, CharValueSeparator, CharColon, CharComment, CharNot,
CharNewLine };
const char *cp = strchr(chars, c1);
return cp ? charTypes[cp - chars] : CharNone;
} }
RuleCharType processCharType(RuleCharType charType, const QChar c) RuleCharType processCharType(RuleCharType charType, const QChar c, const char *extraChars = nullptr)
{ {
if (charType == CharComment) { if (charType == CharComment) {
if (c == '\n') { if (c == '\n') {
@ -40,7 +45,7 @@ RuleCharType processCharType(RuleCharType charType, const QChar c)
return CharComment; return CharComment;
} }
return processChar(c); return processChar(c, extraChars);
} }
} }
@ -58,21 +63,147 @@ void RuleTextParser::setupText(const QString &text)
bool RuleTextParser::parse() bool RuleTextParser::parse()
{ {
const auto charType = nextCharType(); return parseLines();
return false;
} }
RuleCharType RuleTextParser::nextCharType() bool RuleTextParser::parseLines()
{ {
const int listIndex = pushListNode(FORT_RULE_EXPR_LIST_OR);
for (;;) {
if (!parseLine())
break;
}
popListNode(listIndex);
return true;
}
bool RuleTextParser::parseLine()
{
bool ok = false;
const auto charType = nextCharType(CharAnyBegin);
switch (charType) {
case CharListBegin: {
ok = parseLines();
} break;
case CharBracketBegin: {
ok = parseBracketValues();
} break;
case CharLetter: {
ok = parseName();
} break;
case CharNot: {
m_isNot = !m_isNot;
} break;
default:
break;
}
return ok;
}
bool RuleTextParser::parseName()
{
const QChar *name = parsedCharPtr();
while (nextCharType(CharName, extraNameChars) != CharNone) {
continue;
}
if (hasError()) {
return false;
}
ungetChar();
const QStringView nameView(name, currentCharPtr() - name);
const auto nameLower = nameView.toString().toLower();
static const QHash<QString, qint8> exprTypesMap = {
{ "ip", FORT_RULE_EXPR_TYPE_ADDRESS },
{ "port", FORT_RULE_EXPR_TYPE_PORT },
{ "local_ip", FORT_RULE_EXPR_TYPE_LOCAL_ADDRESS },
{ "local_port", FORT_RULE_EXPR_TYPE_LOCAL_PORT },
{ "proto", FORT_RULE_EXPR_TYPE_PROTOCOL },
{ "protocol", FORT_RULE_EXPR_TYPE_PROTOCOL },
{ "dir", FORT_RULE_EXPR_TYPE_DIRECTION },
{ "direction", FORT_RULE_EXPR_TYPE_DIRECTION },
};
m_exprType = exprTypesMap.value(nameLower, -1);
if (m_exprType == -1) {
setErrorMessage(tr("Bad text: %1").arg(nameView));
return false;
}
return true;
}
bool RuleTextParser::parseBracketValues()
{
const auto endCharType = parseValues();
return (endCharType == CharBracketEnd);
}
RuleCharType RuleTextParser::parseValues()
{
return CharNone;
}
int RuleTextParser::pushListNode(int listType)
{
const int listIndex = m_ruleExprArray.size();
RuleExpr ruleExpr;
ruleExpr.flags = FORT_RULE_EXPR_FLAG_LIST;
ruleExpr.type = listType;
m_ruleExprArray.append(ruleExpr);
return listIndex;
}
void RuleTextParser::popListNode(int listIndex)
{
const int curListIndex = m_ruleExprArray.size();
RuleExpr &ruleExpr = m_ruleExprArray[listIndex];
ruleExpr.listCount = curListIndex - listIndex;
}
RuleCharType RuleTextParser::nextCharType(quint32 expectedCharTypes, const char *extraChars)
{
Q_ASSERT(!extraChars || (expectedCharTypes & CharExtra) != 0);
const auto cp = m_p;
RuleCharType charType = CharNone; RuleCharType charType = CharNone;
while (m_p < m_end) { while (m_p < m_end) {
const QChar c = *m_p++; const QChar c = *m_p++;
charType = processCharType(charType, c); charType = processCharType(charType, c, extraChars);
switch (charType) {
case CharNone: {
setErrorMessage(tr("Bad symbol: %1").arg(c));
return CharNone;
} break;
default:
if ((charType & expectedCharTypes) == 0) {
if (cp == m_p) {
setErrorMessage(tr("Unexpected symbol: %1").arg(c));
}
return CharNone;
}
if (charType != CharNone) {
return charType; return charType;
} }
} }

View File

@ -6,19 +6,28 @@
#include <util/util_types.h> #include <util/util_types.h>
enum RuleCharType { using RuleCharTypes = quint16;
enum RuleCharType : RuleCharTypes {
CharNone = 0, CharNone = 0,
CharListBegin = (1 << 0), // { CharListBegin = (1 << 0), // {
CharListEnd = (1 << 1), // } CharListEnd = (1 << 1), // }
CharBracketBegin = (1 << 2), // ( CharBracketBegin = (1 << 2), // (
CharBracketEnd = (1 << 3), // ) CharBracketEnd = (1 << 3), // )
CharNameBegin = (1 << 4), // a-zA-Z CharLetter = (1 << 4), // a-zA-Z
CharName = (1 << 5), // a-zA-Z0-9_- CharDigit = (1 << 5), // 0-9
CharValueBegin = (1 << 6), // [0-9 CharValueBegin = (1 << 6), // [
CharValue = (1 << 7), // 0-9.:-/ CharValueSeparator = (1 << 7), // ,
CharValueSeparator = (1 << 8), // , CharColon = (1 << 8), // :
CharColon = (1 << 9), // : CharComment = (1 << 9), // #
CharComment = (1 << 10), // # CharNot = (1 << 10), // !
CharExtra = (1 << 11), // Name | Value
CharNewLine = (1 << 12), // \n
CharAnyBegin =
(CharListBegin | CharBracketBegin | CharLetter | CharDigit | CharValueBegin | CharNot),
CharName = (CharLetter | CharExtra), // a-zA-Z_
CharValue = (CharDigit | CharValueBegin | CharExtra), // 0-9.:-/]
CharAny = RuleCharTypes(-1),
}; };
struct RuleExpr struct RuleExpr
@ -26,7 +35,6 @@ struct RuleExpr
quint8 flags = 0; quint8 flags = 0;
quint8 type = 0; quint8 type = 0;
quint16 listIndex = 0;
quint16 listCount = 0; quint16 listCount = 0;
StringViewList viewList; StringViewList viewList;
@ -39,21 +47,49 @@ class RuleTextParser : public QObject
public: public:
explicit RuleTextParser(const QString &text, QObject *parent = nullptr); explicit RuleTextParser(const QString &text, QObject *parent = nullptr);
QString errorMessage() const { return m_errorMessage; }
bool hasError() const { return !errorMessage().isEmpty(); }
const QVector<RuleExpr> &ruleExprArray() const { return m_ruleExprArray; } const QVector<RuleExpr> &ruleExprArray() const { return m_ruleExprArray; }
bool parse(); bool parse();
private: private:
void setErrorMessage(const QString &errorMessage) { m_errorMessage = errorMessage; }
void setupText(const QString &text); void setupText(const QString &text);
RuleCharType nextCharType(); bool parseLines();
bool parseLine();
bool parseName();
bool parseBracketValues();
RuleCharType parseValues();
int pushListNode(int listType);
void popListNode(int listIndex);
void ungetChar() { --m_p; }
const QChar *currentCharPtr() const { return m_p; }
const QChar *parsedCharPtr() const { return m_p - 1; }
RuleExpr &listNode(int listIndex) { return m_ruleExprArray[listIndex]; }
RuleCharType nextCharType(quint32 expectedCharTypes, const char *extraChars = nullptr);
private: private:
bool m_isNot = false;
quint8 m_exprType = 0; quint8 m_exprType = 0;
const QChar *m_p = nullptr; const QChar *m_p = nullptr;
const QChar *m_end = nullptr; const QChar *m_end = nullptr;
QString m_errorMessage;
QVector<RuleExpr> m_ruleExprArray; QVector<RuleExpr> m_ruleExprArray;
}; };