//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
// Don't entity encode high chars (160 to 256), to fix bugs VSWhidbey 85857/111927
//
#define ENTITY_ENCODE_HIGH_ASCII_CHARS
namespace System.Net {
using System;
using System.Collections.Generic;
#if !FEATURE_NETCORE
using System.Configuration;
#endif
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Net.Configuration;
using System.Runtime.Versioning;
using System.Text;
#if FEATURE_NETCORE
using System.Security;
#endif
public static class WebUtility
{
// some consts copied from Char / CharUnicodeInfo since we don't have friend access to those types
private const char HIGH_SURROGATE_START = '\uD800';
private const char LOW_SURROGATE_START = '\uDC00';
private const char LOW_SURROGATE_END = '\uDFFF';
private const int UNICODE_PLANE00_END = 0x00FFFF;
private const int UNICODE_PLANE01_START = 0x10000;
private const int UNICODE_PLANE16_END = 0x10FFFF;
private const int UnicodeReplacementChar = '\uFFFD';
private static readonly char[] _htmlEntityEndingChars = new char[] { ';', '&' };
private static volatile UnicodeDecodingConformance _htmlDecodeConformance = UnicodeDecodingConformance.Auto;
private static volatile UnicodeEncodingConformance _htmlEncodeConformance = UnicodeEncodingConformance.Auto;
#region HtmlEncode / HtmlDecode methods
public static string HtmlEncode(string value) {
if (String.IsNullOrEmpty(value)) {
return value;
}
// Don't create string writer if we don't have nothing to encode
int index = IndexOfHtmlEncodingChars(value, 0);
if (index == -1) {
return value;
}
StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
HtmlEncode(value, writer);
return writer.ToString();
}
#if FEATURE_NETCORE
[SecuritySafeCritical]
#endif
public static unsafe void HtmlEncode(string value, TextWriter output) {
if (value == null) {
return;
}
if (output == null) {
throw new ArgumentNullException("output");
}
int index = IndexOfHtmlEncodingChars(value, 0);
if (index == -1) {
output.Write(value);
return;
}
Debug.Assert(0 <= index && index <= value.Length, "0 <= index && index <= value.Length");
UnicodeEncodingConformance encodeConformance = HtmlEncodeConformance;
int cch = value.Length - index;
fixed (char* str = value) {
char* pch = str;
while (index-- > 0) {
output.Write(*pch++);
}
for (; cch > 0; cch--, pch++) {
char ch = *pch;
if (ch <= '>') {
switch (ch) {
case '<':
output.Write("<");
break;
case '>':
output.Write(">");
break;
case '"':
output.Write(""");
break;
case '\'':
output.Write("'");
break;
case '&':
output.Write("&");
break;
default:
output.Write(ch);
break;
}
}
else {
int valueToEncode = -1; // set to >= 0 if needs to be encoded
#if ENTITY_ENCODE_HIGH_ASCII_CHARS
#if MONO
// MS starts encoding with from 160 and stops at 255.
// We don't do that. One reason is the 65308/65310 unicode
// characters that look like '<' and '>'.
if (ch >= 160 && !char.IsSurrogate (ch)) {
valueToEncode = ch;
#else
if (ch >= 160 && ch < 256) {
// The seemingly arbitrary 160 comes from RFC
valueToEncode = ch;
#endif
} else
#endif // ENTITY_ENCODE_HIGH_ASCII_CHARS
if (encodeConformance == UnicodeEncodingConformance.Strict && Char.IsSurrogate(ch)) {
int scalarValue = GetNextUnicodeScalarValueFromUtf16Surrogate(ref pch, ref cch);
if (scalarValue >= UNICODE_PLANE01_START) {
valueToEncode = scalarValue;
}
else {
// Don't encode BMP characters (like U+FFFD) since they wouldn't have
// been encoded if explicitly present in the string anyway.
ch = (char)scalarValue;
}
}
if (valueToEncode >= 0) {
// value needs to be encoded
output.Write("");
output.Write(valueToEncode.ToString(NumberFormatInfo.InvariantInfo));
output.Write(';');
}
else {
// write out the character directly
output.Write(ch);
}
}
}
}
}
public static string HtmlDecode(string value) {
if (String.IsNullOrEmpty(value)) {
return value;
}
// Don't create string writer if we don't have nothing to encode
if (!StringRequiresHtmlDecoding(value)) {
return value;
}
StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
HtmlDecode(value, writer);
return writer.ToString();
}
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.UInt16.TryParse(System.String,System.Globalization.NumberStyles,System.IFormatProvider,System.UInt16@)", Justification="UInt16.TryParse guarantees that result is zero if the parse fails.")]
public static void HtmlDecode(string value, TextWriter output) {
if (value == null) {
return;
}
if (output == null) {
throw new ArgumentNullException("output");
}
if (!StringRequiresHtmlDecoding(value)) {
output.Write(value); // good as is
return;
}
UnicodeDecodingConformance decodeConformance = HtmlDecodeConformance;
int l = value.Length;
for (int i = 0; i < l; i++) {
char ch = value[i];
if (ch == '&') {
// We found a '&'. Now look for the next ';' or '&'. The idea is that
// if we find another '&' before finding a ';', then this is not an entity,
// and the next '&' might start a real entity (VSWhidbey 275184)
int index = value.IndexOfAny(_htmlEntityEndingChars, i + 1);
if (index > 0 && value[index] == ';') {
string entity = value.Substring(i + 1, index - i - 1);
if (entity.Length > 1 && entity[0] == '#') {
// The # syntax can be in decimal or hex, e.g.
// å --> decimal
// å --> same char in hex
// See http://www.w3.org/TR/REC-html40/charset.html#entities
bool parsedSuccessfully;
uint parsedValue;
if (entity[1] == 'x' || entity[1] == 'X') {
parsedSuccessfully = UInt32.TryParse(entity.Substring(2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out parsedValue);
}
else {
parsedSuccessfully = UInt32.TryParse(entity.Substring(1), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out parsedValue);
}
if (parsedSuccessfully) {
switch (decodeConformance) {
case UnicodeDecodingConformance.Strict:
// decoded character must be U+0000 .. U+10FFFF, excluding surrogates
parsedSuccessfully = ((parsedValue < HIGH_SURROGATE_START) || (LOW_SURROGATE_END < parsedValue && parsedValue <= UNICODE_PLANE16_END));
break;
case UnicodeDecodingConformance.Compat:
// decoded character must be U+0001 .. U+FFFF
// null chars disallowed for compat with 4.0
parsedSuccessfully = (0 < parsedValue && parsedValue <= UNICODE_PLANE00_END);
break;
case UnicodeDecodingConformance.Loose:
// decoded character must be U+0000 .. U+10FFFF
parsedSuccessfully = (parsedValue <= UNICODE_PLANE16_END);
break;
default:
Debug.Assert(false, "Should never get here!");
parsedSuccessfully = false;
break;
}
}
if (parsedSuccessfully) {
if (parsedValue <= UNICODE_PLANE00_END) {
// single character
output.Write((char)parsedValue);
}
else {
// multi-character
char leadingSurrogate, trailingSurrogate;
ConvertSmpToUtf16(parsedValue, out leadingSurrogate, out trailingSurrogate);
output.Write(leadingSurrogate);
output.Write(trailingSurrogate);
}
i = index; // already looked at everything until semicolon
continue;
}
}
else {
i = index; // already looked at everything until semicolon
char entityChar = HtmlEntities.Lookup(entity);
if (entityChar != (char)0) {
ch = entityChar;
}
else {
output.Write('&');
output.Write(entity);
output.Write(';');
continue;
}
}
}
}
output.Write(ch);
}
}
#if FEATURE_NETCORE
[SecuritySafeCritical]
#endif
private static unsafe int IndexOfHtmlEncodingChars(string s, int startPos) {
Debug.Assert(0 <= startPos && startPos <= s.Length, "0 <= startPos && startPos <= s.Length");
UnicodeEncodingConformance encodeConformance = HtmlEncodeConformance;
int cch = s.Length - startPos;
fixed (char* str = s) {
for (char* pch = &str[startPos]; cch > 0; pch++, cch--) {
char ch = *pch;
if (ch <= '>') {
switch (ch) {
case '<':
case '>':
case '"':
case '\'':
case '&':
return s.Length - cch;
}
}
#if ENTITY_ENCODE_HIGH_ASCII_CHARS
else if (ch >= 160
#if !MONO
&& ch < 256
#endif
) {
return s.Length - cch;
}
#endif // ENTITY_ENCODE_HIGH_ASCII_CHARS
else if (encodeConformance == UnicodeEncodingConformance.Strict && Char.IsSurrogate(ch)) {
return s.Length - cch;
}
}
}
return -1;
}
private static UnicodeDecodingConformance HtmlDecodeConformance {
get {
if (_htmlDecodeConformance != UnicodeDecodingConformance.Auto) {
return _htmlDecodeConformance;
}
UnicodeDecodingConformance defaultDecodeConformance = (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) ? UnicodeDecodingConformance.Strict : UnicodeDecodingConformance.Compat;
UnicodeDecodingConformance decodingConformance = defaultDecodeConformance;
#if !FEATURE_NETCORE && !MOBILE
try {
// Read from config
decodingConformance = SettingsSectionInternal.Section.WebUtilityUnicodeDecodingConformance;
// Normalize conformance settings (turn 'Auto' into the actual setting)
if (decodingConformance <= UnicodeDecodingConformance.Auto || decodingConformance > UnicodeDecodingConformance.Loose) {
decodingConformance = defaultDecodeConformance;
}
}
catch (ConfigurationException) {
// Continue with default values
// HtmlDecode and related methods can still be called and format the error page intended for the client
// No need to retry again to initialize from the config in case of config errors
decodingConformance = defaultDecodeConformance;
}
catch {
// DevDiv: 642025
// ASP.NET uses own ConfigurationManager which can throw in more situations than config errors (i.e. BadRequest)
// It's ok to ---- the exception here and continue using the default value
// Try to initialize again the next time
return defaultDecodeConformance;
}
#endif
_htmlDecodeConformance = decodingConformance;
return _htmlDecodeConformance;
}
}
private static UnicodeEncodingConformance HtmlEncodeConformance {
get {
if (_htmlEncodeConformance != UnicodeEncodingConformance.Auto) {
return _htmlEncodeConformance;
}
UnicodeEncodingConformance defaultEncodeConformance = (BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) ? UnicodeEncodingConformance.Strict : UnicodeEncodingConformance.Compat;
UnicodeEncodingConformance encodingConformance = defaultEncodeConformance;
#if !FEATURE_NETCORE && !MOBILE
try {
// Read from config
encodingConformance = SettingsSectionInternal.Section.WebUtilityUnicodeEncodingConformance;
// Normalize conformance settings (turn 'Auto' into the actual setting)
if (encodingConformance <= UnicodeEncodingConformance.Auto || encodingConformance > UnicodeEncodingConformance.Compat) {
encodingConformance = defaultEncodeConformance;
}
}
catch (ConfigurationException) {
// Continue with default values
// HtmlEncode and related methods can still be called and format the error page intended for the client
// No need to retry again to initialize from the config in case of config errors
encodingConformance = defaultEncodeConformance;
}
catch {
// DevDiv: 642025
// ASP.NET uses own ConfigurationManager which can throw in more situations than config errors (i.e. BadRequest)
// It's ok to ---- the exception here and continue using the default value
// Try to initialize again the next time
return defaultEncodeConformance;
}
#endif
_htmlEncodeConformance = encodingConformance;
return _htmlEncodeConformance;
}
}
#endregion
#region UrlEncode implementation
// *** Source: alm/tfs_core/Framework/Common/UriUtility/HttpUtility.cs
// This specific code was copied from above ASP.NET codebase.
private static byte[] UrlEncode(byte[] bytes, int offset, int count, bool alwaysCreateNewReturnValue)
{
byte[] encoded = UrlEncode(bytes, offset, count);
return (alwaysCreateNewReturnValue && (encoded != null) && (encoded == bytes))
? (byte[])encoded.Clone()
: encoded;
}
private static byte[] UrlEncode(byte[] bytes, int offset, int count)
{
if (!ValidateUrlEncodingParameters(bytes, offset, count))
{
return null;
}
int cSpaces = 0;
int cUnsafe = 0;
// count them first
for (int i = 0; i < count; i++)
{
char ch = (char)bytes[offset + i];
if (ch == ' ')
cSpaces++;
else if (!IsUrlSafeChar(ch))
cUnsafe++;
}
// nothing to expand?
if (cSpaces == 0 && cUnsafe == 0) {
// DevDiv 912606: respect "offset" and "count"
if (0 == offset && bytes.Length == count) {
return bytes;
}
else {
var subarray = new byte[count];
Buffer.BlockCopy(bytes, offset, subarray, 0, count);
return subarray;
}
}
// expand not 'safe' characters into %XX, spaces to +s
byte[] expandedBytes = new byte[count + cUnsafe * 2];
int pos = 0;
for (int i = 0; i < count; i++)
{
byte b = bytes[offset + i];
char ch = (char)b;
if (IsUrlSafeChar(ch))
{
expandedBytes[pos++] = b;
}
else if (ch == ' ')
{
expandedBytes[pos++] = (byte)'+';
}
else
{
expandedBytes[pos++] = (byte)'%';
expandedBytes[pos++] = (byte)IntToHex((b >> 4) & 0xf);
expandedBytes[pos++] = (byte)IntToHex(b & 0x0f);
}
}
return expandedBytes;
}
#endregion
#region UrlEncode public methods
[SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification="Already shipped public API; code moved here as part of API consolidation")]
public static string UrlEncode(string value)
{
if (value == null)
return null;
byte[] bytes = Encoding.UTF8.GetBytes(value);
return Encoding.UTF8.GetString(UrlEncode(bytes, 0, bytes.Length, false /* alwaysCreateNewReturnValue */));
}
public static byte[] UrlEncodeToBytes(byte[] value, int offset, int count)
{
return UrlEncode(value, offset, count, true /* alwaysCreateNewReturnValue */);
}
#endregion
#region UrlDecode implementation
// *** Source: alm/tfs_core/Framework/Common/UriUtility/HttpUtility.cs
// This specific code was copied from above ASP.NET codebase.
// Changes done - Removed the logic to handle %Uxxxx as it is not standards compliant.
private static string UrlDecodeInternal(string value, Encoding encoding)
{
if (value == null)
{
return null;
}
int count = value.Length;
UrlDecoder helper = new UrlDecoder(count, encoding);
// go through the string's chars collapsing %XX and
// appending each char as char, with exception of %XX constructs
// that are appended as bytes
for (int pos = 0; pos < count; pos++)
{
char ch = value[pos];
if (ch == '+')
{
ch = ' ';
}
else if (ch == '%' && pos < count - 2)
{
int h1 = HexToInt(value[pos + 1]);
int h2 = HexToInt(value[pos + 2]);
if (h1 >= 0 && h2 >= 0)
{ // valid 2 hex chars
byte b = (byte)((h1 << 4) | h2);
pos += 2;
// don't add as char
helper.AddByte(b);
continue;
}
}
if ((ch & 0xFF80) == 0)
helper.AddByte((byte)ch); // 7 bit have to go as bytes because of Unicode
else
helper.AddChar(ch);
}
return helper.GetString();
}
private static byte[] UrlDecodeInternal(byte[] bytes, int offset, int count)
{
if (!ValidateUrlEncodingParameters(bytes, offset, count))
{
return null;
}
int decodedBytesCount = 0;
byte[] decodedBytes = new byte[count];
for (int i = 0; i < count; i++)
{
int pos = offset + i;
byte b = bytes[pos];
if (b == '+')
{
b = (byte)' ';
}
else if (b == '%' && i < count - 2)
{
int h1 = HexToInt((char)bytes[pos + 1]);
int h2 = HexToInt((char)bytes[pos + 2]);
if (h1 >= 0 && h2 >= 0)
{ // valid 2 hex chars
b = (byte)((h1 << 4) | h2);
i += 2;
}
}
decodedBytes[decodedBytesCount++] = b;
}
if (decodedBytesCount < decodedBytes.Length)
{
byte[] newDecodedBytes = new byte[decodedBytesCount];
Array.Copy(decodedBytes, newDecodedBytes, decodedBytesCount);
decodedBytes = newDecodedBytes;
}
return decodedBytes;
}
#endregion
#region UrlDecode public methods
[SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification="Already shipped public API; code moved here as part of API consolidation")]
public static string UrlDecode(string encodedValue)
{
if (encodedValue == null)
return null;
return UrlDecodeInternal(encodedValue, Encoding.UTF8);
}
public static byte[] UrlDecodeToBytes(byte[] encodedValue, int offset, int count)
{
return UrlDecodeInternal(encodedValue, offset, count);
}
#endregion
#region Helper methods
// similar to Char.ConvertFromUtf32, but doesn't check arguments or generate strings
// input is assumed to be an SMP character
private static void ConvertSmpToUtf16(uint smpChar, out char leadingSurrogate, out char trailingSurrogate) {
Debug.Assert(UNICODE_PLANE01_START <= smpChar && smpChar <= UNICODE_PLANE16_END);
int utf32 = (int)(smpChar - UNICODE_PLANE01_START);
leadingSurrogate = (char)((utf32 / 0x400) + HIGH_SURROGATE_START);
trailingSurrogate = (char)((utf32 % 0x400) + LOW_SURROGATE_START);
}
#if FEATURE_NETCORE
[SecuritySafeCritical]
#endif
private static unsafe int GetNextUnicodeScalarValueFromUtf16Surrogate(ref char* pch, ref int charsRemaining) {
// invariants
Debug.Assert(charsRemaining >= 1);
Debug.Assert(Char.IsSurrogate(*pch));
if (charsRemaining <= 1) {
// not enough characters remaining to resurrect the original scalar value
return UnicodeReplacementChar;
}
char leadingSurrogate = pch[0];
char trailingSurrogate = pch[1];
if (Char.IsSurrogatePair(leadingSurrogate, trailingSurrogate)) {
// we're going to consume an extra char
pch++;
charsRemaining--;
// below code is from Char.ConvertToUtf32, but without the checks (since we just performed them)
return (((leadingSurrogate - HIGH_SURROGATE_START) * 0x400) + (trailingSurrogate - LOW_SURROGATE_START) + UNICODE_PLANE01_START);
}
else {
// unmatched surrogate
return UnicodeReplacementChar;
}
}
private static int HexToInt(char h)
{
return (h >= '0' && h <= '9') ? h - '0' :
(h >= 'a' && h <= 'f') ? h - 'a' + 10 :
(h >= 'A' && h <= 'F') ? h - 'A' + 10 :
-1;
}
private static char IntToHex(int n)
{
Debug.Assert(n < 0x10);
if (n <= 9)
return (char)(n + (int)'0');
else
return (char)(n - 10 + (int)'A');
}
// Set of safe chars, from RFC 1738.4 minus '+'
private static bool IsUrlSafeChar(char ch)
{
if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9')
return true;
switch (ch)
{
case '-':
case '_':
case '.':
case '!':
case '*':
case '(':
case ')':
return true;
}
return false;
}
private static bool ValidateUrlEncodingParameters(byte[] bytes, int offset, int count)
{
if (bytes == null && count == 0)
return false;
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (offset < 0 || offset > bytes.Length)
{
throw new ArgumentOutOfRangeException("offset");
}
if (count < 0 || offset + count > bytes.Length)
{
throw new ArgumentOutOfRangeException("count");
}
return true;
}
private static bool StringRequiresHtmlDecoding(string s) {
if (HtmlDecodeConformance == UnicodeDecodingConformance.Compat) {
// this string requires html decoding only if it contains '&'
return (s.IndexOf('&') >= 0);
}
else {
// this string requires html decoding if it contains '&' or a surrogate character
for (int i = 0; i < s.Length; i++) {
char c = s[i];
if (c == '&' || Char.IsSurrogate(c)) {
return true;
}
}
return false;
}
}
#endregion
#region UrlDecoder nested class
// *** Source: alm/tfs_core/Framework/Common/UriUtility/HttpUtility.cs
// This specific code was copied from above ASP.NET codebase.
// Internal class to facilitate URL decoding -- keeps char buffer and byte buffer, allows appending of either chars or bytes
private class UrlDecoder
{
private int _bufferSize;
// Accumulate characters in a special array
private int _numChars;
private char[] _charBuffer;
// Accumulate bytes for decoding into characters in a special array
private int _numBytes;
private byte[] _byteBuffer;
// Encoding to convert chars to bytes
private Encoding _encoding;
private void FlushBytes()
{
if (_numBytes > 0)
{
_numChars += _encoding.GetChars(_byteBuffer, 0, _numBytes, _charBuffer, _numChars);
_numBytes = 0;
}
}
internal UrlDecoder(int bufferSize, Encoding encoding)
{
_bufferSize = bufferSize;
_encoding = encoding;
_charBuffer = new char[bufferSize];
// byte buffer created on demand
}
internal void AddChar(char ch)
{
if (_numBytes > 0)
FlushBytes();
_charBuffer[_numChars++] = ch;
}
internal void AddByte(byte b)
{
if (_byteBuffer == null)
_byteBuffer = new byte[_bufferSize];
_byteBuffer[_numBytes++] = b;
}
internal String GetString()
{
if (_numBytes > 0)
FlushBytes();
if (_numChars > 0)
return new String(_charBuffer, 0, _numChars);
else
return String.Empty;
}
}
#endregion
#region HtmlEntities nested class
// helper class for lookup of HTML encoding entities
private static class HtmlEntities {
#if MONO
public static char Lookup (string entity)
{
var token = CalculateKeyValue (entity);
if (token == 0) {
return '\0';
}
var idx = Array.BinarySearch (entities, token);
if (idx < 0) {
return '\0';
}
return entities_values [idx];
}
static long CalculateKeyValue (string s)
{
if (s.Length > 8)
return 0;
long key = 0;
for (int i = 0; i < s.Length; ++i) {
long ch = s[i];
if (ch > 'z' || ch < '0')
return 0;
key |= ch << ((7 - i) * 8);
}
return key;
}
// Must be sorted
static readonly long[] entities = new long[] {
(long)'A' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'A' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'A' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'A' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'A' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24,
(long)'A' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24,
(long)'A' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'A' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'B' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'C' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16,
(long)'C' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'D' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16,
(long)'D' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'E' << 56 | (long)'T' << 48 | (long)'H' << 40,
(long)'E' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'E' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'E' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'E' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'E' << 56 | (long)'t' << 48 | (long)'a' << 40,
(long)'E' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'G' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'I' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'I' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'I' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'I' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'I' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'K' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24,
(long)'L' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16,
(long)'M' << 56 | (long)'u' << 48,
(long)'N' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'N' << 56 | (long)'u' << 48,
(long)'O' << 56 | (long)'E' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'O' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'O' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'O' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'O' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24,
(long)'O' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'O' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16,
(long)'O' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'O' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'P' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'P' << 56 | (long)'i' << 48,
(long)'P' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24,
(long)'P' << 56 | (long)'s' << 48 | (long)'i' << 40,
(long)'R' << 56 | (long)'h' << 48 | (long)'o' << 40,
(long)'S' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16,
(long)'S' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'T' << 56 | (long)'H' << 48 | (long)'O' << 40 | (long)'R' << 32 | (long)'N' << 24,
(long)'T' << 56 | (long)'a' << 48 | (long)'u' << 40,
(long)'T' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'U' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'U' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'U' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'U' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'U' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'X' << 56 | (long)'i' << 48,
(long)'Y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'Y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'Z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'a' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'a' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'a' << 56 | (long)'c' << 48 | (long)'u' << 40 | (long)'t' << 32 | (long)'e' << 24,
(long)'a' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'a' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'a' << 56 | (long)'l' << 48 | (long)'e' << 40 | (long)'f' << 32 | (long)'s' << 24 | (long)'y' << 16 | (long)'m' << 8,
(long)'a' << 56 | (long)'l' << 48 | (long)'p' << 40 | (long)'h' << 32 | (long)'a' << 24,
(long)'a' << 56 | (long)'m' << 48 | (long)'p' << 40,
(long)'a' << 56 | (long)'n' << 48 | (long)'d' << 40,
(long)'a' << 56 | (long)'n' << 48 | (long)'g' << 40,
(long)'a' << 56 | (long)'p' << 48 | (long)'o' << 40 | (long)'s' << 32,
(long)'a' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'g' << 24,
(long)'a' << 56 | (long)'s' << 48 | (long)'y' << 40 | (long)'m' << 32 | (long)'p' << 24,
(long)'a' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'a' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'b' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'b' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'b' << 56 | (long)'r' << 48 | (long)'v' << 40 | (long)'b' << 32 | (long)'a' << 24 | (long)'r' << 16,
(long)'b' << 56 | (long)'u' << 48 | (long)'l' << 40 | (long)'l' << 32,
(long)'c' << 56 | (long)'a' << 48 | (long)'p' << 40,
(long)'c' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'d' << 32 | (long)'i' << 24 | (long)'l' << 16,
(long)'c' << 56 | (long)'e' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'l' << 24,
(long)'c' << 56 | (long)'e' << 48 | (long)'n' << 40 | (long)'t' << 32,
(long)'c' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'c' << 56 | (long)'i' << 48 | (long)'r' << 40 | (long)'c' << 32,
(long)'c' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'b' << 32 | (long)'s' << 24,
(long)'c' << 56 | (long)'o' << 48 | (long)'n' << 40 | (long)'g' << 32,
(long)'c' << 56 | (long)'o' << 48 | (long)'p' << 40 | (long)'y' << 32,
(long)'c' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'r' << 24,
(long)'c' << 56 | (long)'u' << 48 | (long)'p' << 40,
(long)'c' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'n' << 16,
(long)'d' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'d' << 56 | (long)'a' << 48 | (long)'g' << 40 | (long)'g' << 32 | (long)'e' << 24 | (long)'r' << 16,
(long)'d' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'d' << 56 | (long)'e' << 48 | (long)'g' << 40,
(long)'d' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'d' << 56 | (long)'i' << 48 | (long)'a' << 40 | (long)'m' << 32 | (long)'s' << 24,
(long)'d' << 56 | (long)'i' << 48 | (long)'v' << 40 | (long)'i' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'e' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'e' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'e' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'e' << 56 | (long)'m' << 48 | (long)'p' << 40 | (long)'t' << 32 | (long)'y' << 24,
(long)'e' << 56 | (long)'m' << 48 | (long)'s' << 40 | (long)'p' << 32,
(long)'e' << 56 | (long)'n' << 48 | (long)'s' << 40 | (long)'p' << 32,
(long)'e' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'e' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'i' << 32 | (long)'v' << 24,
(long)'e' << 56 | (long)'t' << 48 | (long)'a' << 40,
(long)'e' << 56 | (long)'t' << 48 | (long)'h' << 40,
(long)'e' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'e' << 56 | (long)'u' << 48 | (long)'r' << 40 | (long)'o' << 32,
(long)'e' << 56 | (long)'x' << 48 | (long)'i' << 40 | (long)'s' << 32 | (long)'t' << 24,
(long)'f' << 56 | (long)'n' << 48 | (long)'o' << 40 | (long)'f' << 32,
(long)'f' << 56 | (long)'o' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'l' << 24 | (long)'l' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'2' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'1' << 24 | (long)'4' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'c' << 32 | (long)'3' << 24 | (long)'4' << 16,
(long)'f' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'l' << 24,
(long)'g' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'g' << 56 | (long)'e' << 48,
(long)'g' << 56 | (long)'t' << 48,
(long)'h' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'h' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'h' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'t' << 24 | (long)'s' << 16,
(long)'h' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'l' << 32 | (long)'i' << 24 | (long)'p' << 16,
(long)'i' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'i' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'i' << 56 | (long)'e' << 48 | (long)'x' << 40 | (long)'c' << 32 | (long)'l' << 24,
(long)'i' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'i' << 56 | (long)'m' << 48 | (long)'a' << 40 | (long)'g' << 32 | (long)'e' << 24,
(long)'i' << 56 | (long)'n' << 48 | (long)'f' << 40 | (long)'i' << 32 | (long)'n' << 24,
(long)'i' << 56 | (long)'n' << 48 | (long)'t' << 40,
(long)'i' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'i' << 56 | (long)'q' << 48 | (long)'u' << 40 | (long)'e' << 32 | (long)'s' << 24 | (long)'t' << 16,
(long)'i' << 56 | (long)'s' << 48 | (long)'i' << 40 | (long)'n' << 32,
(long)'i' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'k' << 56 | (long)'a' << 48 | (long)'p' << 40 | (long)'p' << 32 | (long)'a' << 24,
(long)'l' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'l' << 56 | (long)'a' << 48 | (long)'m' << 40 | (long)'b' << 32 | (long)'d' << 24 | (long)'a' << 16,
(long)'l' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32,
(long)'l' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'l' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'l' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24,
(long)'l' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'l' << 56 | (long)'e' << 48,
(long)'l' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16,
(long)'l' << 56 | (long)'o' << 48 | (long)'w' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'t' << 16,
(long)'l' << 56 | (long)'o' << 48 | (long)'z' << 40,
(long)'l' << 56 | (long)'r' << 48 | (long)'m' << 40,
(long)'l' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16,
(long)'l' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'l' << 56 | (long)'t' << 48,
(long)'m' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'r' << 32,
(long)'m' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24,
(long)'m' << 56 | (long)'i' << 48 | (long)'c' << 40 | (long)'r' << 32 | (long)'o' << 24,
(long)'m' << 56 | (long)'i' << 48 | (long)'d' << 40 | (long)'d' << 32 | (long)'o' << 24 | (long)'t' << 16,
(long)'m' << 56 | (long)'i' << 48 | (long)'n' << 40 | (long)'u' << 32 | (long)'s' << 24,
(long)'m' << 56 | (long)'u' << 48,
(long)'n' << 56 | (long)'a' << 48 | (long)'b' << 40 | (long)'l' << 32 | (long)'a' << 24,
(long)'n' << 56 | (long)'b' << 48 | (long)'s' << 40 | (long)'p' << 32,
(long)'n' << 56 | (long)'d' << 48 | (long)'a' << 40 | (long)'s' << 32 | (long)'h' << 24,
(long)'n' << 56 | (long)'e' << 48,
(long)'n' << 56 | (long)'i' << 48,
(long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40,
(long)'n' << 56 | (long)'o' << 48 | (long)'t' << 40 | (long)'i' << 32 | (long)'n' << 24,
(long)'n' << 56 | (long)'s' << 48 | (long)'u' << 40 | (long)'b' << 32,
(long)'n' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'n' << 56 | (long)'u' << 48,
(long)'o' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'o' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'o' << 56 | (long)'e' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'o' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'o' << 56 | (long)'l' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'e' << 24,
(long)'o' << 56 | (long)'m' << 48 | (long)'e' << 40 | (long)'g' << 32 | (long)'a' << 24,
(long)'o' << 56 | (long)'m' << 48 | (long)'i' << 40 | (long)'c' << 32 | (long)'r' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'o' << 56 | (long)'p' << 48 | (long)'l' << 40 | (long)'u' << 32 | (long)'s' << 24,
(long)'o' << 56 | (long)'r' << 48,
(long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'f' << 32,
(long)'o' << 56 | (long)'r' << 48 | (long)'d' << 40 | (long)'m' << 32,
(long)'o' << 56 | (long)'s' << 48 | (long)'l' << 40 | (long)'a' << 32 | (long)'s' << 24 | (long)'h' << 16,
(long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'l' << 32 | (long)'d' << 24 | (long)'e' << 16,
(long)'o' << 56 | (long)'t' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24 | (long)'s' << 16,
(long)'o' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'a' << 32,
(long)'p' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'t' << 32,
(long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'m' << 32 | (long)'i' << 24 | (long)'l' << 16,
(long)'p' << 56 | (long)'e' << 48 | (long)'r' << 40 | (long)'p' << 32,
(long)'p' << 56 | (long)'h' << 48 | (long)'i' << 40,
(long)'p' << 56 | (long)'i' << 48,
(long)'p' << 56 | (long)'i' << 48 | (long)'v' << 40,
(long)'p' << 56 | (long)'l' << 48 | (long)'u' << 40 | (long)'s' << 32 | (long)'m' << 24 | (long)'n' << 16,
(long)'p' << 56 | (long)'o' << 48 | (long)'u' << 40 | (long)'n' << 32 | (long)'d' << 24,
(long)'p' << 56 | (long)'r' << 48 | (long)'i' << 40 | (long)'m' << 32 | (long)'e' << 24,
(long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'d' << 32,
(long)'p' << 56 | (long)'r' << 48 | (long)'o' << 40 | (long)'p' << 32,
(long)'p' << 56 | (long)'s' << 48 | (long)'i' << 40,
(long)'q' << 56 | (long)'u' << 48 | (long)'o' << 40 | (long)'t' << 32,
(long)'r' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'r' << 56 | (long)'a' << 48 | (long)'d' << 40 | (long)'i' << 32 | (long)'c' << 24,
(long)'r' << 56 | (long)'a' << 48 | (long)'n' << 40 | (long)'g' << 32,
(long)'r' << 56 | (long)'a' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'r' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'r' << 56 | (long)'c' << 48 | (long)'e' << 40 | (long)'i' << 32 | (long)'l' << 24,
(long)'r' << 56 | (long)'d' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'r' << 56 | (long)'e' << 48 | (long)'a' << 40 | (long)'l' << 32,
(long)'r' << 56 | (long)'e' << 48 | (long)'g' << 40,
(long)'r' << 56 | (long)'f' << 48 | (long)'l' << 40 | (long)'o' << 32 | (long)'o' << 24 | (long)'r' << 16,
(long)'r' << 56 | (long)'h' << 48 | (long)'o' << 40,
(long)'r' << 56 | (long)'l' << 48 | (long)'m' << 40,
(long)'r' << 56 | (long)'s' << 48 | (long)'a' << 40 | (long)'q' << 32 | (long)'u' << 24 | (long)'o' << 16,
(long)'r' << 56 | (long)'s' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'s' << 56 | (long)'b' << 48 | (long)'q' << 40 | (long)'u' << 32 | (long)'o' << 24,
(long)'s' << 56 | (long)'c' << 48 | (long)'a' << 40 | (long)'r' << 32 | (long)'o' << 24 | (long)'n' << 16,
(long)'s' << 56 | (long)'d' << 48 | (long)'o' << 40 | (long)'t' << 32,
(long)'s' << 56 | (long)'e' << 48 | (long)'c' << 40 | (long)'t' << 32,
(long)'s' << 56 | (long)'h' << 48 | (long)'y' << 40,
(long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24,
(long)'s' << 56 | (long)'i' << 48 | (long)'g' << 40 | (long)'m' << 32 | (long)'a' << 24 | (long)'f' << 16,
(long)'s' << 56 | (long)'i' << 48 | (long)'m' << 40,
(long)'s' << 56 | (long)'p' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24 | (long)'s' << 16,
(long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40,
(long)'s' << 56 | (long)'u' << 48 | (long)'b' << 40 | (long)'e' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'m' << 40,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'1' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'2' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'3' << 32,
(long)'s' << 56 | (long)'u' << 48 | (long)'p' << 40 | (long)'e' << 32,
(long)'s' << 56 | (long)'z' << 48 | (long)'l' << 40 | (long)'i' << 32 | (long)'g' << 24,
(long)'t' << 56 | (long)'a' << 48 | (long)'u' << 40,
(long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'r' << 32 | (long)'e' << 24 | (long)'4' << 16,
(long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24,
(long)'t' << 56 | (long)'h' << 48 | (long)'e' << 40 | (long)'t' << 32 | (long)'a' << 24 | (long)'s' << 16 | (long)'y' << 8 | (long)'m' << 0,
(long)'t' << 56 | (long)'h' << 48 | (long)'i' << 40 | (long)'n' << 32 | (long)'s' << 24 | (long)'p' << 16,
(long)'t' << 56 | (long)'h' << 48 | (long)'o' << 40 | (long)'r' << 32 | (long)'n' << 24,
(long)'t' << 56 | (long)'i' << 48 | (long)'l' << 40 | (long)'d' << 32 | (long)'e' << 24,
(long)'t' << 56 | (long)'i' << 48 | (long)'m' << 40 | (long)'e' << 32 | (long)'s' << 24,
(long)'t' << 56 | (long)'r' << 48 | (long)'a' << 40 | (long)'d' << 32 | (long)'e' << 24,
(long)'u' << 56 | (long)'A' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'u' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'u' << 56 | (long)'a' << 48 | (long)'r' << 40 | (long)'r' << 32,
(long)'u' << 56 | (long)'c' << 48 | (long)'i' << 40 | (long)'r' << 32 | (long)'c' << 24,
(long)'u' << 56 | (long)'g' << 48 | (long)'r' << 40 | (long)'a' << 32 | (long)'v' << 24 | (long)'e' << 16,
(long)'u' << 56 | (long)'m' << 48 | (long)'l' << 40,
(long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'h' << 24,
(long)'u' << 56 | (long)'p' << 48 | (long)'s' << 40 | (long)'i' << 32 | (long)'l' << 24 | (long)'o' << 16 | (long)'n' << 8,
(long)'u' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'w' << 56 | (long)'e' << 48 | (long)'i' << 40 | (long)'e' << 32 | (long)'r' << 24 | (long)'p' << 16,
(long)'x' << 56 | (long)'i' << 48,
(long)'y' << 56 | (long)'a' << 48 | (long)'c' << 40 | (long)'u' << 32 | (long)'t' << 24 | (long)'e' << 16,
(long)'y' << 56 | (long)'e' << 48 | (long)'n' << 40,
(long)'y' << 56 | (long)'u' << 48 | (long)'m' << 40 | (long)'l' << 32,
(long)'z' << 56 | (long)'e' << 48 | (long)'t' << 40 | (long)'a' << 32,
(long)'z' << 56 | (long)'w' << 48 | (long)'j' << 40,
(long)'z' << 56 | (long)'w' << 48 | (long)'n' << 40 | (long)'j' << 32
};
static readonly char[] entities_values = new char[] {
'\u00C6',
'\u00C1',
'\u00C2',
'\u00C0',
'\u0391',
'\u00C5',
'\u00C3',
'\u00C4',
'\u0392',
'\u00C7',
'\u03A7',
'\u2021',
'\u0394',
'\u00D0',
'\u00C9',
'\u00CA',
'\u00C8',
'\u0395',
'\u0397',
'\u00CB',
'\u0393',
'\u00CD',
'\u00CE',
'\u00CC',
'\u0399',
'\u00CF',
'\u039A',
'\u039B',
'\u039C',
'\u00D1',
'\u039D',
'\u0152',
'\u00D3',
'\u00D4',
'\u00D2',
'\u03A9',
'\u039F',
'\u00D8',
'\u00D5',
'\u00D6',
'\u03A6',
'\u03A0',
'\u2033',
'\u03A8',
'\u03A1',
'\u0160',
'\u03A3',
'\u00DE',
'\u03A4',
'\u0398',
'\u00DA',
'\u00DB',
'\u00D9',
'\u03A5',
'\u00DC',
'\u039E',
'\u00DD',
'\u0178',
'\u0396',
'\u00E1',
'\u00E2',
'\u00B4',
'\u00E6',
'\u00E0',
'\u2135',
'\u03B1',
'\u0026',
'\u2227',
'\u2220',
'\u0027',
'\u00E5',
'\u2248',
'\u00E3',
'\u00E4',
'\u201E',
'\u03B2',
'\u00A6',
'\u2022',
'\u2229',
'\u00E7',
'\u00B8',
'\u00A2',
'\u03C7',
'\u02C6',
'\u2663',
'\u2245',
'\u00A9',
'\u21B5',
'\u222A',
'\u00A4',
'\u21D3',
'\u2020',
'\u2193',
'\u00B0',
'\u03B4',
'\u2666',
'\u00F7',
'\u00E9',
'\u00EA',
'\u00E8',
'\u2205',
'\u2003',
'\u2002',
'\u03B5',
'\u2261',
'\u03B7',
'\u00F0',
'\u00EB',
'\u20AC',
'\u2203',
'\u0192',
'\u2200',
'\u00BD',
'\u00BC',
'\u00BE',
'\u2044',
'\u03B3',
'\u2265',
'\u003E',
'\u21D4',
'\u2194',
'\u2665',
'\u2026',
'\u00ED',
'\u00EE',
'\u00A1',
'\u00EC',
'\u2111',
'\u221E',
'\u222B',
'\u03B9',
'\u00BF',
'\u2208',
'\u00EF',
'\u03BA',
'\u21D0',
'\u03BB',
'\u2329',
'\u00AB',
'\u2190',
'\u2308',
'\u201C',
'\u2264',
'\u230A',
'\u2217',
'\u25CA',
'\u200E',
'\u2039',
'\u2018',
'\u003C',
'\u00AF',
'\u2014',
'\u00B5',
'\u00B7',
'\u2212',
'\u03BC',
'\u2207',
'\u00A0',
'\u2013',
'\u2260',
'\u220B',
'\u00AC',
'\u2209',
'\u2284',
'\u00F1',
'\u03BD',
'\u00F3',
'\u00F4',
'\u0153',
'\u00F2',
'\u203E',
'\u03C9',
'\u03BF',
'\u2295',
'\u2228',
'\u00AA',
'\u00BA',
'\u00F8',
'\u00F5',
'\u2297',
'\u00F6',
'\u00B6',
'\u2202',
'\u2030',
'\u22A5',
'\u03C6',
'\u03C0',
'\u03D6',
'\u00B1',
'\u00A3',
'\u2032',
'\u220F',
'\u221D',
'\u03C8',
'\u0022',
'\u21D2',
'\u221A',
'\u232A',
'\u00BB',
'\u2192',
'\u2309',
'\u201D',
'\u211C',
'\u00AE',
'\u230B',
'\u03C1',
'\u200F',
'\u203A',
'\u2019',
'\u201A',
'\u0161',
'\u22C5',
'\u00A7',
'\u00AD',
'\u03C3',
'\u03C2',
'\u223C',
'\u2660',
'\u2282',
'\u2286',
'\u2211',
'\u2283',
'\u00B9',
'\u00B2',
'\u00B3',
'\u2287',
'\u00DF',
'\u03C4',
'\u2234',
'\u03B8',
'\u03D1',
'\u2009',
'\u00FE',
'\u02DC',
'\u00D7',
'\u2122',
'\u21D1',
'\u00FA',
'\u2191',
'\u00FB',
'\u00F9',
'\u00A8',
'\u03D2',
'\u03C5',
'\u00FC',
'\u2118',
'\u03BE',
'\u00FD',
'\u00A5',
'\u00FF',
'\u03B6',
'\u200D',
'\u200C'
};
#else
// The list is from http://www.w3.org/TR/REC-html40/sgml/entities.html, except for ', which
// is defined in http://www.w3.org/TR/2008/REC-xml-20081126/#sec-predefined-ent.
private static String[] _entitiesList = new String[] {
"\x0022-quot",
"\x0026-amp",
"\x0027-apos",
"\x003c-lt",
"\x003e-gt",
"\x00a0-nbsp",
"\x00a1-iexcl",
"\x00a2-cent",
"\x00a3-pound",
"\x00a4-curren",
"\x00a5-yen",
"\x00a6-brvbar",
"\x00a7-sect",
"\x00a8-uml",
"\x00a9-copy",
"\x00aa-ordf",
"\x00ab-laquo",
"\x00ac-not",
"\x00ad-shy",
"\x00ae-reg",
"\x00af-macr",
"\x00b0-deg",
"\x00b1-plusmn",
"\x00b2-sup2",
"\x00b3-sup3",
"\x00b4-acute",
"\x00b5-micro",
"\x00b6-para",
"\x00b7-middot",
"\x00b8-cedil",
"\x00b9-sup1",
"\x00ba-ordm",
"\x00bb-raquo",
"\x00bc-frac14",
"\x00bd-frac12",
"\x00be-frac34",
"\x00bf-iquest",
"\x00c0-Agrave",
"\x00c1-Aacute",
"\x00c2-Acirc",
"\x00c3-Atilde",
"\x00c4-Auml",
"\x00c5-Aring",
"\x00c6-AElig",
"\x00c7-Ccedil",
"\x00c8-Egrave",
"\x00c9-Eacute",
"\x00ca-Ecirc",
"\x00cb-Euml",
"\x00cc-Igrave",
"\x00cd-Iacute",
"\x00ce-Icirc",
"\x00cf-Iuml",
"\x00d0-ETH",
"\x00d1-Ntilde",
"\x00d2-Ograve",
"\x00d3-Oacute",
"\x00d4-Ocirc",
"\x00d5-Otilde",
"\x00d6-Ouml",
"\x00d7-times",
"\x00d8-Oslash",
"\x00d9-Ugrave",
"\x00da-Uacute",
"\x00db-Ucirc",
"\x00dc-Uuml",
"\x00dd-Yacute",
"\x00de-THORN",
"\x00df-szlig",
"\x00e0-agrave",
"\x00e1-aacute",
"\x00e2-acirc",
"\x00e3-atilde",
"\x00e4-auml",
"\x00e5-aring",
"\x00e6-aelig",
"\x00e7-ccedil",
"\x00e8-egrave",
"\x00e9-eacute",
"\x00ea-ecirc",
"\x00eb-euml",
"\x00ec-igrave",
"\x00ed-iacute",
"\x00ee-icirc",
"\x00ef-iuml",
"\x00f0-eth",
"\x00f1-ntilde",
"\x00f2-ograve",
"\x00f3-oacute",
"\x00f4-ocirc",
"\x00f5-otilde",
"\x00f6-ouml",
"\x00f7-divide",
"\x00f8-oslash",
"\x00f9-ugrave",
"\x00fa-uacute",
"\x00fb-ucirc",
"\x00fc-uuml",
"\x00fd-yacute",
"\x00fe-thorn",
"\x00ff-yuml",
"\x0152-OElig",
"\x0153-oelig",
"\x0160-Scaron",
"\x0161-scaron",
"\x0178-Yuml",
"\x0192-fnof",
"\x02c6-circ",
"\x02dc-tilde",
"\x0391-Alpha",
"\x0392-Beta",
"\x0393-Gamma",
"\x0394-Delta",
"\x0395-Epsilon",
"\x0396-Zeta",
"\x0397-Eta",
"\x0398-Theta",
"\x0399-Iota",
"\x039a-Kappa",
"\x039b-Lambda",
"\x039c-Mu",
"\x039d-Nu",
"\x039e-Xi",
"\x039f-Omicron",
"\x03a0-Pi",
"\x03a1-Rho",
"\x03a3-Sigma",
"\x03a4-Tau",
"\x03a5-Upsilon",
"\x03a6-Phi",
"\x03a7-Chi",
"\x03a8-Psi",
"\x03a9-Omega",
"\x03b1-alpha",
"\x03b2-beta",
"\x03b3-gamma",
"\x03b4-delta",
"\x03b5-epsilon",
"\x03b6-zeta",
"\x03b7-eta",
"\x03b8-theta",
"\x03b9-iota",
"\x03ba-kappa",
"\x03bb-lambda",
"\x03bc-mu",
"\x03bd-nu",
"\x03be-xi",
"\x03bf-omicron",
"\x03c0-pi",
"\x03c1-rho",
"\x03c2-sigmaf",
"\x03c3-sigma",
"\x03c4-tau",
"\x03c5-upsilon",
"\x03c6-phi",
"\x03c7-chi",
"\x03c8-psi",
"\x03c9-omega",
"\x03d1-thetasym",
"\x03d2-upsih",
"\x03d6-piv",
"\x2002-ensp",
"\x2003-emsp",
"\x2009-thinsp",
"\x200c-zwnj",
"\x200d-zwj",
"\x200e-lrm",
"\x200f-rlm",
"\x2013-ndash",
"\x2014-mdash",
"\x2018-lsquo",
"\x2019-rsquo",
"\x201a-sbquo",
"\x201c-ldquo",
"\x201d-rdquo",
"\x201e-bdquo",
"\x2020-dagger",
"\x2021-Dagger",
"\x2022-bull",
"\x2026-hellip",
"\x2030-permil",
"\x2032-prime",
"\x2033-Prime",
"\x2039-lsaquo",
"\x203a-rsaquo",
"\x203e-oline",
"\x2044-frasl",
"\x20ac-euro",
"\x2111-image",
"\x2118-weierp",
"\x211c-real",
"\x2122-trade",
"\x2135-alefsym",
"\x2190-larr",
"\x2191-uarr",
"\x2192-rarr",
"\x2193-darr",
"\x2194-harr",
"\x21b5-crarr",
"\x21d0-lArr",
"\x21d1-uArr",
"\x21d2-rArr",
"\x21d3-dArr",
"\x21d4-hArr",
"\x2200-forall",
"\x2202-part",
"\x2203-exist",
"\x2205-empty",
"\x2207-nabla",
"\x2208-isin",
"\x2209-notin",
"\x220b-ni",
"\x220f-prod",
"\x2211-sum",
"\x2212-minus",
"\x2217-lowast",
"\x221a-radic",
"\x221d-prop",
"\x221e-infin",
"\x2220-ang",
"\x2227-and",
"\x2228-or",
"\x2229-cap",
"\x222a-cup",
"\x222b-int",
"\x2234-there4",
"\x223c-sim",
"\x2245-cong",
"\x2248-asymp",
"\x2260-ne",
"\x2261-equiv",
"\x2264-le",
"\x2265-ge",
"\x2282-sub",
"\x2283-sup",
"\x2284-nsub",
"\x2286-sube",
"\x2287-supe",
"\x2295-oplus",
"\x2297-otimes",
"\x22a5-perp",
"\x22c5-sdot",
"\x2308-lceil",
"\x2309-rceil",
"\x230a-lfloor",
"\x230b-rfloor",
"\x2329-lang",
"\x232a-rang",
"\x25ca-loz",
"\x2660-spades",
"\x2663-clubs",
"\x2665-hearts",
"\x2666-diams",
};
private static Dictionary _lookupTable = GenerateLookupTable();
private static Dictionary GenerateLookupTable() {
// e[0] is unicode char, e[1] is '-', e[2+] is entity string
Dictionary lookupTable = new Dictionary(StringComparer.Ordinal);
foreach (string e in _entitiesList) {
lookupTable.Add(e.Substring(2), e[0]);
}
return lookupTable;
}
public static char Lookup(string entity) {
char theChar;
_lookupTable.TryGetValue(entity, out theChar);
return theChar;
}
#endif
}
#endregion
}
}