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 {
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<char, RuleCharType> 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<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;
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;
}
}

View File

@ -6,19 +6,28 @@
#include <util/util_types.h>
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<RuleExpr> &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<RuleExpr> m_ruleExprArray;
};