// // This method reads a standard quoted string. Departing from the RFC, Unicode is permitted for display-name. // // Preconditions: // - Index must be within the bounds of the data string. // - The char at the given index is the initial quote. (data[index] == Quote) // // Return value: The next index past the terminating-quote (data[index + 1] == Quote). // e.g. In (bob "user name"@domain), starting at index=14 (") returns index=3 (space). // // A FormatException will be thrown if: // - A non-escaped character is encountered that is not valid in a quoted string. // - A Unicode character is encountered and Unicode has not been allowed. // - The final double quote is not found. // internal static int ReadReverseQuoted(string data, int index, bool permitUnicode) { Debug.Assert(0 <= index && index < data.Length, "Index out of range: " + index + ", " + data.Length); // Check for the first bounding quote Debug.Assert(data[index] == MailBnfHelper.Quote, "Initial char at index " + index + " was not a quote."); // Skip the bounding quote index--; do { // Check for valid whitespace index = WhitespaceReader.ReadFwsReverse(data, index); if (index < 0) { break; } // Check for escaped characters int quotedCharCount = QuotedPairReader.CountQuotedChars(data, index, permitUnicode); if (quotedCharCount > 0) { // Skip quoted pairs index = index - quotedCharCount; } // Check for the terminating quote else if (data[index] == MailBnfHelper.Quote) { // Skip the final bounding quote return(index - 1); } // Check invalid characters else if (!IsValidQtext(permitUnicode, data[index])) { throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, data[index])); } // Valid char else { index--; } }while (index >= 0); // We started with a quote, but did not end with one throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, MailBnfHelper.Quote)); }
// // Reads a domain literal in reverse // // Preconditions: // - Index must be within the bounds of the data string. // - The char at the given index is the initial bracket. (data[index] == EndSquareBracket) // // Return value: // - The next index past the terminating bracket (data[index + 1] == StartSquareBracket). // e.g. In (user@[domain]), starting at index=12 (]) returns index=4 (@). // // A FormatException will be thrown if: // - A non-escaped character is encountered that is not valid in a domain literal, including Unicode. // - The final bracket is not found. // internal static int ReadReverse(string data, int index) { Debug.Assert(0 <= index && index < data.Length, "index was outside the bounds of the string: " + index); Debug.Assert(data[index] == MailBnfHelper.EndSquareBracket, "data did not end with a square bracket"); // Skip the end bracket index--; do { // Check for valid whitespace index = WhitespaceReader.ReadFwsReverse(data, index); if (index < 0) { break; } // Check for escaped characters int quotedCharCount = QuotedPairReader.CountQuotedChars(data, index, false); if (quotedCharCount > 0) { // Skip quoted pairs index = index - quotedCharCount; } // Check for the terminating bracket else if (data[index] == MailBnfHelper.StartSquareBracket) { // We're done parsing return(index - 1); } // Check for invalid characters else if (data[index] > MailBnfHelper.Ascii7bitMaxValue || !MailBnfHelper.Dtext[data[index]]) { throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, data[index])); } // Valid char else { index--; } }while (index >= 0); // We didn't find a matching '[', throw. throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, MailBnfHelper.EndSquareBracket)); }
// // This method attempts reading quoted-string formatted data when the bounding quotes were omitted. // This is common for e-mail display-names. // // Precondition: The index must be within the bounds of the data string. // // Return value: // - The index of the special delimiter provided. // e.g. In ([email protected], billy box [email protected]), starting at index=19 (x) returns index=9 (,). // - -1 if the terminating character was not found. // e.g. In (my name username@domain), starting at index=5 (e) returns index=-1. // // A FormatException will be thrown if: // - A non-escaped character is encountered that is not valid in a quoted string. This includes double quotes. // - A Unicode character is encountered and Unicode has not been allowed. // internal static int ReadReverseUnQuoted(string data, int index, bool permitUnicode, bool expectCommaDelimiter) { Debug.Assert(0 <= index && index < data.Length, "Index out of range: " + index + ", " + data.Length); do { // Check for valid whitespace index = WhitespaceReader.ReadFwsReverse(data, index); if (index < 0) { break; } // Check for escaped characters int quotedCharCount = QuotedPairReader.CountQuotedChars(data, index, permitUnicode); if (quotedCharCount > 0) { index = index - quotedCharCount; } // Check for the terminating char else if (expectCommaDelimiter && data[index] == MailBnfHelper.Comma) { break; } // Check invalid characters else if (!IsValidQtext(permitUnicode, data[index])) { throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, data[index])); } // Valid char else { index--; } }while (index >= 0); return(index); }
// This method functions similarly to ReadFwsReverse but will also skip any comments. // // Comments are text within '(' and ')' and may be nested. There may also be consecutive comments. Unicode is // allowed, as the comments are not transmitted. // // This method was explicitly written in a non-recursive fashion to avoid malicious or accidental // stack-overflows from user input. // // Preconditions: // - The data string must not be null or empty // - The index must be within the upper bounds of the data string. // // Return value: // - The given index if it data[index] was not a ')' or white space // - The index of the next non comment or white space character // e.g. " d ( ( c o mment) )" returns index 1 // - -1 if skipping the comments and/or whitespace moves you to the beginning of the data string. // e.g. " (comment) " returns -1 // // Throws a FormatException for mismatched '(' and ')', or for unescaped characters not allowed in comments. internal static int ReadCfwsReverse(string data, int index) { Debug.Assert(!String.IsNullOrEmpty(data), "data was null or empty"); Debug.Assert(index < data.Length, "index was outside the bounds of the string"); int commentDepth = 0; // Check for valid whitespace index = ReadFwsReverse(data, index); while (index >= 0) { // Check for escaped characters. They must be within comments. int quotedCharCount = QuotedPairReader.CountQuotedChars(data, index, true); if (commentDepth > 0 && quotedCharCount > 0) { index = index - quotedCharCount; } // Start a new comment else if (data[index] == MailBnfHelper.EndComment) { commentDepth++; index--; } // Finish a comment else if (data[index] == MailBnfHelper.StartComment) { commentDepth--; if (commentDepth < 0) { // Mismatched '(' throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, MailBnfHelper.StartComment)); } index--; } // Check for valid characters within comments. Allow Unicode, as we won't transmit any comments. else if (commentDepth > 0 && (data[index] > MailBnfHelper.Ascii7bitMaxValue || MailBnfHelper.Ctext[data[index]])) { index--; } // If we're still in a comment, this must be an invalid char else if (commentDepth > 0) { throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, data[index])); } // We must no longer be in a comment, and this is not a whitespace char, return else { break; } // Check for valid whitespace index = ReadFwsReverse(data, index); } if (commentDepth > 0) { // Mismatched ')', throw throw new FormatException(string.Format(SR.MailHeaderFieldInvalidCharacter, MailBnfHelper.EndComment)); } return(index); }