/// <summary> /// Decodes a Quoted-Printable string according to <a href="http://tools.ietf.org/html/rfc2047">RFC 2047</a>.<br /> /// RFC 2047 is used for decoding Encoded-Word encoded strings. /// </summary> /// <param name="toDecode">Quoted-Printable encoded string</param> /// <param name="encoding">Specifies which encoding the returned string will be in</param> /// <returns>A decoded string in the correct encoding</returns> /// <exception cref="T:System.ArgumentNullException">If <paramref name="toDecode" /> or <paramref name="encoding" /> is <see langword="null" /></exception> public static string DecodeEncodedWord(string toDecode, Encoding encoding) { if (toDecode == null) { throw new ArgumentNullException("toDecode"); } if (encoding == null) { throw new ArgumentNullException("encoding"); } return(encoding.GetString(QuotedPrintable.Rfc2047QuotedPrintableDecode(toDecode, true))); }
public static string Decode(string encodedWords) { if (encodedWords == null) { throw new ArgumentNullException("encodedWords"); } const string encodedWordRegex = @"\=\?(?<Charset>\S+?)\?(?<Encoding>\w)\?(?<Content>.+?)\?\="; const string replaceRegex = @"(?<first>" + encodedWordRegex + @")\s+(?<second>" + encodedWordRegex + ")"; encodedWords = Regex.Replace(encodedWords, replaceRegex, "${first}${second}"); encodedWords = Regex.Replace(encodedWords, replaceRegex, "${first}${second}"); string decodedWords = encodedWords; MatchCollection matches = Regex.Matches(encodedWords, encodedWordRegex); foreach (Match match in matches) { if (!match.Success) { continue; } string fullMatchValue = match.Value; string encodedText = match.Groups["Content"].Value; string encoding = match.Groups["Encoding"].Value; string charset = match.Groups["Charset"].Value; Encoding charsetEncoding = EncodingFinder.FindEncoding(charset); string decodedText; switch (encoding.ToUpperInvariant()) { case "B": decodedText = Base64Decode(encodedText, charsetEncoding); break; case "Q": decodedText = QuotedPrintable.DecodeEncodedWord(encodedText, charsetEncoding); break; default: throw new ArgumentException("The encoding " + encoding + " was not recognized"); } decodedWords = decodedWords.Replace(fullMatchValue, decodedText); } return(decodedWords); }
/// <summary> /// This is the actual decoder. /// </summary> /// <param name="toDecode">The string to be decoded from Quoted-Printable</param> /// <param name="encodedWordVariant"> /// If <see langword="true" />, specifies that RFC 2047 quoted printable decoding is used.<br /> /// This is for quoted-printable encoded words<br /> /// <br /> /// If <see langword="false" />, specifies that RFC 2045 quoted printable decoding is used.<br /> /// This is for quoted-printable Content-Transfer-Encoding /// </param> /// <returns>A decoded byte array that was described by <paramref name="toDecode" /></returns> /// <exception cref="T:System.ArgumentNullException">If <paramref name="toDecode" /> is <see langword="null" /></exception> /// <remarks>See <a href="http://tools.ietf.org/html/rfc2047#section-4.2">RFC 2047 section 4.2</a> for RFC details</remarks> private static byte[] Rfc2047QuotedPrintableDecode(string toDecode, bool encodedWordVariant) { if (toDecode == null) { throw new ArgumentNullException("toDecode"); } byte[] result; using (MemoryStream byteArrayBuilder = new MemoryStream()) { toDecode = QuotedPrintable.RemoveIllegalControlCharacters(toDecode); for (int i = 0; i < toDecode.Length; i++) { char currentChar = toDecode[i]; if (currentChar == '=') { if (toDecode.Length - i < 3) { QuotedPrintable.WriteAllBytesToStream(byteArrayBuilder, QuotedPrintable.DecodeEqualSignNotLongEnough(toDecode.Substring(i))); break; } string quotedPrintablePart = toDecode.Substring(i, 3); QuotedPrintable.WriteAllBytesToStream(byteArrayBuilder, QuotedPrintable.DecodeEqualSign(quotedPrintablePart)); i += 2; } else if (currentChar == '_' && encodedWordVariant) { byteArrayBuilder.WriteByte(32); } else { byteArrayBuilder.WriteByte((byte)currentChar); } } result = byteArrayBuilder.ToArray(); } return(result); }