in AjaxMinDll/JavaScript/OutputVisitor.cs [4269:4465]
public static string EscapeString(string text)
{
// the quote factor is a calculation based on the relative number of
// double-quotes in the string in relation to single-quotes. If the factor is
// less than zero, then there are more double-quotes than single-quotes and
// we can save bytes by using single-quotes as the delimiter. If it's greater
// than zero, then there are more single quotes than double-quotes and we should
// use double-quotes for the delimiter. If it's exactly zero, then
// there are exactly the same number, so it doesn't matter which delimiter
// we use. In that case, use double-quotes because I think it's easier to read.
// More like other languages (C/C++, C#, Java) that way.
var delimiter = QuoteFactor(text) < 0 ? "\'" : "\"";
// we also don't want to build a new string builder object if we don't have to.
// and we only need to if we end up escaping characters.
var rawStart = 0;
string escapedText = string.Empty;
StringBuilder sb = null;
try
{
if (!string.IsNullOrEmpty(text))
{
// check each character of the string
for (var index = 0; index < text.Length; ++index)
{
var ch = text[index];
switch (ch)
{
case '\'':
case '"':
// we only need to escape whichever one we chose as our delimiter
if (ch == delimiter[0])
{
// need to escape instances of the delimiter character
goto case '\\';
}
break;
case '\b':
// output "\b"
ch = 'b';
goto case '\\';
case '\t':
// output "\t"
ch = 't';
goto case '\\';
case '\n':
// output "\n"
ch = 'n';
goto case '\\';
case '\v':
// w3c-strict can encode this character as a \v escape.
// BUT... IE<9 doesn't recognize that escape sequence,
// so encode is as hex for maximum compatibility.
// if the source actually had "\v" in it, it wouldn't been
// marked as having issues and not get encoded anyway.
goto default;
case '\f':
// output "\f"
ch = 'f';
goto case '\\';
case '\r':
// output "\r"
ch = 'r';
goto case '\\';
case '\\':
// we need to output an escape, so create the string builder
// if we haven't already
if (sb == null)
{
sb = StringBuilderPool.Acquire();
}
// output the block of raw characters we have since the last time
if (rawStart < index)
{
sb.Append(text, rawStart, index - rawStart);
}
// set raw start to the next character
rawStart = index + 1;
// output the escape character, then the escaped character
sb.Append('\\');
sb.Append(ch);
break;
case '\x2028':
case '\x2029':
// issue #14398 - unescaped, these characters (Unicode LineSeparator and ParagraphSeparator)
// would introduce a line-break in the string. they ALWAYS need to be escaped,
// no matter what output encoding we may use.
if (sb == null)
{
sb = StringBuilderPool.Acquire();
}
// output the block of raw characters we have since the last time
if (rawStart < index)
{
sb.Append(text.Substring(rawStart, index - rawStart));
}
// set raw start to the next character
rawStart = index + 1;
// output the escape character, a "u", then the four-digit escaped character
sb.Append(@"\u");
sb.Append(((int)ch).ToStringInvariant("x4"));
break;
default:
if (ch < ' ')
{
// need to escape control codes that aren't handled
// by the single-letter escape codes
// create the string builder if we haven't already
if (sb == null)
{
sb = StringBuilderPool.Acquire();
}
// output the block of raw characters we have since the last time
if (rawStart < index)
{
sb.Append(text, rawStart, index - rawStart);
}
// set raw start to the next character
rawStart = index + 1;
// strict ECMA-262 does not support octal escapes, but octal will
// crunch down a full character more here than hexadecimal. Plus, if we do
// octal, we'll still need to escape these characters to hex for RexExp
// constructor strings so they don't get confused with back references.
// minifies smaller, but octal is too much trouble.
int intValue = ch;
//if (noOctalEscapes)
{
// output the hex escape sequence
sb.Append(@"\x");
sb.Append(intValue.ToStringInvariant("x2"));
}
//else
//{
// // octal representation of 0 through 31 are \0 through \37
// sb.Append('\\');
// if (intValue < 8)
// {
// // single octal digit
// sb.Append(intValue.ToStringInvariant());
// }
// else
// {
// // two octal digits
// sb.Append((intValue / 8).ToStringInvariant());
// sb.Append((intValue % 8).ToStringInvariant());
// }
//}
}
break;
}
}
if (sb != null)
{
// we had escapes; use the string builder
// but first make sure the last batch of raw text is output
if (rawStart < text.Length)
{
sb.Append(text.Substring(rawStart));
}
escapedText = sb.ToString();
}
else
{
// no escaped needed; just use the text as-is
escapedText = text;
}
}
}
finally
{
sb.Release();
}
return delimiter + escapedText + delimiter;
}