private static void EncodePhraseTextInternal( string str, int index, int endIndex, IList<int[]> tokens, StringBuilder builder) { // Assumes the value matches the production "phrase" // and that there are no comments in the value if (index == endIndex) { return; // Empty, so nothing to do } int index2 = HeaderParser.ParseCFWS(str, index, endIndex, null); if (index2 == endIndex) { // Just linear whitespace builder.Append(str.Substring(index, endIndex - index)); return; } if (!PrecededByStartOrLinearWhitespace(str, index2)) { // Append a space before the encoded words builder.Append(' '); } else { // Append the linear whitespace builder.Append(str.Substring(index, index2 - index)); } var encoder = new EncodedWordEncoder(); var builderPhrase = new StringBuilder(); index = index2; while (index < endIndex) { if (str[index] == '"') { // Quoted string index = MediaType.skipQuotedString( str, index, endIndex, builderPhrase); } else { // Atom index2 = HeaderParser.ParsePhraseAtomOrDot( str, index, endIndex, null); builderPhrase.Append(str.Substring(index, index2 - index)); index = index2; } index2 = HeaderParser.ParseFWS(str, index, endIndex, null); if (index2 == endIndex) { encoder.AddString(builderPhrase.ToString()); encoder.FinalizeEncoding(); builder.Append(encoder.ToString()); if (index2 != index) { builder.Append(str.Substring(index, index2 - index)); } else if (!FollowedByEndOrLinearWhitespace( str, endIndex, str.Length)) { // Add a space if no linear whitespace follows builder.Append(' '); } break; } if (index2 != index) { builderPhrase.Append(' '); } index = index2; } }
public static string EncodeComment(string str, int index, int endIndex) { // NOTE: Assumes that the comment is syntactically valid #if DEBUG if (str == null) { throw new ArgumentNullException("str"); } if (index < 0) { throw new ArgumentException("index (" + index + ") is less than " + "0"); } if (index > str.Length) { throw new ArgumentException("index (" + index + ") is more than " + str.Length); } if (endIndex < 0) { throw new ArgumentException("endIndex (" + endIndex + ") is less than " + "0"); } if (endIndex > str.Length) { throw new ArgumentException("endIndex (" + endIndex + ") is more than " + str.Length); } #endif int length = endIndex - index; if (length < 2 || str[index] != '(' || str[endIndex - 1] != ')') { return str.Substring(index, length); } EncodedWordEncoder encoder; int nextComment = str.IndexOf('(', index + 1); int nextBackslash = str.IndexOf('\\', index + 1); // don't count comments or backslashes beyond // the desired portion if (nextComment >= endIndex) { nextComment = -1; } if (nextBackslash >= endIndex) { nextBackslash = -1; } bool haveEscape = nextBackslash >= 0; if (!haveEscape) { // Check for possible folding whitespace nextBackslash = str.IndexOf('\n', index + 1); if (nextBackslash >= endIndex) { nextBackslash = -1; } haveEscape = nextBackslash >= 0; } if (nextComment < 0 && nextBackslash < 0) { // No escapes or nested comments, so it's relatively easy if (length == 2) { return "()"; } encoder = new EncodedWordEncoder(); encoder.AddPrefix("("); encoder.AddString(str, index + 1, length - 2); encoder.FinalizeEncoding(")"); return encoder.ToString(); } if (nextBackslash < 0) { // No escapes; just look for '(' and ')' encoder = new EncodedWordEncoder(); while (true) { int parenStart = index; // Get the next run of parentheses while (index < endIndex) { if (str[index] == '(' || str[index] == ')') { ++index; } else { break; } } // Get the next run of non-parentheses int parenEnd = index; while (index < endIndex) { if (str[index] == '(' || str[index] == ')') { break; } ++index; } if (parenEnd == index) { encoder.FinalizeEncoding( str.Substring( parenStart, parenEnd - parenStart)); break; } encoder.AddPrefix(str.Substring(parenStart, parenEnd - parenStart)); encoder.AddString(str, parenEnd, index - parenEnd); } return encoder.ToString(); } var builder = new StringBuilder(); // escapes, but no nested comments if (nextComment < 0) { // skip the first parenthesis ++index; while (index < endIndex) { if (str[index] == ')') { // End of the comment break; } if (str[index] == '\r' && index + 2 < endIndex && str[index + 1] == '\n' && (str[index + 2] == 0x20 || str[index + 2] == 0x09)) { // Folding whitespace builder.Append(str[index + 2]); index += 3; } else if (str[index] == '\\' && index + 1 < endIndex) { // Quoted pair int cp = DataUtilities.CodePointAt(str, index + 1); if (cp <= 0xffff) { { builder.Append((char)cp); } } else if (cp <= 0x10ffff) { builder.Append((char)((((cp - 0x10000) >> 10) & 0x3ff) + 0xd800)); builder.Append((char)(((cp - 0x10000) & 0x3ff) + 0xdc00)); } index += 1 + (cp >= 0x10000 ? 2 : 1); } else { // Other comment text builder.Append(str[index]); ++index; } } if (builder.Length == 0) { return "()"; } encoder = new EncodedWordEncoder(); encoder.AddPrefix("("); encoder.AddString(builder.ToString()); encoder.FinalizeEncoding(")"); return encoder.ToString(); } // escapes and nested comments encoder = new EncodedWordEncoder(); while (true) { int parenStart = index; // Get the next run of parentheses while (index < endIndex) { if (str[index] == '(' || str[index] == ')') { ++index; } else { break; } } // Get the next run of non-parentheses int parenEnd = index; builder.Remove(0, builder.Length); while (index < endIndex) { if (str[index] == '(' || str[index] == ')') { break; } if (str[index] == '\r' && index + 2 < endIndex && str[index + 1] == '\n' && (str[index + 2] == 0x20 || str[index + 2] == 0x09)) { // Folding whitespace builder.Append(str[index + 2]); index += 3; } else if (str[index] == '\\' && index + 1 < endIndex) { // Quoted pair int cp = DataUtilities.CodePointAt(str, index + 1); if (cp <= 0xffff) { builder.Append((char)cp); } else if (cp <= 0x10ffff) { builder.Append((char)((((cp - 0x10000) >> 10) & 0x3ff) + 0xd800)); builder.Append((char)(((cp - 0x10000) & 0x3ff) + 0xdc00)); } index += 1 + (cp >= 0x10000 ? 2 : 1); } else { // Other comment text builder.Append(str[index]); ++index; } } if (builder.Length == 0) { encoder.FinalizeEncoding( str.Substring( parenStart, parenEnd - parenStart)); break; } encoder.AddPrefix(str.Substring(parenStart, parenEnd - parenStart)); encoder.AddString(builder.ToString()); } return encoder.ToString(); }