private static bool ClassMatcher(REGlobalData gData, RECharSet charSet, char ch) { if (!charSet.converted) { ProcessCharSet(gData, charSet); } int byteIndex = ch >> 3; return (charSet.length == 0 || ch >= charSet.length || (charSet.bits[byteIndex] & (1 << (ch & unchecked((int)(0x7))))) == 0) ^ charSet.sense; }
private static void ProcessCharSetImpl(REGlobalData gData, RECharSet charSet) { int src = charSet.startIndex; int end = src + charSet.strlength; char rangeStart = 0; char thisCh; int byteLength; char c; int n; int nDigits; int i; bool inRange = false; byteLength = (charSet.length + 7) / 8; charSet.bits = new byte[byteLength]; if (src == end) { return; } if (gData.regexp.source[src] == '^') { System.Diagnostics.Debug.Assert((!charSet.sense)); ++src; } else { System.Diagnostics.Debug.Assert((charSet.sense)); } while (src != end) { nDigits = 2; switch (gData.regexp.source[src]) { case '\\': { ++src; c = gData.regexp.source[src++]; switch (c) { case 'b': { thisCh = (char)unchecked((int)(0x8)); break; } case 'f': { thisCh = (char)unchecked((int)(0xC)); break; } case 'n': { thisCh = (char)unchecked((int)(0xA)); break; } case 'r': { thisCh = (char)unchecked((int)(0xD)); break; } case 't': { thisCh = (char)unchecked((int)(0x9)); break; } case 'v': { thisCh = (char)unchecked((int)(0xB)); break; } case 'c': { if ((src < end) && IsControlLetter(gData.regexp.source[src])) { thisCh = (char)(gData.regexp.source[src++] & unchecked((int)(0x1F))); } else { --src; thisCh = '\\'; } break; } case 'u': { nDigits += 2; goto case 'x'; } case 'x': { // fall thru n = 0; for (i = 0; (i < nDigits) && (src < end); i++) { c = gData.regexp.source[src++]; int digit = ToASCIIHexDigit(c); if (digit < 0) { src -= (i + 1); n = '\\'; break; } n = (n << 4) | digit; } thisCh = (char)(n); break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { n = (c - '0'); c = gData.regexp.source[src]; if ('0' <= c && c <= '7') { src++; n = 8 * n + (c - '0'); c = gData.regexp.source[src]; if ('0' <= c && c <= '7') { src++; i = 8 * n + (c - '0'); if (i <= 0xff) { n = i; } else { src--; } } } thisCh = (char)(n); break; } case 'd': { AddCharacterRangeToCharSet(charSet, '0', '9'); continue; } case 'D': { AddCharacterRangeToCharSet(charSet, (char)0, (char)('0' - 1)); AddCharacterRangeToCharSet(charSet, (char)('9' + 1), (char)(charSet.length - 1)); continue; } case 's': { for (i = (charSet.length - 1); i >= 0; i--) { if (IsREWhiteSpace(i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } case 'S': { for (i = (charSet.length - 1); i >= 0; i--) { if (!IsREWhiteSpace(i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } case 'w': { for (i = (charSet.length - 1); i >= 0; i--) { if (IsWord((char)i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } case 'W': { for (i = (charSet.length - 1); i >= 0; i--) { if (!IsWord((char)i)) { AddCharacterToCharSet(charSet, (char)(i)); } } continue; } default: { thisCh = c; break; } } break; } default: { thisCh = gData.regexp.source[src++]; break; } } if (inRange) { if ((gData.regexp.flags & JSREG_FOLD) != 0) { System.Diagnostics.Debug.Assert((rangeStart <= thisCh)); for (c = rangeStart; c <= thisCh; ) { AddCharacterToCharSet(charSet, c); char uch = Upcase(c); char dch = Downcase(c); if (c != uch) { AddCharacterToCharSet(charSet, uch); } if (c != dch) { AddCharacterToCharSet(charSet, dch); } if (++c == 0) { break; } } } else { // overflow AddCharacterRangeToCharSet(charSet, rangeStart, thisCh); } inRange = false; } else { if ((gData.regexp.flags & JSREG_FOLD) != 0) { AddCharacterToCharSet(charSet, Upcase(thisCh)); AddCharacterToCharSet(charSet, Downcase(thisCh)); } else { AddCharacterToCharSet(charSet, thisCh); } if (src < (end - 1)) { if (gData.regexp.source[src] == '-') { ++src; inRange = true; rangeStart = thisCh; } } } } }
private static void AddCharacterRangeToCharSet(RECharSet cs, char c1, char c2) { int i; int byteIndex1 = (c1 / 8); int byteIndex2 = (c2 / 8); if ((c2 >= cs.length) || (c1 > c2)) { throw ScriptRuntime.ConstructError("SyntaxError", "invalid range in character class"); } c1 &= (char)unchecked((int)(0x7)); c2 &= (char)unchecked((int)(0x7)); if (byteIndex1 == byteIndex2) { cs.bits[byteIndex1] |= ((unchecked((int)(0xFF))) >> (7 - (c2 - c1))) << c1; } else { cs.bits[byteIndex1] |= unchecked((int)(0xFF)) << c1; for (i = byteIndex1 + 1; i < byteIndex2; i++) { cs.bits[i] = unchecked((byte)unchecked((int)(0xFF))); } cs.bits[byteIndex2] |= (unchecked((int)(0xFF))) >> (7 - c2); } }
private static void ProcessCharSet(REGlobalData gData, RECharSet charSet) { lock (charSet) { if (!charSet.converted) { ProcessCharSetImpl(gData, charSet); charSet.converted = true; } } }
private static void AddCharacterToCharSet(RECharSet cs, char c) { int byteIndex = (c / 8); if (c >= cs.length) { throw ScriptRuntime.ConstructError("SyntaxError", "invalid range in character class"); } cs.bits[byteIndex] |= 1 << (c & unchecked((int)(0x7))); }