1520 lines
34 KiB
C#
1520 lines
34 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Globalization;
|
|
|
|
namespace System.Text.RegularExpressions.Syntax
|
|
{
|
|
// Token: 0x020002D5 RID: 725
|
|
internal class Parser
|
|
{
|
|
// Token: 0x06001A61 RID: 6753 RVA: 0x0005F7D0 File Offset: 0x0005D9D0
|
|
public Parser()
|
|
{
|
|
this.caps = new ArrayList();
|
|
this.refs = new Hashtable();
|
|
}
|
|
|
|
// Token: 0x06001A62 RID: 6754 RVA: 0x0005F7F0 File Offset: 0x0005D9F0
|
|
public static int ParseDecimal(string str, ref int ptr)
|
|
{
|
|
return Parser.ParseNumber(str, ref ptr, 10, 1, int.MaxValue);
|
|
}
|
|
|
|
// Token: 0x06001A63 RID: 6755 RVA: 0x0005F804 File Offset: 0x0005DA04
|
|
public static int ParseOctal(string str, ref int ptr)
|
|
{
|
|
return Parser.ParseNumber(str, ref ptr, 8, 1, 3);
|
|
}
|
|
|
|
// Token: 0x06001A64 RID: 6756 RVA: 0x0005F810 File Offset: 0x0005DA10
|
|
public static int ParseHex(string str, ref int ptr, int digits)
|
|
{
|
|
return Parser.ParseNumber(str, ref ptr, 16, digits, digits);
|
|
}
|
|
|
|
// Token: 0x06001A65 RID: 6757 RVA: 0x0005F820 File Offset: 0x0005DA20
|
|
public static int ParseNumber(string str, ref int ptr, int b, int min, int max)
|
|
{
|
|
int num = ptr;
|
|
int num2 = 0;
|
|
int num3 = 0;
|
|
if (max < min)
|
|
{
|
|
max = int.MaxValue;
|
|
}
|
|
while (num3 < max && num < str.Length)
|
|
{
|
|
int num4 = Parser.ParseDigit(str[num++], b, num3);
|
|
if (num4 < 0)
|
|
{
|
|
num--;
|
|
break;
|
|
}
|
|
num2 = num2 * b + num4;
|
|
num3++;
|
|
}
|
|
if (num3 < min)
|
|
{
|
|
return -1;
|
|
}
|
|
ptr = num;
|
|
return num2;
|
|
}
|
|
|
|
// Token: 0x06001A66 RID: 6758 RVA: 0x0005F898 File Offset: 0x0005DA98
|
|
public static string ParseName(string str, ref int ptr)
|
|
{
|
|
if (char.IsDigit(str[ptr]))
|
|
{
|
|
int num = Parser.ParseNumber(str, ref ptr, 10, 1, 0);
|
|
if (num > 0)
|
|
{
|
|
return num.ToString();
|
|
}
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
int num2 = ptr;
|
|
while (Parser.IsNameChar(str[ptr]))
|
|
{
|
|
ptr++;
|
|
}
|
|
if (ptr - num2 > 0)
|
|
{
|
|
return str.Substring(num2, ptr - num2);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A67 RID: 6759 RVA: 0x0005F918 File Offset: 0x0005DB18
|
|
public static string Escape(string str)
|
|
{
|
|
string text = string.Empty;
|
|
int i = 0;
|
|
while (i < str.Length)
|
|
{
|
|
char c = str[i];
|
|
char c2 = c;
|
|
switch (c2)
|
|
{
|
|
case ' ':
|
|
case '#':
|
|
case '$':
|
|
case '(':
|
|
case ')':
|
|
case '*':
|
|
case '+':
|
|
case '.':
|
|
goto IL_AF;
|
|
default:
|
|
switch (c2)
|
|
{
|
|
case '\t':
|
|
text += "\\t";
|
|
break;
|
|
case '\n':
|
|
text += "\\n";
|
|
break;
|
|
default:
|
|
switch (c2)
|
|
{
|
|
case '[':
|
|
case '\\':
|
|
case '^':
|
|
goto IL_AF;
|
|
default:
|
|
if (c2 == '{' || c2 == '|' || c2 == '?')
|
|
{
|
|
goto IL_AF;
|
|
}
|
|
text += c;
|
|
break;
|
|
}
|
|
break;
|
|
case '\f':
|
|
text += "\\f";
|
|
break;
|
|
case '\r':
|
|
text += "\\r";
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
IL_11C:
|
|
i++;
|
|
continue;
|
|
IL_AF:
|
|
text = text + "\\" + c;
|
|
goto IL_11C;
|
|
}
|
|
return text;
|
|
}
|
|
|
|
// Token: 0x06001A68 RID: 6760 RVA: 0x0005FA54 File Offset: 0x0005DC54
|
|
public static string Unescape(string str)
|
|
{
|
|
if (str.IndexOf('\\') == -1)
|
|
{
|
|
return str;
|
|
}
|
|
return new Parser().ParseString(str);
|
|
}
|
|
|
|
// Token: 0x06001A69 RID: 6761 RVA: 0x0005FA74 File Offset: 0x0005DC74
|
|
public RegularExpression ParseRegularExpression(string pattern, RegexOptions options)
|
|
{
|
|
this.pattern = pattern;
|
|
this.ptr = 0;
|
|
this.caps.Clear();
|
|
this.refs.Clear();
|
|
this.num_groups = 0;
|
|
RegularExpression regularExpression2;
|
|
try
|
|
{
|
|
RegularExpression regularExpression = new RegularExpression();
|
|
this.ParseGroup(regularExpression, options, null);
|
|
this.ResolveReferences();
|
|
regularExpression.GroupCount = this.num_groups;
|
|
regularExpression2 = regularExpression;
|
|
}
|
|
catch (IndexOutOfRangeException)
|
|
{
|
|
throw this.NewParseException("Unexpected end of pattern.");
|
|
}
|
|
return regularExpression2;
|
|
}
|
|
|
|
// Token: 0x06001A6A RID: 6762 RVA: 0x0005FB08 File Offset: 0x0005DD08
|
|
public int GetMapping(Hashtable mapping)
|
|
{
|
|
int count = this.caps.Count;
|
|
mapping.Add("0", 0);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
CapturingGroup capturingGroup = (CapturingGroup)this.caps[i];
|
|
string text = ((capturingGroup.Name == null) ? capturingGroup.Index.ToString() : capturingGroup.Name);
|
|
if (mapping.Contains(text))
|
|
{
|
|
if ((int)mapping[text] != capturingGroup.Index)
|
|
{
|
|
throw new SystemException("invalid state");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mapping.Add(text, capturingGroup.Index);
|
|
}
|
|
}
|
|
return this.gap;
|
|
}
|
|
|
|
// Token: 0x06001A6B RID: 6763 RVA: 0x0005FBC8 File Offset: 0x0005DDC8
|
|
private void ParseGroup(Group group, RegexOptions options, Assertion assertion)
|
|
{
|
|
bool flag = group is RegularExpression;
|
|
Alternation alternation = null;
|
|
string text = null;
|
|
Group group2 = new Group();
|
|
Expression expression = null;
|
|
bool flag2 = false;
|
|
do
|
|
{
|
|
this.ConsumeWhitespace(Parser.IsIgnorePatternWhitespace(options));
|
|
if (this.ptr >= this.pattern.Length)
|
|
{
|
|
break;
|
|
}
|
|
char c = this.pattern[this.ptr++];
|
|
char c2 = c;
|
|
switch (c2)
|
|
{
|
|
case '$':
|
|
{
|
|
Position position = ((!Parser.IsMultiline(options)) ? Position.End : Position.EndOfLine);
|
|
expression = new PositionAssertion(position);
|
|
break;
|
|
}
|
|
default:
|
|
switch (c2)
|
|
{
|
|
case '[':
|
|
expression = this.ParseCharacterClass(options);
|
|
break;
|
|
case '\\':
|
|
{
|
|
int num = this.ParseEscape();
|
|
if (num >= 0)
|
|
{
|
|
c = (char)num;
|
|
}
|
|
else
|
|
{
|
|
expression = this.ParseSpecial(options);
|
|
if (expression == null)
|
|
{
|
|
c = this.pattern[this.ptr++];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
if (c2 == '?')
|
|
{
|
|
goto IL_25F;
|
|
}
|
|
if (c2 == '|')
|
|
{
|
|
if (text != null)
|
|
{
|
|
group2.AppendExpression(new Literal(text, Parser.IsIgnoreCase(options)));
|
|
text = null;
|
|
}
|
|
if (assertion != null)
|
|
{
|
|
if (assertion.TrueExpression == null)
|
|
{
|
|
assertion.TrueExpression = group2;
|
|
}
|
|
else
|
|
{
|
|
if (assertion.FalseExpression != null)
|
|
{
|
|
goto IL_230;
|
|
}
|
|
assertion.FalseExpression = group2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (alternation == null)
|
|
{
|
|
alternation = new Alternation();
|
|
}
|
|
alternation.AddAlternative(group2);
|
|
}
|
|
group2 = new Group();
|
|
continue;
|
|
}
|
|
break;
|
|
case '^':
|
|
{
|
|
Position position2 = ((!Parser.IsMultiline(options)) ? Position.Start : Position.StartOfLine);
|
|
expression = new PositionAssertion(position2);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case '(':
|
|
{
|
|
bool flag3 = Parser.IsIgnoreCase(options);
|
|
expression = this.ParseGroupingConstruct(ref options);
|
|
if (expression == null)
|
|
{
|
|
if (text != null && Parser.IsIgnoreCase(options) != flag3)
|
|
{
|
|
group2.AppendExpression(new Literal(text, Parser.IsIgnoreCase(options)));
|
|
text = null;
|
|
}
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case ')':
|
|
goto IL_1DA;
|
|
case '*':
|
|
case '+':
|
|
goto IL_25F;
|
|
case '.':
|
|
{
|
|
Category category = ((!Parser.IsSingleline(options)) ? Category.Any : Category.AnySingleline);
|
|
expression = new CharacterClass(category, false);
|
|
break;
|
|
}
|
|
}
|
|
this.ConsumeWhitespace(Parser.IsIgnorePatternWhitespace(options));
|
|
if (this.ptr < this.pattern.Length)
|
|
{
|
|
char c3 = this.pattern[this.ptr];
|
|
int num2 = 0;
|
|
int num3 = 0;
|
|
bool flag4 = false;
|
|
bool flag5 = false;
|
|
if (c3 == '?' || c3 == '*' || c3 == '+')
|
|
{
|
|
this.ptr++;
|
|
flag5 = true;
|
|
c2 = c3;
|
|
if (c2 != '*')
|
|
{
|
|
if (c2 != '+')
|
|
{
|
|
if (c2 == '?')
|
|
{
|
|
num2 = 0;
|
|
num3 = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num2 = 1;
|
|
num3 = int.MaxValue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
num2 = 0;
|
|
num3 = int.MaxValue;
|
|
}
|
|
}
|
|
else if (c3 == '{' && this.ptr + 1 < this.pattern.Length)
|
|
{
|
|
int num4 = this.ptr;
|
|
this.ptr++;
|
|
flag5 = this.ParseRepetitionBounds(out num2, out num3, options);
|
|
if (!flag5)
|
|
{
|
|
this.ptr = num4;
|
|
}
|
|
}
|
|
if (flag5)
|
|
{
|
|
this.ConsumeWhitespace(Parser.IsIgnorePatternWhitespace(options));
|
|
if (this.ptr < this.pattern.Length && this.pattern[this.ptr] == '?')
|
|
{
|
|
this.ptr++;
|
|
flag4 = true;
|
|
}
|
|
Repetition repetition = new Repetition(num2, num3, flag4);
|
|
if (expression == null)
|
|
{
|
|
repetition.Expression = new Literal(c.ToString(), Parser.IsIgnoreCase(options));
|
|
}
|
|
else
|
|
{
|
|
repetition.Expression = expression;
|
|
}
|
|
expression = repetition;
|
|
}
|
|
}
|
|
if (expression == null)
|
|
{
|
|
if (text == null)
|
|
{
|
|
text = string.Empty;
|
|
}
|
|
text += c;
|
|
}
|
|
else
|
|
{
|
|
if (text != null)
|
|
{
|
|
group2.AppendExpression(new Literal(text, Parser.IsIgnoreCase(options)));
|
|
text = null;
|
|
}
|
|
group2.AppendExpression(expression);
|
|
expression = null;
|
|
}
|
|
}
|
|
while (!flag || this.ptr < this.pattern.Length);
|
|
goto IL_484;
|
|
IL_1DA:
|
|
flag2 = true;
|
|
goto IL_484;
|
|
IL_230:
|
|
throw this.NewParseException("Too many | in (?()|).");
|
|
IL_25F:
|
|
throw this.NewParseException("Bad quantifier.");
|
|
IL_484:
|
|
if (flag && flag2)
|
|
{
|
|
throw this.NewParseException("Too many )'s.");
|
|
}
|
|
if (!flag && !flag2)
|
|
{
|
|
throw this.NewParseException("Not enough )'s.");
|
|
}
|
|
if (text != null)
|
|
{
|
|
group2.AppendExpression(new Literal(text, Parser.IsIgnoreCase(options)));
|
|
}
|
|
if (assertion != null)
|
|
{
|
|
if (assertion.TrueExpression == null)
|
|
{
|
|
assertion.TrueExpression = group2;
|
|
}
|
|
else
|
|
{
|
|
assertion.FalseExpression = group2;
|
|
}
|
|
group.AppendExpression(assertion);
|
|
}
|
|
else if (alternation != null)
|
|
{
|
|
alternation.AddAlternative(group2);
|
|
group.AppendExpression(alternation);
|
|
}
|
|
else
|
|
{
|
|
group.AppendExpression(group2);
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A6C RID: 6764 RVA: 0x000600F4 File Offset: 0x0005E2F4
|
|
private Expression ParseGroupingConstruct(ref RegexOptions options)
|
|
{
|
|
if (this.pattern[this.ptr] != '?')
|
|
{
|
|
Group group;
|
|
if (Parser.IsExplicitCapture(options))
|
|
{
|
|
group = new Group();
|
|
}
|
|
else
|
|
{
|
|
group = new CapturingGroup();
|
|
this.caps.Add(group);
|
|
}
|
|
this.ParseGroup(group, options, null);
|
|
return group;
|
|
}
|
|
this.ptr++;
|
|
char c = this.pattern[this.ptr];
|
|
switch (c)
|
|
{
|
|
case '!':
|
|
break;
|
|
default:
|
|
{
|
|
switch (c)
|
|
{
|
|
case 'i':
|
|
case 'm':
|
|
case 'n':
|
|
break;
|
|
default:
|
|
switch (c)
|
|
{
|
|
case ':':
|
|
{
|
|
this.ptr++;
|
|
Group group2 = new Group();
|
|
this.ParseGroup(group2, options, null);
|
|
return group2;
|
|
}
|
|
default:
|
|
if (c != '-' && c != 's' && c != 'x')
|
|
{
|
|
throw this.NewParseException("Bad grouping construct.");
|
|
}
|
|
break;
|
|
case '<':
|
|
case '=':
|
|
goto IL_1E5;
|
|
case '>':
|
|
{
|
|
this.ptr++;
|
|
Group group3 = new NonBacktrackingGroup();
|
|
this.ParseGroup(group3, options, null);
|
|
return group3;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
RegexOptions regexOptions = options;
|
|
this.ParseOptions(ref regexOptions, false);
|
|
if (this.pattern[this.ptr] == '-')
|
|
{
|
|
this.ptr++;
|
|
this.ParseOptions(ref regexOptions, true);
|
|
}
|
|
if (this.pattern[this.ptr] == ':')
|
|
{
|
|
this.ptr++;
|
|
Group group4 = new Group();
|
|
this.ParseGroup(group4, regexOptions, null);
|
|
return group4;
|
|
}
|
|
if (this.pattern[this.ptr] == ')')
|
|
{
|
|
this.ptr++;
|
|
options = regexOptions;
|
|
return null;
|
|
}
|
|
throw this.NewParseException("Bad options");
|
|
}
|
|
case '#':
|
|
this.ptr++;
|
|
while (this.pattern[this.ptr++] != ')')
|
|
{
|
|
if (this.ptr >= this.pattern.Length)
|
|
{
|
|
throw this.NewParseException("Unterminated (?#...) comment.");
|
|
}
|
|
}
|
|
return null;
|
|
case '\'':
|
|
goto IL_21C;
|
|
case '(':
|
|
{
|
|
this.ptr++;
|
|
int num = this.ptr;
|
|
string text = this.ParseName();
|
|
Assertion assertion;
|
|
if (text == null || this.pattern[this.ptr] != ')')
|
|
{
|
|
this.ptr = num;
|
|
ExpressionAssertion expressionAssertion = new ExpressionAssertion();
|
|
if (this.pattern[this.ptr] == '?')
|
|
{
|
|
this.ptr++;
|
|
if (!this.ParseAssertionType(expressionAssertion))
|
|
{
|
|
throw this.NewParseException("Bad conditional.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
expressionAssertion.Negate = false;
|
|
expressionAssertion.Reverse = false;
|
|
}
|
|
Group group5 = new Group();
|
|
this.ParseGroup(group5, options, null);
|
|
expressionAssertion.TestExpression = group5;
|
|
assertion = expressionAssertion;
|
|
}
|
|
else
|
|
{
|
|
this.ptr++;
|
|
assertion = new CaptureAssertion(new Literal(text, Parser.IsIgnoreCase(options)));
|
|
this.refs.Add(assertion, text);
|
|
}
|
|
Group group6 = new Group();
|
|
this.ParseGroup(group6, options, assertion);
|
|
return group6;
|
|
}
|
|
}
|
|
IL_1E5:
|
|
ExpressionAssertion expressionAssertion2 = new ExpressionAssertion();
|
|
if (this.ParseAssertionType(expressionAssertion2))
|
|
{
|
|
Group group7 = new Group();
|
|
this.ParseGroup(group7, options, null);
|
|
expressionAssertion2.TestExpression = group7;
|
|
return expressionAssertion2;
|
|
}
|
|
IL_21C:
|
|
char c2;
|
|
if (this.pattern[this.ptr] == '<')
|
|
{
|
|
c2 = '>';
|
|
}
|
|
else
|
|
{
|
|
c2 = '\'';
|
|
}
|
|
this.ptr++;
|
|
string text2 = this.ParseName();
|
|
if (this.pattern[this.ptr] == c2)
|
|
{
|
|
if (text2 == null)
|
|
{
|
|
throw this.NewParseException("Bad group name.");
|
|
}
|
|
this.ptr++;
|
|
CapturingGroup capturingGroup = new CapturingGroup();
|
|
capturingGroup.Name = text2;
|
|
this.caps.Add(capturingGroup);
|
|
this.ParseGroup(capturingGroup, options, null);
|
|
return capturingGroup;
|
|
}
|
|
else
|
|
{
|
|
if (this.pattern[this.ptr] != '-')
|
|
{
|
|
throw this.NewParseException("Bad group name.");
|
|
}
|
|
this.ptr++;
|
|
string text3 = this.ParseName();
|
|
if (text3 == null || this.pattern[this.ptr] != c2)
|
|
{
|
|
throw this.NewParseException("Bad balancing group name.");
|
|
}
|
|
this.ptr++;
|
|
BalancingGroup balancingGroup = new BalancingGroup();
|
|
balancingGroup.Name = text2;
|
|
if (balancingGroup.IsNamed)
|
|
{
|
|
this.caps.Add(balancingGroup);
|
|
}
|
|
this.refs.Add(balancingGroup, text3);
|
|
this.ParseGroup(balancingGroup, options, null);
|
|
return balancingGroup;
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A6D RID: 6765 RVA: 0x000605EC File Offset: 0x0005E7EC
|
|
private bool ParseAssertionType(ExpressionAssertion assertion)
|
|
{
|
|
if (this.pattern[this.ptr] == '<')
|
|
{
|
|
char c = this.pattern[this.ptr + 1];
|
|
if (c != '!')
|
|
{
|
|
if (c != '=')
|
|
{
|
|
return false;
|
|
}
|
|
assertion.Negate = false;
|
|
}
|
|
else
|
|
{
|
|
assertion.Negate = true;
|
|
}
|
|
assertion.Reverse = true;
|
|
this.ptr += 2;
|
|
}
|
|
else
|
|
{
|
|
char c = this.pattern[this.ptr];
|
|
if (c != '!')
|
|
{
|
|
if (c != '=')
|
|
{
|
|
return false;
|
|
}
|
|
assertion.Negate = false;
|
|
}
|
|
else
|
|
{
|
|
assertion.Negate = true;
|
|
}
|
|
assertion.Reverse = false;
|
|
this.ptr++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Token: 0x06001A6E RID: 6766 RVA: 0x000606C8 File Offset: 0x0005E8C8
|
|
private void ParseOptions(ref RegexOptions options, bool negate)
|
|
{
|
|
for (;;)
|
|
{
|
|
char c = this.pattern[this.ptr];
|
|
switch (c)
|
|
{
|
|
case 'i':
|
|
if (negate)
|
|
{
|
|
options &= ~RegexOptions.IgnoreCase;
|
|
}
|
|
else
|
|
{
|
|
options |= RegexOptions.IgnoreCase;
|
|
}
|
|
break;
|
|
default:
|
|
if (c != 's')
|
|
{
|
|
if (c != 'x')
|
|
{
|
|
return;
|
|
}
|
|
if (negate)
|
|
{
|
|
options &= ~RegexOptions.IgnorePatternWhitespace;
|
|
}
|
|
else
|
|
{
|
|
options |= RegexOptions.IgnorePatternWhitespace;
|
|
}
|
|
}
|
|
else if (negate)
|
|
{
|
|
options &= ~RegexOptions.Singleline;
|
|
}
|
|
else
|
|
{
|
|
options |= RegexOptions.Singleline;
|
|
}
|
|
break;
|
|
case 'm':
|
|
if (negate)
|
|
{
|
|
options &= ~RegexOptions.Multiline;
|
|
}
|
|
else
|
|
{
|
|
options |= RegexOptions.Multiline;
|
|
}
|
|
break;
|
|
case 'n':
|
|
if (negate)
|
|
{
|
|
options &= ~RegexOptions.ExplicitCapture;
|
|
}
|
|
else
|
|
{
|
|
options |= RegexOptions.ExplicitCapture;
|
|
}
|
|
break;
|
|
}
|
|
this.ptr++;
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A6F RID: 6767 RVA: 0x000607C8 File Offset: 0x0005E9C8
|
|
private Expression ParseCharacterClass(RegexOptions options)
|
|
{
|
|
bool flag = false;
|
|
if (this.pattern[this.ptr] == '^')
|
|
{
|
|
flag = true;
|
|
this.ptr++;
|
|
}
|
|
bool flag2 = Parser.IsECMAScript(options);
|
|
CharacterClass characterClass = new CharacterClass(flag, Parser.IsIgnoreCase(options));
|
|
if (this.pattern[this.ptr] == ']')
|
|
{
|
|
characterClass.AddCharacter(']');
|
|
this.ptr++;
|
|
}
|
|
int num = -1;
|
|
bool flag3 = false;
|
|
bool flag4 = false;
|
|
while (this.ptr < this.pattern.Length)
|
|
{
|
|
int num2 = (int)this.pattern[this.ptr++];
|
|
if (num2 == 93)
|
|
{
|
|
flag4 = true;
|
|
break;
|
|
}
|
|
if (num2 == 45 && num >= 0 && !flag3)
|
|
{
|
|
flag3 = true;
|
|
}
|
|
else
|
|
{
|
|
if (num2 == 92)
|
|
{
|
|
num2 = this.ParseEscape();
|
|
if (num2 < 0)
|
|
{
|
|
num2 = (int)this.pattern[this.ptr++];
|
|
int num3 = num2;
|
|
switch (num3)
|
|
{
|
|
case 80:
|
|
goto IL_1D1;
|
|
default:
|
|
switch (num3)
|
|
{
|
|
case 112:
|
|
goto IL_1D1;
|
|
default:
|
|
switch (num3)
|
|
{
|
|
case 98:
|
|
num2 = 8;
|
|
goto IL_212;
|
|
default:
|
|
if (num3 != 68)
|
|
{
|
|
if (num3 != 87 && num3 != 119)
|
|
{
|
|
goto IL_212;
|
|
}
|
|
characterClass.AddCategory((!flag2) ? Category.Word : Category.EcmaWord, num2 == 87);
|
|
goto IL_1EC;
|
|
}
|
|
break;
|
|
case 100:
|
|
break;
|
|
}
|
|
characterClass.AddCategory((!flag2) ? Category.Digit : Category.EcmaDigit, num2 == 68);
|
|
break;
|
|
case 115:
|
|
goto IL_1B3;
|
|
}
|
|
break;
|
|
case 83:
|
|
goto IL_1B3;
|
|
}
|
|
IL_1EC:
|
|
if (flag3)
|
|
{
|
|
throw this.NewParseException("character range cannot have category \\" + num2);
|
|
}
|
|
num = -1;
|
|
continue;
|
|
IL_1B3:
|
|
characterClass.AddCategory((!flag2) ? Category.WhiteSpace : Category.EcmaWhiteSpace, num2 == 83);
|
|
goto IL_1EC;
|
|
IL_1D1:
|
|
characterClass.AddCategory(this.ParseUnicodeCategory(), num2 == 80);
|
|
goto IL_1EC;
|
|
}
|
|
}
|
|
IL_212:
|
|
if (flag3)
|
|
{
|
|
if (num2 < num)
|
|
{
|
|
throw this.NewParseException(string.Concat(new object[] { "[", num, "-", num2, "] range in reverse order." }));
|
|
}
|
|
characterClass.AddRange((char)num, (char)num2);
|
|
num = -1;
|
|
flag3 = false;
|
|
}
|
|
else
|
|
{
|
|
characterClass.AddCharacter((char)num2);
|
|
num = num2;
|
|
}
|
|
}
|
|
}
|
|
if (!flag4)
|
|
{
|
|
throw this.NewParseException("Unterminated [] set.");
|
|
}
|
|
if (flag3)
|
|
{
|
|
characterClass.AddCharacter('-');
|
|
}
|
|
return characterClass;
|
|
}
|
|
|
|
// Token: 0x06001A70 RID: 6768 RVA: 0x00060A90 File Offset: 0x0005EC90
|
|
private bool ParseRepetitionBounds(out int min, out int max, RegexOptions options)
|
|
{
|
|
min = (max = 0);
|
|
this.ConsumeWhitespace(Parser.IsIgnorePatternWhitespace(options));
|
|
int num;
|
|
if (this.pattern[this.ptr] == ',')
|
|
{
|
|
num = -1;
|
|
}
|
|
else
|
|
{
|
|
num = this.ParseNumber(10, 1, 0);
|
|
this.ConsumeWhitespace(Parser.IsIgnorePatternWhitespace(options));
|
|
}
|
|
char c = this.pattern[this.ptr++];
|
|
int num2;
|
|
if (c != ',')
|
|
{
|
|
if (c != '}')
|
|
{
|
|
return false;
|
|
}
|
|
num2 = num;
|
|
}
|
|
else
|
|
{
|
|
this.ConsumeWhitespace(Parser.IsIgnorePatternWhitespace(options));
|
|
num2 = this.ParseNumber(10, 1, 0);
|
|
this.ConsumeWhitespace(Parser.IsIgnorePatternWhitespace(options));
|
|
if (this.pattern[this.ptr++] != '}')
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if (num > 2147483647 || num2 > 2147483647)
|
|
{
|
|
throw this.NewParseException("Illegal {x, y} - maximum of 2147483647.");
|
|
}
|
|
if (num2 >= 0 && num2 < num)
|
|
{
|
|
throw this.NewParseException("Illegal {x, y} with x > y.");
|
|
}
|
|
min = num;
|
|
if (num2 > 0)
|
|
{
|
|
max = num2;
|
|
}
|
|
else
|
|
{
|
|
max = int.MaxValue;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Token: 0x06001A71 RID: 6769 RVA: 0x00060BC8 File Offset: 0x0005EDC8
|
|
private Category ParseUnicodeCategory()
|
|
{
|
|
if (this.pattern[this.ptr++] != '{')
|
|
{
|
|
throw this.NewParseException("Incomplete \\p{X} character escape.");
|
|
}
|
|
string text = Parser.ParseName(this.pattern, ref this.ptr);
|
|
if (text == null)
|
|
{
|
|
throw this.NewParseException("Incomplete \\p{X} character escape.");
|
|
}
|
|
Category category = CategoryUtils.CategoryFromName(text);
|
|
if (category == Category.None)
|
|
{
|
|
throw this.NewParseException("Unknown property '" + text + "'.");
|
|
}
|
|
if (this.pattern[this.ptr++] != '}')
|
|
{
|
|
throw this.NewParseException("Incomplete \\p{X} character escape.");
|
|
}
|
|
return category;
|
|
}
|
|
|
|
// Token: 0x06001A72 RID: 6770 RVA: 0x00060C7C File Offset: 0x0005EE7C
|
|
private Expression ParseSpecial(RegexOptions options)
|
|
{
|
|
int num = this.ptr;
|
|
bool flag = Parser.IsECMAScript(options);
|
|
char c = this.pattern[this.ptr++];
|
|
Expression expression;
|
|
switch (c)
|
|
{
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
{
|
|
this.ptr--;
|
|
int num2 = this.ParseNumber(10, 1, 0);
|
|
if (num2 < 0)
|
|
{
|
|
this.ptr = num;
|
|
return null;
|
|
}
|
|
Reference reference = new BackslashNumber(Parser.IsIgnoreCase(options), flag);
|
|
this.refs.Add(reference, num2.ToString());
|
|
expression = reference;
|
|
break;
|
|
}
|
|
default:
|
|
switch (c)
|
|
{
|
|
case 'P':
|
|
expression = new CharacterClass(this.ParseUnicodeCategory(), true);
|
|
break;
|
|
default:
|
|
switch (c)
|
|
{
|
|
case 'W':
|
|
expression = new CharacterClass((!flag) ? Category.Word : Category.EcmaWord, true);
|
|
break;
|
|
default:
|
|
switch (c)
|
|
{
|
|
case 'p':
|
|
expression = new CharacterClass(this.ParseUnicodeCategory(), false);
|
|
break;
|
|
default:
|
|
switch (c)
|
|
{
|
|
case 'w':
|
|
expression = new CharacterClass((!flag) ? Category.Word : Category.EcmaWord, false);
|
|
break;
|
|
default:
|
|
switch (c)
|
|
{
|
|
case 'b':
|
|
expression = new PositionAssertion(Position.Boundary);
|
|
break;
|
|
default:
|
|
if (c != 'k')
|
|
{
|
|
expression = null;
|
|
}
|
|
else
|
|
{
|
|
char c2 = this.pattern[this.ptr++];
|
|
if (c2 == '<')
|
|
{
|
|
c2 = '>';
|
|
}
|
|
else if (c2 != '\'')
|
|
{
|
|
throw this.NewParseException("Malformed \\k<...> named backreference.");
|
|
}
|
|
string text = this.ParseName();
|
|
if (text == null || this.pattern[this.ptr] != c2)
|
|
{
|
|
throw this.NewParseException("Malformed \\k<...> named backreference.");
|
|
}
|
|
this.ptr++;
|
|
Reference reference2 = new Reference(Parser.IsIgnoreCase(options));
|
|
this.refs.Add(reference2, text);
|
|
expression = reference2;
|
|
}
|
|
break;
|
|
case 'd':
|
|
expression = new CharacterClass((!flag) ? Category.Digit : Category.EcmaDigit, false);
|
|
break;
|
|
}
|
|
break;
|
|
case 'z':
|
|
expression = new PositionAssertion(Position.EndOfString);
|
|
break;
|
|
}
|
|
break;
|
|
case 's':
|
|
expression = new CharacterClass((!flag) ? Category.WhiteSpace : Category.EcmaWhiteSpace, false);
|
|
break;
|
|
}
|
|
break;
|
|
case 'Z':
|
|
expression = new PositionAssertion(Position.End);
|
|
break;
|
|
}
|
|
break;
|
|
case 'S':
|
|
expression = new CharacterClass((!flag) ? Category.WhiteSpace : Category.EcmaWhiteSpace, true);
|
|
break;
|
|
}
|
|
break;
|
|
case 'A':
|
|
expression = new PositionAssertion(Position.StartOfString);
|
|
break;
|
|
case 'B':
|
|
expression = new PositionAssertion(Position.NonBoundary);
|
|
break;
|
|
case 'D':
|
|
expression = new CharacterClass((!flag) ? Category.Digit : Category.EcmaDigit, true);
|
|
break;
|
|
case 'G':
|
|
expression = new PositionAssertion(Position.StartOfScan);
|
|
break;
|
|
}
|
|
if (expression == null)
|
|
{
|
|
this.ptr = num;
|
|
}
|
|
return expression;
|
|
}
|
|
|
|
// Token: 0x06001A73 RID: 6771 RVA: 0x00060FC8 File Offset: 0x0005F1C8
|
|
private int ParseEscape()
|
|
{
|
|
int num = this.ptr;
|
|
if (num >= this.pattern.Length)
|
|
{
|
|
throw new ArgumentException(string.Format("Parsing \"{0}\" - Illegal \\ at end of pattern.", this.pattern), this.pattern);
|
|
}
|
|
char c = this.pattern[this.ptr++];
|
|
switch (c)
|
|
{
|
|
case 'n':
|
|
return 10;
|
|
default:
|
|
switch (c)
|
|
{
|
|
case 'a':
|
|
return 7;
|
|
default:
|
|
if (c != '0')
|
|
{
|
|
if (c != '\\')
|
|
{
|
|
this.ptr = num;
|
|
return -1;
|
|
}
|
|
return 92;
|
|
}
|
|
else
|
|
{
|
|
this.ptr--;
|
|
int num2 = this.ptr;
|
|
int num3 = Parser.ParseOctal(this.pattern, ref this.ptr);
|
|
if (num3 == -1 && num2 == this.ptr)
|
|
{
|
|
return 0;
|
|
}
|
|
return num3;
|
|
}
|
|
break;
|
|
case 'c':
|
|
{
|
|
int num4 = (int)this.pattern[this.ptr++];
|
|
if (num4 >= 64 && num4 <= 95)
|
|
{
|
|
return num4 - 64;
|
|
}
|
|
throw this.NewParseException("Unrecognized control character.");
|
|
}
|
|
case 'e':
|
|
return 27;
|
|
case 'f':
|
|
return 12;
|
|
}
|
|
break;
|
|
case 'r':
|
|
return 13;
|
|
case 't':
|
|
return 9;
|
|
case 'u':
|
|
{
|
|
int num4 = Parser.ParseHex(this.pattern, ref this.ptr, 4);
|
|
if (num4 < 0)
|
|
{
|
|
throw this.NewParseException("Insufficient hex digits");
|
|
}
|
|
return num4;
|
|
}
|
|
case 'v':
|
|
return 11;
|
|
case 'x':
|
|
{
|
|
int num4 = Parser.ParseHex(this.pattern, ref this.ptr, 2);
|
|
if (num4 < 0)
|
|
{
|
|
throw this.NewParseException("Insufficient hex digits");
|
|
}
|
|
return num4;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A74 RID: 6772 RVA: 0x00061188 File Offset: 0x0005F388
|
|
private string ParseName()
|
|
{
|
|
return Parser.ParseName(this.pattern, ref this.ptr);
|
|
}
|
|
|
|
// Token: 0x06001A75 RID: 6773 RVA: 0x0006119C File Offset: 0x0005F39C
|
|
private static bool IsNameChar(char c)
|
|
{
|
|
UnicodeCategory unicodeCategory = char.GetUnicodeCategory(c);
|
|
return unicodeCategory != UnicodeCategory.ModifierLetter && (unicodeCategory == UnicodeCategory.ConnectorPunctuation || char.IsLetterOrDigit(c));
|
|
}
|
|
|
|
// Token: 0x06001A76 RID: 6774 RVA: 0x000611CC File Offset: 0x0005F3CC
|
|
private int ParseNumber(int b, int min, int max)
|
|
{
|
|
return Parser.ParseNumber(this.pattern, ref this.ptr, b, min, max);
|
|
}
|
|
|
|
// Token: 0x06001A77 RID: 6775 RVA: 0x000611E4 File Offset: 0x0005F3E4
|
|
private static int ParseDigit(char c, int b, int n)
|
|
{
|
|
switch (b)
|
|
{
|
|
case 8:
|
|
if (c >= '0' && c <= '7')
|
|
{
|
|
return (int)(c - '0');
|
|
}
|
|
return -1;
|
|
default:
|
|
if (b != 16)
|
|
{
|
|
return -1;
|
|
}
|
|
if (c >= '0' && c <= '9')
|
|
{
|
|
return (int)(c - '0');
|
|
}
|
|
if (c >= 'a' && c <= 'f')
|
|
{
|
|
return (int)('\n' + c - 'a');
|
|
}
|
|
if (c >= 'A' && c <= 'F')
|
|
{
|
|
return (int)('\n' + c - 'A');
|
|
}
|
|
return -1;
|
|
case 10:
|
|
if (c >= '0' && c <= '9')
|
|
{
|
|
return (int)(c - '0');
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A78 RID: 6776 RVA: 0x0006128C File Offset: 0x0005F48C
|
|
private void ConsumeWhitespace(bool ignore)
|
|
{
|
|
while (this.ptr < this.pattern.Length)
|
|
{
|
|
if (this.pattern[this.ptr] == '(')
|
|
{
|
|
if (this.ptr + 3 >= this.pattern.Length)
|
|
{
|
|
return;
|
|
}
|
|
if (this.pattern[this.ptr + 1] != '?' || this.pattern[this.ptr + 2] != '#')
|
|
{
|
|
return;
|
|
}
|
|
this.ptr += 3;
|
|
while (this.ptr < this.pattern.Length && this.pattern[this.ptr++] != ')')
|
|
{
|
|
}
|
|
}
|
|
else if (ignore && this.pattern[this.ptr] == '#')
|
|
{
|
|
while (this.ptr < this.pattern.Length && this.pattern[this.ptr++] != '\n')
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ignore || !char.IsWhiteSpace(this.pattern[this.ptr]))
|
|
{
|
|
return;
|
|
}
|
|
while (this.ptr < this.pattern.Length && char.IsWhiteSpace(this.pattern[this.ptr]))
|
|
{
|
|
this.ptr++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A79 RID: 6777 RVA: 0x00061438 File Offset: 0x0005F638
|
|
private string ParseString(string pattern)
|
|
{
|
|
this.pattern = pattern;
|
|
this.ptr = 0;
|
|
StringBuilder stringBuilder = new StringBuilder(pattern.Length);
|
|
while (this.ptr < pattern.Length)
|
|
{
|
|
int num = (int)pattern[this.ptr++];
|
|
if (num == 92)
|
|
{
|
|
num = this.ParseEscape();
|
|
if (num < 0)
|
|
{
|
|
num = (int)pattern[this.ptr++];
|
|
if (num == 98)
|
|
{
|
|
num = 8;
|
|
}
|
|
}
|
|
}
|
|
stringBuilder.Append((char)num);
|
|
}
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
// Token: 0x06001A7A RID: 6778 RVA: 0x000614D4 File Offset: 0x0005F6D4
|
|
private void ResolveReferences()
|
|
{
|
|
int num = 1;
|
|
Hashtable hashtable = new Hashtable();
|
|
ArrayList arrayList = null;
|
|
foreach (object obj in this.caps)
|
|
{
|
|
CapturingGroup capturingGroup = (CapturingGroup)obj;
|
|
if (capturingGroup.Name == null)
|
|
{
|
|
hashtable.Add(num.ToString(), capturingGroup);
|
|
capturingGroup.Index = num++;
|
|
this.num_groups++;
|
|
}
|
|
}
|
|
foreach (object obj2 in this.caps)
|
|
{
|
|
CapturingGroup capturingGroup2 = (CapturingGroup)obj2;
|
|
if (capturingGroup2.Name != null)
|
|
{
|
|
if (hashtable.Contains(capturingGroup2.Name))
|
|
{
|
|
CapturingGroup capturingGroup3 = (CapturingGroup)hashtable[capturingGroup2.Name];
|
|
capturingGroup2.Index = capturingGroup3.Index;
|
|
if (capturingGroup2.Index == num)
|
|
{
|
|
num++;
|
|
}
|
|
else if (capturingGroup2.Index > num)
|
|
{
|
|
arrayList.Add(capturingGroup2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (char.IsDigit(capturingGroup2.Name[0]))
|
|
{
|
|
int num2 = 0;
|
|
int num3 = Parser.ParseDecimal(capturingGroup2.Name, ref num2);
|
|
if (num2 == capturingGroup2.Name.Length)
|
|
{
|
|
capturingGroup2.Index = num3;
|
|
hashtable.Add(capturingGroup2.Name, capturingGroup2);
|
|
this.num_groups++;
|
|
if (num3 == num)
|
|
{
|
|
num++;
|
|
}
|
|
else
|
|
{
|
|
if (arrayList == null)
|
|
{
|
|
arrayList = new ArrayList(4);
|
|
}
|
|
arrayList.Add(capturingGroup2);
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
string text = num.ToString();
|
|
while (hashtable.Contains(text))
|
|
{
|
|
int num4;
|
|
num = (num4 = num + 1);
|
|
text = num4.ToString();
|
|
}
|
|
hashtable.Add(text, capturingGroup2);
|
|
hashtable.Add(capturingGroup2.Name, capturingGroup2);
|
|
capturingGroup2.Index = num++;
|
|
this.num_groups++;
|
|
}
|
|
}
|
|
}
|
|
this.gap = num;
|
|
if (arrayList != null)
|
|
{
|
|
this.HandleExplicitNumericGroups(arrayList);
|
|
}
|
|
foreach (object obj3 in this.refs.Keys)
|
|
{
|
|
Expression expression = (Expression)obj3;
|
|
string text2 = (string)this.refs[expression];
|
|
if (!hashtable.Contains(text2))
|
|
{
|
|
if (!(expression is CaptureAssertion) || char.IsDigit(text2[0]))
|
|
{
|
|
BackslashNumber backslashNumber = expression as BackslashNumber;
|
|
if (backslashNumber == null || !backslashNumber.ResolveReference(text2, hashtable))
|
|
{
|
|
throw this.NewParseException("Reference to undefined group " + ((!char.IsDigit(text2[0])) ? "name " : "number ") + text2);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CapturingGroup capturingGroup4 = (CapturingGroup)hashtable[text2];
|
|
if (expression is Reference)
|
|
{
|
|
((Reference)expression).CapturingGroup = capturingGroup4;
|
|
}
|
|
else if (expression is CaptureAssertion)
|
|
{
|
|
((CaptureAssertion)expression).CapturingGroup = capturingGroup4;
|
|
}
|
|
else if (expression is BalancingGroup)
|
|
{
|
|
((BalancingGroup)expression).Balance = capturingGroup4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A7B RID: 6779 RVA: 0x000618C4 File Offset: 0x0005FAC4
|
|
private void HandleExplicitNumericGroups(ArrayList explicit_numeric_groups)
|
|
{
|
|
int num = this.gap;
|
|
int i = 0;
|
|
int count = explicit_numeric_groups.Count;
|
|
explicit_numeric_groups.Sort();
|
|
while (i < count)
|
|
{
|
|
CapturingGroup capturingGroup = (CapturingGroup)explicit_numeric_groups[i];
|
|
if (capturingGroup.Index > num)
|
|
{
|
|
break;
|
|
}
|
|
if (capturingGroup.Index == num)
|
|
{
|
|
num++;
|
|
}
|
|
i++;
|
|
}
|
|
this.gap = num;
|
|
int num2 = num;
|
|
while (i < count)
|
|
{
|
|
CapturingGroup capturingGroup2 = (CapturingGroup)explicit_numeric_groups[i];
|
|
if (capturingGroup2.Index == num2)
|
|
{
|
|
capturingGroup2.Index = num - 1;
|
|
}
|
|
else
|
|
{
|
|
num2 = capturingGroup2.Index;
|
|
capturingGroup2.Index = num++;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// Token: 0x06001A7C RID: 6780 RVA: 0x00061980 File Offset: 0x0005FB80
|
|
private static bool IsIgnoreCase(RegexOptions options)
|
|
{
|
|
return (options & RegexOptions.IgnoreCase) != RegexOptions.None;
|
|
}
|
|
|
|
// Token: 0x06001A7D RID: 6781 RVA: 0x0006198C File Offset: 0x0005FB8C
|
|
private static bool IsMultiline(RegexOptions options)
|
|
{
|
|
return (options & RegexOptions.Multiline) != RegexOptions.None;
|
|
}
|
|
|
|
// Token: 0x06001A7E RID: 6782 RVA: 0x00061998 File Offset: 0x0005FB98
|
|
private static bool IsExplicitCapture(RegexOptions options)
|
|
{
|
|
return (options & RegexOptions.ExplicitCapture) != RegexOptions.None;
|
|
}
|
|
|
|
// Token: 0x06001A7F RID: 6783 RVA: 0x000619A4 File Offset: 0x0005FBA4
|
|
private static bool IsSingleline(RegexOptions options)
|
|
{
|
|
return (options & RegexOptions.Singleline) != RegexOptions.None;
|
|
}
|
|
|
|
// Token: 0x06001A80 RID: 6784 RVA: 0x000619B0 File Offset: 0x0005FBB0
|
|
private static bool IsIgnorePatternWhitespace(RegexOptions options)
|
|
{
|
|
return (options & RegexOptions.IgnorePatternWhitespace) != RegexOptions.None;
|
|
}
|
|
|
|
// Token: 0x06001A81 RID: 6785 RVA: 0x000619BC File Offset: 0x0005FBBC
|
|
private static bool IsECMAScript(RegexOptions options)
|
|
{
|
|
return (options & RegexOptions.ECMAScript) != RegexOptions.None;
|
|
}
|
|
|
|
// Token: 0x06001A82 RID: 6786 RVA: 0x000619CC File Offset: 0x0005FBCC
|
|
private ArgumentException NewParseException(string msg)
|
|
{
|
|
msg = "parsing \"" + this.pattern + "\" - " + msg;
|
|
return new ArgumentException(msg, this.pattern);
|
|
}
|
|
|
|
// Token: 0x0400159F RID: 5535
|
|
private string pattern;
|
|
|
|
// Token: 0x040015A0 RID: 5536
|
|
private int ptr;
|
|
|
|
// Token: 0x040015A1 RID: 5537
|
|
private ArrayList caps;
|
|
|
|
// Token: 0x040015A2 RID: 5538
|
|
private Hashtable refs;
|
|
|
|
// Token: 0x040015A3 RID: 5539
|
|
private int num_groups;
|
|
|
|
// Token: 0x040015A4 RID: 5540
|
|
private int gap;
|
|
}
|
|
}
|