diff --git a/src/ui/util/conf/ruletextparser.cpp b/src/ui/util/conf/ruletextparser.cpp index b718818c..0d6bd65b 100644 --- a/src/ui/util/conf/ruletextparser.cpp +++ b/src/ui/util/conf/ruletextparser.cpp @@ -6,31 +6,36 @@ 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()) { - return CharNameBegin; + return CharLetter; } if (c.isDigit()) { - return CharValueBegin; + return CharDigit; } - static const QHash charTypeMap = { - { '{', CharListBegin }, - { '}', CharListEnd }, - { '(', CharBracketBegin }, - { ')', CharBracketEnd }, - { '[', CharValueBegin }, - { ',', CharValueSeparator }, - { ':', CharColon }, - { '#', CharComment }, - }; + const char c1 = c.toLatin1(); - 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 (c == '\n') { @@ -40,7 +45,7 @@ RuleCharType processCharType(RuleCharType charType, const QChar c) return CharComment; } - return processChar(c); + return processChar(c, extraChars); } } @@ -58,21 +63,147 @@ void RuleTextParser::setupText(const QString &text) bool RuleTextParser::parse() { - const auto charType = nextCharType(); - - return false; + return parseLines(); } -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 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; while (m_p < m_end) { 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; } } diff --git a/src/ui/util/conf/ruletextparser.h b/src/ui/util/conf/ruletextparser.h index 6d2dc75e..d38893e7 100644 --- a/src/ui/util/conf/ruletextparser.h +++ b/src/ui/util/conf/ruletextparser.h @@ -6,19 +6,28 @@ #include -enum RuleCharType { +using RuleCharTypes = quint16; + +enum RuleCharType : RuleCharTypes { CharNone = 0, CharListBegin = (1 << 0), // { CharListEnd = (1 << 1), // } CharBracketBegin = (1 << 2), // ( CharBracketEnd = (1 << 3), // ) - CharNameBegin = (1 << 4), // a-zA-Z - CharName = (1 << 5), // a-zA-Z0-9_- - CharValueBegin = (1 << 6), // [0-9 - CharValue = (1 << 7), // 0-9.:-/ - CharValueSeparator = (1 << 8), // , - CharColon = (1 << 9), // : - CharComment = (1 << 10), // # + CharLetter = (1 << 4), // a-zA-Z + CharDigit = (1 << 5), // 0-9 + CharValueBegin = (1 << 6), // [ + CharValueSeparator = (1 << 7), // , + CharColon = (1 << 8), // : + CharComment = (1 << 9), // # + 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 @@ -26,7 +35,6 @@ struct RuleExpr quint8 flags = 0; quint8 type = 0; - quint16 listIndex = 0; quint16 listCount = 0; StringViewList viewList; @@ -39,21 +47,49 @@ class RuleTextParser : public QObject public: explicit RuleTextParser(const QString &text, QObject *parent = nullptr); + QString errorMessage() const { return m_errorMessage; } + + bool hasError() const { return !errorMessage().isEmpty(); } + const QVector &ruleExprArray() const { return m_ruleExprArray; } bool parse(); private: + void setErrorMessage(const QString &errorMessage) { m_errorMessage = errorMessage; } + 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: + bool m_isNot = false; + quint8 m_exprType = 0; const QChar *m_p = nullptr; const QChar *m_end = nullptr; + QString m_errorMessage; + QVector m_ruleExprArray; };