Proper String and Regexp parsing and escaping.

Added parsing of dialplan style %pattern% that is converted internally to regexp.
This allows for example %+1xxxxxxxxxx% to be same as /^\+1[0-9]{10}$/i


git-svn-id: http://yate.null.ro/svn/yate/trunk@5070 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2012-05-22 10:06:50 +00:00
parent 3ac7372757
commit 06cf56e116
3 changed files with 184 additions and 9 deletions

View File

@ -316,22 +316,67 @@ bool ExpEvaluator::getString(const char*& expr)
XDebug(this,DebugAll,"getString '%.30s'",expr);
char c = skipComments(expr);
if (c == '"' || c == '\'') {
char sep = c;
const char* start = ++expr;
while ((c = *expr++)) {
if (c != sep)
continue;
String str(start,expr-start-1);
DDebug(this,DebugAll,"Found '%s'",str.safe());
String str;
if (getString(expr,str)) {
addOpcode(str);
return true;
}
expr--;
return gotError("Expecting string end");
}
return false;
}
bool ExpEvaluator::getString(const char*& expr, String& str)
{
char sep = *expr++;
const char* start = expr;
while (char c = *expr++) {
if (c != '\\' && c != sep)
continue;
String tmp(start,expr-start-1);
str += tmp;
if (c == sep) {
DDebug(this,DebugAll,"Found '%s'",str.safe());
return true;
}
tmp.clear();
if (!getEscape(expr,tmp,sep))
break;
str += tmp;
start = expr;
}
expr--;
return gotError("Expecting string end");
}
bool ExpEvaluator::getEscape(const char*& expr, String& str, char sep)
{
char c = *expr++;
switch (c) {
case '\0':
return false;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
case 'v':
c = '\v';
break;
}
str = c;
return true;
}
int ExpEvaluator::getKeyword(const char* str) const
{
int len = 0;

View File

@ -103,6 +103,8 @@ public:
JsObject* parseArray(const char*& expr, bool constOnly);
JsObject* parseObject(const char*& expr, bool constOnly);
protected:
virtual bool getString(const char*& expr);
virtual bool getEscape(const char*& expr, String& str, char sep);
virtual bool keywordChar(char c) const;
virtual int getKeyword(const char* str) const;
virtual char skipComments(const char*& expr, GenObject* context = 0) const;
@ -381,6 +383,117 @@ bool JsCode::link()
return true;
}
bool JsCode::getString(const char*& expr)
{
if (inError())
return false;
char c = skipComments(expr);
if (c != '/' && c != '%')
return ExpEvaluator::getString(expr);
String str;
if (!ExpEvaluator::getString(expr,str))
return false;
bool extended = true;
bool insensitive = false;
if (c == '%') {
// dialplan pattern - turn it into a regular expression
insensitive = true;
String tmp = str;
tmp.toUpper();
str = "^";
char last = '\0';
int count = 0;
bool esc = false;
for (unsigned int i = 0; ; i++) {
c = tmp.at(i);
if (last && c != last) {
switch (last) {
case 'X':
str << "[0-9]";
break;
case 'Z':
str << "[1-9]";
break;
case 'N':
str << "[2-9]";
break;
case '.':
str << ".+";
count = 1;
break;
}
if (count > 1)
str << "{" << count << "}";
last = '\0';
count = 0;
}
if (!c) {
str << "$";
break;
}
switch (c) {
case '.':
if (esc) {
str << c;
break;
}
// fall through
case 'X':
case 'Z':
case 'N':
last = c;
count++;
break;
case '+':
case '*':
str << "\\";
// fall through
default:
str << c;
}
esc = (c == '\\');
}
}
else {
// regexp - check for flags
do {
c = *expr;
switch (c) {
case 'i':
expr++;
insensitive = true;
break;
case 'b':
expr++;
extended = false;
break;
default:
c = 0;
}
} while (c);
}
XDebug(this,DebugInfo,"Regexp '%s' flags '%s%s'",str.c_str(),
(insensitive ? "i" : ""),(extended ? "" : "b"));
addOpcode(str);
//m_opcodes.append(new ExpWrapper(obj));
return true;
}
bool JsCode::getEscape(const char*& expr, String& str, char sep)
{
if (sep != '\'' && sep != '"') {
// this is not a string but a regexp or dialplan template
char c = *expr++;
if (!c)
return false;
if (c != '\\' && c != sep)
str << '\\';
str << c;
return true;
}
return ExpEvaluator::getEscape(expr,str,sep);
}
bool JsCode::keywordChar(char c) const
{
return ExpEvaluator::keywordChar(c) || (c == '$');

View File

@ -561,6 +561,23 @@ protected:
*/
virtual bool getFunction(const char*& expr);
/**
* Helper method - get a string, advance parsing pointer past it
* @param expr Pointer to string separator, gets advanced on success
* @param str String in which the result is returned
* @return True if succeeded
*/
virtual bool getString(const char*& expr, String& str);
/**
* Helper method - get an escaped component of a string
* @param expr Pointer past escape character, gets advanced on success
* @param str String in which the result is returned
* @param sep String separator character
* @return True if succeeded
*/
virtual bool getEscape(const char*& expr, String& str, char sep);
/**
* Get a field keyword, advance parsing pointer past it
* @param expr Pointer to text to parse, gets advanced on success