public unsafe String Decode(Byte *start, Byte *end) { var current = start; //Used for not encoded text. var buffer = new Byte[end - current]; Int32 index = 0; Byte *rfc2047Start = null; Byte *rfc2047Current = null; Rfc2047ParsingState state = Rfc2047ParsingState.NotParsing; Encoding charset = null; Rfc2047Encoding? encoding = null; Int32 whiteSpaceCount = 0; StringBuilder sb = new StringBuilder(buffer.Length); var cx = new ParseContextData(_Base64Converter, _QuotedPrintableHeaderConverter); while (current < end) { switch (state) { case Rfc2047ParsingState.NotParsing: #region if (*current == '=') { state = Rfc2047ParsingState.Start; rfc2047Start = current; } break; #endregion case Rfc2047ParsingState.Start: #region if (*current == '?') { state = Rfc2047ParsingState.Charset; rfc2047Current = current + 1; } else { state = Rfc2047ParsingState.NotParsing; } break; #endregion case Rfc2047ParsingState.Charset: #region if (*current == '?') { var bb = CreateNewBytes(new IntPtr(rfc2047Current), current - rfc2047Current); charset = EncodingDictionary.Current.GetEncoding(this.Encoding.GetString(bb)); if (charset == null) { state = Rfc2047ParsingState.NotParsing; rfc2047Current = null; } else { state = Rfc2047ParsingState.BorQ; rfc2047Current = current + 1; } } break; #endregion case Rfc2047ParsingState.BorQ: #region if (*current == '?') { var bb = CreateNewBytes(new IntPtr(rfc2047Current), current - rfc2047Current); var BorQ = this.Encoding.GetString(bb).ToUpper(); if (BorQ == "B" || BorQ == "Q") { switch (BorQ) { case "B": encoding = Rfc2047Encoding.Base64; break; case "Q": encoding = Rfc2047Encoding.QuotedPrintable; break; default: throw new InvalidOperationException(); } state = Rfc2047ParsingState.Value; rfc2047Current = current + 1; } else { state = Rfc2047ParsingState.NotParsing; rfc2047Current = null; } } break; #endregion case Rfc2047ParsingState.Value: #region if (*current == '?') { state = Rfc2047ParsingState.ValueEnd; } break; #endregion case Rfc2047ParsingState.ValueEnd: #region if (*current == '=') { if (index > 0) { sb.Append(cx.Decode()); cx.Clear(); sb.Append(this.Encoding.GetString(buffer.Take(index).ToArray())); index = 0; } var bb = CreateNewBytes(new IntPtr(rfc2047Current), current - rfc2047Current - 1); if (cx.Encoding != encoding || cx.Charset != charset) { sb.Append(cx.Decode()); cx.Clear(); } else { var text = cx.Decode(); if (text[text.Length - 1] == '�') { //Invalid encoding.Maybe encoder devide middle of 2byte char. //Concat current line and next line. } else { sb.Append(cx.Decode()); cx.Clear(); } } cx.Add(encoding.Value, charset, bb); rfc2047Start = null; rfc2047Current = null; whiteSpaceCount = 0; state = Rfc2047ParsingState.End; } else { state = Rfc2047ParsingState.NotParsing; } break; #endregion case Rfc2047ParsingState.End: state = Rfc2047ParsingState.NotParsing; break; default: break; } if (state == Rfc2047ParsingState.NotParsing) { #region Add text that is invalid format like "=?Charset?S" if (rfc2047Start != null) { this.AddChar(buffer, ref index, whiteSpaceCount); whiteSpaceCount = -1; var length = current - rfc2047Start; for (int i = 0; i < length; i++) { buffer[index++] = *rfc2047Start; rfc2047Start++; } rfc2047Start = null; } #endregion #region if (*current == (Byte)'=') { continue; } if (*current == (Byte)' ') { if (whiteSpaceCount > -1) { whiteSpaceCount++; } else { buffer[index++] = (Byte)' '; } } else if (*current != (Byte)'\r' && *current != (Byte)'\n' && *current != (Byte)'\t') { this.AddChar(buffer, ref index, whiteSpaceCount); whiteSpaceCount = -1; buffer[index++] = *current; } #endregion } current++; } if (cx.HasData()) { sb.Append(cx.Decode()); } sb.Append(this.Encoding.GetString(buffer.Take(index).ToArray())); return(sb.ToString()); }
public unsafe String Decode(Byte *start, Byte *end) { var current = start; var buffer = new Byte[end - current]; Int32 index = 0; Byte *rfc2047Start = null; Byte *rfc2047Current = null; Rfc2047ParsingState state = Rfc2047ParsingState.NotPasing; Encoding charset = null; Rfc2047Encoding? encoding = null; Int32 whiteSpaceCount = 0; StringBuilder sb = new StringBuilder(buffer.Length); while (current < end) { switch (state) { case Rfc2047ParsingState.NotPasing: #region if (*current == '=') { state = Rfc2047ParsingState.Start; rfc2047Start = current; } break; #endregion case Rfc2047ParsingState.Start: #region if (*current == '?') { state = Rfc2047ParsingState.Charset; rfc2047Current = current + 1; } else { state = Rfc2047ParsingState.NotPasing; } break; #endregion case Rfc2047ParsingState.Charset: #region if (*current == '?') { var bb = CreateNewBytes(new IntPtr(rfc2047Current), current - rfc2047Current); charset = EncodingDictionary.Current.GetEncoding(this.Encoding.GetString(bb)); if (charset == null) { state = Rfc2047ParsingState.NotPasing; rfc2047Current = null; } else { state = Rfc2047ParsingState.BorQ; rfc2047Current = current + 1; } } break; #endregion case Rfc2047ParsingState.BorQ: #region if (*current == '?') { var bb = CreateNewBytes(new IntPtr(rfc2047Current), current - rfc2047Current); var BorQ = this.Encoding.GetString(bb).ToUpper(); if (BorQ == "B" || BorQ == "Q") { switch (BorQ) { case "B": encoding = Rfc2047Encoding.Base64; break; case "Q": encoding = Rfc2047Encoding.QuotedPrintable; break; default: throw new InvalidOperationException(); } state = Rfc2047ParsingState.Value; rfc2047Current = current + 1; } else { state = Rfc2047ParsingState.NotPasing; rfc2047Current = null; } } break; #endregion case Rfc2047ParsingState.Value: #region if (*current == '?') { state = Rfc2047ParsingState.ValueEnd; } break; #endregion case Rfc2047ParsingState.ValueEnd: #region if (*current == '=') { sb.Append(this.Encoding.GetString(buffer.Take(index).ToArray())); index = 0; var bb = CreateNewBytes(new IntPtr(rfc2047Current), current - rfc2047Current - 1); switch (encoding) { case Rfc2047Encoding.Base64: sb.Append(charset.GetString(_Base64Converter.Decode(bb))); break; case Rfc2047Encoding.QuotedPrintable: sb.Append(charset.GetString(_QuotedPrintableHeaderConverter.Decode(bb))); break; default: throw new InvalidOperationException(); } rfc2047Start = null; rfc2047Current = null; whiteSpaceCount = 0; state = Rfc2047ParsingState.End; } else { state = Rfc2047ParsingState.NotPasing; } break; #endregion case Rfc2047ParsingState.End: state = Rfc2047ParsingState.NotPasing; break; default: break; } if (state == Rfc2047ParsingState.NotPasing) { #region Add text that is invalid format like "=?Charset?S" if (rfc2047Start != null) { this.AddChar(buffer, (Byte)' ', ref index, whiteSpaceCount); whiteSpaceCount = -1; var length = current - rfc2047Start; for (int i = 0; i < length; i++) { buffer[index++] = *rfc2047Start; rfc2047Start++; } rfc2047Start = null; } #endregion #region if (*current == (Byte)' ') { if (whiteSpaceCount > -1) { whiteSpaceCount++; } else { buffer[index++] = (Byte)' '; } } else if (*current != (Byte)'\r' && *current != (Byte)'\n' && *current != (Byte)'\t') { this.AddChar(buffer, (Byte)' ', ref index, whiteSpaceCount); whiteSpaceCount = -1; buffer[index++] = *current; } #endregion } current++; } sb.Append(this.Encoding.GetString(buffer.Take(index).ToArray())); return(sb.ToString()); }